fastify 3.25.2 → 3.27.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/LICENSE +1 -1
- package/build/build-validation.js +2 -0
- package/docs/Guides/Index.md +2 -0
- package/docs/Guides/Prototype-Poisoning.md +391 -0
- package/docs/Guides/Recommendations.md +1 -1
- package/docs/Reference/Plugins.md +4 -4
- package/docs/Reference/Request.md +3 -0
- package/docs/Reference/Server.md +16 -2
- package/docs/Reference/TypeScript.md +1 -1
- package/fastify.d.ts +2 -1
- package/fastify.js +23 -5
- package/lib/errors.js +5 -0
- package/lib/noop-set.js +10 -0
- package/lib/pluginUtils.js +5 -0
- package/lib/reply.js +16 -6
- package/lib/route.js +34 -1
- package/lib/symbols.js +3 -1
- package/lib/warnings.js +1 -1
- package/package.json +7 -7
- package/test/404s.test.js +1 -1
- package/test/bundler/esbuild/bundler-test.js +31 -0
- package/test/bundler/esbuild/package.json +10 -0
- package/test/bundler/esbuild/src/fail-plugin-version.js +12 -0
- package/test/bundler/esbuild/src/index.js +7 -0
- package/test/bundler/webpack/bundler-test.js +15 -4
- package/test/bundler/webpack/src/fail-plugin-version.js +1 -3
- package/test/bundler/webpack/src/index.js +1 -3
- package/test/close.test.js +38 -0
- package/test/custom-parser.test.js +30 -31
- package/test/noop-set.test.js +19 -0
- package/test/plugin.name.display.js +10 -0
- package/test/plugin.test.js +18 -0
- package/test/route.test.js +12 -0
- package/test/schema-serialization.test.js +41 -0
- package/test/types/fastify.test-d.ts +17 -0
- package/test/types/hooks.test-d.ts +28 -4
- package/test/types/instance.test-d.ts +25 -0
- package/test/versioned-routes.test.js +27 -3
- package/types/hooks.d.ts +19 -19
- package/types/instance.d.ts +13 -1
- package/types/schema.d.ts +14 -0
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import fastify, { RouteOptions, FastifyReply, FastifyRequest } from '../../fastify'
|
|
2
|
-
import { expectType, expectError, expectAssignable } from 'tsd'
|
|
3
|
-
import { FastifyInstance } from '../../types/instance'
|
|
4
1
|
import { FastifyError } from 'fastify-error'
|
|
5
|
-
import {
|
|
2
|
+
import { expectAssignable, expectError, expectType } from 'tsd'
|
|
3
|
+
import fastify, {
|
|
4
|
+
FastifyInstance,
|
|
5
|
+
FastifyReply,
|
|
6
|
+
FastifyRequest,
|
|
7
|
+
RawReplyDefaultExpression,
|
|
8
|
+
RawRequestDefaultExpression,
|
|
9
|
+
RawServerBase,
|
|
10
|
+
RouteOptions
|
|
11
|
+
} from '../../fastify'
|
|
12
|
+
import { preHandlerAsyncHookHandler, RequestPayload } from '../../types/hooks'
|
|
6
13
|
|
|
7
14
|
const server = fastify()
|
|
8
15
|
|
|
@@ -198,3 +205,20 @@ server.addHook('onReady', async function () {
|
|
|
198
205
|
server.addHook('onClose', async (instance) => {
|
|
199
206
|
expectType<FastifyInstance>(instance)
|
|
200
207
|
})
|
|
208
|
+
|
|
209
|
+
// Use case to monitor any regression on issue #3620
|
|
210
|
+
// ref.: https://github.com/fastify/fastify/issues/3620
|
|
211
|
+
const customTypedHook: preHandlerAsyncHookHandler<
|
|
212
|
+
RawServerBase,
|
|
213
|
+
RawRequestDefaultExpression,
|
|
214
|
+
RawReplyDefaultExpression,
|
|
215
|
+
Record<string, unknown>
|
|
216
|
+
> = async function (request, reply) {
|
|
217
|
+
expectType<FastifyInstance>(this)
|
|
218
|
+
expectAssignable<FastifyRequest>(request)
|
|
219
|
+
expectAssignable<FastifyReply>(reply)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
server.register(async (instance) => {
|
|
223
|
+
instance.addHook('preHandler', customTypedHook)
|
|
224
|
+
})
|
|
@@ -10,6 +10,7 @@ import { expectAssignable, expectError, expectType } from 'tsd'
|
|
|
10
10
|
import { FastifyRequest } from '../../types/request'
|
|
11
11
|
import { FastifyReply } from '../../types/reply'
|
|
12
12
|
import { HookHandlerDoneFunction } from '../../types/hooks'
|
|
13
|
+
import { FastifySchemaControllerOptions } from '../../types/schema'
|
|
13
14
|
|
|
14
15
|
const server = fastify()
|
|
15
16
|
|
|
@@ -112,6 +113,29 @@ server.setNotFoundHandler({ preHandler: notFoundpreHandlerHandler, preValidation
|
|
|
112
113
|
function invalidErrorHandler (error: number) {}
|
|
113
114
|
expectError(server.setErrorHandler(invalidErrorHandler))
|
|
114
115
|
|
|
116
|
+
server.setSchemaController({
|
|
117
|
+
bucket: (parentSchemas: unknown) => {
|
|
118
|
+
return {
|
|
119
|
+
addSchema (schema: unknown) {
|
|
120
|
+
expectType<unknown>(schema)
|
|
121
|
+
expectType<FastifyInstance>(server.addSchema({ type: 'null' }))
|
|
122
|
+
return server.addSchema({ type: 'null' })
|
|
123
|
+
},
|
|
124
|
+
getSchema (schemaId: string) {
|
|
125
|
+
expectType<string>(schemaId)
|
|
126
|
+
return server.getSchema('SchemaId')
|
|
127
|
+
},
|
|
128
|
+
getSchemas () {
|
|
129
|
+
expectType<Record<string, unknown>>(server.getSchemas())
|
|
130
|
+
return server.getSchemas()
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
function invalidSchemaController (schemaControllerOptions: FastifySchemaControllerOptions) {}
|
|
137
|
+
expectError(server.setSchemaController(invalidSchemaController))
|
|
138
|
+
|
|
115
139
|
server.setReplySerializer(function (payload, statusCode) {
|
|
116
140
|
expectType<unknown>(payload)
|
|
117
141
|
expectType<number>(statusCode)
|
|
@@ -171,6 +195,7 @@ type InitialConfig = Readonly<{
|
|
|
171
195
|
keepAliveTimeout?: number,
|
|
172
196
|
bodyLimit?: number,
|
|
173
197
|
caseSensitive?: boolean,
|
|
198
|
+
forceCloseConnections?: boolean,
|
|
174
199
|
http2?: boolean,
|
|
175
200
|
https?: boolean | Readonly<{ allowHTTP1: boolean }>,
|
|
176
201
|
ignoreTrailingSlash?: boolean,
|
|
@@ -296,10 +296,25 @@ test('Shorthand route declaration', t => {
|
|
|
296
296
|
})
|
|
297
297
|
})
|
|
298
298
|
|
|
299
|
-
test('The not found handler should not
|
|
300
|
-
t.plan(
|
|
299
|
+
test('The not found handler should not erase the Accept-Version header', t => {
|
|
300
|
+
t.plan(13)
|
|
301
301
|
const fastify = Fastify()
|
|
302
302
|
|
|
303
|
+
fastify.addHook('onRequest', function (req, reply, done) {
|
|
304
|
+
t.same(req.headers['accept-version'], '2.x')
|
|
305
|
+
done()
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
fastify.addHook('preValidation', function (req, reply, done) {
|
|
309
|
+
t.same(req.headers['accept-version'], '2.x')
|
|
310
|
+
done()
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
fastify.addHook('preHandler', function (req, reply, done) {
|
|
314
|
+
t.same(req.headers['accept-version'], '2.x')
|
|
315
|
+
done()
|
|
316
|
+
})
|
|
317
|
+
|
|
303
318
|
fastify.route({
|
|
304
319
|
method: 'GET',
|
|
305
320
|
url: '/',
|
|
@@ -310,7 +325,16 @@ test('The not found handler should not use the Accept-Version header', t => {
|
|
|
310
325
|
})
|
|
311
326
|
|
|
312
327
|
fastify.setNotFoundHandler(function (req, reply) {
|
|
313
|
-
t.
|
|
328
|
+
t.same(req.headers['accept-version'], '2.x')
|
|
329
|
+
// we check if the symbol is exposed on key or not
|
|
330
|
+
for (const key in req.headers) {
|
|
331
|
+
t.same(typeof key, 'string')
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
for (const key of Object.keys(req.headers)) {
|
|
335
|
+
t.same(typeof key, 'string')
|
|
336
|
+
}
|
|
337
|
+
|
|
314
338
|
reply.code(404).send('not found handler')
|
|
315
339
|
})
|
|
316
340
|
|
package/types/hooks.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface onRequestHookHandler<
|
|
|
27
27
|
ContextConfig = ContextConfigDefault
|
|
28
28
|
> {
|
|
29
29
|
(
|
|
30
|
-
this: FastifyInstance
|
|
30
|
+
this: FastifyInstance,
|
|
31
31
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
32
32
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
33
33
|
done: HookHandlerDoneFunction
|
|
@@ -42,7 +42,7 @@ export interface onRequestAsyncHookHandler<
|
|
|
42
42
|
ContextConfig = ContextConfigDefault
|
|
43
43
|
> {
|
|
44
44
|
(
|
|
45
|
-
this: FastifyInstance
|
|
45
|
+
this: FastifyInstance,
|
|
46
46
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
47
47
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
48
48
|
): Promise<unknown>;
|
|
@@ -60,7 +60,7 @@ export interface preParsingHookHandler<
|
|
|
60
60
|
ContextConfig = ContextConfigDefault
|
|
61
61
|
> {
|
|
62
62
|
(
|
|
63
|
-
this: FastifyInstance
|
|
63
|
+
this: FastifyInstance,
|
|
64
64
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
65
65
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
66
66
|
payload: RequestPayload,
|
|
@@ -76,7 +76,7 @@ export interface preParsingAsyncHookHandler<
|
|
|
76
76
|
ContextConfig = ContextConfigDefault
|
|
77
77
|
> {
|
|
78
78
|
(
|
|
79
|
-
this: FastifyInstance
|
|
79
|
+
this: FastifyInstance,
|
|
80
80
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
81
81
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
82
82
|
payload: RequestPayload,
|
|
@@ -94,7 +94,7 @@ export interface preValidationHookHandler<
|
|
|
94
94
|
ContextConfig = ContextConfigDefault
|
|
95
95
|
> {
|
|
96
96
|
(
|
|
97
|
-
this: FastifyInstance
|
|
97
|
+
this: FastifyInstance,
|
|
98
98
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
99
99
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
100
100
|
done: HookHandlerDoneFunction
|
|
@@ -109,7 +109,7 @@ export interface preValidationAsyncHookHandler<
|
|
|
109
109
|
ContextConfig = ContextConfigDefault
|
|
110
110
|
> {
|
|
111
111
|
(
|
|
112
|
-
this: FastifyInstance
|
|
112
|
+
this: FastifyInstance,
|
|
113
113
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
114
114
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
115
115
|
): Promise<unknown>;
|
|
@@ -126,7 +126,7 @@ export interface preHandlerHookHandler<
|
|
|
126
126
|
ContextConfig = ContextConfigDefault
|
|
127
127
|
> {
|
|
128
128
|
(
|
|
129
|
-
this: FastifyInstance
|
|
129
|
+
this: FastifyInstance,
|
|
130
130
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
131
131
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
132
132
|
done: HookHandlerDoneFunction
|
|
@@ -141,7 +141,7 @@ export interface preHandlerAsyncHookHandler<
|
|
|
141
141
|
ContextConfig = ContextConfigDefault
|
|
142
142
|
> {
|
|
143
143
|
(
|
|
144
|
-
this: FastifyInstance
|
|
144
|
+
this: FastifyInstance,
|
|
145
145
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
146
146
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
147
147
|
): Promise<unknown>;
|
|
@@ -167,7 +167,7 @@ export interface preSerializationHookHandler<
|
|
|
167
167
|
ContextConfig = ContextConfigDefault
|
|
168
168
|
> {
|
|
169
169
|
(
|
|
170
|
-
this: FastifyInstance
|
|
170
|
+
this: FastifyInstance,
|
|
171
171
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
172
172
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
173
173
|
payload: PreSerializationPayload,
|
|
@@ -184,7 +184,7 @@ export interface preSerializationAsyncHookHandler<
|
|
|
184
184
|
ContextConfig = ContextConfigDefault
|
|
185
185
|
> {
|
|
186
186
|
(
|
|
187
|
-
this: FastifyInstance
|
|
187
|
+
this: FastifyInstance,
|
|
188
188
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
189
189
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
190
190
|
payload: PreSerializationPayload
|
|
@@ -204,7 +204,7 @@ export interface onSendHookHandler<
|
|
|
204
204
|
ContextConfig = ContextConfigDefault
|
|
205
205
|
> {
|
|
206
206
|
(
|
|
207
|
-
this: FastifyInstance
|
|
207
|
+
this: FastifyInstance,
|
|
208
208
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
209
209
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
210
210
|
payload: OnSendPayload,
|
|
@@ -221,7 +221,7 @@ export interface onSendAsyncHookHandler<
|
|
|
221
221
|
ContextConfig = ContextConfigDefault
|
|
222
222
|
> {
|
|
223
223
|
(
|
|
224
|
-
this: FastifyInstance
|
|
224
|
+
this: FastifyInstance,
|
|
225
225
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
226
226
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
227
227
|
payload: OnSendPayload,
|
|
@@ -240,7 +240,7 @@ export interface onResponseHookHandler<
|
|
|
240
240
|
ContextConfig = ContextConfigDefault
|
|
241
241
|
> {
|
|
242
242
|
(
|
|
243
|
-
this: FastifyInstance
|
|
243
|
+
this: FastifyInstance,
|
|
244
244
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
245
245
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
246
246
|
done: HookHandlerDoneFunction
|
|
@@ -255,7 +255,7 @@ export interface onResponseAsyncHookHandler<
|
|
|
255
255
|
ContextConfig = ContextConfigDefault
|
|
256
256
|
> {
|
|
257
257
|
(
|
|
258
|
-
this: FastifyInstance
|
|
258
|
+
this: FastifyInstance,
|
|
259
259
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
260
260
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>
|
|
261
261
|
): Promise<unknown>;
|
|
@@ -273,7 +273,7 @@ export interface onTimeoutHookHandler<
|
|
|
273
273
|
ContextConfig = ContextConfigDefault
|
|
274
274
|
> {
|
|
275
275
|
(
|
|
276
|
-
this: FastifyInstance
|
|
276
|
+
this: FastifyInstance,
|
|
277
277
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
278
278
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
279
279
|
done: HookHandlerDoneFunction
|
|
@@ -288,7 +288,7 @@ export interface onTimeoutAsyncHookHandler<
|
|
|
288
288
|
ContextConfig = ContextConfigDefault
|
|
289
289
|
> {
|
|
290
290
|
(
|
|
291
|
-
this: FastifyInstance
|
|
291
|
+
this: FastifyInstance,
|
|
292
292
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
293
293
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>
|
|
294
294
|
): Promise<unknown>;
|
|
@@ -309,7 +309,7 @@ export interface onErrorHookHandler<
|
|
|
309
309
|
TError extends Error = FastifyError
|
|
310
310
|
> {
|
|
311
311
|
(
|
|
312
|
-
this: FastifyInstance
|
|
312
|
+
this: FastifyInstance,
|
|
313
313
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
314
314
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
315
315
|
error: TError,
|
|
@@ -326,7 +326,7 @@ export interface onErrorAsyncHookHandler<
|
|
|
326
326
|
TError extends Error = FastifyError
|
|
327
327
|
> {
|
|
328
328
|
(
|
|
329
|
-
this: FastifyInstance
|
|
329
|
+
this: FastifyInstance,
|
|
330
330
|
request: FastifyRequest<RouteGeneric, RawServer, RawRequest>,
|
|
331
331
|
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig>,
|
|
332
332
|
error: TError
|
|
@@ -346,7 +346,7 @@ export interface onRouteHookHandler<
|
|
|
346
346
|
ContextConfig = ContextConfigDefault
|
|
347
347
|
> {
|
|
348
348
|
(
|
|
349
|
-
this: FastifyInstance
|
|
349
|
+
this: FastifyInstance,
|
|
350
350
|
opts: RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig> & { routePath: string; path: string; prefix: string }
|
|
351
351
|
): Promise<unknown> | void;
|
|
352
352
|
}
|
package/types/instance.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRequestResponse, CallbackFunc as LightMyRequestCallback } from 'light-my-request'
|
|
2
2
|
import { RouteOptions, RouteShorthandMethod, RouteGenericInterface, DefaultRoute } from './route'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
FastifySchema,
|
|
5
|
+
FastifySchemaCompiler,
|
|
6
|
+
FastifySchemaValidationError,
|
|
7
|
+
FastifySerializerCompiler,
|
|
8
|
+
FastifySchemaControllerOptions
|
|
9
|
+
} from './schema'
|
|
4
10
|
import { RawServerBase, RawRequestDefaultExpression, RawServerDefault, RawReplyDefaultExpression, ContextConfigDefault } from './utils'
|
|
5
11
|
import { FastifyLoggerInstance } from './logger'
|
|
6
12
|
import { FastifyRegister } from './register'
|
|
@@ -380,6 +386,11 @@ export interface FastifyInstance<
|
|
|
380
386
|
*/
|
|
381
387
|
setSerializerCompiler<T = FastifySchema>(schemaCompiler: FastifySerializerCompiler<T>): FastifyInstance<RawServer, RawRequest, RawReply, Logger>;
|
|
382
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Set the schema controller for all routes.
|
|
391
|
+
*/
|
|
392
|
+
setSchemaController(schemaControllerOpts: FastifySchemaControllerOptions): FastifyInstance<RawServer, RawRequest, RawReply, Logger>;
|
|
393
|
+
|
|
383
394
|
/**
|
|
384
395
|
* Set the reply serializer for all routes.
|
|
385
396
|
*/
|
|
@@ -427,6 +438,7 @@ export interface FastifyInstance<
|
|
|
427
438
|
initialConfig: Readonly<{
|
|
428
439
|
connectionTimeout?: number,
|
|
429
440
|
keepAliveTimeout?: number,
|
|
441
|
+
forceCloseConnections?: boolean,
|
|
430
442
|
bodyLimit?: number,
|
|
431
443
|
caseSensitive?: boolean,
|
|
432
444
|
http2?: boolean,
|
package/types/schema.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { ValidatorCompiler } from '@fastify/ajv-compiler'
|
|
2
|
+
import { FastifyInstance, FastifyServerOptions } from '../fastify'
|
|
1
3
|
/**
|
|
2
4
|
* Schemas in Fastify follow the JSON-Schema standard. For this reason
|
|
3
5
|
* we have opted to not ship strict schema based types. Instead we provide
|
|
@@ -36,3 +38,15 @@ export interface FastifyValidationResult {
|
|
|
36
38
|
export type FastifySchemaCompiler<T> = (routeSchema: FastifyRouteSchemaDef<T>) => FastifyValidationResult
|
|
37
39
|
|
|
38
40
|
export type FastifySerializerCompiler<T> = (routeSchema: FastifyRouteSchemaDef<T>) => (data: any) => string
|
|
41
|
+
|
|
42
|
+
export interface FastifySchemaControllerOptions{
|
|
43
|
+
bucket?: (parentSchemas?: unknown) => {
|
|
44
|
+
addSchema(schema: unknown): FastifyInstance;
|
|
45
|
+
getSchema(schemaId: string): unknown;
|
|
46
|
+
getSchemas(): Record<string, unknown>;
|
|
47
|
+
};
|
|
48
|
+
compilersFactory?: {
|
|
49
|
+
buildValidator?: ValidatorCompiler;
|
|
50
|
+
buildSerializer?: (externalSchemas: unknown, serializerOptsServerOption: FastifyServerOptions['serializerOpts']) => FastifySerializerCompiler<unknown>;
|
|
51
|
+
};
|
|
52
|
+
}
|