@depup/mysql2 3.23.3-depup.0 → 3.24.0-depup.0
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 +2 -2
- package/changes.json +1 -1
- package/index.js +5 -0
- package/lib/base/connection.js +3 -1
- package/lib/commands/execute.js +4 -1
- package/lib/commands/query.js +8 -8
- package/lib/compressed_protocol.js +5 -2
- package/lib/constants/types.js +1 -0
- package/lib/packet_parser.js +20 -16
- package/lib/packets/column_definition.js +11 -10
- package/lib/packets/encode_parameter.js +37 -7
- package/lib/packets/execute.js +74 -34
- package/lib/packets/packet.js +151 -21
- package/lib/packets/query.js +102 -66
- package/lib/packets/typed_parameter.js +381 -0
- package/lib/parsers/binary_parser.js +2 -2
- package/lib/parsers/parser_cache.js +21 -15
- package/lib/parsers/string.js +41 -0
- package/lib/promise/connection.js +6 -2
- package/lib/promise/pool.js +6 -2
- package/package.json +3 -3
- package/promise.js +5 -0
- package/typings/mysql/index.d.ts +1 -0
- package/typings/mysql/lib/Pool.d.ts +10 -0
- package/typings/mysql/lib/PoolConnection.d.ts +7 -2
- package/typings/mysql/lib/TypedParameter.d.ts +84 -0
- package/typings/mysql/lib/protocol/sequences/Query.d.ts +2 -0
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ npm install @depup/mysql2
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [mysql2](https://www.npmjs.com/package/mysql2) @ 3.
|
|
17
|
-
| Processed | 2026-08-
|
|
16
|
+
| Original | [mysql2](https://www.npmjs.com/package/mysql2) @ 3.24.0 |
|
|
17
|
+
| Processed | 2026-08-24 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
19
|
| Deps updated | 0 |
|
|
20
20
|
|
package/changes.json
CHANGED
package/index.js
CHANGED
|
@@ -60,6 +60,11 @@ exports.__defineGetter__(
|
|
|
60
60
|
|
|
61
61
|
exports.__defineGetter__('Types', () => require('./lib/constants/types.js'));
|
|
62
62
|
|
|
63
|
+
exports.__defineGetter__(
|
|
64
|
+
'TypedParameter',
|
|
65
|
+
() => require('./lib/packets/typed_parameter.js').types
|
|
66
|
+
);
|
|
67
|
+
|
|
63
68
|
exports.__defineGetter__('Charsets', () =>
|
|
64
69
|
require('./lib/constants/charsets.js')
|
|
65
70
|
);
|
package/lib/base/connection.js
CHANGED
|
@@ -496,7 +496,9 @@ class BaseConnection extends EventEmitter {
|
|
|
496
496
|
|
|
497
497
|
handlePacket(packet) {
|
|
498
498
|
if (this._paused) {
|
|
499
|
-
|
|
499
|
+
// the parser reuses its packet instance; keep a stable copy when
|
|
500
|
+
// queueing for later
|
|
501
|
+
this._paused_packets.push(packet ? packet.clone() : packet);
|
|
500
502
|
return;
|
|
501
503
|
}
|
|
502
504
|
if (this.config.debug) {
|
package/lib/commands/execute.js
CHANGED
|
@@ -22,6 +22,8 @@ class Execute extends Command {
|
|
|
22
22
|
this.queryTimeout = null;
|
|
23
23
|
this._rows = [];
|
|
24
24
|
this._fields = [];
|
|
25
|
+
this._currentRows = null;
|
|
26
|
+
this._currentFields = null;
|
|
25
27
|
this._result = [];
|
|
26
28
|
this._fieldCount = 0;
|
|
27
29
|
this._rowParser = null;
|
|
@@ -54,7 +56,8 @@ class Execute extends Command {
|
|
|
54
56
|
connection.config.timezone,
|
|
55
57
|
this._executeOptions.attributes,
|
|
56
58
|
clientFlags,
|
|
57
|
-
connection._isMariaDB
|
|
59
|
+
connection._isMariaDB,
|
|
60
|
+
this.statement.parameters
|
|
58
61
|
);
|
|
59
62
|
//For reasons why this try-catch is here, please see
|
|
60
63
|
// https://github.com/sidorares/node-mysql2/pull/689
|
package/lib/commands/query.js
CHANGED
|
@@ -33,6 +33,8 @@ class Query extends Command {
|
|
|
33
33
|
this._rowParser = null;
|
|
34
34
|
this._fields = [];
|
|
35
35
|
this._rows = [];
|
|
36
|
+
this._currentRows = null;
|
|
37
|
+
this._currentFields = null;
|
|
36
38
|
this._receivedFieldsCount = 0;
|
|
37
39
|
this._resultIndex = 0;
|
|
38
40
|
this._localStream = null;
|
|
@@ -137,8 +139,10 @@ class Query extends Command {
|
|
|
137
139
|
return this._streamLocalInfile(connection, rs.infileName);
|
|
138
140
|
}
|
|
139
141
|
this._receivedFieldsCount = 0;
|
|
140
|
-
this.
|
|
141
|
-
this.
|
|
142
|
+
this._currentRows = [];
|
|
143
|
+
this._currentFields = [];
|
|
144
|
+
this._rows.push(this._currentRows);
|
|
145
|
+
this._fields.push(this._currentFields);
|
|
142
146
|
return this.readField;
|
|
143
147
|
}
|
|
144
148
|
|
|
@@ -252,17 +256,13 @@ class Query extends Command {
|
|
|
252
256
|
}
|
|
253
257
|
let row;
|
|
254
258
|
try {
|
|
255
|
-
row = this._rowParser.next(
|
|
256
|
-
packet,
|
|
257
|
-
this._fields[this._resultIndex],
|
|
258
|
-
this.options
|
|
259
|
-
);
|
|
259
|
+
row = this._rowParser.next(packet, this._currentFields, this.options);
|
|
260
260
|
} catch (err) {
|
|
261
261
|
this._localStreamError = err;
|
|
262
262
|
return this.doneInsert(null);
|
|
263
263
|
}
|
|
264
264
|
if (this.onResult) {
|
|
265
|
-
this.
|
|
265
|
+
this._currentRows.push(row);
|
|
266
266
|
} else {
|
|
267
267
|
this.emit('result', row, this._resultIndex);
|
|
268
268
|
}
|
|
@@ -36,6 +36,9 @@ function handleCompressedPacket(packet) {
|
|
|
36
36
|
const connection = this;
|
|
37
37
|
const deflatedLength = packet.readInt24();
|
|
38
38
|
const body = packet.readBuffer();
|
|
39
|
+
// the packet parser reuses its packet instance, so everything needed after
|
|
40
|
+
// the queued (asynchronous) inflate step must be read out now
|
|
41
|
+
const numPackets = packet.numPackets;
|
|
39
42
|
|
|
40
43
|
if (deflatedLength !== 0) {
|
|
41
44
|
connection.inflateQueue.push((task) => {
|
|
@@ -44,14 +47,14 @@ function handleCompressedPacket(packet) {
|
|
|
44
47
|
connection._handleNetworkError(err);
|
|
45
48
|
return;
|
|
46
49
|
}
|
|
47
|
-
connection._bumpCompressedSequenceId(
|
|
50
|
+
connection._bumpCompressedSequenceId(numPackets);
|
|
48
51
|
connection._inflatedPacketsParser.execute(data);
|
|
49
52
|
task.done();
|
|
50
53
|
});
|
|
51
54
|
});
|
|
52
55
|
} else {
|
|
53
56
|
connection.inflateQueue.push((task) => {
|
|
54
|
-
connection._bumpCompressedSequenceId(
|
|
57
|
+
connection._bumpCompressedSequenceId(numPackets);
|
|
55
58
|
connection._inflatedPacketsParser.execute(body);
|
|
56
59
|
task.done();
|
|
57
60
|
});
|
package/lib/constants/types.js
CHANGED
package/lib/packet_parser.js
CHANGED
|
@@ -33,6 +33,10 @@ class PacketParser {
|
|
|
33
33
|
this.largePacketParts = [];
|
|
34
34
|
this.firstPacketSequenceId = 0;
|
|
35
35
|
this.onPacket = onPacket;
|
|
36
|
+
// complete packets are handed to onPacket through this single mutable
|
|
37
|
+
// instance; consumers that keep a packet past the synchronous callback
|
|
38
|
+
// (e.g. a paused connection) must clone() it
|
|
39
|
+
this._reusablePacket = new Packet(0, Buffer.allocUnsafe(4), 0, 4);
|
|
36
40
|
this.execute = PacketParser.prototype.executeStart;
|
|
37
41
|
this._flushLargePacket =
|
|
38
42
|
packetHeaderLength === 7
|
|
@@ -72,14 +76,14 @@ class PacketParser {
|
|
|
72
76
|
this.length < MAX_PACKET_LENGTH &&
|
|
73
77
|
this.largePacketParts.length === 0
|
|
74
78
|
) {
|
|
75
|
-
this.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
);
|
|
79
|
+
const packet = this._reusablePacket;
|
|
80
|
+
packet.sequenceId = sequenceId;
|
|
81
|
+
packet.numPackets = 1;
|
|
82
|
+
packet.buffer = chunk;
|
|
83
|
+
packet.start = start;
|
|
84
|
+
packet.offset = start + 4;
|
|
85
|
+
packet.end = start + this.packetHeaderLength + this.length;
|
|
86
|
+
this.onPacket(packet);
|
|
83
87
|
} else {
|
|
84
88
|
// first large packet - remember it's id
|
|
85
89
|
if (this.largePacketParts.length === 0) {
|
|
@@ -136,14 +140,14 @@ class PacketParser {
|
|
|
136
140
|
this.length < MAX_PACKET_LENGTH &&
|
|
137
141
|
this.largePacketParts.length === 0
|
|
138
142
|
) {
|
|
139
|
-
this.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
);
|
|
143
|
+
const packet = this._reusablePacket;
|
|
144
|
+
packet.sequenceId = sequenceId;
|
|
145
|
+
packet.numPackets = 1;
|
|
146
|
+
packet.buffer = payload;
|
|
147
|
+
packet.start = 0;
|
|
148
|
+
packet.offset = 4;
|
|
149
|
+
packet.end = this.length + this.packetHeaderLength;
|
|
150
|
+
this.onPacket(packet);
|
|
147
151
|
} else {
|
|
148
152
|
// first large packet - remember it's id
|
|
149
153
|
if (this.largePacketParts.length === 0) {
|
|
@@ -288,24 +288,25 @@ class ColumnDefinition {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
const addString = function (name) {
|
|
291
|
+
const cacheKey = `_${name}Value`;
|
|
292
|
+
const startKey = `_${name}Start`;
|
|
293
|
+
const lengthKey = `_${name}Length`;
|
|
294
|
+
ColumnDefinition.prototype[cacheKey] = undefined;
|
|
291
295
|
Object.defineProperty(ColumnDefinition.prototype, name, {
|
|
292
296
|
get: function () {
|
|
293
|
-
const
|
|
294
|
-
|
|
297
|
+
const cached = this[cacheKey];
|
|
298
|
+
if (cached !== undefined) {
|
|
299
|
+
return cached;
|
|
300
|
+
}
|
|
301
|
+
const start = this[startKey];
|
|
302
|
+
const end = start + this[lengthKey];
|
|
295
303
|
const val = StringParser.decode(
|
|
296
304
|
this._buf,
|
|
297
305
|
this.encoding === 'binary' ? this._clientEncoding : this.encoding,
|
|
298
306
|
start,
|
|
299
307
|
end
|
|
300
308
|
);
|
|
301
|
-
|
|
302
|
-
Object.defineProperty(this, name, {
|
|
303
|
-
value: val,
|
|
304
|
-
writable: false,
|
|
305
|
-
configurable: false,
|
|
306
|
-
enumerable: false,
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
+
this[cacheKey] = val;
|
|
309
310
|
return val;
|
|
310
311
|
},
|
|
311
312
|
});
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const Types = require('../constants/types');
|
|
4
4
|
const Packet = require('../packets/packet');
|
|
5
|
+
const StringParser = require('../parsers/string.js');
|
|
6
|
+
const {
|
|
7
|
+
TypedParameter,
|
|
8
|
+
encodeTypedParameter,
|
|
9
|
+
integerHint,
|
|
10
|
+
} = require('./typed_parameter.js');
|
|
11
|
+
const FieldFlags = require('../constants/field_flags.js');
|
|
5
12
|
|
|
6
13
|
function isJSON(value) {
|
|
7
14
|
return (
|
|
@@ -11,12 +18,23 @@ function isJSON(value) {
|
|
|
11
18
|
);
|
|
12
19
|
}
|
|
13
20
|
|
|
14
|
-
function toParameter(value, encoding, timezone, jsonAsString) {
|
|
21
|
+
function toParameter(value, encoding, timezone, jsonAsString, hint) {
|
|
22
|
+
if (value instanceof TypedParameter) {
|
|
23
|
+
return encodeTypedParameter(value, encoding, timezone, jsonAsString);
|
|
24
|
+
}
|
|
25
|
+
if (hint) {
|
|
26
|
+
const hinted = integerHint(
|
|
27
|
+
value,
|
|
28
|
+
hint.columnType,
|
|
29
|
+
Boolean(hint.flags & FieldFlags.UNSIGNED)
|
|
30
|
+
);
|
|
31
|
+
if (hinted) {
|
|
32
|
+
return encodeTypedParameter(hinted, encoding, timezone, jsonAsString);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
15
35
|
let type = Types.VAR_STRING;
|
|
16
36
|
let length;
|
|
17
|
-
let writer =
|
|
18
|
-
return Packet.prototype.writeLengthCodedString.call(this, value, encoding);
|
|
19
|
-
};
|
|
37
|
+
let writer = Packet.prototype.writeLengthCodedBuffer;
|
|
20
38
|
if (value !== null) {
|
|
21
39
|
switch (typeof value) {
|
|
22
40
|
case 'undefined':
|
|
@@ -67,11 +85,23 @@ function toParameter(value, encoding, timezone, jsonAsString) {
|
|
|
67
85
|
} else {
|
|
68
86
|
value = '';
|
|
69
87
|
type = Types.NULL;
|
|
88
|
+
length = 0;
|
|
89
|
+
writer = writeNothing;
|
|
70
90
|
}
|
|
71
|
-
if (
|
|
72
|
-
|
|
91
|
+
if (length === undefined) {
|
|
92
|
+
value = StringParser.encode(value, encoding);
|
|
93
|
+
length = Packet.lengthCodedNumberLength(value.length) + value.length;
|
|
73
94
|
}
|
|
74
|
-
return {
|
|
95
|
+
return {
|
|
96
|
+
value,
|
|
97
|
+
type,
|
|
98
|
+
length,
|
|
99
|
+
writer,
|
|
100
|
+
unsigned: false,
|
|
101
|
+
isNull: type === Types.NULL,
|
|
102
|
+
};
|
|
75
103
|
}
|
|
76
104
|
|
|
105
|
+
function writeNothing() {}
|
|
106
|
+
|
|
77
107
|
module.exports = { toParameter, isJSON };
|
package/lib/packets/execute.js
CHANGED
|
@@ -5,6 +5,7 @@ const CommandCodes = require('../constants/commands');
|
|
|
5
5
|
const ClientConstants = require('../constants/client');
|
|
6
6
|
const Types = require('../constants/types');
|
|
7
7
|
const Packet = require('../packets/packet');
|
|
8
|
+
const StringParser = require('../parsers/string.js');
|
|
8
9
|
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
|
9
10
|
const { toParameter } = require('./encode_parameter.js');
|
|
10
11
|
|
|
@@ -16,7 +17,8 @@ class Execute {
|
|
|
16
17
|
timezone,
|
|
17
18
|
attributes,
|
|
18
19
|
clientFlags,
|
|
19
|
-
jsonAsString
|
|
20
|
+
jsonAsString,
|
|
21
|
+
parameterDefinitions
|
|
20
22
|
) {
|
|
21
23
|
this.id = id;
|
|
22
24
|
this.parameters = parameters;
|
|
@@ -25,6 +27,7 @@ class Execute {
|
|
|
25
27
|
this.attributes = attributes;
|
|
26
28
|
this.clientFlags = clientFlags || 0;
|
|
27
29
|
this.jsonAsString = jsonAsString || false;
|
|
30
|
+
this.parameterDefinitions = parameterDefinitions || [];
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
static fromPacket(packet, encoding) {
|
|
@@ -95,7 +98,7 @@ class Execute {
|
|
|
95
98
|
return { stmtId, flags, iterationCount, values };
|
|
96
99
|
}
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
toPacket() {
|
|
99
102
|
const useQueryAttributes =
|
|
100
103
|
this.clientFlags & ClientConstants.CLIENT_QUERY_ATTRIBUTES;
|
|
101
104
|
|
|
@@ -105,7 +108,53 @@ class Execute {
|
|
|
105
108
|
const numAttrs = attrNames.length;
|
|
106
109
|
const totalParams = numParams + numAttrs;
|
|
107
110
|
|
|
108
|
-
|
|
111
|
+
// packet header, command, statement id, cursor flags, iteration count
|
|
112
|
+
let length = 14;
|
|
113
|
+
if (useQueryAttributes) {
|
|
114
|
+
length += Packet.lengthCodedNumberLength(totalParams);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let allParams = null;
|
|
118
|
+
let attrNameBuffers = null;
|
|
119
|
+
if (totalParams > 0) {
|
|
120
|
+
allParams = new Array(totalParams);
|
|
121
|
+
for (let i = 0; i < numParams; i++) {
|
|
122
|
+
allParams[i] = toParameter(
|
|
123
|
+
this.parameters[i],
|
|
124
|
+
this.encoding,
|
|
125
|
+
this.timezone,
|
|
126
|
+
this.jsonAsString,
|
|
127
|
+
this.parameterDefinitions[i]
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
for (let i = 0; i < numAttrs; i++) {
|
|
131
|
+
allParams[numParams + i] = toParameter(
|
|
132
|
+
this.attributes[attrNames[i]],
|
|
133
|
+
this.encoding,
|
|
134
|
+
this.timezone
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// null bitmap, new-params-bound flag, type and unsigned byte per parameter
|
|
139
|
+
length += ((totalParams + 7) >> 3) + 1 + totalParams * 2;
|
|
140
|
+
if (useQueryAttributes) {
|
|
141
|
+
// one empty length-coded name per bind parameter
|
|
142
|
+
length += numParams;
|
|
143
|
+
attrNameBuffers = new Array(numAttrs);
|
|
144
|
+
for (let i = 0; i < numAttrs; i++) {
|
|
145
|
+
const name = StringParser.encode(attrNames[i], this.encoding);
|
|
146
|
+
attrNameBuffers[i] = name;
|
|
147
|
+
length += Packet.lengthCodedNumberLength(name.length) + name.length;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (let i = 0; i < totalParams; i++) {
|
|
151
|
+
if (!allParams[i].isNull) {
|
|
152
|
+
length += allParams[i].length;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const packet = new Packet(0, Buffer.allocUnsafe(length), 0, length);
|
|
109
158
|
packet.offset = 4;
|
|
110
159
|
packet.writeInt8(CommandCodes.STMT_EXECUTE);
|
|
111
160
|
packet.writeInt32(this.id);
|
|
@@ -122,23 +171,11 @@ class Execute {
|
|
|
122
171
|
}
|
|
123
172
|
|
|
124
173
|
if (totalParams > 0) {
|
|
125
|
-
const bindParams =
|
|
126
|
-
numParams > 0
|
|
127
|
-
? this.parameters.map((v) =>
|
|
128
|
-
toParameter(v, this.encoding, this.timezone, this.jsonAsString)
|
|
129
|
-
)
|
|
130
|
-
: [];
|
|
131
|
-
const attrParams = attrNames.map((name) =>
|
|
132
|
-
toParameter(this.attributes[name], this.encoding, this.timezone)
|
|
133
|
-
);
|
|
134
|
-
const allParams = bindParams.concat(attrParams);
|
|
135
|
-
|
|
136
|
-
// null bitmap
|
|
137
174
|
let bitmap = 0;
|
|
138
175
|
let bitValue = 1;
|
|
139
|
-
|
|
140
|
-
if (
|
|
141
|
-
bitmap
|
|
176
|
+
for (let i = 0; i < totalParams; i++) {
|
|
177
|
+
if (allParams[i].isNull) {
|
|
178
|
+
bitmap |= bitValue;
|
|
142
179
|
}
|
|
143
180
|
bitValue *= 2;
|
|
144
181
|
if (bitValue === 256) {
|
|
@@ -146,38 +183,41 @@ class Execute {
|
|
|
146
183
|
bitmap = 0;
|
|
147
184
|
bitValue = 1;
|
|
148
185
|
}
|
|
149
|
-
}
|
|
186
|
+
}
|
|
150
187
|
if (bitValue !== 1) {
|
|
151
188
|
packet.writeInt8(bitmap);
|
|
152
189
|
}
|
|
153
190
|
|
|
154
191
|
packet.writeInt8(1); // new-params-bound-flag
|
|
155
192
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
packet.writeInt8(
|
|
159
|
-
packet.writeInt8(0);
|
|
193
|
+
for (let i = 0; i < totalParams; i++) {
|
|
194
|
+
const parameter = allParams[i];
|
|
195
|
+
packet.writeInt8(parameter.type);
|
|
196
|
+
packet.writeInt8(parameter.unsigned ? 0x80 : 0);
|
|
160
197
|
if (useQueryAttributes) {
|
|
161
|
-
|
|
162
|
-
|
|
198
|
+
if (i < numParams) {
|
|
199
|
+
packet.writeInt8(0); // bind parameters have an empty name
|
|
200
|
+
} else {
|
|
201
|
+
packet.writeLengthCodedBuffer(attrNameBuffers[i - numParams]);
|
|
202
|
+
}
|
|
163
203
|
}
|
|
164
204
|
}
|
|
165
205
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (parameter.
|
|
206
|
+
for (let i = 0; i < totalParams; i++) {
|
|
207
|
+
const parameter = allParams[i];
|
|
208
|
+
if (!parameter.isNull) {
|
|
169
209
|
parameter.writer.call(packet, parameter.value);
|
|
170
210
|
}
|
|
171
|
-
}
|
|
211
|
+
}
|
|
172
212
|
}
|
|
173
213
|
|
|
214
|
+
if (packet.offset !== length) {
|
|
215
|
+
throw new Error(
|
|
216
|
+
`Internal error: COM_STMT_EXECUTE serialized ${packet.offset - 4} bytes, expected ${length - 4}`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
174
219
|
return packet;
|
|
175
220
|
}
|
|
176
|
-
|
|
177
|
-
toPacket() {
|
|
178
|
-
const p = this._serializeToBuffer(Packet.MockBuffer());
|
|
179
|
-
return this._serializeToBuffer(Buffer.allocUnsafe(p.offset));
|
|
180
|
-
}
|
|
181
221
|
}
|
|
182
222
|
|
|
183
223
|
module.exports = Execute;
|