@felloh-org/lambda-wrapper 1.0.22 → 1.0.25
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/cli/seed/create-schema.js +1 -0
- package/dist/entity/index.js +3 -1
- package/dist/entity/token/index.js +14 -0
- package/dist/entity/token/token/index.js +128 -0
- package/dist/entity/user/user/index.js +13 -1
- package/dist/index.js +8 -0
- package/dist/migration/token/1645613145774-token.js +15 -0
- package/dist/migration/token/1645618345963-token_secret_length.js +15 -0
- package/dist/migration/token/1645621420506-token_user.js +17 -0
- package/dist/migration/user/1645621100580-user_is_api_user.js +13 -0
- package/dist/service/request.js +5 -3
- package/dist/wrapper/index.js +10 -24
- package/package.json +1 -1
package/dist/entity/index.js
CHANGED
|
@@ -19,8 +19,10 @@ var _trustPayments = _interopRequireDefault(require("./trust-payments"));
|
|
|
19
19
|
|
|
20
20
|
var _totalProcessing = _interopRequireDefault(require("./total-processing"));
|
|
21
21
|
|
|
22
|
+
var _token = _interopRequireDefault(require("./token"));
|
|
23
|
+
|
|
22
24
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
25
|
|
|
24
|
-
const ENTITIES = [..._agentData.default, ..._bank.default, ..._nuapay.default, ..._payment.default, ..._totalProcessing.default, ..._trustPayments.default, ..._user.default];
|
|
26
|
+
const ENTITIES = [..._agentData.default, ..._bank.default, ..._nuapay.default, ..._payment.default, ..._token.default, ..._totalProcessing.default, ..._trustPayments.default, ..._user.default];
|
|
25
27
|
var _default = ENTITIES;
|
|
26
28
|
exports.default = _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _token = _interopRequireDefault(require("./token"));
|
|
9
|
+
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
|
+
|
|
12
|
+
const ENTITIES = [_token.default];
|
|
13
|
+
var _default = ENTITIES;
|
|
14
|
+
exports.default = _default;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
|
|
8
|
+
var _typeorm = require("typeorm");
|
|
9
|
+
|
|
10
|
+
var _uuid = require("uuid");
|
|
11
|
+
|
|
12
|
+
var _organisation = _interopRequireDefault(require("../../user/organisation"));
|
|
13
|
+
|
|
14
|
+
var _user = _interopRequireDefault(require("../../user/user"));
|
|
15
|
+
|
|
16
|
+
var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _dec11, _dec12, _class, _class2, _descriptor, _descriptor2, _descriptor3, _descriptor4, _descriptor5, _descriptor6, _descriptor7, _descriptor8, _descriptor9;
|
|
17
|
+
|
|
18
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
+
|
|
20
|
+
function _initializerDefineProperty(target, property, descriptor, context) { if (!descriptor) return; Object.defineProperty(target, property, { enumerable: descriptor.enumerable, configurable: descriptor.configurable, writable: descriptor.writable, value: descriptor.initializer ? descriptor.initializer.call(context) : void 0 }); }
|
|
21
|
+
|
|
22
|
+
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object.keys(descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object.defineProperty(target, property, desc); desc = null; } return desc; }
|
|
23
|
+
|
|
24
|
+
function _initializerWarningHelper(descriptor, context) { throw new Error('Decorating class property failed. Please ensure that ' + 'proposal-class-properties is enabled and runs after the decorators transform.'); }
|
|
25
|
+
|
|
26
|
+
let Token = (_dec = (0, _typeorm.Entity)({
|
|
27
|
+
name: 'token',
|
|
28
|
+
schema: 'token'
|
|
29
|
+
}), _dec2 = (0, _typeorm.PrimaryColumn)("varchar"), _dec3 = (0, _typeorm.ManyToOne)(() => _organisation.default), _dec4 = (0, _typeorm.JoinColumn)({
|
|
30
|
+
name: 'organisation_id',
|
|
31
|
+
referencedColumnName: 'id'
|
|
32
|
+
}), _dec5 = (0, _typeorm.Column)({
|
|
33
|
+
type: "varchar",
|
|
34
|
+
length: "250"
|
|
35
|
+
}), _dec6 = (0, _typeorm.Column)({
|
|
36
|
+
type: "varchar",
|
|
37
|
+
length: "150"
|
|
38
|
+
}), _dec7 = (0, _typeorm.Column)({
|
|
39
|
+
type: "varchar",
|
|
40
|
+
length: "250"
|
|
41
|
+
}), _dec8 = (0, _typeorm.Column)({
|
|
42
|
+
type: "varchar",
|
|
43
|
+
length: "4"
|
|
44
|
+
}), _dec9 = (0, _typeorm.ManyToOne)(() => _user.default), _dec10 = (0, _typeorm.JoinColumn)({
|
|
45
|
+
name: 'user_id',
|
|
46
|
+
referencedColumnName: 'id'
|
|
47
|
+
}), _dec11 = (0, _typeorm.CreateDateColumn)(), _dec12 = (0, _typeorm.DeleteDateColumn)(), _dec(_class = (_class2 = class Token {
|
|
48
|
+
constructor() {
|
|
49
|
+
_initializerDefineProperty(this, "id", _descriptor, this);
|
|
50
|
+
|
|
51
|
+
_initializerDefineProperty(this, "organisation", _descriptor2, this);
|
|
52
|
+
|
|
53
|
+
_initializerDefineProperty(this, "name", _descriptor3, this);
|
|
54
|
+
|
|
55
|
+
_initializerDefineProperty(this, "public_key", _descriptor4, this);
|
|
56
|
+
|
|
57
|
+
_initializerDefineProperty(this, "secret_key", _descriptor5, this);
|
|
58
|
+
|
|
59
|
+
_initializerDefineProperty(this, "secret_key_last_four", _descriptor6, this);
|
|
60
|
+
|
|
61
|
+
_initializerDefineProperty(this, "user", _descriptor7, this);
|
|
62
|
+
|
|
63
|
+
_initializerDefineProperty(this, "created_at", _descriptor8, this);
|
|
64
|
+
|
|
65
|
+
_initializerDefineProperty(this, "deleted_at", _descriptor9, this);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}, (_descriptor = _applyDecoratedDescriptor(_class2.prototype, "id", [_dec2], {
|
|
69
|
+
configurable: true,
|
|
70
|
+
enumerable: true,
|
|
71
|
+
writable: true,
|
|
72
|
+
initializer: function () {
|
|
73
|
+
return (0, _uuid.v4)();
|
|
74
|
+
}
|
|
75
|
+
}), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, "organisation", [_dec3, _dec4], {
|
|
76
|
+
configurable: true,
|
|
77
|
+
enumerable: true,
|
|
78
|
+
writable: true,
|
|
79
|
+
initializer: function () {
|
|
80
|
+
return _organisation.default;
|
|
81
|
+
}
|
|
82
|
+
}), _descriptor3 = _applyDecoratedDescriptor(_class2.prototype, "name", [_dec5], {
|
|
83
|
+
configurable: true,
|
|
84
|
+
enumerable: true,
|
|
85
|
+
writable: true,
|
|
86
|
+
initializer: function () {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
}), _descriptor4 = _applyDecoratedDescriptor(_class2.prototype, "public_key", [_dec6], {
|
|
90
|
+
configurable: true,
|
|
91
|
+
enumerable: true,
|
|
92
|
+
writable: true,
|
|
93
|
+
initializer: function () {
|
|
94
|
+
return "";
|
|
95
|
+
}
|
|
96
|
+
}), _descriptor5 = _applyDecoratedDescriptor(_class2.prototype, "secret_key", [_dec7], {
|
|
97
|
+
configurable: true,
|
|
98
|
+
enumerable: true,
|
|
99
|
+
writable: true,
|
|
100
|
+
initializer: function () {
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
}), _descriptor6 = _applyDecoratedDescriptor(_class2.prototype, "secret_key_last_four", [_dec8], {
|
|
104
|
+
configurable: true,
|
|
105
|
+
enumerable: true,
|
|
106
|
+
writable: true,
|
|
107
|
+
initializer: function () {
|
|
108
|
+
return "";
|
|
109
|
+
}
|
|
110
|
+
}), _descriptor7 = _applyDecoratedDescriptor(_class2.prototype, "user", [_dec9, _dec10], {
|
|
111
|
+
configurable: true,
|
|
112
|
+
enumerable: true,
|
|
113
|
+
writable: true,
|
|
114
|
+
initializer: function () {
|
|
115
|
+
return _user.default;
|
|
116
|
+
}
|
|
117
|
+
}), _descriptor8 = _applyDecoratedDescriptor(_class2.prototype, "created_at", [_dec11], {
|
|
118
|
+
configurable: true,
|
|
119
|
+
enumerable: true,
|
|
120
|
+
writable: true,
|
|
121
|
+
initializer: null
|
|
122
|
+
}), _descriptor9 = _applyDecoratedDescriptor(_class2.prototype, "deleted_at", [_dec12], {
|
|
123
|
+
configurable: true,
|
|
124
|
+
enumerable: true,
|
|
125
|
+
writable: true,
|
|
126
|
+
initializer: null
|
|
127
|
+
})), _class2)) || _class);
|
|
128
|
+
exports.default = Token;
|
|
@@ -9,7 +9,7 @@ var _typeorm = require("typeorm");
|
|
|
9
9
|
|
|
10
10
|
var _organisation = _interopRequireDefault(require("../organisation"));
|
|
11
11
|
|
|
12
|
-
var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _dec11, _dec12, _dec13, _dec14, _class, _class2, _descriptor, _descriptor2, _descriptor3, _descriptor4, _descriptor5, _descriptor6, _descriptor7, _descriptor8, _descriptor9, _descriptor10, _descriptor11;
|
|
12
|
+
var _dec, _dec2, _dec3, _dec4, _dec5, _dec6, _dec7, _dec8, _dec9, _dec10, _dec11, _dec12, _dec13, _dec14, _dec15, _class, _class2, _descriptor, _descriptor2, _descriptor3, _descriptor4, _descriptor5, _descriptor6, _descriptor7, _descriptor8, _descriptor9, _descriptor10, _descriptor11, _descriptor12;
|
|
13
13
|
|
|
14
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
15
|
|
|
@@ -60,6 +60,9 @@ let User = (_dec = (0, _typeorm.Entity)({
|
|
|
60
60
|
name: "organisation_id",
|
|
61
61
|
referencedColumnName: "id"
|
|
62
62
|
}
|
|
63
|
+
}), _dec15 = (0, _typeorm.Column)({
|
|
64
|
+
type: "boolean",
|
|
65
|
+
default: false
|
|
63
66
|
}), _dec(_class = (_class2 = class User {
|
|
64
67
|
constructor() {
|
|
65
68
|
_initializerDefineProperty(this, "id", _descriptor, this);
|
|
@@ -83,6 +86,8 @@ let User = (_dec = (0, _typeorm.Entity)({
|
|
|
83
86
|
_initializerDefineProperty(this, "deleted_at", _descriptor10, this);
|
|
84
87
|
|
|
85
88
|
_initializerDefineProperty(this, "organisations", _descriptor11, this);
|
|
89
|
+
|
|
90
|
+
_initializerDefineProperty(this, "is_api_user", _descriptor12, this);
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
propgate(email, mobile, status, firstName, lastName) {
|
|
@@ -182,5 +187,12 @@ let User = (_dec = (0, _typeorm.Entity)({
|
|
|
182
187
|
enumerable: true,
|
|
183
188
|
writable: true,
|
|
184
189
|
initializer: null
|
|
190
|
+
}), _descriptor12 = _applyDecoratedDescriptor(_class2.prototype, "is_api_user", [_dec15], {
|
|
191
|
+
configurable: true,
|
|
192
|
+
enumerable: true,
|
|
193
|
+
writable: true,
|
|
194
|
+
initializer: function () {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
185
197
|
})), _class2)) || _class);
|
|
186
198
|
exports.default = User;
|
package/dist/index.js
CHANGED
|
@@ -249,6 +249,12 @@ Object.defineProperty(exports, "TProTransactionMetadataEntity", {
|
|
|
249
249
|
return _transactionMetadata2.default;
|
|
250
250
|
}
|
|
251
251
|
});
|
|
252
|
+
Object.defineProperty(exports, "TokenEntity", {
|
|
253
|
+
enumerable: true,
|
|
254
|
+
get: function () {
|
|
255
|
+
return _token.default;
|
|
256
|
+
}
|
|
257
|
+
});
|
|
252
258
|
Object.defineProperty(exports, "TransactionEntity", {
|
|
253
259
|
enumerable: true,
|
|
254
260
|
get: function () {
|
|
@@ -392,6 +398,8 @@ var _transaction3 = _interopRequireDefault(require("./entity/total-processing/tr
|
|
|
392
398
|
|
|
393
399
|
var _transactionMetadata2 = _interopRequireDefault(require("./entity/total-processing/transaction-metadata"));
|
|
394
400
|
|
|
401
|
+
var _token = _interopRequireDefault(require("./entity/token/token"));
|
|
402
|
+
|
|
395
403
|
var _batch = _interopRequireDefault(require("./entity/trust-payments/batch"));
|
|
396
404
|
|
|
397
405
|
var _merchant = _interopRequireDefault(require("./entity/trust-payments/merchant"));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { MigrationInterface, QueryRunner } = require("typeorm");
|
|
2
|
+
|
|
3
|
+
module.exports = class token1645613145774 {
|
|
4
|
+
name = 'token1645613145774'
|
|
5
|
+
|
|
6
|
+
async up(queryRunner) {
|
|
7
|
+
await queryRunner.query(`CREATE TABLE "token"."token" ("id" character varying NOT NULL, "name" character varying(250) NOT NULL, "public_key" character varying(150) NOT NULL, "secret_key" character varying(150) NOT NULL, "secret_key_last_four" character varying(4) NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "organisation_id" character varying(150), CONSTRAINT "PK_82fae97f905930df5d62a702fc9" PRIMARY KEY ("id"))`);
|
|
8
|
+
await queryRunner.query(`ALTER TABLE "token"."token" ADD CONSTRAINT "FK_56e183ecf0324bbecebec1b4057" FOREIGN KEY ("organisation_id") REFERENCES "user"."organisation"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async down(queryRunner) {
|
|
12
|
+
await queryRunner.query(`ALTER TABLE "token"."token" DROP CONSTRAINT "FK_56e183ecf0324bbecebec1b4057"`);
|
|
13
|
+
await queryRunner.query(`DROP TABLE "token"."token"`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { MigrationInterface, QueryRunner } = require("typeorm");
|
|
2
|
+
|
|
3
|
+
module.exports = class tokenSecretLength1645618345963 {
|
|
4
|
+
name = 'tokenSecretLength1645618345963'
|
|
5
|
+
|
|
6
|
+
async up(queryRunner) {
|
|
7
|
+
await queryRunner.query(`ALTER TABLE "token"."token" DROP COLUMN "secret_key"`);
|
|
8
|
+
await queryRunner.query(`ALTER TABLE "token"."token" ADD "secret_key" character varying(250) NOT NULL`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async down(queryRunner) {
|
|
12
|
+
await queryRunner.query(`ALTER TABLE "token"."token" DROP COLUMN "secret_key"`);
|
|
13
|
+
await queryRunner.query(`ALTER TABLE "token"."token" ADD "secret_key" character varying(150) NOT NULL`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { MigrationInterface, QueryRunner } = require("typeorm");
|
|
2
|
+
|
|
3
|
+
module.exports = class tokenUser1645621420506 {
|
|
4
|
+
name = 'tokenUser1645621420506'
|
|
5
|
+
|
|
6
|
+
async up(queryRunner) {
|
|
7
|
+
await queryRunner.query(`ALTER TABLE "token"."token" ADD "deleted_at" TIMESTAMP`);
|
|
8
|
+
await queryRunner.query(`ALTER TABLE "token"."token" ADD "user_id" character varying`);
|
|
9
|
+
await queryRunner.query(`ALTER TABLE "token"."token" ADD CONSTRAINT "FK_e50ca89d635960fda2ffeb17639" FOREIGN KEY ("user_id") REFERENCES "user"."user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async down(queryRunner) {
|
|
13
|
+
await queryRunner.query(`ALTER TABLE "token"."token" DROP CONSTRAINT "FK_e50ca89d635960fda2ffeb17639"`);
|
|
14
|
+
await queryRunner.query(`ALTER TABLE "token"."token" DROP COLUMN "user_id"`);
|
|
15
|
+
await queryRunner.query(`ALTER TABLE "token"."token" DROP COLUMN "deleted_at"`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { MigrationInterface, QueryRunner } = require("typeorm");
|
|
2
|
+
|
|
3
|
+
module.exports = class userIsApiUser1645621100580 {
|
|
4
|
+
name = 'userIsApiUser1645621100580'
|
|
5
|
+
|
|
6
|
+
async up(queryRunner) {
|
|
7
|
+
await queryRunner.query(`ALTER TABLE "user"."user" ADD "is_api_user" boolean NOT NULL DEFAULT false`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async down(queryRunner) {
|
|
11
|
+
await queryRunner.query(`ALTER TABLE "user"."user" DROP COLUMN "is_api_user"`);
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/service/request.js
CHANGED
|
@@ -259,11 +259,13 @@ class Request extends _dependencyAware.default {
|
|
|
259
259
|
Logger.label('request-validation-failed');
|
|
260
260
|
const validationErrorResponse = new _response.default({}, 422);
|
|
261
261
|
Object.keys(validation).forEach(validationKey => {
|
|
262
|
-
validation[validationKey].forEach(
|
|
262
|
+
validation[validationKey].forEach(message => {
|
|
263
263
|
validationErrorResponse.addError({
|
|
264
|
+
title: 'Validation Error',
|
|
265
|
+
message,
|
|
266
|
+
documentation_url: 'https://developers.felloh.com/errors#error-responses',
|
|
264
267
|
type: 'validation',
|
|
265
|
-
|
|
266
|
-
description
|
|
268
|
+
code: `validation.${validationKey}`
|
|
267
269
|
});
|
|
268
270
|
});
|
|
269
271
|
});
|
package/dist/wrapper/index.js
CHANGED
|
@@ -34,7 +34,7 @@ const handleSuccess = (di, outcome) => {
|
|
|
34
34
|
} // Outcome may be undefined as not all lambdas have a return value.
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
logger.metric('lambda.
|
|
37
|
+
logger.metric('lambda.status_code', outcome && outcome.statusCode || 200);
|
|
38
38
|
return outcome;
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
@@ -54,40 +54,26 @@ const handleSuccess = (di, outcome) => {
|
|
|
54
54
|
*
|
|
55
55
|
* @param {DependencyInjection} di
|
|
56
56
|
* @param {Error} error
|
|
57
|
-
* @param {boolean} [throwError=false]
|
|
58
57
|
*/
|
|
59
58
|
|
|
60
59
|
|
|
61
60
|
exports.handleSuccess = handleSuccess;
|
|
62
61
|
|
|
63
|
-
const handleError = (di, error
|
|
62
|
+
const handleError = (di, error) => {
|
|
64
63
|
const logger = di.get(_dependencies.DEFINITIONS.LOGGER);
|
|
65
|
-
logger.metric('lambda.
|
|
64
|
+
logger.metric('lambda.status_code', error.code || 500);
|
|
65
|
+
logger.error(error);
|
|
66
66
|
|
|
67
|
-
if (error
|
|
68
|
-
|
|
69
|
-
} else {
|
|
70
|
-
logger.info(error);
|
|
67
|
+
if (error instanceof _response.default) {
|
|
68
|
+
return error.generate();
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
if (error instanceof Error) {
|
|
75
|
-
return error;
|
|
76
|
-
} // We want to be absolutely sure
|
|
77
|
-
// that we are returning an error
|
|
78
|
-
// as Lambda sync handlers will only fail
|
|
79
|
-
// if the object is instanceof Error
|
|
71
|
+
const response = new _response.default({}, Number.isInteger(error.code) ? error.code : 500);
|
|
80
72
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (error instanceof _response.default) {
|
|
86
|
-
return error.generate();
|
|
73
|
+
if (typeof error.body !== 'undefined') {
|
|
74
|
+
response.setErrors(error.body || {});
|
|
87
75
|
}
|
|
88
76
|
|
|
89
|
-
const response = new _response.default({}, error.code || 500);
|
|
90
|
-
response.setErrors(error.body || {});
|
|
91
77
|
return response.generate();
|
|
92
78
|
};
|
|
93
79
|
/**
|
|
@@ -118,7 +104,7 @@ const wrapper = (configuration, handler, throwError = false) => {
|
|
|
118
104
|
|
|
119
105
|
|
|
120
106
|
if (request.getIp() !== null) {
|
|
121
|
-
logger.metric('
|
|
107
|
+
logger.metric('ip_address', request.getIp(), true);
|
|
122
108
|
} // Add metrics with user browser information for rapid debugging
|
|
123
109
|
|
|
124
110
|
|