@modernpoacher/halacious 7.0.3 → 7.0.4
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 +15 -17
- package/babel.config.cjs +44 -0
- package/package.json +9 -2
- package/src/index.d.mts +205 -20
- package/src/plugin.mjs +765 -671
- package/src/representation.mjs +282 -108
- package/src/utils/getFieldValueByPath.mjs +20 -0
- package/src/utils/getMediaType.mjs +15 -0
- package/src/utils/getTemplateContext.mjs +32 -0
- package/src/utils.mjs +382 -0
- package/views/namespaces.jade +11 -0
- package/views/rel.jade +7 -0
- package/index.d.mts +0 -7
package/README.md
CHANGED
|
@@ -33,20 +33,20 @@ be accomplished without writing any code at all.
|
|
|
33
33
|
Start by npm installing Halicious into your Hapi project folder:
|
|
34
34
|
|
|
35
35
|
```shell
|
|
36
|
-
npm
|
|
36
|
+
npm i -P @modernpoacher/halacious
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
or
|
|
40
40
|
|
|
41
41
|
```shell
|
|
42
|
-
yarn add @modernpoacher/halacious
|
|
42
|
+
yarn add @modernpoacher/halacious
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
Register the plugin with the app server
|
|
46
46
|
|
|
47
47
|
```javascript
|
|
48
48
|
import hapi from '@hapi/hapi'
|
|
49
|
-
import halacious from '
|
|
49
|
+
import halacious from '@modernpoacher/halacious'
|
|
50
50
|
|
|
51
51
|
async function init () {
|
|
52
52
|
const server = hapi.server({ port: 8080 })
|
|
@@ -54,16 +54,14 @@ async function init () {
|
|
|
54
54
|
await server.register(halacious)
|
|
55
55
|
|
|
56
56
|
server.route({
|
|
57
|
-
method: '
|
|
57
|
+
method: 'GET',
|
|
58
58
|
path: '/hello/{name}',
|
|
59
59
|
handler (req) {
|
|
60
|
-
return { message: 'Hello, '+req.params.name }
|
|
60
|
+
return { message: 'Hello, ' + req.params.name }
|
|
61
61
|
}
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
await server.start()
|
|
65
|
-
|
|
66
|
-
console.info('Server started at %s', server.info.uri)
|
|
67
65
|
}
|
|
68
66
|
|
|
69
67
|
init()
|
|
@@ -100,7 +98,7 @@ Links may be declared directly within the route config.
|
|
|
100
98
|
|
|
101
99
|
```javascript
|
|
102
100
|
server.route({
|
|
103
|
-
method: '
|
|
101
|
+
method: 'GET',
|
|
104
102
|
path: '/users/{userId}',
|
|
105
103
|
handler (req) {
|
|
106
104
|
return { id: req.params.userId, name: 'User ' + req.params.userId, googlePlusId: '107835557095464780852' }
|
|
@@ -146,7 +144,7 @@ automatically convert nested objects into embedded HAL representations (if you a
|
|
|
146
144
|
|
|
147
145
|
```javascript
|
|
148
146
|
server.route({
|
|
149
|
-
method: '
|
|
147
|
+
method: 'GET',
|
|
150
148
|
path: '/users/{userId}',
|
|
151
149
|
handler (req) {
|
|
152
150
|
return {
|
|
@@ -233,7 +231,7 @@ In either case, the method signature is the same: `fn(rep, callback)` where
|
|
|
233
231
|
|
|
234
232
|
```javascript
|
|
235
233
|
server.route({
|
|
236
|
-
method: '
|
|
234
|
+
method: 'GET',
|
|
237
235
|
path: '/users',
|
|
238
236
|
handler (req) {
|
|
239
237
|
return {
|
|
@@ -333,7 +331,7 @@ User.prototype.toHal = function(rep, next) {
|
|
|
333
331
|
}
|
|
334
332
|
|
|
335
333
|
server.route({
|
|
336
|
-
method: '
|
|
334
|
+
method: 'GET',
|
|
337
335
|
path: '/users',
|
|
338
336
|
handler (req) {
|
|
339
337
|
return {
|
|
@@ -401,7 +399,7 @@ Halacious exposes its api to your Hapi server so that you may configure it at ru
|
|
|
401
399
|
|
|
402
400
|
```javascript
|
|
403
401
|
import hapi from '@hapi/hapi'
|
|
404
|
-
import halacious from '
|
|
402
|
+
import halacious from '@modernpoacher/halacious'
|
|
405
403
|
|
|
406
404
|
async function init () {
|
|
407
405
|
const server = hapi.server({ port: 8080 })
|
|
@@ -414,7 +412,7 @@ async function init () {
|
|
|
414
412
|
namespace.rel({ name: 'boss', description: 'a users boss' })
|
|
415
413
|
|
|
416
414
|
server.route({
|
|
417
|
-
method: '
|
|
415
|
+
method: 'GET',
|
|
418
416
|
path: '/users/{userId}',
|
|
419
417
|
handler (req) {
|
|
420
418
|
return { id: req.params.userId, name: 'User ' + req.params.userId, bossId: 200 }
|
|
@@ -472,7 +470,7 @@ company's namespace. We can suck all these into the system in one fell swoop:
|
|
|
472
470
|
|
|
473
471
|
```javascript
|
|
474
472
|
import hapi from '@hapi/hapi'
|
|
475
|
-
import halacious from '
|
|
473
|
+
import halacious from '@modernpoacher/halacious'
|
|
476
474
|
|
|
477
475
|
async function init () {
|
|
478
476
|
const server = hapi.server({ port: 8080 })
|
|
@@ -505,7 +503,7 @@ configuration option. For example:
|
|
|
505
503
|
|
|
506
504
|
```javascript
|
|
507
505
|
import hapi from '@hapi/hapi'
|
|
508
|
-
import halacious from '
|
|
506
|
+
import halacious from '@modernpoacher/halacious'
|
|
509
507
|
|
|
510
508
|
async function init () {
|
|
511
509
|
const server = hapi.server({ port: 8080 })
|
|
@@ -517,7 +515,7 @@ async function init () {
|
|
|
517
515
|
namespace.rel({ name: 'user', description: 'a single user' })
|
|
518
516
|
|
|
519
517
|
server.route({
|
|
520
|
-
method: '
|
|
518
|
+
method: 'GET',
|
|
521
519
|
path: '/users',
|
|
522
520
|
handler () {
|
|
523
521
|
return {}
|
|
@@ -532,7 +530,7 @@ async function init () {
|
|
|
532
530
|
})
|
|
533
531
|
|
|
534
532
|
server.route({
|
|
535
|
-
method: '
|
|
533
|
+
method: 'GET',
|
|
536
534
|
path: '/users/{userId}',
|
|
537
535
|
handler () {
|
|
538
536
|
return {}
|
package/babel.config.cjs
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const debug = require('debug')
|
|
2
|
+
|
|
3
|
+
const log = debug('@modernpoacher/halacious')
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
env: {
|
|
7
|
+
NODE_ENV = 'development'
|
|
8
|
+
}
|
|
9
|
+
} = process
|
|
10
|
+
|
|
11
|
+
log('`@modernpoacher/halacious` is awake')
|
|
12
|
+
|
|
13
|
+
function env () {
|
|
14
|
+
log({ NODE_ENV })
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
NODE_ENV === 'production'
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const presets = [
|
|
22
|
+
[
|
|
23
|
+
'@babel/env', {
|
|
24
|
+
targets: {
|
|
25
|
+
node: 'current'
|
|
26
|
+
},
|
|
27
|
+
useBuiltIns: 'usage',
|
|
28
|
+
corejs: 3
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const plugins = [
|
|
34
|
+
'@babel/syntax-import-assertions'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
module.exports = (api) => {
|
|
38
|
+
if (api) api.cache.using(env)
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
presets,
|
|
42
|
+
plugins
|
|
43
|
+
}
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modernpoacher/halacious",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.4",
|
|
4
4
|
"description": "A HAL processor for Hapi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"HAL",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"main": "./src/index.mjs",
|
|
12
12
|
"type": "module",
|
|
13
|
+
"types": "./src/index.d.mts",
|
|
13
14
|
"author": {
|
|
14
15
|
"name": "Jonathan Perry for Modern Poacher Limited",
|
|
15
16
|
"email": "modernpoacher@modernpoacher.com",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"@hapi/boom": "^10.0.1",
|
|
41
42
|
"@hapi/hoek": "^11.0.4",
|
|
42
43
|
"async": "^3.2.5",
|
|
44
|
+
"debug": "^4.3.4",
|
|
43
45
|
"joi": "^17.12.0",
|
|
44
46
|
"lodash": "^4.17.21",
|
|
45
47
|
"marked": "^11.1.1",
|
|
@@ -51,6 +53,8 @@
|
|
|
51
53
|
"devDependencies": {
|
|
52
54
|
"@babel/core": "^7.23.7",
|
|
53
55
|
"@babel/eslint-parser": "^7.23.3",
|
|
56
|
+
"@babel/plugin-syntax-import-assertions": "^7.23.3",
|
|
57
|
+
"@babel/preset-env": "^7.23.8",
|
|
54
58
|
"@hapi/hapi": "^21.3.2",
|
|
55
59
|
"@hapi/vision": "^7.0.3",
|
|
56
60
|
"@modernpoacher/hooks": "^1.0.457",
|
|
@@ -67,11 +71,14 @@
|
|
|
67
71
|
"sinon": "^17.0.1"
|
|
68
72
|
},
|
|
69
73
|
"imports": {
|
|
74
|
+
"#package": "./package.json",
|
|
70
75
|
"#halacious/*": "./src/*.mjs",
|
|
71
76
|
"#halacious": "./src/index.mjs",
|
|
72
77
|
"#where-am-i": "./where-am-i.mjs"
|
|
73
78
|
},
|
|
74
79
|
"exports": {
|
|
75
|
-
".": "./src/index.mjs"
|
|
80
|
+
".": "./src/index.mjs",
|
|
81
|
+
"./utils/*": "./src/utils/*.mjs",
|
|
82
|
+
"./utils": "./src/utils.mjs"
|
|
76
83
|
}
|
|
77
84
|
}
|
package/src/index.d.mts
CHANGED
|
@@ -1,30 +1,215 @@
|
|
|
1
|
-
declare
|
|
2
|
-
|
|
3
|
-
uid: string
|
|
4
|
-
}
|
|
1
|
+
declare module '@modernpoacher/halacious/utils' {
|
|
2
|
+
import type Negotiator from 'negotiator'
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
4
|
+
import type {
|
|
5
|
+
HalaciousTypes
|
|
6
|
+
} from '@modernpoacher/halacious'
|
|
7
|
+
|
|
8
|
+
type Representation = HalaciousTypes.Representation
|
|
9
|
+
|
|
10
|
+
export function getRepresentationSelf (arg: Representation): Record<string, any> | undefined
|
|
11
|
+
|
|
12
|
+
export function hasRepresentationSelf (arg: Representation): boolean
|
|
13
|
+
|
|
14
|
+
export function getRepresentationSelfHref (arg: Representation): string | undefined
|
|
15
|
+
|
|
16
|
+
export function hasRepresentationSelfHref (arg: Representation): boolean
|
|
17
|
+
|
|
18
|
+
export function getRepresentationEntity (arg: Representation): Record<string, any> | undefined
|
|
19
|
+
|
|
20
|
+
export function hasRepresentationEntity (arg: Representation): boolean
|
|
21
|
+
|
|
22
|
+
export function getRepresentationRequest (arg: Representation): Record<string, any> | undefined
|
|
23
|
+
|
|
24
|
+
export function hasRepresentationRequest (arg: Representation): boolean
|
|
25
|
+
|
|
26
|
+
export function getRepresentationRequestServer (arg: Representation): Record<string, any> | undefined
|
|
27
|
+
|
|
28
|
+
export function hasRepresentationRequestServer (arg: Representation): boolean
|
|
29
|
+
|
|
30
|
+
export function getRepresentationRequestPath (arg: Representation): string | undefined
|
|
31
|
+
|
|
32
|
+
export function hasRepresentationRequestPath (arg: Representation): boolean
|
|
33
|
+
|
|
34
|
+
export function getRepresentationRequestRoute (arg: Representation): Record<string, any> | undefined
|
|
35
|
+
|
|
36
|
+
export function hasRepresentationRequestRoute (arg: Representation): boolean
|
|
37
|
+
|
|
38
|
+
export function getRepresentationRequestRoutePath (arg: Representation): string | undefined
|
|
39
|
+
|
|
40
|
+
export function hasRepresentationRequestRoutePath (arg: Representation): boolean
|
|
41
|
+
|
|
42
|
+
export function getRepresentationRequestRouteMethod (arg: Representation): string | undefined
|
|
43
|
+
|
|
44
|
+
export function hasRepresentationRequestRouteMethod (arg: Representation): boolean
|
|
45
|
+
|
|
46
|
+
export function getRoutePath (arg: { path?: string }): string | undefined
|
|
47
|
+
|
|
48
|
+
export function hasRoutePath (arg: { path?: string }): boolean
|
|
49
|
+
|
|
50
|
+
export function getRouteSettings (arg: { settings?: Record<string, any> }): Record<string, any>
|
|
51
|
+
|
|
52
|
+
export function getRouteSettingsIsInternal (arg: { settings?: { isInternal?: boolean } }): boolean
|
|
53
|
+
|
|
54
|
+
export function getRouteSettingsPlugins (arg: { settings?: { plugins?: Record<string, any> } }): Record<string, any>
|
|
55
|
+
|
|
56
|
+
export function getRouteSettingsPluginsHal (arg: { settings?: { plugins?: { hal?: Record<string, any> } } }): Record<string, any>
|
|
57
|
+
|
|
58
|
+
export function getRouteSettingsPluginsHalApi (arg: { settings?: { plugins?: { hal?: { api?: Record<string, any> } } } }): Record<string, any> | null
|
|
59
|
+
|
|
60
|
+
export function getRouteSettingsPluginsHalQuery (arg: { settings?: { plugins?: { hal?: { query?: string } } } }): string | null
|
|
61
|
+
|
|
62
|
+
export function getRouteSettingsPluginsHalAbsolute (arg: { settings?: { plugins?: { hal?: { absolute?: boolean } } } }): boolean | null
|
|
63
|
+
|
|
64
|
+
export function getRequestPath (arg: { path?: string }): string | undefined
|
|
65
|
+
|
|
66
|
+
export function hasRequestPath (arg: { path?: string }): boolean
|
|
67
|
+
|
|
68
|
+
export function getRequestMethod (arg: { method?: string }): string | undefined
|
|
69
|
+
|
|
70
|
+
export function hasRequestMethod (arg: { method?: string }): boolean
|
|
71
|
+
|
|
72
|
+
export function getRequestRoute (arg: { route?: Record<string, any> }): Record<string, any> | undefined
|
|
73
|
+
|
|
74
|
+
export function hasRequestRoute (arg: { route?: Record<string, any> }): boolean
|
|
75
|
+
|
|
76
|
+
export function getRequestRoutePath (arg: { route?: { path?: string } }): string | undefined
|
|
77
|
+
|
|
78
|
+
export function hasRequestRoutePath (arg: { route?: { path?: string } }): boolean
|
|
79
|
+
|
|
80
|
+
export function getRequestRouteMethod (arg: { route?: { method?: string } }): string | undefined
|
|
81
|
+
|
|
82
|
+
export function hasRequestRouteMethod (arg: { route?: { method?: string } }): boolean
|
|
83
|
+
|
|
84
|
+
export function getRequestServer (arg: { server?: Record<string, any> }): Record<string, any> | undefined
|
|
85
|
+
|
|
86
|
+
export function hasRequestServer (arg: { server?: Record<string, any> }): boolean
|
|
87
|
+
|
|
88
|
+
export function getRequestHeaders (arg: { headers?: Record<string, any> }): Record<string, any> | undefined
|
|
89
|
+
|
|
90
|
+
export function hasRequestHeaders (arg: { headers?: Record<string, any> }): boolean
|
|
91
|
+
|
|
92
|
+
export function getRequestHeadersAccept (arg: { headers?: { accept?: string } }): string | undefined
|
|
93
|
+
|
|
94
|
+
export function getRequestResponse (arg: { response?: Record<string, any> }): Record<string, any> | undefined
|
|
95
|
+
|
|
96
|
+
export function hasRequestResponse (arg: { response?: Record<string, any> }): boolean
|
|
97
|
+
|
|
98
|
+
export function getRequestResponseSource (arg: { response?: { source?: Record<string, any> } }): Record<string, any> | undefined
|
|
99
|
+
|
|
100
|
+
export function getRequestResponseHeaders (arg: { response?: { headers?: Record<string, any> } }): Record<string, any> | undefined
|
|
9
101
|
|
|
10
|
-
export
|
|
11
|
-
|
|
102
|
+
export function getRequestResponseHeadersLocation (arg: { response?: { headers?: { location?: string } } }): string | undefined
|
|
103
|
+
|
|
104
|
+
export function getResponseVariety (arg: { variety?: string }): string | undefined
|
|
105
|
+
|
|
106
|
+
export function getResponseStatusCode (arg: { statusCode?: number }): number | undefined
|
|
107
|
+
|
|
108
|
+
export function isResponseStatusCodeInSuccessRange (statusCode: number | undefined): boolean
|
|
109
|
+
|
|
110
|
+
export function getFieldValueByPath (path?: string, context: Record<string, any>): Record<string, any>
|
|
111
|
+
|
|
112
|
+
export function getMediaType (request: { headers: Negotiator.Headers }, mediaTypes: string[]): string
|
|
113
|
+
|
|
114
|
+
export function getTemplateContext (template: string, context: Record<string, any>): Record<string, any>
|
|
115
|
+
|
|
116
|
+
export function getPath (arg: { path?: string }): string | undefined
|
|
117
|
+
|
|
118
|
+
export function hasPath (arg: { path?: string }): boolean
|
|
119
|
+
|
|
120
|
+
export function getMethod (arg: { method?: string }): string | undefined
|
|
121
|
+
|
|
122
|
+
export function hasMethod (arg: { method?: string }): boolean
|
|
123
|
+
|
|
124
|
+
export function getSelf (arg: { self?: Record<string, any> }): Record<string, any> | undefined
|
|
125
|
+
|
|
126
|
+
export function hasSelf (arg: { self?: Record<string, any> }): boolean
|
|
127
|
+
|
|
128
|
+
export function getHref (arg: { href?: string }): string | undefined
|
|
129
|
+
|
|
130
|
+
export function hasHref (arg: { href?: string }): boolean
|
|
131
|
+
|
|
132
|
+
export function getServer (arg: { server?: Record<string, any> }): Record<string, any> | undefined
|
|
133
|
+
|
|
134
|
+
export function hasServer (arg: { server?: Record<string, any> }): boolean
|
|
135
|
+
|
|
136
|
+
export function getRequest (arg: { request?: Record<string, any> }): Record<string, any> | undefined
|
|
137
|
+
|
|
138
|
+
export function hasRequest (arg: { request?: Record<string, any> }): boolean
|
|
139
|
+
|
|
140
|
+
export function getResponse (arg: { response?: Record<string, any> }): Record<string, any> | undefined
|
|
141
|
+
|
|
142
|
+
export function hasResponse (arg: { response?: Record<string, any> }): boolean
|
|
143
|
+
|
|
144
|
+
export function getSettings (arg: { settings?: Record<string, any> }): Record<string, any> | undefined
|
|
145
|
+
|
|
146
|
+
export function hasSettings (arg: { settings?: Record<string, any> }): boolean
|
|
147
|
+
|
|
148
|
+
export function getHeaders (arg: { headers?: Record<string, any> }): Record<string, any> | undefined
|
|
149
|
+
|
|
150
|
+
export function hasHeaders (arg: { headers?: Record<string, any> }): boolean
|
|
151
|
+
|
|
152
|
+
export function getEntity (arg: { entity?: Record<string, any> }): Record<string, any> | undefined
|
|
153
|
+
|
|
154
|
+
export function hasEntity (arg: { entity?: Record<string, any> }): boolean
|
|
155
|
+
|
|
156
|
+
export function getRoute (arg: { route?: string }): string | undefined
|
|
157
|
+
|
|
158
|
+
export function hasRoute (arg: { route?: string }): boolean
|
|
159
|
+
|
|
160
|
+
export function getName (arg: { name?: string }): string | undefined
|
|
161
|
+
|
|
162
|
+
export function hasName (arg: { name?: string }): boolean
|
|
163
|
+
|
|
164
|
+
export function getPrefix (arg: { prefix?: string }): string | undefined
|
|
165
|
+
|
|
166
|
+
export function hasPrefix (arg: { prefix?: string }): boolean
|
|
167
|
+
|
|
168
|
+
export function getRels (arg: { rels?: Record<string, any> }): Record<string, any> | undefined
|
|
169
|
+
|
|
170
|
+
export function hasRels (arg: { rels?: Record<string, any> }): boolean
|
|
171
|
+
|
|
172
|
+
export function getAbsolute (arg: { absolute?: boolean }): boolean | undefined
|
|
173
|
+
|
|
174
|
+
export function hasAbsolute (arg: { absolute?: boolean }): boolean
|
|
175
|
+
|
|
176
|
+
export function getQuery (arg: { query?: string }): string | undefined
|
|
177
|
+
|
|
178
|
+
export function hasQuery (arg: { query?: string }): boolean
|
|
179
|
+
|
|
180
|
+
export function getIgnore (arg: { ignore?: string }): string | undefined
|
|
181
|
+
|
|
182
|
+
export function hasIgnore (arg: { ignore?: string }): boolean
|
|
183
|
+
|
|
184
|
+
export function isRelativePath (path?: string): boolean
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
declare module '@modernpoacher/halacious' {
|
|
188
|
+
export namespace HalaciousTypes {
|
|
189
|
+
interface Request {
|
|
190
|
+
method?: string
|
|
191
|
+
path?: string
|
|
192
|
+
server: Record<string, any>
|
|
12
193
|
route: {
|
|
13
194
|
method?: string
|
|
14
195
|
path?: string
|
|
15
196
|
}
|
|
16
|
-
params:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
197
|
+
params: Record<string, any>
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface Representation {
|
|
201
|
+
factory: RepresentationFactory
|
|
202
|
+
request: Request
|
|
203
|
+
self: string | { href?: string }
|
|
204
|
+
entity: Record<string, any>
|
|
205
|
+
ignore: (v: string) => void
|
|
206
|
+
embed: (v: string, u: string, m: object) => void
|
|
20
207
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
208
|
+
|
|
209
|
+
export interface RepresentationFactory {
|
|
210
|
+
create: (entity: Record<string, any>, self?: string | { href?: string }, root?: Representation) => Representation
|
|
24
211
|
}
|
|
25
|
-
ignore: (v: string) => void
|
|
26
|
-
embed: (v: string, u: string, m: object) => void
|
|
27
212
|
}
|
|
28
|
-
}
|
|
29
213
|
|
|
30
|
-
export
|
|
214
|
+
export const plugin: object
|
|
215
|
+
}
|