- Fixed issue #315

This commit is contained in:
Ferdi Koomen 2020-08-08 10:05:11 +02:00
parent 012f0856a8
commit 0bd80eb8e8
9 changed files with 127 additions and 72 deletions

View File

@ -1,6 +1,6 @@
{
"name": "openapi-typescript-codegen",
"version": "0.4.9",
"version": "0.4.10",
"description": "NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification.",
"author": "Ferdi Koomen",
"homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen",

View File

@ -1,4 +1,5 @@
import { Operation } from '../../../client/interfaces/Operation';
import { OperationParameters } from '../../../client/interfaces/OperationParameters';
import { OpenApi } from '../interfaces/OpenApi';
import { OpenApiOperation } from '../interfaces/OpenApiOperation';
import { getComment } from './getComment';
@ -11,7 +12,7 @@ import { getOperationResponses } from './getOperationResponses';
import { getOperationResults } from './getOperationResults';
import { getServiceClassName } from './getServiceClassName';
export function getOperation(openApi: OpenApi, url: string, method: string, op: OpenApiOperation): Operation {
export function getOperation(openApi: OpenApi, url: string, method: string, op: OpenApiOperation, pathParams: OperationParameters): Operation {
const serviceName = (op.tags && op.tags[0]) || 'Service';
const serviceClassName = getServiceClassName(serviceName);
const operationNameFallback = `${method}${serviceClassName}`;
@ -27,13 +28,13 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op:
deprecated: op.deprecated === true,
method: method,
path: operationPath,
parameters: [],
parametersPath: [],
parametersQuery: [],
parametersForm: [],
parametersHeader: [],
parametersCookie: [],
parametersBody: null,
parameters: [...pathParams.parameters],
parametersPath: [...pathParams.parametersPath],
parametersQuery: [...pathParams.parametersQuery],
parametersForm: [...pathParams.parametersForm],
parametersHeader: [...pathParams.parametersHeader],
parametersCookie: [...pathParams.parametersCookie],
parametersBody: pathParams.parametersBody,
imports: [],
errors: [],
results: [],

View File

@ -2,6 +2,7 @@ import { Service } from '../../../client/interfaces/Service';
import { OpenApi } from '../interfaces/OpenApi';
import { Method } from './constants';
import { getOperation } from './getOperation';
import { getOperationParameters } from './getOperationParameters';
/**
* Get the OpenAPI services
@ -10,7 +11,11 @@ export function getServices(openApi: OpenApi): Service[] {
const services = new Map<string, Service>();
for (const url in openApi.paths) {
if (openApi.paths.hasOwnProperty(url)) {
// Grab path and parse any global path parameters
const path = openApi.paths[url];
const pathParams = getOperationParameters(openApi, path.parameters || []);
// Parse all the methods for this path
for (const method in path) {
if (path.hasOwnProperty(method)) {
switch (method) {
@ -23,7 +28,7 @@ export function getServices(openApi: OpenApi): Service[] {
case Method.PATCH:
// Each method contains an OpenAPI operation, we parse the operation
const op = path[method]!;
const operation = getOperation(openApi, url, method, op);
const operation = getOperation(openApi, url, method, op, pathParams);
// If we have already declared a service, then we should fetch that and
// append the new method to it. Otherwise we should create a new service object.

View File

@ -1,4 +1,5 @@
import { Operation } from '../../../client/interfaces/Operation';
import { OperationParameters } from '../../../client/interfaces/OperationParameters';
import { OpenApi } from '../interfaces/OpenApi';
import { OpenApiOperation } from '../interfaces/OpenApiOperation';
import { getComment } from './getComment';
@ -13,7 +14,7 @@ import { getOperationResults } from './getOperationResults';
import { getServiceClassName } from './getServiceClassName';
import { sortByRequired } from './sortByRequired';
export function getOperation(openApi: OpenApi, url: string, method: string, op: OpenApiOperation): Operation {
export function getOperation(openApi: OpenApi, url: string, method: string, op: OpenApiOperation, pathParams: OperationParameters): Operation {
const serviceName = (op.tags && op.tags[0]) || 'Service';
const serviceClassName = getServiceClassName(serviceName);
const operationNameFallback = `${method}${serviceClassName}`;
@ -29,13 +30,13 @@ export function getOperation(openApi: OpenApi, url: string, method: string, op:
deprecated: op.deprecated === true,
method: method,
path: operationPath,
parameters: [],
parametersPath: [],
parametersQuery: [],
parametersForm: [],
parametersHeader: [],
parametersCookie: [],
parametersBody: null,
parameters: [...pathParams.parameters],
parametersPath: [...pathParams.parametersPath],
parametersQuery: [...pathParams.parametersQuery],
parametersForm: [...pathParams.parametersForm],
parametersHeader: [...pathParams.parametersHeader],
parametersCookie: [...pathParams.parametersCookie],
parametersBody: pathParams.parametersBody,
imports: [],
errors: [],
results: [],

View File

@ -2,6 +2,7 @@ import { Service } from '../../../client/interfaces/Service';
import { OpenApi } from '../interfaces/OpenApi';
import { Method } from './constants';
import { getOperation } from './getOperation';
import { getOperationParameters } from './getOperationParameters';
/**
* Get the OpenAPI services
@ -10,7 +11,11 @@ export function getServices(openApi: OpenApi): Service[] {
const services = new Map<string, Service>();
for (const url in openApi.paths) {
if (openApi.paths.hasOwnProperty(url)) {
// Grab path and parse any global path parameters
const path = openApi.paths[url];
const pathParams = getOperationParameters(openApi, path.parameters || []);
// Parse all the methods for this path
for (const method in path) {
if (path.hasOwnProperty(method)) {
switch (method) {
@ -23,7 +28,7 @@ export function getServices(openApi: OpenApi): Service[] {
case Method.PATCH:
// Each method contains an OpenAPI operation, we parse the operation
const op = path[method]!;
const operation = getOperation(openApi, url, method, op);
const operation = getOperation(openApi, url, method, op, pathParams);
// If we have already declared a service, then we should fetch that and
// append the new method to it. Otherwise we should create a new service object.

View File

@ -2246,10 +2246,11 @@ import { OpenAPI } from '../core/OpenAPI';
export class ParametersService {
/**
* @param parameterHeader This is the parameter that goes into the request header
* @param parameterQuery This is the parameter that goes into the request query params
* @param parameterForm This is the parameter that goes into the request form data
* @param parameterHeader This is the parameter that goes into the header
* @param parameterQuery This is the parameter that goes into the query params
* @param parameterForm This is the parameter that goes into the form data
* @param parameterBody This is the parameter that is send as request body
* @param parameterPath This is the parameter that goes into the path
* @throws ApiError
*/
public static async callWithParameters(
@ -2257,11 +2258,12 @@ export class ParametersService {
parameterQuery: string,
parameterForm: string,
parameterBody: string,
parameterPath: string,
): Promise<void> {
const result = await __request({
method: 'get',
path: \`/api/v\${OpenAPI.VERSION}/parameters\`,
path: \`/api/v\${OpenAPI.VERSION}/parameters/\${parameterPath}\`,
headers: {
'parameterHeader': parameterHeader,
},
@ -4993,10 +4995,11 @@ import { OpenAPI } from '../core/OpenAPI';
export class ParametersService {
/**
* @param parameterHeader This is the parameter that goes into the request header
* @param parameterQuery This is the parameter that goes into the request query params
* @param parameterForm This is the parameter that goes into the request form data
* @param parameterHeader This is the parameter that goes into the header
* @param parameterQuery This is the parameter that goes into the query params
* @param parameterForm This is the parameter that goes into the form data
* @param parameterCookie This is the parameter that goes into the cookie
* @param parameterPath This is the parameter that goes into the path
* @param requestBody This is the parameter that goes into the body
* @throws ApiError
*/
@ -5005,12 +5008,13 @@ export class ParametersService {
parameterQuery: string | null,
parameterForm: string | null,
parameterCookie: string | null,
parameterPath: string | null,
requestBody: ModelWithString | null,
): Promise<void> {
const result = await __request({
method: 'get',
path: \`/api/v\${OpenAPI.VERSION}/parameters\`,
path: \`/api/v\${OpenAPI.VERSION}/parameters/\${parameterPath}\`,
cookies: {
'parameterCookie': parameterCookie,
},

View File

@ -54,7 +54,7 @@
"operationId": "PatchCallWithoutParametersAndResponse"
}
},
"/api/v{api-version}/parameters": {
"/api/v{api-version}/parameters/{parameterPath}": {
"get": {
"tags": [
"Parameters"
@ -62,21 +62,21 @@
"operationId": "CallWithParameters",
"parameters": [
{
"description": "This is the parameter that goes into the request header",
"description": "This is the parameter that goes into the header",
"name": "parameterHeader",
"in": "header",
"type": "string",
"required": true
},
{
"description": "This is the parameter that goes into the request query params",
"description": "This is the parameter that goes into the query params",
"name": "parameterQuery",
"in": "query",
"type": "string",
"required": true
},
{
"description": "This is the parameter that goes into the request form data",
"description": "This is the parameter that goes into the form data",
"name": "parameterForm",
"in": "formData",
"type": "string",
@ -89,6 +89,13 @@
"type": "string",
"required": true
},
{
"description": "This is the parameter that goes into the path",
"name": "parameterPath",
"in": "path",
"type": "string",
"required": true
},
{
"name": "api-version",
"in": "path",

View File

@ -54,7 +54,7 @@
"operationId": "PatchCallWithoutParametersAndResponse"
}
},
"/api/v{api-version}/parameters": {
"/api/v{api-version}/parameters/{parameterPath}": {
"get": {
"tags": [
"Parameters"
@ -62,7 +62,7 @@
"operationId": "CallWithParameters",
"parameters": [
{
"description": "This is the parameter that goes into the request header",
"description": "This is the parameter that goes into the header",
"name": "parameterHeader",
"in": "header",
"required": true,
@ -72,7 +72,7 @@
}
},
{
"description": "This is the parameter that goes into the request query params",
"description": "This is the parameter that goes into the query params",
"name": "parameterQuery",
"in": "query",
"required": true,
@ -82,7 +82,7 @@
}
},
{
"description": "This is the parameter that goes into the request form data",
"description": "This is the parameter that goes into the form data",
"name": "parameterForm",
"in": "formData",
"required": true,
@ -101,6 +101,16 @@
"type": "string"
}
},
{
"description": "This is the parameter that goes into the path",
"name": "parameterPath",
"in": "path",
"required": true,
"nullable": true,
"schema": {
"type": "string"
}
},
{
"name": "api-version",
"in": "path",

View File

@ -18,7 +18,7 @@
invariant "^2.2.4"
semver "^5.5.0"
"@babel/core@7.11.0", "@babel/core@^7.1.0", "@babel/core@^7.7.5":
"@babel/core@7.11.0":
version "7.11.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.0.tgz#73b9c33f1658506887f767c26dae07798b30df76"
integrity sha512-mkLq8nwaXmDtFmRkQ8ED/eA2CnVw4zr7dCztKalZXBvdK5EeNUAesrrwUqjQEzFgomJssayzB0aqlOsP1vGLqg==
@ -40,6 +40,28 @@
semver "^5.4.1"
source-map "^0.5.0"
"@babel/core@^7.1.0", "@babel/core@^7.7.5":
version "7.11.1"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.1.tgz#2c55b604e73a40dc21b0e52650b11c65cf276643"
integrity sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/generator" "^7.11.0"
"@babel/helper-module-transforms" "^7.11.0"
"@babel/helpers" "^7.10.4"
"@babel/parser" "^7.11.1"
"@babel/template" "^7.10.4"
"@babel/traverse" "^7.11.0"
"@babel/types" "^7.11.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.1"
json5 "^2.1.2"
lodash "^4.17.19"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
"@babel/generator@^7.11.0":
version "7.11.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c"
@ -258,10 +280,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0":
version "7.11.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.0.tgz#a9d7e11aead25d3b422d17b2c6502c8dddef6a5d"
integrity sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw==
"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1":
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.2.tgz#0882ab8a455df3065ea2dcb4c753b2460a24bead"
integrity sha512-Vuj/+7vLo6l1Vi7uuO+1ngCDNeVmNbTngcJFKCR/oEtz8tKz0CJxZEGmPt9KcIloZhOZ3Zit6xbpXT2MDlS9Vw==
"@babel/plugin-proposal-async-generator-functions@^7.10.4":
version "7.10.5"
@ -499,9 +521,9 @@
"@babel/helper-plugin-utils" "^7.10.4"
"@babel/plugin-transform-block-scoping@^7.10.4":
version "7.10.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz#b81b8aafefbfe68f0f65f7ef397b9ece68a6037d"
integrity sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg==
version "7.11.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215"
integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew==
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
@ -829,9 +851,9 @@
"@babel/plugin-transform-typescript" "^7.10.4"
"@babel/runtime@^7.8.4":
version "7.11.0"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.0.tgz#f10245877042a815e07f7e693faff0ae9d3a2aac"
integrity sha512-qArkXsjJq7H+T86WrIFV0Fnu/tNOkZ4cgXmjkzAu3b/58D5mFIO8JH/y77t7C9q0OdDRdh9s7Ue5GasYssxtXw==
version "7.11.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
dependencies:
regenerator-runtime "^0.13.4"
@ -1381,9 +1403,9 @@ acorn-walk@^7.1.1:
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
acorn@^7.1.1, acorn@^7.3.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd"
integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==
version "7.4.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c"
integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==
agent-base@5:
version "5.1.1"
@ -1663,14 +1685,14 @@ browser-process-hrtime@^1.0.0:
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
browserslist@^4.12.0, browserslist@^4.8.5:
version "4.13.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.13.0.tgz#42556cba011e1b0a2775b611cba6a8eca18e940d"
integrity sha512-MINatJ5ZNrLnQ6blGvePd/QOz9Xtu+Ne+x29iQSCHfkU5BugKVJwZKn/iiL8UbpIpa3JhviKjz+XxMo0m2caFQ==
version "4.14.0"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.0.tgz#2908951abfe4ec98737b72f34c3bcedc8d43b000"
integrity sha512-pUsXKAF2lVwhmtpeA3LJrZ76jXuusrNyhduuQs7CDFf9foT4Y38aQOserd2lMe5DSSrjf3fx34oHwryuvxAUgQ==
dependencies:
caniuse-lite "^1.0.30001093"
electron-to-chromium "^1.3.488"
escalade "^3.0.1"
node-releases "^1.1.58"
caniuse-lite "^1.0.30001111"
electron-to-chromium "^1.3.523"
escalade "^3.0.2"
node-releases "^1.1.60"
bser@2.1.1:
version "2.1.1"
@ -1719,10 +1741,10 @@ camelcase@^6.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e"
integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==
caniuse-lite@^1.0.30001093:
version "1.0.30001109"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001109.tgz#a9f3f26a0c3753b063d7acbb48dfb9c0e46f2b19"
integrity sha512-4JIXRodHzdS3HdK8nSgIqXYLExOvG+D2/EenSvcub2Kp3QEADjo2v2oUn5g0n0D+UNwG9BtwKOyGcSq2qvQXvQ==
caniuse-lite@^1.0.30001111:
version "1.0.30001112"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001112.tgz#0fffc3b934ff56ff0548c37bc9dad7d882bcf672"
integrity sha512-J05RTQlqsatidif/38aN3PGULCLrg8OYQOlJUKbeYVzC2mGZkZLIztwRlB3MtrfLmawUmjFlNJvy/uhwniIe1Q==
capture-exit@^2.0.0:
version "2.0.0"
@ -2068,10 +2090,10 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
electron-to-chromium@^1.3.488:
version "1.3.516"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.516.tgz#03ec071b061e462b786bf7e7ce226fd7ab7cf1f6"
integrity sha512-WDM5AAQdOrvLqSX8g3Zd5AujBXfMxf96oeZkff0U2HF5op3tjShE+on2yay3r1UD4M9I3p0iHpAS4+yV8U8A9A==
electron-to-chromium@^1.3.523:
version "1.3.526"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.526.tgz#0e004899edf75afc172cce1b8189aac5dca646aa"
integrity sha512-HiroW5ZbGwgT8kCnoEO8qnGjoTPzJxduvV/Vv/wH63eo2N6Zj3xT5fmmaSPAPUM05iN9/5fIEkIg3owTtV6QZg==
emittery@^0.7.1:
version "0.7.1"
@ -2109,7 +2131,7 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
escalade@^3.0.1:
escalade@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4"
integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==
@ -2251,9 +2273,9 @@ estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642"
integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==
version "5.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
estree-walker@^1.0.1:
version "1.0.1"
@ -2849,9 +2871,9 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2:
kind-of "^6.0.2"
is-docker@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b"
integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ==
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156"
integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
@ -3794,7 +3816,7 @@ node-notifier@^7.0.0:
uuid "^8.2.0"
which "^2.0.2"
node-releases@^1.1.58:
node-releases@^1.1.60:
version "1.1.60"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084"
integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA==