@uniweb/runtime 0.1.2 → 0.2.1
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 +48 -171
- package/package.json +8 -20
- package/src/index.jsx +27 -44
- package/src/components/Link.jsx +0 -28
- package/src/components/SafeHtml.jsx +0 -22
- package/src/core/block.js +0 -311
- package/src/core/input.js +0 -15
- package/src/core/page.js +0 -75
- package/src/core/uniweb.js +0 -103
- package/src/core/website.js +0 -157
- package/src/vite/content-collector.js +0 -269
- package/src/vite/foundation-plugin.js +0 -194
- package/src/vite/index.js +0 -7
- package/src/vite/site-content-plugin.js +0 -135
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# @uniweb/runtime
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Minimal runtime for loading Uniweb foundations and orchestrating rendering.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
This package provides the runtime
|
|
7
|
+
This package provides the browser-side runtime for Uniweb sites. It loads foundations dynamically and renders content using React Router.
|
|
8
|
+
|
|
9
|
+
For Vite build plugins, see [`@uniweb/build`](https://github.com/uniweb/build).
|
|
8
10
|
|
|
9
11
|
## Installation
|
|
10
12
|
|
|
@@ -12,13 +14,6 @@ This package provides the runtime environment for Uniweb sites—content-driven
|
|
|
12
14
|
npm install @uniweb/runtime
|
|
13
15
|
```
|
|
14
16
|
|
|
15
|
-
## Features
|
|
16
|
-
|
|
17
|
-
- **Foundation Loading** - Load Foundations via dynamic import or import maps
|
|
18
|
-
- **Content Rendering** - Render pages from structured content (JSON/YAML)
|
|
19
|
-
- **Vite Plugins** - Collect site content and serve foundations in development
|
|
20
|
-
- **React Integration** - Built on React with React Router for navigation
|
|
21
|
-
|
|
22
17
|
## Usage
|
|
23
18
|
|
|
24
19
|
### Runtime Loading
|
|
@@ -26,7 +21,7 @@ npm install @uniweb/runtime
|
|
|
26
21
|
Initialize the runtime with a Foundation URL:
|
|
27
22
|
|
|
28
23
|
```jsx
|
|
29
|
-
import
|
|
24
|
+
import initRuntime from '@uniweb/runtime'
|
|
30
25
|
|
|
31
26
|
// Load foundation from URL
|
|
32
27
|
initRuntime('/foundation/foundation.js', {
|
|
@@ -40,194 +35,76 @@ initRuntime({
|
|
|
40
35
|
})
|
|
41
36
|
```
|
|
42
37
|
|
|
43
|
-
###
|
|
44
|
-
|
|
45
|
-
Use the Vite plugins to collect content and optionally serve a foundation:
|
|
46
|
-
|
|
47
|
-
```js
|
|
48
|
-
// vite.config.js
|
|
49
|
-
import { defineConfig } from 'vite'
|
|
50
|
-
import react from '@vitejs/plugin-react'
|
|
51
|
-
import { siteContentPlugin, foundationPlugin } from '@uniweb/runtime/vite'
|
|
52
|
-
|
|
53
|
-
export default defineConfig({
|
|
54
|
-
plugins: [
|
|
55
|
-
react(),
|
|
56
|
-
|
|
57
|
-
// Collect content from pages/ directory
|
|
58
|
-
siteContentPlugin({
|
|
59
|
-
sitePath: './',
|
|
60
|
-
inject: true, // Inject into HTML
|
|
61
|
-
}),
|
|
62
|
-
|
|
63
|
-
// Optional: Serve foundation in dev mode
|
|
64
|
-
foundationPlugin({
|
|
65
|
-
name: 'my-foundation',
|
|
66
|
-
path: '../my-foundation',
|
|
67
|
-
serve: '/foundation',
|
|
68
|
-
}),
|
|
69
|
-
]
|
|
70
|
-
})
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Site Content Structure
|
|
74
|
-
|
|
75
|
-
Sites use a pages/ directory structure:
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
site/
|
|
79
|
-
├── site.yml # Site configuration
|
|
80
|
-
├── theme.yml # Theme configuration
|
|
81
|
-
└── pages/
|
|
82
|
-
├── @header/ # Special: header section
|
|
83
|
-
│ └── 1.md
|
|
84
|
-
├── @footer/ # Special: footer section
|
|
85
|
-
│ └── 1.md
|
|
86
|
-
├── home/ # Home page (route: /)
|
|
87
|
-
│ ├── page.yml # Page metadata
|
|
88
|
-
│ ├── 1.md # First section
|
|
89
|
-
│ └── 2.md # Second section
|
|
90
|
-
└── about/ # About page (route: /about)
|
|
91
|
-
├── page.yml
|
|
92
|
-
└── 1.md
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Section Markdown Format
|
|
96
|
-
|
|
97
|
-
Each `.md` file is a section with YAML frontmatter for configuration and markdown body for content:
|
|
98
|
-
|
|
99
|
-
```markdown
|
|
100
|
-
---
|
|
101
|
-
component: Hero
|
|
102
|
-
preset: default
|
|
103
|
-
theme: dark
|
|
104
|
-
---
|
|
38
|
+
### Static Bundling
|
|
105
39
|
|
|
106
|
-
|
|
40
|
+
Foundation imported directly and bundled with the site:
|
|
107
41
|
|
|
108
|
-
|
|
42
|
+
```jsx
|
|
43
|
+
import * as Foundation from '@my-org/my-foundation'
|
|
44
|
+
import initRuntime from '@uniweb/runtime'
|
|
109
45
|
|
|
110
|
-
|
|
46
|
+
initRuntime(Foundation)
|
|
111
47
|
```
|
|
112
48
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
## API Reference
|
|
116
|
-
|
|
117
|
-
### Runtime Functions
|
|
118
|
-
|
|
119
|
-
| Function | Description |
|
|
120
|
-
|----------|-------------|
|
|
121
|
-
| `initRuntime(source, options)` | Initialize runtime with foundation |
|
|
122
|
-
| `initRTE(source, options)` | Alias for initRuntime |
|
|
123
|
-
|
|
124
|
-
### Exported Components
|
|
125
|
-
|
|
126
|
-
| Component | Description |
|
|
127
|
-
|-----------|-------------|
|
|
128
|
-
| `Link` | Router-aware link component |
|
|
129
|
-
| `SafeHtml` | Safe HTML rendering |
|
|
130
|
-
| `ChildBlocks` | Render child sections |
|
|
131
|
-
| `ErrorBoundary` | Error boundary wrapper |
|
|
132
|
-
|
|
133
|
-
### Vite Plugins
|
|
49
|
+
## API
|
|
134
50
|
|
|
135
|
-
|
|
136
|
-
|--------|-------------|
|
|
137
|
-
| `siteContentPlugin(options)` | Collect and inject site content |
|
|
138
|
-
| `foundationPlugin(options)` | Build and serve foundation in dev |
|
|
139
|
-
| `collectSiteContent(sitePath)` | Programmatic content collection |
|
|
51
|
+
### initRuntime(source, options)
|
|
140
52
|
|
|
141
|
-
|
|
53
|
+
Initialize the runtime with a foundation.
|
|
142
54
|
|
|
143
|
-
**
|
|
144
|
-
|
|
145
|
-
{
|
|
146
|
-
|
|
147
|
-
pagesDir: 'pages', // Pages subdirectory
|
|
148
|
-
inject: true, // Inject into HTML
|
|
149
|
-
filename: 'site-content.json', // Output filename
|
|
150
|
-
watch: true // Watch for changes (dev)
|
|
151
|
-
}
|
|
152
|
-
```
|
|
55
|
+
**source** - One of:
|
|
56
|
+
- URL string to foundation module
|
|
57
|
+
- Object with `{ url, cssUrl }`
|
|
58
|
+
- Foundation module object (for static bundling)
|
|
153
59
|
|
|
154
|
-
**
|
|
60
|
+
**options:**
|
|
155
61
|
```js
|
|
156
62
|
{
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
watch: true, // Watch for changes
|
|
161
|
-
buildOnStart: true // Build when dev server starts
|
|
63
|
+
development: false, // Enable dev mode (StrictMode, verbose errors)
|
|
64
|
+
configData: null, // Site content (or reads from DOM)
|
|
65
|
+
basename: undefined // React Router basename
|
|
162
66
|
}
|
|
163
67
|
```
|
|
164
68
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
### Uniweb
|
|
168
|
-
|
|
169
|
-
The main runtime instance (available as `globalThis.uniweb`):
|
|
170
|
-
|
|
171
|
-
```js
|
|
172
|
-
uniweb.getComponent(name) // Get component from foundation
|
|
173
|
-
uniweb.listComponents() // List available components
|
|
174
|
-
uniweb.activeWebsite // Current website instance
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Website
|
|
69
|
+
For core classes (`Uniweb`, `Website`, `Block`, etc.), import from [`@uniweb/core`](https://github.com/uniweb/core).
|
|
178
70
|
|
|
179
|
-
|
|
71
|
+
## Architecture
|
|
180
72
|
|
|
181
|
-
```js
|
|
182
|
-
website.getPage(route) // Get page by route
|
|
183
|
-
website.setActivePage(route) // Navigate to page
|
|
184
|
-
website.localize(value) // Localize a value
|
|
185
|
-
website.getLanguage() // Get current language
|
|
186
73
|
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
```js
|
|
193
|
-
block.initComponent() // Initialize foundation component
|
|
194
|
-
block.getBlockContent() // Get structured content
|
|
195
|
-
block.getBlockProperties() // Get configuration properties
|
|
196
|
-
block.getBlockLinks() // Get links from content
|
|
74
|
+
@uniweb/runtime (browser)
|
|
75
|
+
│
|
|
76
|
+
├── Loads foundation dynamically
|
|
77
|
+
├── Creates Uniweb instance via @uniweb/core
|
|
78
|
+
└── Orchestrates React/Router rendering
|
|
197
79
|
```
|
|
198
80
|
|
|
199
|
-
|
|
81
|
+
Foundations should:
|
|
82
|
+
- Import components from `@uniweb/kit` (bundled)
|
|
83
|
+
- Mark `@uniweb/core` as external (provided by runtime)
|
|
200
84
|
|
|
201
|
-
|
|
85
|
+
## Build Plugins
|
|
202
86
|
|
|
203
|
-
|
|
87
|
+
Vite plugins have moved to `@uniweb/build`:
|
|
204
88
|
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
"react": "https://esm.sh/react@18",
|
|
210
|
-
"react-dom": "https://esm.sh/react-dom@18"
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
</script>
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Static Bundling
|
|
217
|
-
|
|
218
|
-
Foundation imported directly and bundled with the site.
|
|
219
|
-
|
|
220
|
-
```jsx
|
|
221
|
-
import * as Foundation from '@my-org/my-foundation'
|
|
222
|
-
import { initRuntime } from '@uniweb/runtime'
|
|
89
|
+
```js
|
|
90
|
+
// vite.config.js
|
|
91
|
+
import { siteContentPlugin } from '@uniweb/build/site'
|
|
92
|
+
import { foundationDevPlugin } from '@uniweb/build/dev'
|
|
223
93
|
|
|
224
|
-
|
|
94
|
+
export default defineConfig({
|
|
95
|
+
plugins: [
|
|
96
|
+
siteContentPlugin({ sitePath: './', inject: true }),
|
|
97
|
+
foundationDevPlugin({ path: '../foundation', serve: '/foundation' }),
|
|
98
|
+
]
|
|
99
|
+
})
|
|
225
100
|
```
|
|
226
101
|
|
|
227
102
|
## Related Packages
|
|
228
103
|
|
|
229
|
-
- [
|
|
230
|
-
- [`@uniweb/
|
|
104
|
+
- [`@uniweb/core`](https://github.com/uniweb/core) - Core classes (Uniweb, Website, Block)
|
|
105
|
+
- [`@uniweb/kit`](https://github.com/uniweb/kit) - Component library for foundations
|
|
106
|
+
- [`@uniweb/build`](https://github.com/uniweb/build) - Vite build plugins
|
|
107
|
+
- [`uniweb`](https://github.com/uniweb/cli) - CLI for creating projects
|
|
231
108
|
|
|
232
109
|
## License
|
|
233
110
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/runtime",
|
|
3
|
-
"version": "0.1
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Minimal runtime for loading Uniweb foundations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
|
-
".": "./src/index.jsx"
|
|
8
|
-
"./vite": "./src/vite/index.js"
|
|
7
|
+
".": "./src/index.jsx"
|
|
9
8
|
},
|
|
10
9
|
"files": [
|
|
11
10
|
"src"
|
|
@@ -13,9 +12,8 @@
|
|
|
13
12
|
"keywords": [
|
|
14
13
|
"uniweb",
|
|
15
14
|
"runtime",
|
|
16
|
-
"vite",
|
|
17
15
|
"react",
|
|
18
|
-
"
|
|
16
|
+
"foundation"
|
|
19
17
|
],
|
|
20
18
|
"author": "Proximify",
|
|
21
19
|
"license": "Apache-2.0",
|
|
@@ -31,21 +29,11 @@
|
|
|
31
29
|
"node": ">=20.19"
|
|
32
30
|
},
|
|
33
31
|
"dependencies": {
|
|
34
|
-
"
|
|
35
|
-
"@uniweb/semantic-parser": "1.0.1"
|
|
32
|
+
"@uniweb/core": "0.1.2"
|
|
36
33
|
},
|
|
37
34
|
"peerDependencies": {
|
|
38
|
-
"react": "^18.0.0",
|
|
39
|
-
"react-dom": "^18.0.0",
|
|
40
|
-
"react-router-dom": "^6.0.0 || ^7.0.0"
|
|
41
|
-
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
|
|
42
|
-
},
|
|
43
|
-
"peerDependenciesMeta": {
|
|
44
|
-
"vite": {
|
|
45
|
-
"optional": true
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
"optionalDependencies": {
|
|
49
|
-
"@uniweb/content-reader": "1.0.1"
|
|
35
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
36
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
37
|
+
"react-router-dom": "^6.0.0 || ^7.0.0"
|
|
50
38
|
}
|
|
51
39
|
}
|
package/src/index.jsx
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @uniweb/runtime - Main Entry Point
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Minimal runtime for loading foundations and orchestrating rendering.
|
|
5
|
+
* Foundations should import components from @uniweb/kit.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React from 'react'
|
|
9
9
|
import { createRoot } from 'react-dom/client'
|
|
10
|
-
import { BrowserRouter, Routes, Route
|
|
10
|
+
import { BrowserRouter, Routes, Route } from 'react-router-dom'
|
|
11
11
|
|
|
12
12
|
// Components
|
|
13
13
|
import { ChildBlocks } from './components/PageRenderer.jsx'
|
|
14
|
-
import Link from './components/Link.jsx'
|
|
15
|
-
import SafeHtml from './components/SafeHtml.jsx'
|
|
16
14
|
import WebsiteRenderer from './components/WebsiteRenderer.jsx'
|
|
17
15
|
import ErrorBoundary from './components/ErrorBoundary.jsx'
|
|
18
16
|
|
|
19
|
-
// Core
|
|
20
|
-
import
|
|
17
|
+
// Core factory from @uniweb/core
|
|
18
|
+
import { createUniweb } from '@uniweb/core'
|
|
21
19
|
|
|
22
20
|
/**
|
|
23
21
|
* Load foundation CSS from URL
|
|
@@ -60,8 +58,10 @@ async function loadFoundation(source) {
|
|
|
60
58
|
import(/* @vite-ignore */ url)
|
|
61
59
|
])
|
|
62
60
|
|
|
63
|
-
console.log(
|
|
64
|
-
|
|
61
|
+
console.log(
|
|
62
|
+
'[Runtime] Foundation loaded. Available components:',
|
|
63
|
+
typeof foundation.listComponents === 'function' ? foundation.listComponents() : 'unknown'
|
|
64
|
+
)
|
|
65
65
|
|
|
66
66
|
return foundation
|
|
67
67
|
} catch (error) {
|
|
@@ -76,23 +76,12 @@ async function loadFoundation(source) {
|
|
|
76
76
|
* @returns {Uniweb}
|
|
77
77
|
*/
|
|
78
78
|
function initUniweb(configData) {
|
|
79
|
-
|
|
79
|
+
// Create singleton via @uniweb/core (also assigns to globalThis.uniweb)
|
|
80
|
+
const uniwebInstance = createUniweb(configData)
|
|
80
81
|
|
|
81
|
-
//
|
|
82
|
-
globalThis.uniweb = uniwebInstance
|
|
83
|
-
|
|
84
|
-
// Set up child block renderer
|
|
82
|
+
// Set up child block renderer for nested blocks
|
|
85
83
|
uniwebInstance.childBlockRenderer = ChildBlocks
|
|
86
84
|
|
|
87
|
-
// Set up routing components for foundation components to use
|
|
88
|
-
uniwebInstance.routingComponents = {
|
|
89
|
-
Link,
|
|
90
|
-
SafeHtml,
|
|
91
|
-
useNavigate,
|
|
92
|
-
useParams,
|
|
93
|
-
useLocation
|
|
94
|
-
}
|
|
95
|
-
|
|
96
85
|
return uniwebInstance
|
|
97
86
|
}
|
|
98
87
|
|
|
@@ -149,9 +138,10 @@ async function initRuntime(foundationSource, options = {}) {
|
|
|
149
138
|
} = options
|
|
150
139
|
|
|
151
140
|
// Get config data from options, DOM, or global
|
|
152
|
-
const configData =
|
|
153
|
-
??
|
|
154
|
-
|
|
141
|
+
const configData =
|
|
142
|
+
providedConfig ??
|
|
143
|
+
JSON.parse(document.getElementById('__SITE_CONTENT__')?.textContent || 'null') ??
|
|
144
|
+
globalThis.__SITE_CONTENT__
|
|
155
145
|
|
|
156
146
|
if (!configData) {
|
|
157
147
|
console.error('[Runtime] No site configuration found')
|
|
@@ -205,7 +195,7 @@ async function initRuntime(foundationSource, options = {}) {
|
|
|
205
195
|
'%c<%c>%c Uniweb Runtime',
|
|
206
196
|
'color: #FA8400; font-weight: bold; font-size: 18px;',
|
|
207
197
|
'color: #00ADFE; font-weight: bold; font-size: 18px;',
|
|
208
|
-
|
|
198
|
+
'color: #333; font-size: 18px; font-family: system-ui, sans-serif;'
|
|
209
199
|
)
|
|
210
200
|
}
|
|
211
201
|
} catch (error) {
|
|
@@ -216,7 +206,15 @@ async function initRuntime(foundationSource, options = {}) {
|
|
|
216
206
|
if (container) {
|
|
217
207
|
const root = createRoot(container)
|
|
218
208
|
root.render(
|
|
219
|
-
<div
|
|
209
|
+
<div
|
|
210
|
+
style={{
|
|
211
|
+
padding: '2rem',
|
|
212
|
+
margin: '1rem',
|
|
213
|
+
background: '#fef2f2',
|
|
214
|
+
borderRadius: '0.5rem',
|
|
215
|
+
color: '#dc2626'
|
|
216
|
+
}}
|
|
217
|
+
>
|
|
220
218
|
<h2>Runtime Error</h2>
|
|
221
219
|
<p>{error.message}</p>
|
|
222
220
|
{development && <pre style={{ fontSize: '0.75rem', overflow: 'auto' }}>{error.stack}</pre>}
|
|
@@ -226,20 +224,5 @@ async function initRuntime(foundationSource, options = {}) {
|
|
|
226
224
|
}
|
|
227
225
|
}
|
|
228
226
|
|
|
229
|
-
|
|
230
|
-
const initRTE = initRuntime
|
|
231
|
-
|
|
232
|
-
// Exports
|
|
233
|
-
export {
|
|
234
|
-
initRuntime,
|
|
235
|
-
initRTE,
|
|
236
|
-
// Components for external use
|
|
237
|
-
Link,
|
|
238
|
-
SafeHtml,
|
|
239
|
-
ChildBlocks,
|
|
240
|
-
ErrorBoundary,
|
|
241
|
-
// Core classes
|
|
242
|
-
Uniweb
|
|
243
|
-
}
|
|
244
|
-
|
|
227
|
+
export { initRuntime }
|
|
245
228
|
export default initRuntime
|
package/src/components/Link.jsx
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Link
|
|
3
|
-
*
|
|
4
|
-
* A wrapper around React Router's Link that integrates with the runtime.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React from 'react'
|
|
8
|
-
import { Link as RouterLink } from 'react-router-dom'
|
|
9
|
-
|
|
10
|
-
export default function Link({ to, href, children, className, ...props }) {
|
|
11
|
-
const target = to || href
|
|
12
|
-
|
|
13
|
-
// External links
|
|
14
|
-
if (target?.startsWith('http') || target?.startsWith('mailto:') || target?.startsWith('tel:')) {
|
|
15
|
-
return (
|
|
16
|
-
<a href={target} className={className} {...props}>
|
|
17
|
-
{children}
|
|
18
|
-
</a>
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Internal links via React Router
|
|
23
|
-
return (
|
|
24
|
-
<RouterLink to={target || '/'} className={className} {...props}>
|
|
25
|
-
{children}
|
|
26
|
-
</RouterLink>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SafeHtml
|
|
3
|
-
*
|
|
4
|
-
* Safely render HTML content with sanitization.
|
|
5
|
-
* TODO: Add DOMPurify for production use
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react'
|
|
9
|
-
|
|
10
|
-
export default function SafeHtml({ html, className, as: Component = 'div', ...props }) {
|
|
11
|
-
if (!html) return null
|
|
12
|
-
|
|
13
|
-
// For now, render directly
|
|
14
|
-
// TODO: Integrate DOMPurify for sanitization
|
|
15
|
-
return (
|
|
16
|
-
<Component
|
|
17
|
-
className={className}
|
|
18
|
-
dangerouslySetInnerHTML={{ __html: html }}
|
|
19
|
-
{...props}
|
|
20
|
-
/>
|
|
21
|
-
)
|
|
22
|
-
}
|