@depup/systeminformation 5.33.12-depup.0 → 5.33.15-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/lib/cpu.js +23 -23
- package/lib/graphics.js +1 -1
- package/lib/memory.js +3 -5
- package/lib/network.js +16 -3
- package/lib/users.js +1 -1
- package/lib/util.js +39 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ npm install @depup/systeminformation
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [systeminformation](https://www.npmjs.com/package/systeminformation) @ 5.33.
|
|
17
|
-
| Processed | 2026-
|
|
16
|
+
| Original | [systeminformation](https://www.npmjs.com/package/systeminformation) @ 5.33.15 |
|
|
17
|
+
| Processed | 2026-10-04 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
19
|
| Deps updated | 0 |
|
|
20
20
|
|
package/changes.json
CHANGED
package/lib/cpu.js
CHANGED
|
@@ -58,7 +58,7 @@ let _current_cpu = {
|
|
|
58
58
|
rawCurrentLoadSteal: 0,
|
|
59
59
|
rawCurrentLoadGuest: 0
|
|
60
60
|
};
|
|
61
|
-
|
|
61
|
+
const _cpus = [];
|
|
62
62
|
let _corecount = 0;
|
|
63
63
|
|
|
64
64
|
const AMDBaseFrequencies = {
|
|
@@ -843,7 +843,7 @@ function cpuBrandManufacturer(res) {
|
|
|
843
843
|
res.brand = res.brand.replace(/CPU+/g, '').replace(/\s+/g, ' ').trim();
|
|
844
844
|
res.manufacturer = cpuManufacturer(res.brand);
|
|
845
845
|
|
|
846
|
-
|
|
846
|
+
const parts = res.brand.split(' ');
|
|
847
847
|
parts.shift();
|
|
848
848
|
res.brand = parts.join(' ');
|
|
849
849
|
return res;
|
|
@@ -851,9 +851,9 @@ function cpuBrandManufacturer(res) {
|
|
|
851
851
|
|
|
852
852
|
function getAMDSpeed(brand) {
|
|
853
853
|
let result = '0';
|
|
854
|
-
for (
|
|
854
|
+
for (const key in AMDBaseFrequencies) {
|
|
855
855
|
if ({}.hasOwnProperty.call(AMDBaseFrequencies, key)) {
|
|
856
|
-
|
|
856
|
+
const parts = key.split('|');
|
|
857
857
|
let found = 0;
|
|
858
858
|
parts.forEach((item) => {
|
|
859
859
|
if (brand.indexOf(item) > -1) {
|
|
@@ -1140,8 +1140,8 @@ function getCpu() {
|
|
|
1140
1140
|
workload.push(util.powerShell('(Get-CimInstance Win32_ComputerSystem).HypervisorPresent'));
|
|
1141
1141
|
|
|
1142
1142
|
Promise.all(workload).then((data) => {
|
|
1143
|
-
|
|
1144
|
-
|
|
1143
|
+
const lines = data[0].split('\r\n');
|
|
1144
|
+
const name = util.getValue(lines, 'name', ':') || '';
|
|
1145
1145
|
if (name.indexOf('@') >= 0) {
|
|
1146
1146
|
result.brand = name.split('@')[0].trim();
|
|
1147
1147
|
result.speed = name.split('@')[1] ? parseFloat(name.split('@')[1].trim()) : 0;
|
|
@@ -1162,7 +1162,7 @@ function getCpu() {
|
|
|
1162
1162
|
}
|
|
1163
1163
|
result.speedMin = result.speed;
|
|
1164
1164
|
|
|
1165
|
-
|
|
1165
|
+
const description = util.getValue(lines, 'description', ':').split(' ');
|
|
1166
1166
|
for (let i = 0; i < description.length; i++) {
|
|
1167
1167
|
if (description[i].toLowerCase().startsWith('family') && i + 1 < description.length && description[i + 1]) {
|
|
1168
1168
|
result.family = description[i + 1];
|
|
@@ -1242,8 +1242,8 @@ function getCpuCurrentSpeedSync() {
|
|
|
1242
1242
|
const cores = [];
|
|
1243
1243
|
const speeds = [];
|
|
1244
1244
|
|
|
1245
|
-
if (cpus && cpus.length &&
|
|
1246
|
-
for (
|
|
1245
|
+
if (cpus && cpus.length && {}.hasOwnProperty.call(cpus[0], 'speed')) {
|
|
1246
|
+
for (const i in cpus) {
|
|
1247
1247
|
speeds.push(cpus[i].speed > 100 ? (cpus[i].speed + 1) / 1000 : cpus[i].speed / 10);
|
|
1248
1248
|
}
|
|
1249
1249
|
} else if (_linux) {
|
|
@@ -1252,7 +1252,7 @@ function getCpuCurrentSpeedSync() {
|
|
|
1252
1252
|
.toString()
|
|
1253
1253
|
.split('\n')
|
|
1254
1254
|
.filter((line) => line.length > 0);
|
|
1255
|
-
for (
|
|
1255
|
+
for (const i in speedStrings) {
|
|
1256
1256
|
speeds.push(Math.floor(parseInt(speedStrings[i], 10) / 10) / 100);
|
|
1257
1257
|
}
|
|
1258
1258
|
} catch {
|
|
@@ -1352,7 +1352,7 @@ function cpuTemperature(callback) {
|
|
|
1352
1352
|
result.chipset = Math.round(parseInt(lines2[i], 10) / 100) / 10;
|
|
1353
1353
|
}
|
|
1354
1354
|
// CPU thermal zone (e.g. cpu-thermal on Raspberry Pi)
|
|
1355
|
-
if (cpuThermal === null && line.indexOf('cpu') !== -1 && lines2[i]) {
|
|
1355
|
+
if (cpuThermal === null && line.toLowerCase().indexOf('cpu') !== -1 && lines2[i]) {
|
|
1356
1356
|
cpuThermal = Math.round(parseInt(lines2[i], 10) / 100) / 10;
|
|
1357
1357
|
}
|
|
1358
1358
|
}
|
|
@@ -1393,7 +1393,7 @@ function cpuTemperature(callback) {
|
|
|
1393
1393
|
if (result.main === null) {
|
|
1394
1394
|
result.main = Math.round(result.cores.reduce((a, b) => a + b, 0) / result.cores.length);
|
|
1395
1395
|
}
|
|
1396
|
-
|
|
1396
|
+
const maxtmp = Math.max.apply(Math, result.cores);
|
|
1397
1397
|
result.max = maxtmp > result.main ? maxtmp : result.main;
|
|
1398
1398
|
}
|
|
1399
1399
|
if (result.main !== null) {
|
|
@@ -1663,13 +1663,13 @@ function cpuFlags(callback) {
|
|
|
1663
1663
|
try {
|
|
1664
1664
|
exec('reg query "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0" /v FeatureSet', util.execOptsWin, (error, stdout) => {
|
|
1665
1665
|
if (!error) {
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1666
|
+
const flag_hex = stdout.split('0x').pop().trim();
|
|
1667
|
+
const flag_bin_unpadded = parseInt(flag_hex, 16).toString(2);
|
|
1668
|
+
const flag_bin = '0'.repeat(32 - flag_bin_unpadded.length) + flag_bin_unpadded;
|
|
1669
1669
|
// empty flags are the reserved fields in the CPUID feature bit list
|
|
1670
1670
|
// as found on wikipedia:
|
|
1671
1671
|
// https://en.wikipedia.org/wiki/CPUID
|
|
1672
|
-
|
|
1672
|
+
const all_flags = [
|
|
1673
1673
|
'fpu',
|
|
1674
1674
|
'vme',
|
|
1675
1675
|
'de',
|
|
@@ -1726,7 +1726,7 @@ function cpuFlags(callback) {
|
|
|
1726
1726
|
try {
|
|
1727
1727
|
exec('export LC_ALL=C; lscpu; unset LC_ALL', (error, stdout) => {
|
|
1728
1728
|
if (!error) {
|
|
1729
|
-
|
|
1729
|
+
const lines = stdout.toString().split('\n');
|
|
1730
1730
|
lines.forEach((line) => {
|
|
1731
1731
|
if (line.split(':')[0].toUpperCase().indexOf('FLAGS') !== -1) {
|
|
1732
1732
|
result = line.split(':')[1].trim().toLowerCase();
|
|
@@ -1736,7 +1736,7 @@ function cpuFlags(callback) {
|
|
|
1736
1736
|
if (!result) {
|
|
1737
1737
|
fs.readFile('/proc/cpuinfo', (error, stdout) => {
|
|
1738
1738
|
if (!error) {
|
|
1739
|
-
|
|
1739
|
+
const lines = stdout.toString().split('\n');
|
|
1740
1740
|
result = util.getValue(lines, 'features', ':', true).toLowerCase();
|
|
1741
1741
|
}
|
|
1742
1742
|
if (callback) {
|
|
@@ -1781,7 +1781,7 @@ function cpuFlags(callback) {
|
|
|
1781
1781
|
if (_darwin) {
|
|
1782
1782
|
exec('sysctl machdep.cpu.features', (error, stdout) => {
|
|
1783
1783
|
if (!error) {
|
|
1784
|
-
|
|
1784
|
+
const lines = stdout.toString().split('\n');
|
|
1785
1785
|
if (lines.length > 0 && lines[0].indexOf('machdep.cpu.features:') !== -1) {
|
|
1786
1786
|
result = lines[0].split(':')[1].trim().toLowerCase();
|
|
1787
1787
|
}
|
|
@@ -1883,9 +1883,9 @@ function cpuCache(callback) {
|
|
|
1883
1883
|
if (_darwin) {
|
|
1884
1884
|
exec('sysctl hw.l1icachesize hw.l1dcachesize hw.l2cachesize hw.l3cachesize', (error, stdout) => {
|
|
1885
1885
|
if (!error) {
|
|
1886
|
-
|
|
1886
|
+
const lines = stdout.toString().split('\n');
|
|
1887
1887
|
lines.forEach((line) => {
|
|
1888
|
-
|
|
1888
|
+
const parts = line.split(':');
|
|
1889
1889
|
if (parts[0].toLowerCase().indexOf('hw.l1icachesize') !== -1) {
|
|
1890
1890
|
result.l1i = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
|
|
1891
1891
|
}
|
|
@@ -1946,7 +1946,7 @@ function parseWinCache(linesProc, linesCache) {
|
|
|
1946
1946
|
};
|
|
1947
1947
|
|
|
1948
1948
|
// Win32_processor
|
|
1949
|
-
|
|
1949
|
+
const lines = linesProc.split('\r\n');
|
|
1950
1950
|
result.l1d = 0;
|
|
1951
1951
|
result.l1i = 0;
|
|
1952
1952
|
result.l2 = util.getValue(lines, 'l2cachesize', ':');
|
|
@@ -2043,7 +2043,7 @@ function getLoad() {
|
|
|
2043
2043
|
lines.shift();
|
|
2044
2044
|
if (lines.length === cpus.length) {
|
|
2045
2045
|
for (let i = 0; i < lines.length; i++) {
|
|
2046
|
-
|
|
2046
|
+
const parts = lines[i].split(' ');
|
|
2047
2047
|
if (parts.length >= 10) {
|
|
2048
2048
|
const steal = parseFloat(parts[8]) || 0;
|
|
2049
2049
|
const guest = parseFloat(parts[9]) || 0;
|
package/lib/graphics.js
CHANGED
|
@@ -228,7 +228,7 @@ function graphics(callback) {
|
|
|
228
228
|
// PCI bus IDs
|
|
229
229
|
let pciIDs = [];
|
|
230
230
|
try {
|
|
231
|
-
pciIDs = execSync('export LC_ALL=C; dmidecode -t 9 2>/dev/null
|
|
231
|
+
pciIDs = execSync('export LC_ALL=C; dmidecode -t 9 2>/dev/null | grep "Bus Address: "', util.execOptsLinux).toString().split('\n');
|
|
232
232
|
for (let i = 0; i < pciIDs.length; i++) {
|
|
233
233
|
pciIDs[i] = pciIDs[i].replace('Bus Address:', '').replace('0000:', '').trim();
|
|
234
234
|
}
|
package/lib/memory.js
CHANGED
|
@@ -380,11 +380,9 @@ function memLayout(callback) {
|
|
|
380
380
|
bank,
|
|
381
381
|
type: util.getValue(lines, 'Type:'),
|
|
382
382
|
ecc: dataWidth && totalWidth ? totalWidth > dataWidth : false,
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
? parseInt(util.getValue(lines, 'Speed:'), 10)
|
|
387
|
-
: null,
|
|
383
|
+
// dmidecode >= 3.1 renamed "Configured Clock Speed" to "Configured Memory Speed" - without
|
|
384
|
+
// the new label this silently fell back to Speed, the rated instead of the running speed
|
|
385
|
+
clockSpeed: util.toInt(util.getValue(lines, 'Configured Memory Speed:')) || util.toInt(util.getValue(lines, 'Configured Clock Speed:')) || util.toInt(util.getValue(lines, 'Speed:')) || null,
|
|
388
386
|
formFactor: util.getValue(lines, 'Form Factor:'),
|
|
389
387
|
manufacturer: getManufacturer(util.getValue(lines, 'Manufacturer:')),
|
|
390
388
|
partNum: util.getValue(lines, 'Part Number:'),
|
package/lib/network.js
CHANGED
|
@@ -32,7 +32,7 @@ const _openbsd = _platform === 'openbsd';
|
|
|
32
32
|
const _netbsd = _platform === 'netbsd';
|
|
33
33
|
const _sunos = _platform === 'sunos';
|
|
34
34
|
|
|
35
|
-
const _network =
|
|
35
|
+
const _network = Object.create(null);
|
|
36
36
|
let _default_iface = '';
|
|
37
37
|
let _ifaces = {};
|
|
38
38
|
let _dhcpNics = [];
|
|
@@ -1360,6 +1360,13 @@ function networkStatsSingle(iface) {
|
|
|
1360
1360
|
ms: 0
|
|
1361
1361
|
};
|
|
1362
1362
|
|
|
1363
|
+
// an interface name never starts with a dash - passed on to ifconfig / netstat it would be
|
|
1364
|
+
// read as an option instead of as an interface name (index access, so a polluted
|
|
1365
|
+
// String.prototype cannot bypass it)
|
|
1366
|
+
if (ifaceSanitized[0] === '-') {
|
|
1367
|
+
return resolve(result);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1363
1370
|
let operstate = 'unknown';
|
|
1364
1371
|
let rx_bytes = 0;
|
|
1365
1372
|
let tx_bytes = 0;
|
|
@@ -1375,7 +1382,9 @@ function networkStatsSingle(iface) {
|
|
|
1375
1382
|
(_network[ifaceSanitized] && _network[ifaceSanitized].ms && Date.now() - _network[ifaceSanitized].ms >= 500)
|
|
1376
1383
|
) {
|
|
1377
1384
|
if (_linux) {
|
|
1378
|
-
|
|
1385
|
+
// interface name must stay a single path segment inside /sys/class/net (no traversal)
|
|
1386
|
+
const ifaceIsSegment = ifaceSanitized !== '' && ifaceSanitized !== '.' && ifaceSanitized !== '..' && ifaceSanitized.split('').every((c) => c !== '/');
|
|
1387
|
+
if (ifaceIsSegment && fs.existsSync('/sys/class/net/' + ifaceSanitized)) {
|
|
1379
1388
|
cmd =
|
|
1380
1389
|
'cat /sys/class/net/' +
|
|
1381
1390
|
ifaceSanitized +
|
|
@@ -1529,7 +1538,10 @@ function networkStatsSingle(iface) {
|
|
|
1529
1538
|
});
|
|
1530
1539
|
});
|
|
1531
1540
|
if (rx_bytes && tx_bytes) {
|
|
1532
|
-
|
|
1541
|
+
// cache under the requested name, but report the adapter name
|
|
1542
|
+
result = calcNetworkSpeed(ifaceSanitized, parseInt(rx_bytes), parseInt(tx_bytes), operstate, rx_dropped, rx_errors, tx_dropped, tx_errors);
|
|
1543
|
+
result.iface = ifaceName;
|
|
1544
|
+
_network[ifaceSanitized].ifaceName = ifaceName;
|
|
1533
1545
|
}
|
|
1534
1546
|
resolve(result);
|
|
1535
1547
|
});
|
|
@@ -1542,6 +1554,7 @@ function networkStatsSingle(iface) {
|
|
|
1542
1554
|
result.tx_sec = _network[ifaceSanitized].tx_sec;
|
|
1543
1555
|
result.ms = _network[ifaceSanitized].last_ms;
|
|
1544
1556
|
result.operstate = _network[ifaceSanitized].operstate;
|
|
1557
|
+
result.iface = _network[ifaceSanitized].ifaceName || ifaceSanitized;
|
|
1545
1558
|
resolve(result);
|
|
1546
1559
|
}
|
|
1547
1560
|
});
|
package/lib/users.js
CHANGED
|
@@ -175,7 +175,7 @@ function users(callback) {
|
|
|
175
175
|
|
|
176
176
|
// linux
|
|
177
177
|
if (_linux) {
|
|
178
|
-
exec('export LC_ALL=C; who --ips; echo "---"; w
|
|
178
|
+
exec('export LC_ALL=C; who --ips; echo "---"; w | tail -n +2', (error, stdout) => {
|
|
179
179
|
if (!error) {
|
|
180
180
|
// lines / split
|
|
181
181
|
let lines = stdout.toString().split('\n');
|
package/lib/util.js
CHANGED
|
@@ -95,7 +95,7 @@ const stringStartWith = new String().startsWith;
|
|
|
95
95
|
const mathMin = Math.min;
|
|
96
96
|
|
|
97
97
|
function isFunction(functionToCheck) {
|
|
98
|
-
|
|
98
|
+
const getType = {};
|
|
99
99
|
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -103,7 +103,7 @@ function unique(obj) {
|
|
|
103
103
|
const uniques = [];
|
|
104
104
|
const stringify = {};
|
|
105
105
|
for (let i = 0; i < obj.length; i++) {
|
|
106
|
-
|
|
106
|
+
const keys = Object.keys(obj[i]);
|
|
107
107
|
keys.sort((a, b) => {
|
|
108
108
|
return a - b;
|
|
109
109
|
});
|
|
@@ -202,7 +202,7 @@ function parseTime(t, pmDesignator) {
|
|
|
202
202
|
parts[1] += parts[2];
|
|
203
203
|
}
|
|
204
204
|
const p1 = (parts[1] || '').toLowerCase();
|
|
205
|
-
|
|
205
|
+
const isPM =
|
|
206
206
|
p1.indexOf('pm') > -1 ||
|
|
207
207
|
p1.indexOf('p.m.') > -1 ||
|
|
208
208
|
p1.indexOf('p. m.') > -1 ||
|
|
@@ -670,7 +670,7 @@ function execWin(cmd, opts, callback) {
|
|
|
670
670
|
callback = opts;
|
|
671
671
|
opts = execOptsWin;
|
|
672
672
|
}
|
|
673
|
-
|
|
673
|
+
const newCmd = 'chcp 65001 > nul && cmd /C ' + cmd + ' && chcp ' + codepage + ' > nul';
|
|
674
674
|
exec(newCmd, opts, (error, stdout) => {
|
|
675
675
|
callback(error, stdout);
|
|
676
676
|
});
|
|
@@ -1118,7 +1118,7 @@ function decodePiCpuinfo(lines) {
|
|
|
1118
1118
|
model,
|
|
1119
1119
|
serial,
|
|
1120
1120
|
revisionCode,
|
|
1121
|
-
memory: 256 *
|
|
1121
|
+
memory: 256 * 2 ** memSizeCode,
|
|
1122
1122
|
manufacturer,
|
|
1123
1123
|
processor,
|
|
1124
1124
|
type: {}.hasOwnProperty.call(typeList, typeCode) ? typeList[typeCode] : '',
|
|
@@ -1237,7 +1237,7 @@ function plistParser(xmlStr) {
|
|
|
1237
1237
|
const startStr = '<plist version';
|
|
1238
1238
|
|
|
1239
1239
|
let pos = xmlStr.indexOf(startStr);
|
|
1240
|
-
|
|
1240
|
+
const len = xmlStr.length;
|
|
1241
1241
|
while (xmlStr[pos] !== '>' && pos < len) {
|
|
1242
1242
|
pos++;
|
|
1243
1243
|
}
|
|
@@ -1246,7 +1246,7 @@ function plistParser(xmlStr) {
|
|
|
1246
1246
|
let inTagStart = false;
|
|
1247
1247
|
let inTagContent = false;
|
|
1248
1248
|
let inTagEnd = false;
|
|
1249
|
-
|
|
1249
|
+
const metaData = [{ tagStart: '', tagEnd: '', tagContent: '', key: '', data: null }];
|
|
1250
1250
|
let c = '';
|
|
1251
1251
|
let cn = xmlStr[pos];
|
|
1252
1252
|
|
|
@@ -1447,6 +1447,38 @@ function semverCompare(v1, v2) {
|
|
|
1447
1447
|
|
|
1448
1448
|
function getAppleModel(key) {
|
|
1449
1449
|
const appleModelIds = [
|
|
1450
|
+
{
|
|
1451
|
+
key: 'Mac18,5',
|
|
1452
|
+
name: 'Mac mini',
|
|
1453
|
+
size: '',
|
|
1454
|
+
processor: 'M6',
|
|
1455
|
+
year: '2026',
|
|
1456
|
+
additional: ''
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
key: 'Mac17,16',
|
|
1460
|
+
name: 'Mac mini',
|
|
1461
|
+
size: '',
|
|
1462
|
+
processor: 'M5 Pro',
|
|
1463
|
+
year: '2026',
|
|
1464
|
+
additional: ''
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
key: 'Mac17,15',
|
|
1468
|
+
name: 'Mac Studio',
|
|
1469
|
+
size: '',
|
|
1470
|
+
processor: 'M5 Ultra',
|
|
1471
|
+
year: '2026',
|
|
1472
|
+
additional: ''
|
|
1473
|
+
},
|
|
1474
|
+
{
|
|
1475
|
+
key: 'Mac17,14',
|
|
1476
|
+
name: 'Mac Studio',
|
|
1477
|
+
size: '',
|
|
1478
|
+
processor: 'M5 Max',
|
|
1479
|
+
year: '2026',
|
|
1480
|
+
additional: ''
|
|
1481
|
+
},
|
|
1450
1482
|
{
|
|
1451
1483
|
key: 'Mac17,9',
|
|
1452
1484
|
name: 'MacBook Pro',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/systeminformation",
|
|
3
|
-
"version": "5.33.
|
|
3
|
+
"version": "5.33.15-depup.0",
|
|
4
4
|
"description": "Advanced, lightweight system and OS information library (with updated dependencies)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Sebastian Hildebrandt <hildebrandt@plus-innovations.com> (https://plus-innovations.com)",
|
|
@@ -111,8 +111,8 @@
|
|
|
111
111
|
"changes": {},
|
|
112
112
|
"depsUpdated": 0,
|
|
113
113
|
"originalPackage": "systeminformation",
|
|
114
|
-
"originalVersion": "5.33.
|
|
115
|
-
"processedAt": "2026-
|
|
114
|
+
"originalVersion": "5.33.15",
|
|
115
|
+
"processedAt": "2026-10-04T01:30:45.352Z",
|
|
116
116
|
"smokeTest": "passed"
|
|
117
117
|
}
|
|
118
118
|
}
|