feat(backend): Setup Swagger
Setup algemene config en pad
This commit is contained in:
		
							parent
							
								
									3cd7496989
								
							
						
					
					
						commit
						41dcb57b25
					
				
					 4 changed files with 480 additions and 8 deletions
				
			
		|  | @ -25,6 +25,8 @@ | ||||||
|         "js-yaml": "^4.1.0", |         "js-yaml": "^4.1.0", | ||||||
|         "loki-logger-ts": "^1.0.2", |         "loki-logger-ts": "^1.0.2", | ||||||
|         "response-time": "^2.3.3", |         "response-time": "^2.3.3", | ||||||
|  |         "swagger-jsdoc": "^6.2.8", | ||||||
|  |         "swagger-ui-express": "^5.0.1", | ||||||
|         "uuid": "^11.1.0", |         "uuid": "^11.1.0", | ||||||
|         "winston": "^3.17.0", |         "winston": "^3.17.0", | ||||||
|         "winston-loki": "^6.1.3" |         "winston-loki": "^6.1.3" | ||||||
|  | @ -34,6 +36,8 @@ | ||||||
|         "@types/express": "^5.0.0", |         "@types/express": "^5.0.0", | ||||||
|         "@types/node": "^22.13.4", |         "@types/node": "^22.13.4", | ||||||
|         "@types/response-time": "^2.3.8", |         "@types/response-time": "^2.3.8", | ||||||
|  |         "@types/swagger-jsdoc": "^6.0.4", | ||||||
|  |         "@types/swagger-ui-express": "^4.1.8", | ||||||
|         "globals": "^15.15.0", |         "globals": "^15.15.0", | ||||||
|         "ts-node": "^10.9.2", |         "ts-node": "^10.9.2", | ||||||
|         "tsx": "^4.19.3", |         "tsx": "^4.19.3", | ||||||
|  |  | ||||||
|  | @ -16,6 +16,8 @@ import { getLogger, Logger } from './logging/initalize.js'; | ||||||
| import { responseTimeLogger } from './logging/responseTimeLogger.js'; | import { responseTimeLogger } from './logging/responseTimeLogger.js'; | ||||||
| import responseTime from 'response-time'; | import responseTime from 'response-time'; | ||||||
| import { EnvVars, getNumericEnvVar } from './util/envvars.js'; | import { EnvVars, getNumericEnvVar } from './util/envvars.js'; | ||||||
|  | import swaggerUi from 'swagger-ui-express'; | ||||||
|  | import swaggerMiddleware from './swagger'; | ||||||
| 
 | 
 | ||||||
| const logger: Logger = getLogger(); | const logger: Logger = getLogger(); | ||||||
| 
 | 
 | ||||||
|  | @ -23,7 +25,6 @@ const app: Express = express(); | ||||||
| const port: string | number = getNumericEnvVar(EnvVars.Port); | const port: string | number = getNumericEnvVar(EnvVars.Port); | ||||||
| 
 | 
 | ||||||
| app.use(express.json()); | app.use(express.json()); | ||||||
| app.use(responseTime(responseTimeLogger)); |  | ||||||
| 
 | 
 | ||||||
| // TODO Replace with Express routes
 | // TODO Replace with Express routes
 | ||||||
| app.get('/', (_, res: Response) => { | app.get('/', (_, res: Response) => { | ||||||
|  | @ -33,6 +34,7 @@ app.get('/', (_, res: Response) => { | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | // Routes
 | ||||||
| app.use('/student', studentRouter); | app.use('/student', studentRouter); | ||||||
| app.use('/group', groupRouter); | app.use('/group', groupRouter); | ||||||
| app.use('/assignment', assignmentRouter); | app.use('/assignment', assignmentRouter); | ||||||
|  | @ -45,6 +47,12 @@ app.use('/theme', themeRoutes); | ||||||
| app.use('/learningPath', learningPathRoutes); | app.use('/learningPath', learningPathRoutes); | ||||||
| app.use('/learningObject', learningObjectRoutes); | app.use('/learningObject', learningObjectRoutes); | ||||||
| 
 | 
 | ||||||
|  | // Add response time logging
 | ||||||
|  | app.use(responseTime(responseTimeLogger)); | ||||||
|  | 
 | ||||||
|  | // Swagger UI for API documentation
 | ||||||
|  | app.use('/api-docs', swaggerUi.serve, swaggerMiddleware); | ||||||
|  | 
 | ||||||
| async function startServer() { | async function startServer() { | ||||||
|     await initORM(); |     await initORM(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								backend/src/swagger.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								backend/src/swagger.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | import swaggerJSDoc from 'swagger-jsdoc'; | ||||||
|  | import { RequestHandler } from 'express'; | ||||||
|  | import swaggerUi from 'swagger-ui-express'; | ||||||
|  | 
 | ||||||
|  | const swaggerJSDocOptions: swaggerJSDoc.Options = { | ||||||
|  |     definition: { | ||||||
|  |         openapi: '3.1.0', | ||||||
|  |         info: { | ||||||
|  |             title: 'Dwengo-1 Backend API', | ||||||
|  |             version: '0.1.0', | ||||||
|  |             description: 'Dwengo-1 Backend API Using Express, based on VZW Dwengo', | ||||||
|  |             license: { | ||||||
|  |                 'name': 'MIT', | ||||||
|  |                 'url': 'https://github.com/SELab-2/Dwengo-1/blob/336496ab6352ee3f8bf47490c90b5cf81526cef6/LICENSE' | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         servers: [ | ||||||
|  |             { | ||||||
|  |                 url: 'http://localhost:3000', | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |                 url: 'https://sel2-1.ugent.be/api' | ||||||
|  |             } | ||||||
|  |         ] | ||||||
|  |     }, | ||||||
|  |     apis: [ './src/routes/*.ts', './src/entities/**/*.ts' ] | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const swaggerOptions = { | ||||||
|  |     explorer: true | ||||||
|  | }; | ||||||
|  | const swaggerDocument = swaggerJSDoc(swaggerJSDocOptions); | ||||||
|  | 
 | ||||||
|  | const swaggerMiddleware: RequestHandler = swaggerUi.setup(swaggerDocument, swaggerOptions); | ||||||
|  | 
 | ||||||
|  | export default swaggerMiddleware; | ||||||
							
								
								
									
										438
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										438
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -39,6 +39,8 @@ | ||||||
|                 "js-yaml": "^4.1.0", |                 "js-yaml": "^4.1.0", | ||||||
|                 "loki-logger-ts": "^1.0.2", |                 "loki-logger-ts": "^1.0.2", | ||||||
|                 "response-time": "^2.3.3", |                 "response-time": "^2.3.3", | ||||||
|  |                 "swagger-jsdoc": "^6.2.8", | ||||||
|  |                 "swagger-ui-express": "^5.0.1", | ||||||
|                 "uuid": "^11.1.0", |                 "uuid": "^11.1.0", | ||||||
|                 "winston": "^3.17.0", |                 "winston": "^3.17.0", | ||||||
|                 "winston-loki": "^6.1.3" |                 "winston-loki": "^6.1.3" | ||||||
|  | @ -48,10 +50,13 @@ | ||||||
|                 "@types/express": "^5.0.0", |                 "@types/express": "^5.0.0", | ||||||
|                 "@types/node": "^22.13.4", |                 "@types/node": "^22.13.4", | ||||||
|                 "@types/response-time": "^2.3.8", |                 "@types/response-time": "^2.3.8", | ||||||
|  |                 "@types/swagger-jsdoc": "^6.0.4", | ||||||
|  |                 "@types/swagger-ui-express": "^4.1.8", | ||||||
|                 "globals": "^15.15.0", |                 "globals": "^15.15.0", | ||||||
|                 "ts-node": "^10.9.2", |                 "ts-node": "^10.9.2", | ||||||
|                 "tsx": "^4.19.3", |                 "tsx": "^4.19.3", | ||||||
|                 "typescript": "^5.7.3", |                 "typescript": "^5.7.3", | ||||||
|  |                 "typescript-json-schema": "^0.65.1", | ||||||
|                 "vitest": "^3.0.6" |                 "vitest": "^3.0.6" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  | @ -142,6 +147,50 @@ | ||||||
|                 "url": "https://github.com/sponsors/antfu" |                 "url": "https://github.com/sponsors/antfu" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/@apidevtools/json-schema-ref-parser": { | ||||||
|  |             "version": "9.1.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", | ||||||
|  |             "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "@jsdevtools/ono": "^7.1.3", | ||||||
|  |                 "@types/json-schema": "^7.0.6", | ||||||
|  |                 "call-me-maybe": "^1.0.1", | ||||||
|  |                 "js-yaml": "^4.1.0" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/@apidevtools/openapi-schemas": { | ||||||
|  |             "version": "2.1.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", | ||||||
|  |             "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">=10" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/@apidevtools/swagger-methods": { | ||||||
|  |             "version": "3.0.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", | ||||||
|  |             "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|  |         "node_modules/@apidevtools/swagger-parser": { | ||||||
|  |             "version": "10.0.3", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", | ||||||
|  |             "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "@apidevtools/json-schema-ref-parser": "^9.0.6", | ||||||
|  |                 "@apidevtools/openapi-schemas": "^2.0.4", | ||||||
|  |                 "@apidevtools/swagger-methods": "^3.0.2", | ||||||
|  |                 "@jsdevtools/ono": "^7.1.3", | ||||||
|  |                 "call-me-maybe": "^1.0.1", | ||||||
|  |                 "z-schema": "^5.0.1" | ||||||
|  |             }, | ||||||
|  |             "peerDependencies": { | ||||||
|  |                 "openapi-types": ">=7" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "node_modules/@asamuzakjp/css-color": { |         "node_modules/@asamuzakjp/css-color": { | ||||||
|             "version": "2.8.3", |             "version": "2.8.3", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -1035,6 +1084,12 @@ | ||||||
|                 "@jridgewell/sourcemap-codec": "^1.4.10" |                 "@jridgewell/sourcemap-codec": "^1.4.10" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/@jsdevtools/ono": { | ||||||
|  |             "version": "7.1.3", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", | ||||||
|  |             "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|         "node_modules/@mikro-orm/cli": { |         "node_modules/@mikro-orm/cli": { | ||||||
|             "version": "6.4.6", |             "version": "6.4.6", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -1556,6 +1611,13 @@ | ||||||
|                 "linux" |                 "linux" | ||||||
|             ] |             ] | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/@scarf/scarf": { | ||||||
|  |             "version": "1.4.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", | ||||||
|  |             "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", | ||||||
|  |             "hasInstallScript": true, | ||||||
|  |             "license": "Apache-2.0" | ||||||
|  |         }, | ||||||
|         "node_modules/@sec-ant/readable-stream": { |         "node_modules/@sec-ant/readable-stream": { | ||||||
|             "version": "0.4.1", |             "version": "0.4.1", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -1684,7 +1746,6 @@ | ||||||
|         }, |         }, | ||||||
|         "node_modules/@types/json-schema": { |         "node_modules/@types/json-schema": { | ||||||
|             "version": "7.0.15", |             "version": "7.0.15", | ||||||
|             "dev": true, |  | ||||||
|             "license": "MIT" |             "license": "MIT" | ||||||
|         }, |         }, | ||||||
|         "node_modules/@types/mime": { |         "node_modules/@types/mime": { | ||||||
|  | @ -1739,6 +1800,24 @@ | ||||||
|                 "@types/send": "*" |                 "@types/send": "*" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/@types/swagger-jsdoc": { | ||||||
|  |             "version": "6.0.4", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz", | ||||||
|  |             "integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|  |         "node_modules/@types/swagger-ui-express": { | ||||||
|  |             "version": "4.1.8", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz", | ||||||
|  |             "integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "@types/express": "*", | ||||||
|  |                 "@types/serve-static": "*" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "node_modules/@types/tough-cookie": { |         "node_modules/@types/tough-cookie": { | ||||||
|             "version": "4.0.5", |             "version": "4.0.5", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -2873,6 +2952,12 @@ | ||||||
|                 "url": "https://github.com/sponsors/ljharb" |                 "url": "https://github.com/sponsors/ljharb" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/call-me-maybe": { | ||||||
|  |             "version": "1.0.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", | ||||||
|  |             "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|         "node_modules/callsites": { |         "node_modules/callsites": { | ||||||
|             "version": "3.1.0", |             "version": "3.1.0", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -3114,7 +3199,6 @@ | ||||||
|         }, |         }, | ||||||
|         "node_modules/concat-map": { |         "node_modules/concat-map": { | ||||||
|             "version": "0.0.1", |             "version": "0.0.1", | ||||||
|             "devOptional": true, |  | ||||||
|             "license": "MIT" |             "license": "MIT" | ||||||
|         }, |         }, | ||||||
|         "node_modules/config-chain": { |         "node_modules/config-chain": { | ||||||
|  | @ -3389,6 +3473,18 @@ | ||||||
|                 "node": ">=8" |                 "node": ">=8" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/doctrine": { | ||||||
|  |             "version": "3.0.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", | ||||||
|  |             "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", | ||||||
|  |             "license": "Apache-2.0", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "esutils": "^2.0.2" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">=6.0.0" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "node_modules/dotenv": { |         "node_modules/dotenv": { | ||||||
|             "version": "16.4.7", |             "version": "16.4.7", | ||||||
|             "license": "BSD-2-Clause", |             "license": "BSD-2-Clause", | ||||||
|  | @ -3944,7 +4040,6 @@ | ||||||
|         }, |         }, | ||||||
|         "node_modules/esutils": { |         "node_modules/esutils": { | ||||||
|             "version": "2.0.3", |             "version": "2.0.3", | ||||||
|             "dev": true, |  | ||||||
|             "license": "BSD-2-Clause", |             "license": "BSD-2-Clause", | ||||||
|             "engines": { |             "engines": { | ||||||
|                 "node": ">=0.10.0" |                 "node": ">=0.10.0" | ||||||
|  | @ -4355,8 +4450,22 @@ | ||||||
|         }, |         }, | ||||||
|         "node_modules/fs.realpath": { |         "node_modules/fs.realpath": { | ||||||
|             "version": "1.0.0", |             "version": "1.0.0", | ||||||
|             "license": "ISC", |             "license": "ISC" | ||||||
|             "optional": true |         }, | ||||||
|  |         "node_modules/fsevents": { | ||||||
|  |             "version": "2.3.3", | ||||||
|  |             "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", | ||||||
|  |             "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", | ||||||
|  |             "dev": true, | ||||||
|  |             "hasInstallScript": true, | ||||||
|  |             "license": "MIT", | ||||||
|  |             "optional": true, | ||||||
|  |             "os": [ | ||||||
|  |                 "darwin" | ||||||
|  |             ], | ||||||
|  |             "engines": { | ||||||
|  |                 "node": "^8.16.0 || ^10.6.0 || >=11.0.0" | ||||||
|  |             } | ||||||
|         }, |         }, | ||||||
|         "node_modules/function-bind": { |         "node_modules/function-bind": { | ||||||
|             "version": "1.1.2", |             "version": "1.1.2", | ||||||
|  | @ -4807,7 +4916,6 @@ | ||||||
|         "node_modules/inflight": { |         "node_modules/inflight": { | ||||||
|             "version": "1.0.6", |             "version": "1.0.6", | ||||||
|             "license": "ISC", |             "license": "ISC", | ||||||
|             "optional": true, |  | ||||||
|             "dependencies": { |             "dependencies": { | ||||||
|                 "once": "^1.3.0", |                 "once": "^1.3.0", | ||||||
|                 "wrappy": "1" |                 "wrappy": "1" | ||||||
|  | @ -5302,11 +5410,31 @@ | ||||||
|             "version": "4.17.21", |             "version": "4.17.21", | ||||||
|             "license": "MIT" |             "license": "MIT" | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/lodash.get": { | ||||||
|  |             "version": "4.4.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", | ||||||
|  |             "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", | ||||||
|  |             "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|  |         "node_modules/lodash.isequal": { | ||||||
|  |             "version": "4.5.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", | ||||||
|  |             "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", | ||||||
|  |             "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|         "node_modules/lodash.merge": { |         "node_modules/lodash.merge": { | ||||||
|             "version": "4.6.2", |             "version": "4.6.2", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|             "license": "MIT" |             "license": "MIT" | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/lodash.mergewith": { | ||||||
|  |             "version": "4.6.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", | ||||||
|  |             "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|         "node_modules/logform": { |         "node_modules/logform": { | ||||||
|             "version": "2.7.0", |             "version": "2.7.0", | ||||||
|             "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", |             "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", | ||||||
|  | @ -6106,6 +6234,13 @@ | ||||||
|                 "url": "https://github.com/sponsors/sindresorhus" |                 "url": "https://github.com/sponsors/sindresorhus" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/openapi-types": { | ||||||
|  |             "version": "12.1.3", | ||||||
|  |             "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", | ||||||
|  |             "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "peer": true | ||||||
|  |         }, | ||||||
|         "node_modules/optionator": { |         "node_modules/optionator": { | ||||||
|             "version": "0.9.4", |             "version": "0.9.4", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -6220,6 +6355,13 @@ | ||||||
|             "version": "1.0.1", |             "version": "1.0.1", | ||||||
|             "license": "MIT" |             "license": "MIT" | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/path-equal": { | ||||||
|  |             "version": "1.2.5", | ||||||
|  |             "resolved": "https://registry.npmjs.org/path-equal/-/path-equal-1.2.5.tgz", | ||||||
|  |             "integrity": "sha512-i73IctDr3F2W+bsOWDyyVm/lqsXO47aY9nsFZUjTT/aljSbkxHxxCoyZ9UUrM8jK0JVod+An+rl48RCsvWM+9g==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|         "node_modules/path-exists": { |         "node_modules/path-exists": { | ||||||
|             "version": "4.0.0", |             "version": "4.0.0", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -6231,7 +6373,6 @@ | ||||||
|         "node_modules/path-is-absolute": { |         "node_modules/path-is-absolute": { | ||||||
|             "version": "1.0.1", |             "version": "1.0.1", | ||||||
|             "license": "MIT", |             "license": "MIT", | ||||||
|             "optional": true, |  | ||||||
|             "engines": { |             "engines": { | ||||||
|                 "node": ">=0.10.0" |                 "node": ">=0.10.0" | ||||||
|             } |             } | ||||||
|  | @ -6449,6 +6590,21 @@ | ||||||
|                 "node": ">=18" |                 "node": ">=18" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/playwright/node_modules/fsevents": { | ||||||
|  |             "version": "2.3.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", | ||||||
|  |             "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", | ||||||
|  |             "dev": true, | ||||||
|  |             "hasInstallScript": true, | ||||||
|  |             "license": "MIT", | ||||||
|  |             "optional": true, | ||||||
|  |             "os": [ | ||||||
|  |                 "darwin" | ||||||
|  |             ], | ||||||
|  |             "engines": { | ||||||
|  |                 "node": "^8.16.0 || ^10.6.0 || >=11.0.0" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "node_modules/postcss": { |         "node_modules/postcss": { | ||||||
|             "version": "8.5.3", |             "version": "8.5.3", | ||||||
|             "funding": [ |             "funding": [ | ||||||
|  | @ -7649,6 +7805,123 @@ | ||||||
|             "version": "1.0.0", |             "version": "1.0.0", | ||||||
|             "dev": true |             "dev": true | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/swagger-jsdoc": { | ||||||
|  |             "version": "6.2.8", | ||||||
|  |             "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", | ||||||
|  |             "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "commander": "6.2.0", | ||||||
|  |                 "doctrine": "3.0.0", | ||||||
|  |                 "glob": "7.1.6", | ||||||
|  |                 "lodash.mergewith": "^4.6.2", | ||||||
|  |                 "swagger-parser": "^10.0.3", | ||||||
|  |                 "yaml": "2.0.0-1" | ||||||
|  |             }, | ||||||
|  |             "bin": { | ||||||
|  |                 "swagger-jsdoc": "bin/swagger-jsdoc.js" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">=12.0.0" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-jsdoc/node_modules/brace-expansion": { | ||||||
|  |             "version": "1.1.11", | ||||||
|  |             "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | ||||||
|  |             "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "balanced-match": "^1.0.0", | ||||||
|  |                 "concat-map": "0.0.1" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-jsdoc/node_modules/commander": { | ||||||
|  |             "version": "6.2.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", | ||||||
|  |             "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">= 6" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-jsdoc/node_modules/glob": { | ||||||
|  |             "version": "7.1.6", | ||||||
|  |             "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", | ||||||
|  |             "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", | ||||||
|  |             "deprecated": "Glob versions prior to v9 are no longer supported", | ||||||
|  |             "license": "ISC", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "fs.realpath": "^1.0.0", | ||||||
|  |                 "inflight": "^1.0.4", | ||||||
|  |                 "inherits": "2", | ||||||
|  |                 "minimatch": "^3.0.4", | ||||||
|  |                 "once": "^1.3.0", | ||||||
|  |                 "path-is-absolute": "^1.0.0" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": "*" | ||||||
|  |             }, | ||||||
|  |             "funding": { | ||||||
|  |                 "url": "https://github.com/sponsors/isaacs" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-jsdoc/node_modules/minimatch": { | ||||||
|  |             "version": "3.1.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | ||||||
|  |             "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | ||||||
|  |             "license": "ISC", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "brace-expansion": "^1.1.7" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": "*" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-jsdoc/node_modules/yaml": { | ||||||
|  |             "version": "2.0.0-1", | ||||||
|  |             "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", | ||||||
|  |             "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", | ||||||
|  |             "license": "ISC", | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">= 6" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-parser": { | ||||||
|  |             "version": "10.0.3", | ||||||
|  |             "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", | ||||||
|  |             "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "@apidevtools/swagger-parser": "10.0.3" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">=10" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-ui-dist": { | ||||||
|  |             "version": "5.20.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.20.0.tgz", | ||||||
|  |             "integrity": "sha512-V5pozVTZxivdoQq/SQWxj3A4cOu5opk9MEbcZANX3Pj8X8xCrD1QCtBT7744Pz9msOvt0nnmy9JvM/9PGonCdg==", | ||||||
|  |             "license": "Apache-2.0", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "@scarf/scarf": "=1.4.0" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/swagger-ui-express": { | ||||||
|  |             "version": "5.0.1", | ||||||
|  |             "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", | ||||||
|  |             "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "swagger-ui-dist": ">=5.0.0" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">= v0.10.32" | ||||||
|  |             }, | ||||||
|  |             "peerDependencies": { | ||||||
|  |                 "express": ">=4.0.0 || >=5.0.0-beta" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "node_modules/symbol-tree": { |         "node_modules/symbol-tree": { | ||||||
|             "version": "3.2.4", |             "version": "3.2.4", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -8023,6 +8296,103 @@ | ||||||
|                 "typescript": ">=4.8.4 <5.8.0" |                 "typescript": ">=4.8.4 <5.8.0" | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/typescript-json-schema": { | ||||||
|  |             "version": "0.65.1", | ||||||
|  |             "resolved": "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.65.1.tgz", | ||||||
|  |             "integrity": "sha512-tuGH7ff2jPaUYi6as3lHyHcKpSmXIqN7/mu50x3HlYn0EHzLpmt3nplZ7EuhUkO0eqDRc9GqWNkfjgBPIS9kxg==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "BSD-3-Clause", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "@types/json-schema": "^7.0.9", | ||||||
|  |                 "@types/node": "^18.11.9", | ||||||
|  |                 "glob": "^7.1.7", | ||||||
|  |                 "path-equal": "^1.2.5", | ||||||
|  |                 "safe-stable-stringify": "^2.2.0", | ||||||
|  |                 "ts-node": "^10.9.1", | ||||||
|  |                 "typescript": "~5.5.0", | ||||||
|  |                 "yargs": "^17.1.1" | ||||||
|  |             }, | ||||||
|  |             "bin": { | ||||||
|  |                 "typescript-json-schema": "bin/typescript-json-schema" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/typescript-json-schema/node_modules/@types/node": { | ||||||
|  |             "version": "18.19.79", | ||||||
|  |             "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.79.tgz", | ||||||
|  |             "integrity": "sha512-90K8Oayimbctc5zTPHPfZloc/lGVs7f3phUAAMcTgEPtg8kKquGZDERC8K4vkBYkQQh48msiYUslYtxTWvqcAg==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "undici-types": "~5.26.4" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/typescript-json-schema/node_modules/brace-expansion": { | ||||||
|  |             "version": "1.1.11", | ||||||
|  |             "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | ||||||
|  |             "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "balanced-match": "^1.0.0", | ||||||
|  |                 "concat-map": "0.0.1" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/typescript-json-schema/node_modules/glob": { | ||||||
|  |             "version": "7.2.3", | ||||||
|  |             "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", | ||||||
|  |             "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", | ||||||
|  |             "deprecated": "Glob versions prior to v9 are no longer supported", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "ISC", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "fs.realpath": "^1.0.0", | ||||||
|  |                 "inflight": "^1.0.4", | ||||||
|  |                 "inherits": "2", | ||||||
|  |                 "minimatch": "^3.1.1", | ||||||
|  |                 "once": "^1.3.0", | ||||||
|  |                 "path-is-absolute": "^1.0.0" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": "*" | ||||||
|  |             }, | ||||||
|  |             "funding": { | ||||||
|  |                 "url": "https://github.com/sponsors/isaacs" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/typescript-json-schema/node_modules/minimatch": { | ||||||
|  |             "version": "3.1.2", | ||||||
|  |             "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", | ||||||
|  |             "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "ISC", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "brace-expansion": "^1.1.7" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": "*" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/typescript-json-schema/node_modules/typescript": { | ||||||
|  |             "version": "5.5.4", | ||||||
|  |             "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", | ||||||
|  |             "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "Apache-2.0", | ||||||
|  |             "bin": { | ||||||
|  |                 "tsc": "bin/tsc", | ||||||
|  |                 "tsserver": "bin/tsserver" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">=14.17" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/typescript-json-schema/node_modules/undici-types": { | ||||||
|  |             "version": "5.26.5", | ||||||
|  |             "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", | ||||||
|  |             "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "MIT" | ||||||
|  |         }, | ||||||
|         "node_modules/undici-types": { |         "node_modules/undici-types": { | ||||||
|             "version": "6.20.0", |             "version": "6.20.0", | ||||||
|             "license": "MIT" |             "license": "MIT" | ||||||
|  | @ -8138,6 +8508,15 @@ | ||||||
|             "dev": true, |             "dev": true, | ||||||
|             "license": "MIT" |             "license": "MIT" | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/validator": { | ||||||
|  |             "version": "13.12.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", | ||||||
|  |             "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">= 0.10" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "node_modules/vary": { |         "node_modules/vary": { | ||||||
|             "version": "1.1.2", |             "version": "1.1.2", | ||||||
|             "license": "MIT", |             "license": "MIT", | ||||||
|  | @ -8930,6 +9309,21 @@ | ||||||
|             "dev": true, |             "dev": true, | ||||||
|             "license": "ISC" |             "license": "ISC" | ||||||
|         }, |         }, | ||||||
|  |         "node_modules/yaml": { | ||||||
|  |             "version": "2.7.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", | ||||||
|  |             "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", | ||||||
|  |             "dev": true, | ||||||
|  |             "license": "ISC", | ||||||
|  |             "optional": true, | ||||||
|  |             "peer": true, | ||||||
|  |             "bin": { | ||||||
|  |                 "yaml": "bin.mjs" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">= 14" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|         "node_modules/yargs": { |         "node_modules/yargs": { | ||||||
|             "version": "17.7.2", |             "version": "17.7.2", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -9021,6 +9415,36 @@ | ||||||
|             "funding": { |             "funding": { | ||||||
|                 "url": "https://github.com/sponsors/sindresorhus" |                 "url": "https://github.com/sponsors/sindresorhus" | ||||||
|             } |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/z-schema": { | ||||||
|  |             "version": "5.0.5", | ||||||
|  |             "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", | ||||||
|  |             "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "dependencies": { | ||||||
|  |                 "lodash.get": "^4.4.2", | ||||||
|  |                 "lodash.isequal": "^4.5.0", | ||||||
|  |                 "validator": "^13.7.0" | ||||||
|  |             }, | ||||||
|  |             "bin": { | ||||||
|  |                 "z-schema": "bin/z-schema" | ||||||
|  |             }, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": ">=8.0.0" | ||||||
|  |             }, | ||||||
|  |             "optionalDependencies": { | ||||||
|  |                 "commander": "^9.4.1" | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         "node_modules/z-schema/node_modules/commander": { | ||||||
|  |             "version": "9.5.0", | ||||||
|  |             "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", | ||||||
|  |             "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", | ||||||
|  |             "license": "MIT", | ||||||
|  |             "optional": true, | ||||||
|  |             "engines": { | ||||||
|  |                 "node": "^12.20.0 || >=14" | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Reference in a new issue