swagger-client 3.10.8 → 3.10.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +10 -2
  2. package/dist/swagger-client.browser.js +24191 -0
  3. package/dist/swagger-client.browser.min.js +3 -0
  4. package/dist/swagger-client.browser.min.js.map +1 -0
  5. package/es/commonjs.js +9 -0
  6. package/es/constants.js +2 -0
  7. package/es/execute/index.js +391 -0
  8. package/es/execute/oas3/build-request.js +149 -0
  9. package/es/execute/oas3/content-serializer.js +18 -0
  10. package/es/execute/oas3/parameter-builders.js +119 -0
  11. package/es/execute/oas3/style-serializer.js +232 -0
  12. package/es/execute/swagger2/build-request.js +119 -0
  13. package/es/execute/swagger2/parameter-builders.js +78 -0
  14. package/es/helpers.js +272 -0
  15. package/es/http.js +621 -0
  16. package/es/index.js +116 -0
  17. package/es/interfaces.js +145 -0
  18. package/es/internal/form-data-monkey-patch.js +94 -0
  19. package/es/resolver.js +123 -0
  20. package/es/specmap/helpers.js +62 -0
  21. package/es/specmap/index.js +613 -0
  22. package/es/specmap/lib/all-of.js +81 -0
  23. package/es/specmap/lib/context-tree.js +111 -0
  24. package/es/specmap/lib/create-error.js +24 -0
  25. package/es/specmap/lib/index.js +391 -0
  26. package/es/specmap/lib/parameters.js +31 -0
  27. package/es/specmap/lib/properties.js +23 -0
  28. package/es/specmap/lib/refs.js +516 -0
  29. package/es/subtree-resolver/index.js +92 -0
  30. package/lib/commonjs.js +10 -0
  31. package/lib/constants.js +7 -0
  32. package/lib/execute/index.js +421 -0
  33. package/lib/execute/oas3/build-request.js +161 -0
  34. package/lib/execute/oas3/content-serializer.js +21 -0
  35. package/lib/execute/oas3/parameter-builders.js +138 -0
  36. package/lib/execute/oas3/style-serializer.js +208 -0
  37. package/lib/execute/swagger2/build-request.js +120 -0
  38. package/lib/execute/swagger2/parameter-builders.js +88 -0
  39. package/lib/helpers.js +261 -0
  40. package/lib/http.js +470 -0
  41. package/lib/index.js +142 -0
  42. package/lib/interfaces.js +159 -0
  43. package/lib/internal/form-data-monkey-patch.js +83 -0
  44. package/lib/resolver.js +125 -0
  45. package/lib/specmap/helpers.js +65 -0
  46. package/lib/specmap/index.js +446 -0
  47. package/lib/specmap/lib/all-of.js +89 -0
  48. package/lib/specmap/lib/context-tree.js +111 -0
  49. package/lib/specmap/lib/create-error.js +25 -0
  50. package/lib/specmap/lib/index.js +402 -0
  51. package/lib/specmap/lib/parameters.js +42 -0
  52. package/lib/specmap/lib/properties.js +38 -0
  53. package/lib/specmap/lib/refs.js +509 -0
  54. package/lib/subtree-resolver/index.js +55 -0
  55. package/package.json +80 -106
  56. package/browser/index.js +0 -54
  57. package/dist/index.js +0 -4372
@@ -0,0 +1,509 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = void 0;
5
+
6
+ var _crossFetch = require("cross-fetch");
7
+
8
+ var _jsYaml = _interopRequireDefault(require("js-yaml"));
9
+
10
+ var _querystringBrowser = _interopRequireDefault(require("querystring-browser"));
11
+
12
+ var _url = _interopRequireDefault(require("url"));
13
+
14
+ var _ = _interopRequireDefault(require("."));
15
+
16
+ var _createError = _interopRequireDefault(require("./create-error"));
17
+
18
+ var _helpers = require("../helpers");
19
+
20
+ var _constants = require("../../constants");
21
+
22
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
+
24
+ const ABSOLUTE_URL_REGEXP = new RegExp('^([a-z]+://|//)', 'i');
25
+ const JSONRefError = (0, _createError.default)('JSONRefError', function cb(message, extra, oriError) {
26
+ this.originalError = oriError;
27
+ Object.assign(this, extra || {});
28
+ });
29
+ const docCache = {};
30
+ const specmapRefs = new WeakMap();
31
+ const skipResolutionTestFns = [path => // OpenAPI 3.0 Response Media Type Example
32
+ // ["paths", *, *, "responses", *, "content", *, "example"]
33
+ path[0] === 'paths' && path[3] === 'responses' && path[5] === 'content' && path[7] === 'example', path => // OpenAPI 3.0 Request Body Media Type Example
34
+ // ["paths", *, *, "responses", *, "content", *, "example"]
35
+ path[0] === 'paths' && path[3] === 'requestBody' && path[4] === 'content' && path[6] === 'example'];
36
+
37
+ const shouldSkipResolution = path => skipResolutionTestFns.some(fn => fn(path)); // =========================
38
+ // Core
39
+ // =========================
40
+
41
+ /**
42
+ * This plugin resolves the JSON pointers.
43
+ * A major part of this plugin deals with cyclic references via 2 mechanisms.
44
+ * 1. If a pointer was already resolved before in this path, halt.
45
+ * 2. If the patch value points to one of the ancestors in this path, halt.
46
+ *
47
+ * Note that either one of these mechanism is sufficient, both must be in place.
48
+ * For examples:
49
+ *
50
+ * Given the following spec, #1 alone is insufficient because after the 2nd
51
+ * application, there will be a cyclic object reference.
52
+ * a.b.c: $ref-d
53
+ * d.e.f: $ref-a (per #1, safe to return patch as no immediate cycle)
54
+ *
55
+ * Given the following spec, #2 alone is insufficient because although there will
56
+ * never be any cyclic object reference, the plugin will keep producing patches.
57
+ * a: $ref-b
58
+ * b: $ref-a
59
+ */
60
+
61
+
62
+ const plugin = {
63
+ key: '$ref',
64
+ plugin: (ref, key, fullPath, specmap) => {
65
+ const specmapInstance = specmap.getInstance();
66
+ const parent = fullPath.slice(0, -1);
67
+
68
+ if ((0, _helpers.isFreelyNamed)(parent) || shouldSkipResolution(parent)) {
69
+ return undefined;
70
+ }
71
+
72
+ const {
73
+ baseDoc
74
+ } = specmap.getContext(fullPath);
75
+
76
+ if (typeof ref !== 'string') {
77
+ return new JSONRefError('$ref: must be a string (JSON-Ref)', {
78
+ $ref: ref,
79
+ baseDoc,
80
+ fullPath
81
+ });
82
+ }
83
+
84
+ const splitString = split(ref);
85
+ const refPath = splitString[0];
86
+ const pointer = splitString[1] || '';
87
+ let basePath;
88
+
89
+ try {
90
+ basePath = baseDoc || refPath ? absoluteify(refPath, baseDoc) : null;
91
+ } catch (e) {
92
+ return wrapError(e, {
93
+ pointer,
94
+ $ref: ref,
95
+ basePath,
96
+ fullPath
97
+ });
98
+ }
99
+
100
+ let promOrVal;
101
+ let tokens;
102
+
103
+ if (pointerAlreadyInPath(pointer, basePath, parent, specmap)) {
104
+ // Cyclic reference!
105
+ // if `useCircularStructures` is not set, just leave the reference
106
+ // unresolved, but absolutify it so that we don't leave an invalid $ref
107
+ // path in the content
108
+ if (!specmapInstance.useCircularStructures) {
109
+ const absolutifiedRef = (0, _helpers.absolutifyPointer)(ref, basePath);
110
+
111
+ if (ref === absolutifiedRef) {
112
+ // avoids endless looping
113
+ // without this, the ref plugin never stops seeing this $ref
114
+ return null;
115
+ }
116
+
117
+ return _.default.replace(fullPath, absolutifiedRef);
118
+ }
119
+ }
120
+
121
+ if (basePath == null) {
122
+ tokens = jsonPointerToArray(pointer);
123
+ promOrVal = specmap.get(tokens);
124
+
125
+ if (typeof promOrVal === 'undefined') {
126
+ promOrVal = new JSONRefError(`Could not resolve reference: ${ref}`, {
127
+ pointer,
128
+ $ref: ref,
129
+ baseDoc,
130
+ fullPath
131
+ });
132
+ }
133
+ } else {
134
+ promOrVal = extractFromDoc(basePath, pointer); // eslint-disable-next-line no-underscore-dangle
135
+
136
+ if (promOrVal.__value != null) {
137
+ promOrVal = promOrVal.__value; // eslint-disable-line no-underscore-dangle
138
+ } else {
139
+ promOrVal = promOrVal.catch(e => {
140
+ throw wrapError(e, {
141
+ pointer,
142
+ $ref: ref,
143
+ baseDoc,
144
+ fullPath
145
+ });
146
+ });
147
+ }
148
+ }
149
+
150
+ if (promOrVal instanceof Error) {
151
+ return [_.default.remove(fullPath), promOrVal];
152
+ }
153
+
154
+ const absolutifiedRef = (0, _helpers.absolutifyPointer)(ref, basePath);
155
+
156
+ const patch = _.default.replace(parent, promOrVal, {
157
+ $$ref: absolutifiedRef
158
+ });
159
+
160
+ if (basePath && basePath !== baseDoc) {
161
+ return [patch, _.default.context(parent, {
162
+ baseDoc: basePath
163
+ })];
164
+ }
165
+
166
+ try {
167
+ // prevents circular values from being constructed, unless we specifically
168
+ // want that to happen
169
+ if (!patchValueAlreadyInPath(specmap.state, patch) || specmapInstance.useCircularStructures) {
170
+ return patch;
171
+ }
172
+ } catch (e) {
173
+ // if we're catching here, path traversal failed, so we should
174
+ // ditch without sending any patches back up.
175
+ //
176
+ // this is a narrow fix for the larger problem of patches being queued
177
+ // and then having the state they were generated against be modified
178
+ // before they are applied.
179
+ //
180
+ // TODO: re-engineer specmap patch/state management to avoid this
181
+ return null;
182
+ }
183
+
184
+ return undefined;
185
+ }
186
+ };
187
+ const mod = Object.assign(plugin, {
188
+ docCache,
189
+ absoluteify,
190
+ clearCache,
191
+ JSONRefError,
192
+ wrapError,
193
+ getDoc,
194
+ split,
195
+ extractFromDoc,
196
+ fetchJSON,
197
+ extract,
198
+ jsonPointerToArray,
199
+ unescapeJsonPointerToken
200
+ });
201
+ var _default = mod; // =========================
202
+ // Utilities
203
+ // =========================
204
+
205
+ /**
206
+ * Resolves a path and its base to an abolute URL.
207
+ * @api public
208
+ */
209
+
210
+ exports.default = _default;
211
+
212
+ function absoluteify(path, basePath) {
213
+ if (!ABSOLUTE_URL_REGEXP.test(path)) {
214
+ if (!basePath) {
215
+ throw new JSONRefError(`Tried to resolve a relative URL, without having a basePath. path: '${path}' basePath: '${basePath}'`);
216
+ }
217
+
218
+ return _url.default.resolve(basePath, path);
219
+ }
220
+
221
+ return path;
222
+ }
223
+ /**
224
+ * Wraps an error as JSONRefError.
225
+ * @param {Error} e the error.
226
+ * @param {Object} extra (optional) optional data.
227
+ * @return {Error} an instance of JSONRefError.
228
+ * @api public
229
+ */
230
+
231
+
232
+ function wrapError(e, extra) {
233
+ let message;
234
+
235
+ if (e && e.response && e.response.body) {
236
+ message = `${e.response.body.code} ${e.response.body.message}`;
237
+ } else {
238
+ message = e.message;
239
+ }
240
+
241
+ return new JSONRefError(`Could not resolve reference: ${message}`, extra, e);
242
+ }
243
+ /**
244
+ * Splits a pointer by the hash delimiter.
245
+ * @api public
246
+ */
247
+
248
+
249
+ function split(ref) {
250
+ return (ref + '').split('#'); // eslint-disable-line prefer-template
251
+ }
252
+ /**
253
+ * Extracts a pointer from its document.
254
+ * @param {String} docPath the absolute document URL.
255
+ * @param {String} pointer the pointer whose value is to be extracted.
256
+ * @return {Promise} a promise of the pointer value.
257
+ * @api public
258
+ */
259
+
260
+
261
+ function extractFromDoc(docPath, pointer) {
262
+ const doc = docCache[docPath];
263
+
264
+ if (doc && !_.default.isPromise(doc)) {
265
+ // If doc is already available, return __value together with the promise.
266
+ // __value is for special handling in cycle check:
267
+ // pointerAlreadyInPath() won't work if patch.value is a promise,
268
+ // thus when that promise is finally resolved, cycle might happen (because
269
+ // `spec` and `docCache[basePath]` refer to the exact same object).
270
+ // See test "should resolve a cyclic spec when baseDoc is specified".
271
+ try {
272
+ const v = extract(pointer, doc);
273
+ return Object.assign(Promise.resolve(v), {
274
+ __value: v
275
+ });
276
+ } catch (e) {
277
+ return Promise.reject(e);
278
+ }
279
+ }
280
+
281
+ return getDoc(docPath).then(_doc => extract(pointer, _doc));
282
+ }
283
+ /**
284
+ * Clears all document caches.
285
+ * @param {String} item (optional) the name of the cache item to be cleared.
286
+ * @api public
287
+ */
288
+
289
+
290
+ function clearCache(item) {
291
+ if (typeof item !== 'undefined') {
292
+ delete docCache[item];
293
+ } else {
294
+ Object.keys(docCache).forEach(key => {
295
+ delete docCache[key];
296
+ });
297
+ }
298
+ }
299
+ /**
300
+ * Fetches and caches a document.
301
+ * @param {String} docPath the absolute URL of the document.
302
+ * @return {Promise} a promise of the document content.
303
+ * @api public
304
+ */
305
+
306
+
307
+ function getDoc(docPath) {
308
+ const val = docCache[docPath];
309
+
310
+ if (val) {
311
+ return _.default.isPromise(val) ? val : Promise.resolve(val);
312
+ } // NOTE: we need to use `mod.fetchJSON` in order to be able to overwrite it.
313
+ // Any tips on how to make this cleaner, please ping!
314
+
315
+
316
+ docCache[docPath] = mod.fetchJSON(docPath).then(doc => {
317
+ docCache[docPath] = doc;
318
+ return doc;
319
+ });
320
+ return docCache[docPath];
321
+ }
322
+ /**
323
+ * Fetches a document.
324
+ * @param {String} docPath the absolute URL of the document.
325
+ * @return {Promise} a promise of the document content.
326
+ * @api public
327
+ */
328
+
329
+
330
+ function fetchJSON(docPath) {
331
+ return (0, _crossFetch.fetch)(docPath, {
332
+ headers: {
333
+ Accept: _constants.ACCEPT_HEADER_VALUE_FOR_DOCUMENTS
334
+ },
335
+ loadSpec: true
336
+ }).then(res => res.text()).then(text => _jsYaml.default.safeLoad(text));
337
+ }
338
+ /**
339
+ * Extracts a pointer from an object.
340
+ * @param {String[]} pointer the JSON pointer.
341
+ * @param {Object} obj an object whose value is to be extracted.
342
+ * @return {Object} the value to be extracted.
343
+ * @api public
344
+ */
345
+
346
+
347
+ function extract(pointer, obj) {
348
+ const tokens = jsonPointerToArray(pointer);
349
+
350
+ if (tokens.length < 1) {
351
+ return obj;
352
+ }
353
+
354
+ const val = _.default.getIn(obj, tokens);
355
+
356
+ if (typeof val === 'undefined') {
357
+ throw new JSONRefError(`Could not resolve pointer: ${pointer} does not exist in document`, {
358
+ pointer
359
+ });
360
+ }
361
+
362
+ return val;
363
+ }
364
+ /**
365
+ * Converts a JSON pointer to array.
366
+ * @api public
367
+ */
368
+
369
+
370
+ function jsonPointerToArray(pointer) {
371
+ if (typeof pointer !== 'string') {
372
+ throw new TypeError(`Expected a string, got a ${typeof pointer}`);
373
+ }
374
+
375
+ if (pointer[0] === '/') {
376
+ pointer = pointer.substr(1);
377
+ }
378
+
379
+ if (pointer === '') {
380
+ return [];
381
+ }
382
+
383
+ return pointer.split('/').map(unescapeJsonPointerToken);
384
+ }
385
+ /**
386
+ * Unescapes a JSON pointer.
387
+ * @api public
388
+ */
389
+
390
+
391
+ function unescapeJsonPointerToken(token) {
392
+ if (typeof token !== 'string') {
393
+ return token;
394
+ }
395
+
396
+ return _querystringBrowser.default.unescape(token.replace(/~1/g, '/').replace(/~0/g, '~'));
397
+ }
398
+ /**
399
+ * Escapes a JSON pointer.
400
+ * @api public
401
+ */
402
+
403
+
404
+ function escapeJsonPointerToken(token) {
405
+ return _querystringBrowser.default.escape(token.replace(/~/g, '~0').replace(/\//g, '~1'));
406
+ }
407
+
408
+ function arrayToJsonPointer(arr) {
409
+ if (arr.length === 0) {
410
+ return '';
411
+ }
412
+
413
+ return `/${arr.map(escapeJsonPointerToken).join('/')}`;
414
+ }
415
+
416
+ const pointerBoundaryChar = c => !c || c === '/' || c === '#';
417
+
418
+ function pointerIsAParent(pointer, parentPointer) {
419
+ if (pointerBoundaryChar(parentPointer)) {
420
+ // This is the root of the document, so its naturally a parent
421
+ return true;
422
+ }
423
+
424
+ const nextChar = pointer.charAt(parentPointer.length);
425
+ const lastParentChar = parentPointer.slice(-1);
426
+ return pointer.indexOf(parentPointer) === 0 && (!nextChar || nextChar === '/' || nextChar === '#') && lastParentChar !== '#';
427
+ } // =========================
428
+ // Private
429
+ // =========================
430
+
431
+ /**
432
+ * Checks if this pointer points back to one or more pointers along the path.
433
+ */
434
+
435
+
436
+ function pointerAlreadyInPath(pointer, basePath, parent, specmap) {
437
+ let refs = specmapRefs.get(specmap);
438
+
439
+ if (!refs) {
440
+ // Stores all resolved references of a specmap instance.
441
+ // Schema: path -> pointer (path's $ref value).
442
+ refs = {};
443
+ specmapRefs.set(specmap, refs);
444
+ }
445
+
446
+ const parentPointer = arrayToJsonPointer(parent);
447
+ const fullyQualifiedPointer = `${basePath || '<specmap-base>'}#${pointer}`; // dirty hack to strip `allof/[index]` from the path, in order to avoid cases
448
+ // where we get false negatives because:
449
+ // - we resolve a path, then
450
+ // - allOf plugin collapsed `allOf/[index]` out of the path, then
451
+ // - we try to work on a child $ref within that collapsed path.
452
+ //
453
+ // because of the path collapse, we lose track of it in our specmapRefs hash
454
+ // solution: always throw the allOf constructs out of paths we store
455
+ // TODO: solve this with a global register, or by writing more metadata in
456
+ // either allOf or refs plugin
457
+
458
+ const safeParentPointer = parentPointer.replace(/allOf\/\d+\/?/g, ''); // Case 1: direct cycle, e.g. a.b.c.$ref: '/a.b'
459
+ // Detect by checking that the parent path doesn't start with pointer.
460
+ // This only applies if the pointer is internal, i.e. basePath === rootPath (could be null)
461
+
462
+ const rootDoc = specmap.contextTree.get([]).baseDoc;
463
+
464
+ if (basePath == rootDoc && pointerIsAParent(safeParentPointer, pointer)) {
465
+ // eslint-disable-line
466
+ return true;
467
+ } // Case 2: indirect cycle
468
+ // ex1: a.$ref: '/b' & b.c.$ref: '/b/c'
469
+ // ex2: a.$ref: '/b/c' & b.c.$ref: '/b'
470
+ // Detect by retrieving all the $refs along the path of parent
471
+ // and checking if any starts with pointer or vice versa.
472
+
473
+
474
+ let currPath = '';
475
+ const hasIndirectCycle = parent.some(token => {
476
+ currPath = `${currPath}/${escapeJsonPointerToken(token)}`;
477
+ return refs[currPath] && refs[currPath].some(ref => {
478
+ return pointerIsAParent(ref, fullyQualifiedPointer) || pointerIsAParent(fullyQualifiedPointer, ref);
479
+ });
480
+ });
481
+
482
+ if (hasIndirectCycle) {
483
+ return true;
484
+ } // No cycle, this ref will be resolved, so stores it now for future detection.
485
+ // No need to store if has cycle, as parent path is a dead-end and won't be checked again.
486
+
487
+
488
+ refs[safeParentPointer] = (refs[safeParentPointer] || []).concat(fullyQualifiedPointer);
489
+ return undefined;
490
+ }
491
+ /**
492
+ * Checks if the value of this patch ends up pointing to an ancestor along the path.
493
+ */
494
+
495
+
496
+ function patchValueAlreadyInPath(root, patch) {
497
+ const ancestors = [root];
498
+ patch.path.reduce((parent, p) => {
499
+ ancestors.push(parent[p]);
500
+ return parent[p];
501
+ }, root);
502
+ return pointToAncestor(patch.value);
503
+
504
+ function pointToAncestor(obj) {
505
+ return _.default.isObject(obj) && (ancestors.indexOf(obj) >= 0 || Object.keys(obj).some(k => {
506
+ return pointToAncestor(obj[k]);
507
+ }));
508
+ }
509
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.default = resolveSubtree;
5
+
6
+ var _get = _interopRequireDefault(require("lodash/get"));
7
+
8
+ var _resolver = _interopRequireDefault(require("../resolver"));
9
+
10
+ var _helpers = require("../helpers");
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
15
+
16
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
17
+
18
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
19
+
20
+ async function resolveSubtree(obj, path, opts = {}) {
21
+ const {
22
+ returnEntireTree,
23
+ baseDoc,
24
+ requestInterceptor,
25
+ responseInterceptor,
26
+ parameterMacro,
27
+ modelPropertyMacro,
28
+ useCircularStructures
29
+ } = opts;
30
+ const resolveOptions = {
31
+ pathDiscriminator: path,
32
+ baseDoc,
33
+ requestInterceptor,
34
+ responseInterceptor,
35
+ parameterMacro,
36
+ modelPropertyMacro,
37
+ useCircularStructures
38
+ };
39
+ const {
40
+ spec: normalized
41
+ } = (0, _helpers.normalizeSwagger)({
42
+ spec: obj
43
+ });
44
+ const result = await (0, _resolver.default)(_objectSpread(_objectSpread({}, resolveOptions), {}, {
45
+ spec: normalized,
46
+ allowMetaPatches: true,
47
+ skipNormalization: true
48
+ }));
49
+
50
+ if (!returnEntireTree && Array.isArray(path) && path.length) {
51
+ result.spec = (0, _get.default)(result.spec, path) || null;
52
+ }
53
+
54
+ return result;
55
+ }