@ama-sdk/core 13.0.0-next.4 → 13.0.0-next.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/cjs/fwk/mocks/helpers.js +2 -1
- package/cjs/plugins/index.js +1 -0
- package/cjs/plugins/open-telemetry/index.js +18 -0
- package/cjs/plugins/open-telemetry/traceparent/index.js +20 -0
- package/cjs/plugins/open-telemetry/traceparent/interfaces.js +18 -0
- package/cjs/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.js +234 -0
- package/cjs/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.spec.js +550 -0
- package/cjs/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.js +146 -0
- package/cjs/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.spec.js +345 -0
- package/esm2015/fwk/mocks/helpers.js +5 -2
- package/esm2015/plugins/index.js +1 -0
- package/esm2015/plugins/open-telemetry/index.js +1 -0
- package/esm2015/plugins/open-telemetry/traceparent/index.js +3 -0
- package/esm2015/plugins/open-telemetry/traceparent/interfaces.js +8 -0
- package/esm2015/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.js +225 -0
- package/esm2015/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.spec.js +546 -0
- package/esm2015/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.js +139 -0
- package/esm2015/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.spec.js +341 -0
- package/package.json +7 -8
- package/src/fwk/mocks/helpers.d.ts +3 -1
- package/src/fwk/mocks/helpers.d.ts.map +1 -1
- package/src/fwk/mocks/helpers.js +5 -2
- package/src/fwk/mocks/helpers.js.map +1 -1
- package/src/fwk/mocks/path-object.d.ts +3 -1
- package/src/fwk/mocks/path-object.d.ts.map +1 -1
- package/src/plugins/index.d.ts +1 -0
- package/src/plugins/index.d.ts.map +1 -1
- package/src/plugins/index.js +1 -0
- package/src/plugins/index.js.map +1 -1
- package/src/plugins/open-telemetry/index.d.ts +2 -0
- package/src/plugins/open-telemetry/index.d.ts.map +1 -0
- package/src/plugins/open-telemetry/index.js +2 -0
- package/src/plugins/open-telemetry/index.js.map +1 -0
- package/src/plugins/open-telemetry/traceparent/index.d.ts +4 -0
- package/src/plugins/open-telemetry/traceparent/index.d.ts.map +1 -0
- package/src/plugins/open-telemetry/traceparent/index.js +4 -0
- package/src/plugins/open-telemetry/traceparent/index.js.map +1 -0
- package/src/plugins/open-telemetry/traceparent/interfaces.d.ts +38 -0
- package/src/plugins/open-telemetry/traceparent/interfaces.d.ts.map +1 -0
- package/src/plugins/open-telemetry/traceparent/interfaces.js +6 -0
- package/src/plugins/open-telemetry/traceparent/interfaces.js.map +1 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.d.ts +36 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.d.ts.map +1 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.js +87 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.reply.js.map +1 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.d.ts +39 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.d.ts.map +1 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.js +56 -0
- package/src/plugins/open-telemetry/traceparent/open-telemetry.traceparent.request.js.map +1 -0
- package/src/utils/perf/perf-metric.service.d.ts +6 -0
- package/src/utils/perf/perf-metric.service.d.ts.map +1 -1
- package/src/utils/perf/perf-metric.service.js.map +1 -1
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ Please refer to the [ama-sdk-schematics](../schematics/README.md) package for ge
|
|
|
21
21
|
- [fetch-credentials](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core/src/plugins/fetch-credentials)
|
|
22
22
|
- [json-token](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core/src/plugins/json-token)
|
|
23
23
|
- [mock-intercept](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core/src/plugins/mock-intercept)
|
|
24
|
+
- [OpenTelemetry Traceparent](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core/src/plugins/open-telemetry/traceparent)
|
|
24
25
|
- [pii-tokenizer](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core/src/plugins/pii-tokenizer)
|
|
25
26
|
- [raw-response-info](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core/src/plugins/raw-response-info)
|
|
26
27
|
- [reviver](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core/src/plugins/reviver)
|
package/cjs/fwk/mocks/helpers.js
CHANGED
|
@@ -33,7 +33,8 @@ function getPath(requestUrl, pathObjects, method) {
|
|
|
33
33
|
}
|
|
34
34
|
// Find all matching paths
|
|
35
35
|
var matches = pathObjects.reduce(function(newMatches, pathObject, index) {
|
|
36
|
-
|
|
36
|
+
var regexp = pathObject.urlPattern ? new RegExp(pathObject.urlPattern) : pathObject.regexp;
|
|
37
|
+
if (regexp.test(pathName)) {
|
|
37
38
|
newMatches.push({
|
|
38
39
|
index: index,
|
|
39
40
|
segments: pathObject.path.split('/'),
|
package/cjs/plugins/index.js
CHANGED
|
@@ -14,6 +14,7 @@ _export_star(require("./fetch-cache/index"), exports);
|
|
|
14
14
|
_export_star(require("./fetch-credentials/index"), exports);
|
|
15
15
|
_export_star(require("./json-token/index"), exports);
|
|
16
16
|
_export_star(require("./mgw-mdw-auth/index"), exports);
|
|
17
|
+
_export_star(require("./open-telemetry/traceparent/index"), exports);
|
|
17
18
|
_export_star(require("./mock-intercept/index"), exports);
|
|
18
19
|
_export_star(require("./pii-tokenizer/index"), exports);
|
|
19
20
|
_export_star(require("./raw-response-info/index"), exports);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./traceparent/index"), exports);
|
|
6
|
+
function _export_star(from, to) {
|
|
7
|
+
Object.keys(from).forEach(function(k) {
|
|
8
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
9
|
+
Object.defineProperty(to, k, {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function() {
|
|
12
|
+
return from[k];
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return from;
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./interfaces"), exports);
|
|
6
|
+
_export_star(require("./open-telemetry.traceparent.reply"), exports);
|
|
7
|
+
_export_star(require("./open-telemetry.traceparent.request"), exports);
|
|
8
|
+
function _export_star(from, to) {
|
|
9
|
+
Object.keys(from).forEach(function(k) {
|
|
10
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
11
|
+
Object.defineProperty(to, k, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function() {
|
|
14
|
+
return from[k];
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return from;
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface reporting the decoded {@link https://www.w3.org/TR/trace-context/#traceparent-header | Traceparent header} information for the
|
|
3
|
+
* {@link https://opentelemetry.io/ | OpenTelemetry} specification.
|
|
4
|
+
*/ "use strict";
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
Object.defineProperty(exports, "DEFAULT_COMMON_OPTIONS", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function() {
|
|
11
|
+
return DEFAULT_COMMON_OPTIONS;
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
var DEFAULT_COMMON_OPTIONS = {
|
|
15
|
+
storage: globalThis.sessionStorage,
|
|
16
|
+
parentIdStorageKey: 'traceparent-parent-id',
|
|
17
|
+
traceparentHeader: 'traceparent'
|
|
18
|
+
};
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get OpenTelemetryTraceparentReply () {
|
|
13
|
+
return OpenTelemetryTraceparentReply;
|
|
14
|
+
},
|
|
15
|
+
get decodeTraceparentHeader () {
|
|
16
|
+
return decodeTraceparentHeader;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
var _interfaces = require("./interfaces");
|
|
20
|
+
function _array_like_to_array(arr, len) {
|
|
21
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
22
|
+
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
23
|
+
return arr2;
|
|
24
|
+
}
|
|
25
|
+
function _array_with_holes(arr) {
|
|
26
|
+
if (Array.isArray(arr)) return arr;
|
|
27
|
+
}
|
|
28
|
+
function _class_call_check(instance, Constructor) {
|
|
29
|
+
if (!(instance instanceof Constructor)) {
|
|
30
|
+
throw new TypeError("Cannot call a class as a function");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function _defineProperties(target, props) {
|
|
34
|
+
for(var i = 0; i < props.length; i++){
|
|
35
|
+
var descriptor = props[i];
|
|
36
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
|
37
|
+
descriptor.configurable = true;
|
|
38
|
+
if ("value" in descriptor) descriptor.writable = true;
|
|
39
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function _create_class(Constructor, protoProps, staticProps) {
|
|
43
|
+
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
44
|
+
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
45
|
+
return Constructor;
|
|
46
|
+
}
|
|
47
|
+
function _define_property(obj, key, value) {
|
|
48
|
+
if (key in obj) {
|
|
49
|
+
Object.defineProperty(obj, key, {
|
|
50
|
+
value: value,
|
|
51
|
+
enumerable: true,
|
|
52
|
+
configurable: true,
|
|
53
|
+
writable: true
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
obj[key] = value;
|
|
57
|
+
}
|
|
58
|
+
return obj;
|
|
59
|
+
}
|
|
60
|
+
function _iterable_to_array_limit(arr, i) {
|
|
61
|
+
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
62
|
+
if (_i == null) return;
|
|
63
|
+
var _arr = [];
|
|
64
|
+
var _n = true;
|
|
65
|
+
var _d = false;
|
|
66
|
+
var _s, _e;
|
|
67
|
+
try {
|
|
68
|
+
for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
|
|
69
|
+
_arr.push(_s.value);
|
|
70
|
+
if (i && _arr.length === i) break;
|
|
71
|
+
}
|
|
72
|
+
} catch (err) {
|
|
73
|
+
_d = true;
|
|
74
|
+
_e = err;
|
|
75
|
+
} finally{
|
|
76
|
+
try {
|
|
77
|
+
if (!_n && _i["return"] != null) _i["return"]();
|
|
78
|
+
} finally{
|
|
79
|
+
if (_d) throw _e;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return _arr;
|
|
83
|
+
}
|
|
84
|
+
function _non_iterable_rest() {
|
|
85
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
86
|
+
}
|
|
87
|
+
function _object_spread(target) {
|
|
88
|
+
for(var i = 1; i < arguments.length; i++){
|
|
89
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
90
|
+
var ownKeys = Object.keys(source);
|
|
91
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
92
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
93
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
ownKeys.forEach(function(key) {
|
|
97
|
+
_define_property(target, key, source[key]);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return target;
|
|
101
|
+
}
|
|
102
|
+
function ownKeys(object, enumerableOnly) {
|
|
103
|
+
var keys = Object.keys(object);
|
|
104
|
+
if (Object.getOwnPropertySymbols) {
|
|
105
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
106
|
+
if (enumerableOnly) {
|
|
107
|
+
symbols = symbols.filter(function(sym) {
|
|
108
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
keys.push.apply(keys, symbols);
|
|
112
|
+
}
|
|
113
|
+
return keys;
|
|
114
|
+
}
|
|
115
|
+
function _object_spread_props(target, source) {
|
|
116
|
+
source = source != null ? source : {};
|
|
117
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
118
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
119
|
+
} else {
|
|
120
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
121
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return target;
|
|
125
|
+
}
|
|
126
|
+
function _sliced_to_array(arr, i) {
|
|
127
|
+
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
128
|
+
}
|
|
129
|
+
function _type_of(obj) {
|
|
130
|
+
"@swc/helpers - typeof";
|
|
131
|
+
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
132
|
+
}
|
|
133
|
+
function _unsupported_iterable_to_array(o, minLen) {
|
|
134
|
+
if (!o) return;
|
|
135
|
+
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
136
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
137
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
138
|
+
if (n === "Map" || n === "Set") return Array.from(n);
|
|
139
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
140
|
+
}
|
|
141
|
+
var DEFAULT_OPTIONS = _object_spread_props(_object_spread({}, _interfaces.DEFAULT_COMMON_OPTIONS), {
|
|
142
|
+
dataField: '_traceparent'
|
|
143
|
+
});
|
|
144
|
+
var TRACE_ID_LENGTH = 32;
|
|
145
|
+
var PARENT_ID_LENGTH = 16;
|
|
146
|
+
var TRACE_ID_REGEXP = new RegExp("^[a-f0-9]{".concat(TRACE_ID_LENGTH, "}$"));
|
|
147
|
+
var PARENT_ID_REGEXP = new RegExp("^[a-f0-9]{".concat(PARENT_ID_LENGTH, "}$"));
|
|
148
|
+
var decodeTraceparentHeader = function(traceparent, options) {
|
|
149
|
+
var content = traceparent.split('-');
|
|
150
|
+
var dataField = {};
|
|
151
|
+
var logWarning = function() {
|
|
152
|
+
var _options_logger;
|
|
153
|
+
return options === null || options === void 0 ? void 0 : (_options_logger = options.logger) === null || _options_logger === void 0 ? void 0 : _options_logger.warn("Invalid traceparent header ".concat(traceparent, ", will be ignored"));
|
|
154
|
+
};
|
|
155
|
+
if (content.length < 2) {
|
|
156
|
+
logWarning();
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (content[0].length < PARENT_ID_LENGTH) {
|
|
160
|
+
var ref;
|
|
161
|
+
ref = _sliced_to_array(content, 4), dataField.version = ref[0], dataField.traceId = ref[1], dataField.parentId = ref[2], dataField.traceFlags = ref[3], ref;
|
|
162
|
+
} else {
|
|
163
|
+
var ref1;
|
|
164
|
+
ref1 = _sliced_to_array(content, 3), dataField.traceId = ref1[0], dataField.parentId = ref1[1], dataField.traceFlags = ref1[2], ref1;
|
|
165
|
+
dataField.version = '00';
|
|
166
|
+
}
|
|
167
|
+
if (!PARENT_ID_REGEXP.test(dataField.parentId) || !TRACE_ID_REGEXP.test(dataField.traceId)) {
|
|
168
|
+
logWarning();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
return dataField;
|
|
172
|
+
};
|
|
173
|
+
var OpenTelemetryTraceparentReply = /*#__PURE__*/ function() {
|
|
174
|
+
"use strict";
|
|
175
|
+
function OpenTelemetryTraceparentReply(options) {
|
|
176
|
+
_class_call_check(this, OpenTelemetryTraceparentReply);
|
|
177
|
+
_define_property(this, "options", void 0);
|
|
178
|
+
this.options = _object_spread({}, DEFAULT_OPTIONS, options);
|
|
179
|
+
}
|
|
180
|
+
_create_class(OpenTelemetryTraceparentReply, [
|
|
181
|
+
{
|
|
182
|
+
key: "updateParentId",
|
|
183
|
+
value: function updateParentId(parentId, logger) {
|
|
184
|
+
if (parentId) {
|
|
185
|
+
var currentParentId = this.options.storage.getItem(this.options.parentIdStorageKey);
|
|
186
|
+
if (!currentParentId || currentParentId !== parentId) {
|
|
187
|
+
var _logger_info;
|
|
188
|
+
logger === null || logger === void 0 ? void 0 : (_logger_info = logger.info) === null || _logger_info === void 0 ? void 0 : _logger_info.call(logger, "The current Traceparent ParentId ".concat(currentParentId, " will be replaced by the received one ").concat(parentId, "."));
|
|
189
|
+
this.options.storage.setItem(this.options.parentIdStorageKey, parentId);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
key: "decodeTraceparentHeader",
|
|
196
|
+
value: function decodeTraceparentHeader1(traceparent, logger) {
|
|
197
|
+
var dataField = decodeTraceparentHeader(traceparent, {
|
|
198
|
+
logger: logger
|
|
199
|
+
});
|
|
200
|
+
if (dataField) {
|
|
201
|
+
this.updateParentId(dataField.parentId, logger);
|
|
202
|
+
}
|
|
203
|
+
return dataField;
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
key: "load",
|
|
208
|
+
value: /** @inheritdoc */ function load(context) {
|
|
209
|
+
var _this = this;
|
|
210
|
+
return {
|
|
211
|
+
transform: function(data) {
|
|
212
|
+
if (!context.response) {
|
|
213
|
+
return data;
|
|
214
|
+
}
|
|
215
|
+
var content = context.response.headers.get(_this.options.traceparentHeader);
|
|
216
|
+
if (!content) {
|
|
217
|
+
var _context_logger_debug, _context_logger;
|
|
218
|
+
(_context_logger = context.logger) === null || _context_logger === void 0 ? void 0 : (_context_logger_debug = _context_logger.debug) === null || _context_logger_debug === void 0 ? void 0 : _context_logger_debug.call(_context_logger, "The reply of the request ".concat(context.url, " does not contain ").concat(_this.options.traceparentHeader, " header, the open telemetry information will not be retrieved."));
|
|
219
|
+
return data;
|
|
220
|
+
}
|
|
221
|
+
var dataField = _this.decodeTraceparentHeader(content, context.logger);
|
|
222
|
+
var extendedData = _define_property({}, _this.options.dataField, dataField);
|
|
223
|
+
if ((typeof data === "undefined" ? "undefined" : _type_of(data)) === 'object' && data && _this.options.dataField in data) {
|
|
224
|
+
var _context_logger1;
|
|
225
|
+
(_context_logger1 = context.logger) === null || _context_logger1 === void 0 ? void 0 : _context_logger1.warn('The field "'.concat(_this.options.dataField, '" already exist in the response, it will be overridden by the traceparent information.'));
|
|
226
|
+
}
|
|
227
|
+
return data ? Object.assign(data, extendedData) : extendedData;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
]);
|
|
233
|
+
return OpenTelemetryTraceparentReply;
|
|
234
|
+
}();
|