From 1988a67b359e10e4746719ea1f07861e35f4b9b0 Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Tue, 28 Jul 2020 10:30:10 +0200 Subject: [PATCH] modified api.ts to directly incorporate swagger-ui-express code --- data_import/import.js | 4 +- package-lock.json | 14 +- package.json | 2 +- src/api.ts | 155 +++++++++++++---- src/index.ts | 36 +++- src/routes/template.ts | 9 +- static/img/favicon.ico | Bin 0 -> 1150 bytes static/styles/swagger-ui.css | 323 +++++++++++++++++++++++++++++++++++ static/styles/swagger.css | 323 ----------------------------------- 9 files changed, 489 insertions(+), 377 deletions(-) create mode 100644 static/img/favicon.ico create mode 100644 static/styles/swagger-ui.css delete mode 100644 static/styles/swagger.css diff --git a/data_import/import.js b/data_import/import.js index 24a0292..aa84bf3 100644 --- a/data_import/import.js +++ b/data_import/import.js @@ -30,8 +30,8 @@ const docs = [ const errors = []; const nmDocs = 'C:\\Users\\vle2fe\\Documents\\Data\\All_200717\\nmDocs'; // NormMaster Documents const dptFiles = 'C:\\Users\\vle2fe\\Documents\\Data\\All_200717\\DPT'; // Spectrum files -// const host = 'http://localhost:3000'; -const host = 'https://definma-api.apps.de1.bosch-iot-cloud.com'; +const host = 'http://localhost:3000'; +// const host = 'https://definma-api.apps.de1.bosch-iot-cloud.com'; const requiredProperties = ['samplenumber','materialnumber','materialname','supplier','reinforcementmaterial','material','granulate/part','color','charge/batch','comments']; dict = { // dictionary 'Granulat': 'granulate', diff --git a/package-lock.json b/package-lock.json index 34fb53e..6749f0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3773,17 +3773,9 @@ } }, "swagger-ui-dist": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.24.3.tgz", - "integrity": "sha512-kB8qobP42Xazaym7sD9g5mZuRL4416VIIYZMqPEIskkzKqbPLQGEiHA3ga31bdzyzFLgr6Z797+6X1Am6zYpbg==" - }, - "swagger-ui-express": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.1.2.tgz", - "integrity": "sha512-bVT16qj6WdNlEKFkSLOoTeGuqEm2lfOFRq6mVHAx+viA/ikORE+n4CS3WpVcYmQzM4HE6+DUFgAWcMRBJNpjcw==", - "requires": { - "swagger-ui-dist": "^3.18.1" - } + "version": "3.30.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.30.2.tgz", + "integrity": "sha512-hAu/ig5N8i0trXXbrC7rwbXV4DhpEAsZhYXDs1305OjmDgjGC0thINbb0197idy3Pp+B6w7u426SUM43GAP7qw==" }, "term-size": { "version": "2.2.0", diff --git a/package.json b/package.json index ae69e4f..7bf20ea 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "lodash": "^4.17.15", "mongo-sanitize": "^1.1.0", "mongoose": "^5.8.7", - "swagger-ui-express": "4.1.2" + "swagger-ui-dist": "^3.30.2" }, "devDependencies": { "@types/bcrypt": "^3.0.0", diff --git a/src/api.ts b/src/api.ts index aab7b80..d82a99e 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,48 +1,131 @@ -import swagger from 'swagger-ui-express'; +import express from 'express'; +import swaggerUi from 'swagger-ui-dist'; import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser'; import oasParser from '@apidevtools/swagger-parser'; -// modifies the normal swagger-ui-express package +// modified from https://github.com/scottie1984/swagger-ui-express // usage: app.use('/api-doc', api.serve(), api.setup()); // the paths property can be split using allOf // further route documentation can be included in the x-doc property -export default class api { - static serve () { - return swagger.serve; - } - static setup () { - let apiDoc: JSONSchema = {}; - jsonRefParser.bundle('api/api.yaml', (err, doc) => { // parse yaml - if (err) throw err; - apiDoc = doc; - apiDoc.servers.splice(process.env.NODE_ENV === 'production', 1); - apiDoc.paths = apiDoc.paths.allOf.reduce((s, e) => Object.assign(s, e)); // bundle routes - apiDoc = this.resolveXDoc(apiDoc); - oasParser.validate(apiDoc, (err, api) => { // validate oas schema - if (err) { - console.error(err); - } - else { - console.info(process.env.NODE_ENV === 'test' ? '' : 'API ok, version ' + api.info.version); - swagger.setup(apiDoc); - } - }); - }); - return swagger.setup(apiDoc, {customCssUrl: '/static/styles/swagger.css'}) - } - - private static resolveXDoc (doc) { // resolve x-doc properties recursively - Object.keys(doc).forEach(key => { - if (doc[key] !== null && doc[key].hasOwnProperty('x-doc')) { // add x-doc to description, is styled via css - doc[key].description += '
docs' + doc[key]['x-doc'] + '
'; +export default function api () { + // generate apiDoc + let apiDoc: JSONSchema = {}; + jsonRefParser.bundle('api/api.yaml', (err, doc) => { // parse yaml + if (err) throw err; + apiDoc = doc; + apiDoc.servers.splice(process.env.NODE_ENV === 'production', 1); + apiDoc.paths = apiDoc.paths.allOf.reduce((s, e) => Object.assign(s, e)); // bundle routes + apiDoc = resolveXDoc(apiDoc); + oasParser.validate(apiDoc, (err, api) => { // validate oas schema + if (err) { + console.error(err); } - else if (typeof doc[key] === 'object' && doc[key] !== null) { // go deeper into recursion - doc[key] = this.resolveXDoc(doc[key]); + else { + console.info(process.env.NODE_ENV === 'test' ? '' : 'API ok, version ' + api.info.version); } }); - return doc; - } -} \ No newline at end of file + }); + + return [ + (req, res, next) => { // serve init js and apiDoc file + switch (req.url) { + case '/swagger-ui-init.js': + res.set('Content-Type', 'application/javascript'); + res.send(jsTplString); + break; + case '/apidoc.json': + res.set('Content-Type', 'application/json'); + res.send(apiDoc); + break; + default: + next(); + } + }, // serve swagger files + express.static(swaggerUi.getAbsoluteFSPath(), {index: false}), + (req, res) => { // serve html file as default + res.send(htmlTplString); + } + ]; +} + + +function resolveXDoc (doc) { // resolve x-doc properties recursively + Object.keys(doc).forEach(key => { + if (doc[key] !== null && doc[key].hasOwnProperty('x-doc')) { // add x-doc to description, is styled via css + doc[key].description += '
docs' + doc[key]['x-doc'] + '
'; + } + else if (typeof doc[key] === 'object' && doc[key] !== null) { // go deeper into recursion + doc[key] = resolveXDoc(doc[key]); + } + }); + return doc; +} + + +// templates + +const htmlTplString = ` + + + + + API documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +`; + +const jsTplString = ` +window.onload = function() { + // Build a system + window.ui = SwaggerUIBundle({ + url: '/api-doc/apidoc.json', + dom_id: '#swagger-ui', + deepLinking: true, + presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIStandalonePreset + ], + plugins: [ + SwaggerUIBundle.plugins.DownloadUrl + ], + layout: 'StandaloneLayout' + }); +} +`; \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index d6ea865..b7b5e2e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,8 +24,38 @@ app.disable('x-powered-by'); // get port from environment, defaults to 3000 const port = process.env.PORT || 3000; -//middleware -app.use(helmet()); +// security headers +app.use(helmet({ + contentSecurityPolicy: { + directives: { + defaultSrc: [`'none'`], + baseUri: [`'self'`], + formAction: [`'none'`], + frameAncestors: [`'none'`] + } + } +})); +// special CSP header for api-doc +app.use('/api-doc', helmet.contentSecurityPolicy({ + directives: { + defaultSrc: [`'none'`], + scriptSrc: [`'self'`], + connectSrc: [`'self'`], + styleSrc: [`'self'`, `'unsafe-inline'`], + imgSrc: [`'self'`, 'data:'], + baseUri: [`'self'`], + formAction: [`'none'`], + frameAncestors: [`'none'`] + } +})); +// special CSP header for the bosch-logo.svg +app.use('/static/img/bosch-logo.svg', helmet.contentSecurityPolicy({ + directives: { + styleSrc: [`'unsafe-inline'`] + } +})); + +// middleware app.use(contentFilter()); // filter URL query attacks app.use(express.json({ limit: '5mb'})); app.use(express.urlencoded({ extended: false, limit: '5mb' })); @@ -71,7 +101,7 @@ app.use('/', require('./routes/measurement')); app.use('/static', express.static('static')); // Swagger UI -app.use('/api-doc', api.serve(), api.setup()); +app.use('/api-doc', api()); app.use((req, res) => { // 404 error handling res.status(404).json({status: 'Not found'}); diff --git a/src/routes/template.ts b/src/routes/template.ts index 20f1b3b..5641d1b 100644 --- a/src/routes/template.ts +++ b/src/routes/template.ts @@ -44,7 +44,14 @@ router.put('/template/:collection(measurement|condition|material)/' + IdValidate const {error, value: template} = TemplateValidate.input(req.body, 'change'); if (error) return res400(error, res); - const templateData = await model(req).findById(req.params.id).lean().exec().catch(err => {next(err);}) as any; + // find given template + const templateRef = await model(req).findById(req.params.id).lean().exec().catch(err => {next(err);}) as any; + if (templateRef instanceof Error) return; + if (!templateRef) { + return res.status(404).json({status: 'Not found'}); + } + // find latest version + const templateData = await model(req).findOne({first_id: templateRef.first_id}).sort({version: -1}).lean().exec().catch(err => {next(err);}) as any; if (templateData instanceof Error) return; if (!templateData) { return res.status(404).json({status: 'Not found'}); diff --git a/static/img/favicon.ico b/static/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..41ab51387eac958f34ed8db0be6c968e860bec98 GIT binary patch literal 1150 zcma))e`phD7{_mH^N%s6Fx+s^bxbLnF#lK?4iQG@WDFIHXv#|4SxxC`u=T`qZE&T; zSdVzS#u(GAh7i(lT(i)WtXRn|RXdZ@3YuXTZC7h)(_MRMa=+U&G_CL3E#S%qyW@NB z-E+_9`9AmDiy$w7bJHdST;D^!eFZ_@LJ;HwAP@qPzv5s)5b$pOvAVj7NMio=>8V`N zvx%kR@C|KmU$1)5Ppi7?{n}Sdc;O2nv%C@J{g)mmvL#n-lA(i;(EgCR&+AcY&bNuJ z*PL?Qj}Ez>rql}V&)nPp#?Q?zZ|>_=%CFjF!xgLC2pIh(T*d-^?eMu~q229Lj=8!N zeW*`6@LOE^XnhT7SStnGNytGjkY5Y^LH|d7ut;ZGjlu<=SE+6_ie{hhr>_%JnTHYVh4nR*ot>`Y{5_a~qKy=z?8jMDx+2irl@I3!!p@!s@ zswKB{lmgz+2k?i${K{!cses>enUqk8^3PT*nKZIF4f!MO8p`+B*%Lg~Jxqh1Vb-kH>ce z0)ayoiv@#uutzYbYUl%W3dVuXIGs*?ho$56C^3po|2ng4N>bl}JXFLTIZ8RHx*odc z$lrZ7fqB)pwY7Z@)C$Yh&70&d(iAIa2j9E$gDL z=&_(V*mB!(yPoy3RlJQiq`m2?1_{kq1vkY5S;NhCdWHu&~$t~On_u)J< z|9NUSRmu%MM-60%iz8HpRq2sb}_cN_74g*vP(-FCR6F6*>q;} z#9XQvYBD3eJ0YpXV}iPEgiCGzd0_D1Bikc`Ovx2_Ilnf)0uR^h^74k^kwj^T8QjlA z*|P8*c2DHiP#JUWR$Ua2VgfE;i+2}4d68Lv55M8*lcy!3Q`C#3*d&7eq=mIT`CNW& b&;2tW0rN+Y6`<8`fPz5J5acF&{vUb{Q9#4% literal 0 HcmV?d00001 diff --git a/static/styles/swagger-ui.css b/static/styles/swagger-ui.css new file mode 100644 index 0000000..9372efb --- /dev/null +++ b/static/styles/swagger-ui.css @@ -0,0 +1,323 @@ +/*Bosch styling for swagger*/ + +/*GET: dark blue*/ +/*POST: dark green*/ +/*PUT: turquoise*/ +/*DELETE: fuchsia*/ + +:root { + --red: #ea0016; + --dark-blue: #005691; + --dark-blue-w75: #bfd5e3; + --dark-green: #006249; + --dark-green-w75: #bfd8d1; + --turquoise: #00a8b0; + --turquoise-w75: #bfe9eb; + --fuchsia: #b90276; + --fuchsia-w75: #edc0dd; + --light-grey: #bfc0c2; + --light-grey-w75: #efeff0; + --light-green: #78be20; +} + +body { + background: #fff; +} + +body:before { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 16px; + content: ''; + background-repeat: no-repeat; + background-size: cover; + background-image: url(/static/img/header.svg); +} + +body:after { + position: absolute; + right: 25px; + top: 36px; + width: 135px; + height: 48px; + content: ''; + background-repeat: no-repeat; + background-size: cover; + background-image: url(/static/img/bosch-logo.svg); +} + +.swagger-ui { + font-family: "Bosch Sans", sans-serif; +} + +/*custom docs*/ +.docs { + position: relative; + font-size: 14px; +} + +.docs > summary { + position: absolute; + right: 0; + top: -25px; + cursor: pointer; +} + +.docs-open:hover { + text-decoration: underline; +} + +/*Remove topbar*/ +.swagger-ui .topbar { + display: none +} + +/*Remove models view*/ +.swagger-ui .models { + display: none; +} + +/*Remove application/json select*/ +.swagger-ui .opblock .opblock-section-header > label, .swagger-ui .response-controls { + display: none; +} + +/*Remove border radius*/ +.swagger-ui .opblock, .swagger-ui .opblock .opblock-summary-method, .swagger-ui select { + border-radius: 0; + box-shadow: none; +} + +/*remove links in response*/ +.swagger-ui .response-col_links { + display: none; +} + +/*remove version*/ +.swagger-ui .info .title span { + display: none; +} + +/*separator before methods*/ +.swagger-ui .scheme-container { + box-shadow: none; + border-bottom: 1px solid var(--light-grey); +} + +/*tag separator*/ +.swagger-ui .opblock-tag { + border-bottom: 1px solid var(--light-grey); +} + +/*parameters/responses bar*/ +.swagger-ui .opblock .opblock-section-header { + box-shadow: none; + background: #fff; +} + +/*select*/ +.swagger-ui select { + background-color: var(--light-grey-w75); + border: none; + height: 36px; +} + +/*button*/ +.swagger-ui .btn { + border-radius: 0; + box-shadow: none; +} + +.swagger-ui .btn:hover { + box-shadow: none; +} + +/*authorize button */ +.swagger-ui .btn.authorize { + color: var(--light-green); + border-color: var(--light-green); +} + +.swagger-ui .btn.authorize svg { + fill: var(--light-green); +} + +/*auth inputs*/ +.swagger-ui .auth-container input[type="password"], .swagger-ui .auth-container input[type="text"] { + border-radius: 0; + box-shadow: none; + border-color: var(--light-grey); +} + +.swagger-ui .dialog-ux .modal-ux { + border-radius: 0; +} + +/*cancel button*/ +.swagger-ui .btn.cancel { + color: var(--red); + border-color: var(--red); +} + +/*download button*/ +.swagger-ui .download-contents { + border-radius: 0; + height: 28px; + width: 80px; +} + +/*model*/ +.swagger-ui .model-box { + border-radius: 0; +} + +/*execute button*/ +.swagger-ui .btn.execute { + background-color: var(--dark-blue); + border-color: var(--dark-blue); + height: 30px; + line-height: 0.7; +} + +.swagger-ui .btn-group .btn:last-child { + border-radius: 0; + height: 30px; + border-color: var(--dark-blue); +} + +.swagger-ui .btn-group .btn:first-child { + border-radius: 0; +} + +.swagger-ui .btn-group { + padding: 0 20px; +} + +/*parameter input*/ +.swagger-ui .parameters-col_description input[type="text"] { + border-radius: 0; +} + +/*required label*/ +.swagger-ui .parameter__name.required > span { + color: var(--red) !important; +} + +.swagger-ui .parameter__name.required::after { + color: var(--red); +} +/*Remove colored parameters bar*/ +.swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span::after, .swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span::after, .swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span::after, .swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span::after { + background: none; +} + +/*code*/ +.swagger-ui .opblock-body pre.microlight { + border-radius: 0; +} + +.swagger-ui .highlight-code > .microlight { + min-height: 0; +} + +/*request body*/ +.swagger-ui textarea { + border-radius: 0; +} + +/*parameters smaller padding*/ +.swagger-ui .execute-wrapper { + padding-top: 0; + padding-bottom: 0; +} + +.swagger-ui .btn.execute { + margin-bottom: 20px; +} + +.swagger-ui .opblock-description-wrapper { + margin-top: 20px; +} + +.swagger-ui .opblock-description-wrapper { + margin-top: 5px; +} + +.opblock-section .opblock-section-request-body > div > div { + padding-top: 18px; +} + +/*response element positions*/ +.swagger-ui .model-example { + position: relative; + margin-top: 0; +} + +.swagger-ui .tab { + position: absolute; + top: -35px; + right: 0; +} + +.swagger-ui table tbody tr td { + padding: 0; +} + +.swagger-ui .renderedMarkdown p { + margin: 8px auto; +} + +/*Method colors*/ +.swagger-ui .opblock.opblock-get .opblock-summary-method { + background: var(--dark-blue); +} + +.swagger-ui .opblock.opblock-get .opblock-summary { + border-color: var(--dark-blue); +} + +.swagger-ui .opblock.opblock-get { + background: var(--dark-blue-w75); + border-color: var(--dark-blue); +} + +.swagger-ui .opblock.opblock-post .opblock-summary-method { + background: var(--dark-green); +} + +.swagger-ui .opblock.opblock-post .opblock-summary { + border-color: var(--dark-green); +} + +.swagger-ui .opblock.opblock-post { + background: var(--dark-green-w75); + border-color: var(--dark-green); +} + +.swagger-ui .opblock.opblock-put .opblock-summary-method { + background: var(--turquoise); +} + +.swagger-ui .opblock.opblock-put .opblock-summary { + border-color: var(--turquoise); +} + +.swagger-ui .opblock.opblock-put { + background: var(--turquoise-w75); + border-color: var(--turquoise); +} + +.swagger-ui .opblock.opblock-delete .opblock-summary-method { + background: var(--fuchsia); +} + +.swagger-ui .opblock.opblock-delete .opblock-summary { + border-color: var(--fuchsia); +} + +.swagger-ui .opblock.opblock-delete { + background: var(--fuchsia-w75); + border-color: var(--fuchsia); +} \ No newline at end of file diff --git a/static/styles/swagger.css b/static/styles/swagger.css deleted file mode 100644 index 9760ed4..0000000 --- a/static/styles/swagger.css +++ /dev/null @@ -1,323 +0,0 @@ -/*Bosch styling for swagger*/ - -/*GET: dark blue*/ -/*POST: dark green*/ -/*PUT: turquoise*/ -/*DELETE: fuchsia*/ - -:root { - --red: #ea0016; - --dark-blue: #005691; - --dark-blue-w75: #bfd5e3; - --dark-green: #006249; - --dark-green-w75: #bfd8d1; - --turquoise: #00a8b0; - --turquoise-w75: #bfe9eb; - --fuchsia: #b90276; - --fuchsia-w75: #edc0dd; - --light-grey: #bfc0c2; - --light-grey-w75: #efeff0; - --light-green: #78be20; -} - -body { - background: #fff; -} - -body:before { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 16px; - content: ''; - background-repeat: no-repeat; - background-size: cover; - background-image: url(data:image/svg+xml;base64,PHN2ZwogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICB4bWw6c3BhY2U9InByZXNlcnZlIgogIGhlaWdodD0iMzAwIgogIHdpZHRoPSI3MjAiCiAgdmVyc2lvbj0iMS4xIgogIHk9IjAiCiAgeD0iMCIKICB2aWV3Qm94PSIwIDAgNzIwIDMwMCI+CiAgPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KICAgIC5zdDAgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF8xXyIpOwogICAgfQogICAgLnN0MSB7CiAgICAgIGZpbGw6IHVybCgiI1NWR0lEXzJfIik7CiAgICB9CiAgICAuc3QyIHsKICAgICAgZmlsbDogdXJsKCIjU1ZHSURfM18iKTsKICAgIH0KICAgIC5zdDMgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF80XyIpOwogICAgfQogICAgLnN0NCB7CiAgICAgIGZpbGw6IHVybCgiI1NWR0lEXzVfIik7CiAgICB9CiAgICAuc3Q1IHsKICAgICAgZmlsbDogI0FGMjAyNDsKICAgIH0KICAgIC5zdDYgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF82XyIpOwogICAgfQogICAgLnN0NyB7CiAgICAgIGZpbGw6ICM5NDFCMUU7CiAgICB9CiAgICAuc3Q4IHsKICAgICAgZmlsbDogI0IxMjczOTsKICAgIH0KICAgIC5zdDkgewogICAgICBmaWxsOiAjOTUyNDMyOwogICAgfQogICAgLnN0MTAgewogICAgICBmaWxsOiAjRDQyMDI3OwogICAgfQogICAgLnN0MTEgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF83XyIpOwogICAgfQogICAgLnN0MTIgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF84XyIpOwogICAgfQogICAgLnN0MTMgewogICAgICBmaWxsOiAjMUM5QTQ4OwogICAgfQogICAgLnN0MTQgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF85XyIpOwogICAgfQogICAgLnN0MTUgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF8xMF8iKTsKICAgIH0KICAgIC5zdDE2IHsKICAgICAgZmlsbDogIzJBMzg4NjsKICAgIH0KICAgIC5zdDE3IHsKICAgICAgZmlsbDogdXJsKCIjU1ZHSURfMTFfIik7CiAgICB9CiAgICAuc3QxOCB7CiAgICAgIGZpbGw6IHVybCgiI1NWR0lEXzEyXyIpOwogICAgfQogICAgLnN0MTkgewogICAgICBmaWxsOiB1cmwoIiNTVkdJRF8xM18iKTsKICAgIH0KICAgIC5zdDIwIHsKICAgICAgZmlsbDogdXJsKCIjU1ZHSURfMTRfIik7CiAgICB9CiAgPC9zdHlsZT4KICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMS41NSwtMy4zKSI+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzFfIiB5Mj0iLTMyLjY2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHkxPSItMzIuNjYzIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9Ijg0Mi4wOCIgeDE9IjExOC45OCI+PHN0b3Agc3RvcC1jb2xvcj0iIzk1MjMzMSIgb2Zmc2V0PSIwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzkyMUMxRCIgb2Zmc2V0PSIuMDM2MDk0Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0IwMjczOSIgb2Zmc2V0PSIuMDg0NjQ5Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0FEMUYyNCIgb2Zmc2V0PSIuMTIzNyIvPjxzdG9wIHN0b3AtY29sb3I9IiNDNzIwMjYiIG9mZnNldD0iLjE1MDkiLz48c3RvcCBzdG9wLWNvbG9yPSIjRDQyMDI3IiBvZmZzZXQ9Ii4xNjk3Ii8+PHN0b3Agc3RvcC1jb2xvcj0iI0NDMjQzMSIgb2Zmc2V0PSIuMTc1OCIvPjxzdG9wIHN0b3AtY29sb3I9IiNCNzJCNEMiIG9mZnNldD0iLjE4ODgiLz48c3RvcCBzdG9wLWNvbG9yPSIjOTUzMzcxIiBvZmZzZXQ9Ii4yMDc0Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzg4MzU3RiIgb2Zmc2V0PSIuMjE0MiIvPjxzdG9wIHN0b3AtY29sb3I9IiM4NTM2ODEiIG9mZnNldD0iLjI0MzYiLz48c3RvcCBzdG9wLWNvbG9yPSIjNkYzNjhCIiBvZmZzZXQ9Ii4yNjM4Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzM5NDI4RiIgb2Zmc2V0PSIuMjkxMSIvPjxzdG9wIHN0b3AtY29sb3I9IiMyMzNEN0QiIG9mZnNldD0iLjMyNDIiLz48c3RvcCBzdG9wLWNvbG9yPSIjMzIyQzZGIiBvZmZzZXQ9Ii40MTgxIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzJBMzg4NSIgb2Zmc2V0PSIuNDk0Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzFENjJBMSIgb2Zmc2V0PSIuNTU4MSIvPjxzdG9wIHN0b3AtY29sb3I9IiMyNzZDQTUiIG9mZnNldD0iLjU3MDIiLz48c3RvcCBzdG9wLWNvbG9yPSIjNDM4RUIzIiBvZmZzZXQ9Ii42MTAzIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzU1QTVCQyIgb2Zmc2V0PSIuNjM5OSIvPjxzdG9wIHN0b3AtY29sb3I9IiM1Q0FGQkYiIG9mZnNldD0iLjY1NTYiLz48c3RvcCBzdG9wLWNvbG9yPSIjNTZBQkJEIiBvZmZzZXQ9Ii42Nzc3Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzQzOUZCOCIgb2Zmc2V0PSIuNzA1OCIvPjxzdG9wIHN0b3AtY29sb3I9IiMxODhFQUYiIG9mZnNldD0iLjczNzIiLz48c3RvcCBzdG9wLWNvbG9yPSIjMDM4QkFFIiBvZmZzZXQ9Ii43NDI2Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzA2OTI5MiIgb2Zmc2V0PSIuNzg5OCIvPjxzdG9wIHN0b3AtY29sb3I9IiMwNUExNEIiIG9mZnNldD0iLjg4NzUiLz48c3RvcCBzdG9wLWNvbG9yPSIjMDM5MjdFIiBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHdpZHRoPSI3MjMuMSIgeT0iMCIgeD0iMCIgaGVpZ2h0PSIzMDYuNCIgY2xhc3M9InN0MCIgZmlsbD0idXJsKCNTVkdJRF8xXykiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMl8iIHkyPSItMTA5LjI2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeTE9Ii0xMDkuMjYiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSAwIDAgLTEgLTExOC45OCAxMjAuNTQpIiB4Mj0iMjM1Ljk4IiB4MT0iMzI1LjA4Ij48c3RvcCBzdG9wLWNvbG9yPSIjODkzNjgwIiBvZmZzZXQ9IjAiLz48c3RvcCBzdG9wLWNvbG9yPSIjODkzNjgwIiBvZmZzZXQ9Ii4zMzU0Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzhEMzE2RCIgb2Zmc2V0PSIuNTAyNSIvPjxzdG9wIHN0b3AtY29sb3I9IiM5MDI5NEQiIG9mZnNldD0iLjgzOTgiLz48c3RvcCBzdG9wLWNvbG9yPSIjOTAyNTQxIiBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50Pjxwb2x5Z29uIHBvaW50cz0iMTc1LjEgMTUzLjIgMTE3IDMwNi40IDIwNi4xIDMwNi40IiBmaWxsPSJ1cmwoI1NWR0lEXzJfKSIgY2xhc3M9InN0MSIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8zXyIgeTI9Ii04Mi4yODQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5MT0iMTIwLjI0IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9IjQ0Ni41NSIgeDE9IjQ3OC45MyI+PHN0b3Agc3RvcC1jb2xvcj0iIzMyMkM2RiIgb2Zmc2V0PSIwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzMyMkM2RiIgb2Zmc2V0PSIuMjQyNyIvPjxzdG9wIHN0b3AtY29sb3I9IiMzMDJGNzIiIG9mZnNldD0iLjQ1OTkiLz48c3RvcCBzdG9wLWNvbG9yPSIjMkEzQTdFIiBvZmZzZXQ9Ii43MTU1Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzE1NEE5MyIgb2Zmc2V0PSIuOTg5NiIvPjxzdG9wIHN0b3AtY29sb3I9IiMxMzRCOTQiIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PHBvbHlnb24gcG9pbnRzPSIyODguNCAxNTMuMiAzMTAuNyAzMDYuNCAzNTguMSAzMDYuNCAzNTguMSAwIDMxMi45IDAiIGZpbGw9InVybCgjU1ZHSURfM18pIiBjbGFzcz0ic3QyIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzRfIiB5Mj0iLTMyLjY2MyIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHkxPSItMzIuNjYzIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9IjM3Mi44OCIgeDE9IjI5NC4wOCI+PHN0b3Agc3RvcC1jb2xvcj0iIzZGMzc4RCIgb2Zmc2V0PSIwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzNBNDI5MSIgb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48cG9seWdvbiBwb2ludHM9IjE3NS4xIDE1My4yIDIwNi4xIDMwNi40IDI1My45IDE1My4yIDIwOS40IDAgMjA5LjQgMCIgZmlsbD0idXJsKCNTVkdJRF80XykiIGNsYXNzPSJzdDMiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfNV8iIHkyPSItMzIuNjYzIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeTE9Ii0zMi42NjMiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSAwIDAgLTEgLTExOC45OCAxMjAuNTQpIiB4Mj0iMzI1LjA4IiB4MT0iNDMxLjg4Ij48c3RvcCBzdG9wLWNvbG9yPSIjMjMzRDdEIiBvZmZzZXQ9IjAiLz48c3RvcCBzdG9wLWNvbG9yPSIjMjkzRDdEIiBvZmZzZXQ9Ii4yNDk1Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzNBM0M4MCIgb2Zmc2V0PSIuNTQ0NiIvPjxzdG9wIHN0b3AtY29sb3I9IiM1MTNCODQiIG9mZnNldD0iLjg2MTYiLz48c3RvcCBzdG9wLWNvbG9yPSIjNUQzQTg2IiBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50Pjxwb2x5Z29uIHBvaW50cz0iMjUzLjkgMTUzLjIgMjA2LjEgMzA2LjQgMzEwLjcgMzA2LjQgMjg4LjQgMTUzLjIgMzEyLjkgMCAyMDkuNCAwIiBmaWxsPSJ1cmwoI1NWR0lEXzVfKSIgY2xhc3M9InN0NCIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LjEgMCA1NS43IDAgNTUuNyA5NC44IDg5LjkgMTUzLjIgNTUuNyAyMTEuNiA1NS43IDMwNi40IDExNyAzMDYuNCA5NS4yIDE1My4yIiBmaWxsPSIjYWYyMDI0IiBjbGFzcz0ic3Q1Ii8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzZfIiB5Mj0iNDMuOTM3IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeTE9IjQzLjkzNyIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxIDAgMCAtMSAtMTE4Ljk4IDEyMC41NCkiIHgyPSIyMzIuNjciIHgxPSIzMjkuMTEiPjxzdG9wIHN0b3AtY29sb3I9IiM4OTM2ODAiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiM4OTM2ODAiIG9mZnNldD0iLjMzNTQiLz48c3RvcCBzdG9wLWNvbG9yPSIjOEQzMTZEIiBvZmZzZXQ9Ii41MDI1Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzkwMjk0RCIgb2Zmc2V0PSIuODM5OCIvPjxzdG9wIHN0b3AtY29sb3I9IiM5MDI1NDEiIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PHBvbHlnb24gcG9pbnRzPSIxNzUuMSAxNTMuMiAyMDkuNCAwIDExNi4xIDAiIGZpbGw9InVybCgjU1ZHSURfNl8pIiBjbGFzcz0ic3Q2Ii8+PHBvbHlnb24gcG9pbnRzPSI1NS43IDk0LjggNTUuNyAwIDAgMCIgZmlsbD0iIzk0MWIxZSIgY2xhc3M9InN0NyIvPjxwb2x5Z29uIHBvaW50cz0iNTUuNyAyMTEuNiA4OS45IDE1My4yIDU1LjcgOTQuOCIgZmlsbD0iI2IxMjczOSIgY2xhc3M9InN0OCIvPjxwb2x5Z29uIHBvaW50cz0iNTUuNyAyMTEuNiAwIDMwNi40IDU1LjcgMzA2LjQiIGZpbGw9IiM5NDFiMWUiIGNsYXNzPSJzdDciLz48cG9seWdvbiBwb2ludHM9IjU1LjcgOTQuOCAwIDAgMCAzMDYuNCA1NS43IDIxMS42IiBmaWxsPSIjOTUyNDMyIiBjbGFzcz0ic3Q5Ii8+PHBvbHlnb24gcG9pbnRzPSIxMTYuMSAwIDk1LjIgMTUzLjIgMTE3IDMwNi40IDE3NS4xIDE1My4yIiBmaWxsPSIjZDQyMDI3IiBjbGFzcz0ic3QxMCIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF83XyIgeTI9Ii0xODYuMDYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5MT0iMTIwLjQ0IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9Ijc0OC45NiIgeDE9Ijc0OC45NiI+PHN0b3Agc3RvcC1jb2xvcj0iIzk0QkU1NSIgb2Zmc2V0PSIwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzkzQkQ1OCIgb2Zmc2V0PSIuMDQ0MzQwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzhCQkM2QSIgb2Zmc2V0PSIuMzg5MSIvPjxzdG9wIHN0b3AtY29sb3I9IiM4NkJDNzUiIG9mZnNldD0iLjcxNDkiLz48c3RvcCBzdG9wLWNvbG9yPSIjODRCQzc5IiBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoCiAgICAgIGQ9Im02NDEuNiAyNTkuNmMxLjctMjUuNCAxMC01NC42IDE4LjgtODUuNiAxLjQtNSAyLjgtMTAgNC4yLTE1LjEtMS40LTUuNS0yLjgtMTAuOS00LjItMTYuMi04LjgtMzMuMy0xNy02NC43LTE4LjgtOTItMS40LTIxLjIgMS40LTM3IDguOS01MC42aC00NS45Yy03LjUgMTguMy0xMC4zIDI5LjEtOC45IDUwLjMgMS43IDI3LjMgMTAgNTguNyAxOC44IDkyIDEzIDQ5LjMgMjggMTA2LjIgMjMuMiAxNjQuMmgxMi45Yy03LjYtMTIuOC0xMC40LTI3LjMtOS00N3oiCiAgICAgIGNsYXNzPSJzdDExIgogICAgICBmaWxsPSJ1cmwoI1NWR0lEXzdfKSIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF84XyIgeTI9Ii0xODQuNDUiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5MT0iMTE3LjI5IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9IjczMy40OSIgeDE9IjY1My43NiI+PHN0b3Agc3RvcC1jb2xvcj0iIzA4QTI0QiIgb2Zmc2V0PSIwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzBBQTE0RSIgb2Zmc2V0PSIuMTY3OCIvPjxzdG9wIHN0b3AtY29sb3I9IiMwQjlFNTciIG9mZnNldD0iLjQwNDciLz48c3RvcCBzdG9wLWNvbG9yPSIjMDk5QTY3IiBvZmZzZXQ9Ii42ODI3Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzA0OTQ3RCIgb2Zmc2V0PSIuOTg5OCIvPjxzdG9wIHN0b3AtY29sb3I9IiMwNDkzN0UiIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0ibTYxNC41IDE0Mi4zYy04LjgtMzMuMy0xNy02NC43LTE4LjgtOTItMS40LTIxLjIgMS40LTMyIDguOS01MC4zaC0zNS40YzUuNyA1My45LTMuOCAxMDYuNy0xMy42IDE2Ni44LTUuNyAzNS0xMS43IDcxLjMtMTMuMiAxMDAuNi0xLjEgMjEuMSAwLjQgMzIuOCAxLjggMzloOTMuNWM0LjgtNTcuOS0xMC4zLTExNC44LTIzLjItMTY0LjF6IiBjbGFzcz0ic3QxMiIgZmlsbD0idXJsKCNTVkdJRF84XykiLz48cGF0aCBjbGFzcz0ic3QxMyIgZmlsbD0iIzFjOWE0OCIgZD0ibTY2NC42IDE1OC45Yy0xLjQgNS4xLTIuOCAxMC4xLTQuMiAxNS4xLTguOCAzMS0xNyA2MC4yLTE4LjggODUuNi0xLjQgMTkuNyAxLjQgMzQuMiA5IDQ2LjloMzNjNC4yLTUxLjgtNy4yLTEwMi4zLTE5LTE0Ny42eiIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF85XyIgeTI9Ii0xODUuOTYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5MT0iMTIwLjU0IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9IjgxMi44MyIgeDE9IjgxMi44MyI+PHN0b3Agc3RvcC1jb2xvcj0iIzY5QTA2MCIgb2Zmc2V0PSIwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzYzOUQ1QyIgb2Zmc2V0PSIuMDM5ODk1Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzRDOTQ0RiIgb2Zmc2V0PSIuMjE5MiIvPjxzdG9wIHN0b3AtY29sb3I9IiMzNzhFNDciIG9mZnNldD0iLjQxODQiLz48c3RvcCBzdG9wLWNvbG9yPSIjMjk4QjQ0IiBvZmZzZXQ9Ii42NTE1Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzIzOEE0MyIgb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSJtNjgwLjUgMGMxMC43IDU1LjMtMi41IDExMC40LTE1LjkgMTU4LjkgMTEuNyA0NS4zIDIzLjIgOTUuOCAxOC45IDE0Ny42aDM5LjZ2LTMwNi41aC00Mi42eiIgY2xhc3M9InN0MTQiIGZpbGw9InVybCgjU1ZHSURfOV8pIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzEwXyIgeTI9Ii0xODUuODYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5MT0iMTIwLjU0IiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9IjY1Mi40NSIgeDE9IjY1Mi40NSI+PHN0b3Agc3RvcC1jb2xvcj0iIzA1QjVEQyIgb2Zmc2V0PSIwIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzA0QjBENyIgb2Zmc2V0PSIuMjE5NyIvPjxzdG9wIHN0b3AtY29sb3I9IiMwNUE0QzkiIG9mZnNldD0iLjUzNzEiLz48c3RvcCBzdG9wLWNvbG9yPSIjMDU5MUI0IiBvZmZzZXQ9Ii45MTIyIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzA1OENBRSIgb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSJtNTQyLjMgMjY3LjRjMS41LTI5LjQgNy41LTY1LjYgMTMuMi0xMDAuNiA5LjgtNjAuMSAxOS4zLTExMi44IDEzLjYtMTY2LjhoLTcwLjhjLTEuNCAxMS40LTIuOSAxOS4yLTEuOCA0MS44IDEuNSAzMS42IDcuNSA3MC41IDEzLjIgMTA4LjIgOC40IDU1LjQgMTYuNiAxMDguOCAxNS4xIDE1Ni40aDE5LjJjLTEuMy02LjItMi44LTE3LjktMS43LTM5eiIgY2xhc3M9InN0MTUiIGZpbGw9InVybCgjU1ZHSURfMTBfKSIvPjxwb2x5Z29uIHBvaW50cz0iMzc1LjcgMTUzLjIgMzU4LjEgMCAzNTguMSAzMDYuNCIgZmlsbD0iIzJhMzg4NiIgY2xhc3M9InN0MTYiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0iU1ZHSURfMTFfIiB5Mj0iNzcuMTM2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeTE9Ii00LjMyODEiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSAwIDAgLTEgLTExOC45OCAxMjAuNTQpIiB4Mj0iNzk2LjcxIiB4MT0iNzUxLjA1Ij48c3RvcCBzdG9wLWNvbG9yPSIjNjJCMTZFIiBvZmZzZXQ9IjAiLz48c3RvcCBzdG9wLWNvbG9yPSIjODdCOTU3IiBvZmZzZXQ9IjEiLz48L2xpbmVhckdyYWRpZW50PjxwYXRoIGQ9Im02NDEuNiA1MC42YzEuNyAyNy4zIDEwIDU4LjcgMTguOCA5MiAxLjQgNS4zIDIuOCAxMC43IDQuMiAxNi4yIDEzLjUtNDguNCAyNi42LTEwMy41IDE1LjktMTU4LjhoLTMwYy03LjUgMTMuNi0xMC4zIDI5LjQtOC45IDUwLjZ6IiBjbGFzcz0ic3QxNyIgZmlsbD0idXJsKCNTVkdJRF8xMV8pIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9IlNWR0lEXzEyXyIgeTI9Ii0xODkuMjgiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5MT0iMTEzLjcxIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIC0xIC0xMTguOTggMTIwLjU0KSIgeDI9IjYzMS41OSIgeDE9IjU1MC40Ij48c3RvcCBzdG9wLWNvbG9yPSIjMDY5QUQ0IiBvZmZzZXQ9IjAiLz48c3RvcCBzdG9wLWNvbG9yPSIjMzBBMENFIiBvZmZzZXQ9Ii4zNTI1Ii8+PHN0b3Agc3RvcC1jb2xvcj0iIzVCQjBDMCIgb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSJtNTA5LjggMTUwYy01LjctMzcuNy0xMS43LTc2LjYtMTMuMi0xMDguMi0xLjEtMjIuNyAwLjQtMzAuNCAxLjgtNDEuOGgtNDEuNWMxLjUgNDAuMS0xLjUgODUuMy03IDE2MC44LTMuMSA0My41LTggMTEwLjUtNyAxNDUuN2g4Mi4xYzEuNC00Ny43LTYuOC0xMDEuMS0xNS4yLTE1Ni41eiIgY2xhc3M9InN0MTgiIGZpbGw9InVybCgjU1ZHSURfMTJfKSIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8xM18iIHkyPSItMTg1Ljg2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeTE9IjEyMC41NCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxIDAgMCAtMSAtMTE4Ljk4IDEyMC41NCkiIHgyPSI1MDUuMzMiIHgxPSI1MDUuMzMiPjxzdG9wIHN0b3AtY29sb3I9IiMxRTQ1OEUiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiMxRjRGOTYiIG9mZnNldD0iLjI0MTEiLz48c3RvcCBzdG9wLWNvbG9yPSIjMkI2QUFCIiBvZmZzZXQ9Ii43MjkyIi8+PHN0b3Agc3RvcC1jb2xvcj0iIzMzN0JCOSIgb2Zmc2V0PSIxIi8+PC9saW5lYXJHcmFkaWVudD48cG9seWdvbiBwb2ludHM9IjM1OC4xIDMwNi40IDQxNC42IDMwNi40IDQxNC42IDAgMzU4LjEgMCAzNzUuNyAxNTMuMiIgZmlsbD0idXJsKCNTVkdJRF8xM18pIiBjbGFzcz0ic3QxOSIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJTVkdJRF8xNF8iIHkyPSIxMjAuNTQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB5MT0iLTE4NS44NiIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxIDAgMCAtMSAtMTE4Ljk4IDEyMC41NCkiIHgyPSI1NTQuOTIiIHgxPSI1NTQuOTIiPjxzdG9wIHN0b3AtY29sb3I9IiMzRjlBQzkiIG9mZnNldD0iMCIvPjxzdG9wIHN0b3AtY29sb3I9IiMyMDYyQTIiIG9mZnNldD0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0ibTQ0OS45IDE2MC44YzUuNS03NS41IDguNS0xMjAuNiA3LTE2MC44aC00Mi4ybC0wLjEgMzA2LjRoMjguM2MtMS0zNS4xIDMuOC0xMDIuMSA3LTE0NS42eiIgY2xhc3M9InN0MjAiIGZpbGw9InVybCgjU1ZHSURfMTRfKSIvPjwvZz4KPC9zdmc+Cg==); -} - -body:after { - position: absolute; - right: 25px; - top: 36px; - width: 135px; - height: 48px; - content: ''; - background-repeat: no-repeat; - background-size: cover; - background-image: url(/static/img/bosch-logo.svg); -} - -.swagger-ui { - font-family: "Bosch Sans", sans-serif; -} - -/*custom docs*/ -.docs { - position: relative; - font-size: 14px; -} - -.docs > summary { - position: absolute; - right: 0; - top: -25px; - cursor: pointer; -} - -.docs-open:hover { - text-decoration: underline; -} - -/*Remove topbar*/ -.swagger-ui .topbar { - display: none -} - -/*Remove models view*/ -.swagger-ui .models { - display: none; -} - -/*Remove application/json select*/ -.swagger-ui .opblock .opblock-section-header > label, .swagger-ui .response-controls { - display: none; -} - -/*Remove border radius*/ -.swagger-ui .opblock, .swagger-ui .opblock .opblock-summary-method, .swagger-ui select { - border-radius: 0; - box-shadow: none; -} - -/*remove links in response*/ -.swagger-ui .response-col_links { - display: none; -} - -/*remove version*/ -.swagger-ui .info .title span { - display: none; -} - -/*separator before methods*/ -.swagger-ui .scheme-container { - box-shadow: none; - border-bottom: 1px solid var(--light-grey); -} - -/*tag separator*/ -.swagger-ui .opblock-tag { - border-bottom: 1px solid var(--light-grey); -} - -/*parameters/responses bar*/ -.swagger-ui .opblock .opblock-section-header { - box-shadow: none; - background: #fff; -} - -/*select*/ -.swagger-ui select { - background-color: var(--light-grey-w75); - border: none; - height: 36px; -} - -/*button*/ -.swagger-ui .btn { - border-radius: 0; - box-shadow: none; -} - -.swagger-ui .btn:hover { - box-shadow: none; -} - -/*authorize button */ -.swagger-ui .btn.authorize { - color: var(--light-green); - border-color: var(--light-green); -} - -.swagger-ui .btn.authorize svg { - fill: var(--light-green); -} - -/*auth inputs*/ -.swagger-ui .auth-container input[type="password"], .swagger-ui .auth-container input[type="text"] { - border-radius: 0; - box-shadow: none; - border-color: var(--light-grey); -} - -.swagger-ui .dialog-ux .modal-ux { - border-radius: 0; -} - -/*cancel button*/ -.swagger-ui .btn.cancel { - color: var(--red); - border-color: var(--red); -} - -/*download button*/ -.swagger-ui .download-contents { - border-radius: 0; - height: 28px; - width: 80px; -} - -/*model*/ -.swagger-ui .model-box { - border-radius: 0; -} - -/*execute button*/ -.swagger-ui .btn.execute { - background-color: var(--dark-blue); - border-color: var(--dark-blue); - height: 30px; - line-height: 0.7; -} - -.swagger-ui .btn-group .btn:last-child { - border-radius: 0; - height: 30px; - border-color: var(--dark-blue); -} - -.swagger-ui .btn-group .btn:first-child { - border-radius: 0; -} - -.swagger-ui .btn-group { - padding: 0 20px; -} - -/*parameter input*/ -.swagger-ui .parameters-col_description input[type="text"] { - border-radius: 0; -} - -/*required label*/ -.swagger-ui .parameter__name.required > span { - color: var(--red) !important; -} - -.swagger-ui .parameter__name.required::after { - color: var(--red); -} -/*Remove colored parameters bar*/ -.swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span::after, .swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span::after, .swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span::after, .swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span::after { - background: none; -} - -/*code*/ -.swagger-ui .opblock-body pre.microlight { - border-radius: 0; -} - -.swagger-ui .highlight-code > .microlight { - min-height: 0; -} - -/*request body*/ -.swagger-ui textarea { - border-radius: 0; -} - -/*parameters smaller padding*/ -.swagger-ui .execute-wrapper { - padding-top: 0; - padding-bottom: 0; -} - -.swagger-ui .btn.execute { - margin-bottom: 20px; -} - -.swagger-ui .opblock-description-wrapper { - margin-top: 20px; -} - -.swagger-ui .opblock-description-wrapper { - margin-top: 5px; -} - -.opblock-section .opblock-section-request-body > div > div { - padding-top: 18px; -} - -/*response element positions*/ -.swagger-ui .model-example { - position: relative; - margin-top: 0; -} - -.swagger-ui .tab { - position: absolute; - top: -35px; - right: 0; -} - -.swagger-ui table tbody tr td { - padding: 0; -} - -.swagger-ui .renderedMarkdown p { - margin: 8px auto; -} - -/*Method colors*/ -.swagger-ui .opblock.opblock-get .opblock-summary-method { - background: var(--dark-blue); -} - -.swagger-ui .opblock.opblock-get .opblock-summary { - border-color: var(--dark-blue); -} - -.swagger-ui .opblock.opblock-get { - background: var(--dark-blue-w75); - border-color: var(--dark-blue); -} - -.swagger-ui .opblock.opblock-post .opblock-summary-method { - background: var(--dark-green); -} - -.swagger-ui .opblock.opblock-post .opblock-summary { - border-color: var(--dark-green); -} - -.swagger-ui .opblock.opblock-post { - background: var(--dark-green-w75); - border-color: var(--dark-green); -} - -.swagger-ui .opblock.opblock-put .opblock-summary-method { - background: var(--turquoise); -} - -.swagger-ui .opblock.opblock-put .opblock-summary { - border-color: var(--turquoise); -} - -.swagger-ui .opblock.opblock-put { - background: var(--turquoise-w75); - border-color: var(--turquoise); -} - -.swagger-ui .opblock.opblock-delete .opblock-summary-method { - background: var(--fuchsia); -} - -.swagger-ui .opblock.opblock-delete .opblock-summary { - border-color: var(--fuchsia); -} - -.swagger-ui .opblock.opblock-delete { - background: var(--fuchsia-w75); - border-color: var(--fuchsia); -} \ No newline at end of file