util.js 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. 'use strict';
  2. // @ts-check
  3. // ==================================================================================
  4. // utils.js
  5. // ----------------------------------------------------------------------------------
  6. // Description: System Information - library
  7. // for Node.js
  8. // Copyright: (c) 2014 - 2022
  9. // Author: Sebastian Hildebrandt
  10. // ----------------------------------------------------------------------------------
  11. // License: MIT
  12. // ==================================================================================
  13. // 0. helper functions
  14. // ----------------------------------------------------------------------------------
  15. const os = require('os');
  16. const fs = require('fs');
  17. const path = require('path');
  18. const spawn = require('child_process').spawn;
  19. const exec = require('child_process').exec;
  20. const execSync = require('child_process').execSync;
  21. const util = require('util');
  22. let _platform = process.platform;
  23. const _linux = (_platform === 'linux' || _platform === 'android');
  24. const _darwin = (_platform === 'darwin');
  25. const _windows = (_platform === 'win32');
  26. const _freebsd = (_platform === 'freebsd');
  27. const _openbsd = (_platform === 'openbsd');
  28. const _netbsd = (_platform === 'netbsd');
  29. // const _sunos = (_platform === 'sunos');
  30. let _cores = 0;
  31. let wmicPath = '';
  32. let codepage = '';
  33. let _smartMonToolsInstalled = null;
  34. const WINDIR = process.env.WINDIR || 'C:\\Windows';
  35. // powerShell
  36. let _psChild;
  37. let _psResult = '';
  38. let _psCmds = [];
  39. let _psPersistent = false;
  40. const _psToUTF8 = '$OutputEncoding = [System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8 ; ';
  41. const _psCmdStart = '--###START###--';
  42. const _psError = '--ERROR--';
  43. const _psCmdSeperator = '--###ENDCMD###--';
  44. const _psIdSeperator = '--##ID##--';
  45. const execOptsWin = {
  46. windowsHide: true,
  47. maxBuffer: 1024 * 20000,
  48. encoding: 'UTF-8',
  49. env: util._extend({}, process.env, { LANG: 'en_US.UTF-8' })
  50. };
  51. function toInt(value) {
  52. let result = parseInt(value, 10);
  53. if (isNaN(result)) {
  54. result = 0;
  55. }
  56. return result;
  57. }
  58. const stringReplace = new String().replace;
  59. const stringToLower = new String().toLowerCase;
  60. const stringToString = new String().toString;
  61. const stringSubstr = new String().substr;
  62. const stringTrim = new String().trim;
  63. const stringStartWith = new String().startsWith;
  64. const mathMin = Math.min;
  65. function isFunction(functionToCheck) {
  66. let getType = {};
  67. return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
  68. }
  69. function unique(obj) {
  70. let uniques = [];
  71. let stringify = {};
  72. for (let i = 0; i < obj.length; i++) {
  73. let keys = Object.keys(obj[i]);
  74. keys.sort(function (a, b) { return a - b; });
  75. let str = '';
  76. for (let j = 0; j < keys.length; j++) {
  77. str += JSON.stringify(keys[j]);
  78. str += JSON.stringify(obj[i][keys[j]]);
  79. }
  80. if (!{}.hasOwnProperty.call(stringify, str)) {
  81. uniques.push(obj[i]);
  82. stringify[str] = true;
  83. }
  84. }
  85. return uniques;
  86. }
  87. function sortByKey(array, keys) {
  88. return array.sort(function (a, b) {
  89. let x = '';
  90. let y = '';
  91. keys.forEach(function (key) {
  92. x = x + a[key]; y = y + b[key];
  93. });
  94. return ((x < y) ? -1 : ((x > y) ? 1 : 0));
  95. });
  96. }
  97. function cores() {
  98. if (_cores === 0) {
  99. _cores = os.cpus().length;
  100. }
  101. return _cores;
  102. }
  103. function getValue(lines, property, separator, trimmed, lineMatch) {
  104. separator = separator || ':';
  105. property = property.toLowerCase();
  106. trimmed = trimmed || false;
  107. lineMatch = lineMatch || false;
  108. for (let i = 0; i < lines.length; i++) {
  109. let line = lines[i].toLowerCase().replace(/\t/g, '');
  110. if (trimmed) {
  111. line = line.trim();
  112. }
  113. if (line.startsWith(property) && (lineMatch ? (line.match(property + separator)) : true)) {
  114. const parts = trimmed ? lines[i].trim().split(separator) : lines[i].split(separator);
  115. if (parts.length >= 2) {
  116. parts.shift();
  117. return parts.join(separator).trim();
  118. } else {
  119. return '';
  120. }
  121. }
  122. }
  123. return '';
  124. }
  125. function decodeEscapeSequence(str, base) {
  126. base = base || 16;
  127. return str.replace(/\\x([0-9A-Fa-f]{2})/g, function () {
  128. return String.fromCharCode(parseInt(arguments[1], base));
  129. });
  130. }
  131. function detectSplit(str) {
  132. let seperator = '';
  133. let part = 0;
  134. str.split('').forEach(element => {
  135. if (element >= '0' && element <= '9') {
  136. if (part === 1) { part++; }
  137. } else {
  138. if (part === 0) { part++; }
  139. if (part === 1) {
  140. seperator += element;
  141. }
  142. }
  143. });
  144. return seperator;
  145. }
  146. function parseTime(t, pmDesignator) {
  147. pmDesignator = pmDesignator || '';
  148. t = t.toUpperCase();
  149. let hour = 0;
  150. let min = 0;
  151. let splitter = detectSplit(t);
  152. let parts = t.split(splitter);
  153. if (parts.length >= 2) {
  154. if (parts[2]) {
  155. parts[1] += parts[2];
  156. }
  157. let isPM = (parts[1] && (parts[1].toLowerCase().indexOf('pm') > -1) || (parts[1].toLowerCase().indexOf('p.m.') > -1) || (parts[1].toLowerCase().indexOf('p. m.') > -1) || (parts[1].toLowerCase().indexOf('n') > -1) || (parts[1].toLowerCase().indexOf('ch') > -1) || (parts[1].toLowerCase().indexOf('ös') > -1) || (pmDesignator && parts[1].toLowerCase().indexOf(pmDesignator) > -1));
  158. hour = parseInt(parts[0], 10);
  159. min = parseInt(parts[1], 10);
  160. hour = isPM && hour < 12 ? hour + 12 : hour;
  161. return ('0' + hour).substr(-2) + ':' + ('0' + min).substr(-2);
  162. }
  163. }
  164. function parseDateTime(dt, culture) {
  165. const result = {
  166. date: '',
  167. time: ''
  168. };
  169. culture = culture || {};
  170. let dateFormat = (culture.dateFormat || '').toLowerCase();
  171. let pmDesignator = (culture.pmDesignator || '');
  172. const parts = dt.split(' ');
  173. if (parts[0]) {
  174. if (parts[0].indexOf('/') >= 0) {
  175. // Dateformat: mm/dd/yyyy or dd/mm/yyyy or dd/mm/yy or yyyy/mm/dd
  176. const dtparts = parts[0].split('/');
  177. if (dtparts.length === 3) {
  178. if (dtparts[0].length === 4) {
  179. // Dateformat: yyyy/mm/dd
  180. result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
  181. } else if (dtparts[2].length === 2) {
  182. if ((dateFormat.indexOf('/d/') > -1 || dateFormat.indexOf('/dd/') > -1)) {
  183. // Dateformat: mm/dd/yy
  184. result.date = '20' + dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
  185. } else {
  186. // Dateformat: dd/mm/yy
  187. result.date = '20' + dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
  188. }
  189. } else {
  190. // Dateformat: mm/dd/yyyy or dd/mm/yyyy
  191. const isEN = ((dt.toLowerCase().indexOf('pm') > -1) || (dt.toLowerCase().indexOf('p.m.') > -1) || (dt.toLowerCase().indexOf('p. m.') > -1) || (dt.toLowerCase().indexOf('am') > -1) || (dt.toLowerCase().indexOf('a.m.') > -1) || (dt.toLowerCase().indexOf('a. m.') > -1));
  192. if ((isEN || dateFormat.indexOf('/d/') > -1 || dateFormat.indexOf('/dd/') > -1) && dateFormat.indexOf('dd/') !== 0) {
  193. // Dateformat: mm/dd/yyyy
  194. result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2);
  195. } else {
  196. // Dateformat: dd/mm/yyyy
  197. result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
  198. }
  199. }
  200. }
  201. }
  202. if (parts[0].indexOf('.') >= 0) {
  203. const dtparts = parts[0].split('.');
  204. if (dtparts.length === 3) {
  205. if (dateFormat.indexOf('.d.') > -1 || dateFormat.indexOf('.dd.') > -1) {
  206. // Dateformat: mm.dd.yyyy
  207. result.date = dtparts[2] + '-' + ('0' + dtparts[0]).substr(-2) + '-' + ('0' + dtparts[1]).substr(-2);
  208. } else {
  209. // Dateformat: dd.mm.yyyy
  210. result.date = dtparts[2] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[0]).substr(-2);
  211. }
  212. }
  213. }
  214. if (parts[0].indexOf('-') >= 0) {
  215. // Dateformat: yyyy-mm-dd
  216. const dtparts = parts[0].split('-');
  217. if (dtparts.length === 3) {
  218. result.date = dtparts[0] + '-' + ('0' + dtparts[1]).substr(-2) + '-' + ('0' + dtparts[2]).substr(-2);
  219. }
  220. }
  221. }
  222. if (parts[1]) {
  223. parts.shift();
  224. let time = parts.join(' ');
  225. result.time = parseTime(time, pmDesignator);
  226. }
  227. return result;
  228. }
  229. function parseHead(head, rights) {
  230. let space = (rights > 0);
  231. let count = 1;
  232. let from = 0;
  233. let to = 0;
  234. let result = [];
  235. for (let i = 0; i < head.length; i++) {
  236. if (count <= rights) {
  237. // if (head[i] === ' ' && !space) {
  238. if (/\s/.test(head[i]) && !space) {
  239. to = i - 1;
  240. result.push({
  241. from: from,
  242. to: to + 1,
  243. cap: head.substring(from, to + 1)
  244. });
  245. from = to + 2;
  246. count++;
  247. }
  248. space = head[i] === ' ';
  249. } else {
  250. if (!/\s/.test(head[i]) && space) {
  251. to = i - 1;
  252. if (from < to) {
  253. result.push({
  254. from: from,
  255. to: to,
  256. cap: head.substring(from, to)
  257. });
  258. }
  259. from = to + 1;
  260. count++;
  261. }
  262. space = head[i] === ' ';
  263. }
  264. }
  265. to = 1000;
  266. result.push({
  267. from: from,
  268. to: to,
  269. cap: head.substring(from, to)
  270. });
  271. let len = result.length;
  272. for (var i = 0; i < len; i++) {
  273. if (result[i].cap.replace(/\s/g, '').length === 0) {
  274. if (i + 1 < len) {
  275. result[i].to = result[i + 1].to;
  276. result[i].cap = result[i].cap + result[i + 1].cap;
  277. result.splice(i + 1, 1);
  278. len = len - 1;
  279. }
  280. }
  281. }
  282. return result;
  283. }
  284. function findObjectByKey(array, key, value) {
  285. for (let i = 0; i < array.length; i++) {
  286. if (array[i][key] === value) {
  287. return i;
  288. }
  289. }
  290. return -1;
  291. }
  292. function getWmic() {
  293. if (os.type() === 'Windows_NT' && !wmicPath) {
  294. wmicPath = WINDIR + '\\system32\\wbem\\wmic.exe';
  295. if (!fs.existsSync(wmicPath)) {
  296. try {
  297. const wmicPathArray = execSync('WHERE WMIC', execOptsWin).toString().split('\r\n');
  298. if (wmicPathArray && wmicPathArray.length) {
  299. wmicPath = wmicPathArray[0];
  300. } else {
  301. wmicPath = 'wmic';
  302. }
  303. } catch (e) {
  304. wmicPath = 'wmic';
  305. }
  306. }
  307. }
  308. return wmicPath;
  309. }
  310. function wmic(command) {
  311. return new Promise((resolve) => {
  312. process.nextTick(() => {
  313. try {
  314. powerShell(getWmic() + ' ' + command).then(stdout => {
  315. resolve(stdout, '');
  316. });
  317. } catch (e) {
  318. resolve('', e);
  319. }
  320. });
  321. });
  322. }
  323. // function wmic(command, options) {
  324. // options = options || execOptsWin;
  325. // return new Promise((resolve) => {
  326. // process.nextTick(() => {
  327. // try {
  328. // exec(WINDIR + '\\system32\\chcp.com 65001 | ' + getWmic() + ' ' + command, options, function (error, stdout) {
  329. // resolve(stdout, error);
  330. // }).stdin.end();
  331. // } catch (e) {
  332. // resolve('', e);
  333. // }
  334. // });
  335. // });
  336. // }
  337. function getVboxmanage() {
  338. return _windows ? `"${process.env.VBOX_INSTALL_PATH || process.env.VBOX_MSI_INSTALL_PATH}\\VBoxManage.exe"` : 'vboxmanage';
  339. }
  340. function powerShellProceedResults(data) {
  341. let id = '';
  342. let parts;
  343. let res = '';
  344. // startID
  345. if (data.indexOf(_psCmdStart) >= 0) {
  346. parts = data.split(_psCmdStart);
  347. const parts2 = parts[1].split(_psIdSeperator);
  348. id = parts2[0];
  349. if (parts2.length > 1) {
  350. data = parts2.slice(1).join(_psIdSeperator);
  351. }
  352. }
  353. // result;
  354. if (data.indexOf(_psCmdSeperator) >= 0) {
  355. parts = data.split(_psCmdSeperator);
  356. res = parts[0];
  357. }
  358. let remove = -1;
  359. for (let i = 0; i < _psCmds.length; i++) {
  360. if (_psCmds[i].id === id) {
  361. remove = i;
  362. // console.log(`----- TIME : ${(new Date() - _psCmds[i].start) * 0.001} s`);
  363. _psCmds[i].callback(res);
  364. }
  365. }
  366. if (remove >= 0) {
  367. _psCmds.splice(remove, 1);
  368. }
  369. }
  370. function powerShellStart() {
  371. _psChild = spawn('powershell.exe', ['-NoLogo', '-InputFormat', 'Text', '-NoExit', '-Command', '-'], {
  372. stdio: 'pipe',
  373. windowsHide: true,
  374. maxBuffer: 1024 * 20000,
  375. encoding: 'UTF-8',
  376. env: util._extend({}, process.env, { LANG: 'en_US.UTF-8' })
  377. });
  378. if (_psChild && _psChild.pid) {
  379. _psPersistent = true;
  380. _psChild.stdout.on('data', function (data) {
  381. _psResult = _psResult + data.toString('utf8');
  382. if (data.indexOf(_psCmdSeperator) >= 0) {
  383. powerShellProceedResults(_psResult);
  384. _psResult = '';
  385. }
  386. });
  387. _psChild.stderr.on('data', function () {
  388. powerShellProceedResults(_psResult + _psError);
  389. });
  390. _psChild.on('error', function () {
  391. powerShellProceedResults(_psResult + _psError);
  392. });
  393. _psChild.on('close', function () {
  394. _psChild.kill();
  395. });
  396. }
  397. }
  398. function powerShellRelease() {
  399. try {
  400. _psChild.stdin.write('exit' + os.EOL);
  401. _psChild.stdin.end();
  402. _psPersistent = false;
  403. } catch (e) {
  404. _psChild.kill();
  405. }
  406. }
  407. function powerShell(cmd) {
  408. if (_psPersistent) {
  409. const id = Math.random().toString(36).substr(2, 10);
  410. return new Promise((resolve) => {
  411. process.nextTick(() => {
  412. function callback(data) {
  413. resolve(data);
  414. }
  415. _psCmds.push({
  416. id,
  417. cmd,
  418. callback,
  419. start: new Date()
  420. });
  421. try {
  422. if (_psChild && _psChild.pid) {
  423. _psChild.stdin.write(_psToUTF8 + 'echo ' + _psCmdStart + id + _psIdSeperator + '; ' + os.EOL + cmd + os.EOL + 'echo ' + _psCmdSeperator + os.EOL);
  424. }
  425. } catch (e) {
  426. resolve('');
  427. }
  428. });
  429. });
  430. } else {
  431. let result = '';
  432. return new Promise((resolve) => {
  433. process.nextTick(() => {
  434. try {
  435. // const start = new Date();
  436. const child = spawn('powershell.exe', ['-NoLogo', '-InputFormat', 'Text', '-NoExit', '-ExecutionPolicy', 'Unrestricted', '-Command', '-'], {
  437. stdio: 'pipe',
  438. windowsHide: true,
  439. maxBuffer: 1024 * 20000,
  440. encoding: 'UTF-8',
  441. env: util._extend({}, process.env, { LANG: 'en_US.UTF-8' })
  442. });
  443. if (child && !child.pid) {
  444. child.on('error', function () {
  445. resolve(result);
  446. });
  447. }
  448. if (child && child.pid) {
  449. child.stdout.on('data', function (data) {
  450. result = result + data.toString('utf8');
  451. });
  452. child.stderr.on('data', function () {
  453. child.kill();
  454. resolve(result);
  455. });
  456. child.on('close', function () {
  457. child.kill();
  458. // console.log(`----- TIME : ${(new Date() - start) * 0.001} s`);
  459. resolve(result);
  460. });
  461. child.on('error', function () {
  462. child.kill();
  463. resolve(result);
  464. });
  465. try {
  466. child.stdin.write(_psToUTF8 + cmd + os.EOL);
  467. child.stdin.write('exit' + os.EOL);
  468. child.stdin.end();
  469. } catch (e) {
  470. child.kill();
  471. resolve(result);
  472. }
  473. } else {
  474. resolve(result);
  475. }
  476. } catch (e) {
  477. resolve(result);
  478. }
  479. });
  480. });
  481. }
  482. }
  483. function execSafe(cmd, args, options) {
  484. let result = '';
  485. options = options || {};
  486. return new Promise((resolve) => {
  487. process.nextTick(() => {
  488. try {
  489. const child = spawn(cmd, args, options);
  490. if (child && !child.pid) {
  491. child.on('error', function () {
  492. resolve(result);
  493. });
  494. }
  495. if (child && child.pid) {
  496. child.stdout.on('data', function (data) {
  497. result += data.toString();
  498. });
  499. child.on('close', function () {
  500. child.kill();
  501. resolve(result);
  502. });
  503. child.on('error', function () {
  504. child.kill();
  505. resolve(result);
  506. });
  507. } else {
  508. resolve(result);
  509. }
  510. } catch (e) {
  511. resolve(result);
  512. }
  513. });
  514. });
  515. }
  516. function getCodepage() {
  517. if (_windows) {
  518. if (!codepage) {
  519. try {
  520. const stdout = execSync('chcp', execOptsWin);
  521. const lines = stdout.toString().split('\r\n');
  522. const parts = lines[0].split(':');
  523. codepage = parts.length > 1 ? parts[1].replace('.', '') : '';
  524. } catch (err) {
  525. codepage = '437';
  526. }
  527. }
  528. return codepage;
  529. }
  530. if (_linux || _darwin || _freebsd || _openbsd || _netbsd) {
  531. if (!codepage) {
  532. try {
  533. const stdout = execSync('echo $LANG');
  534. const lines = stdout.toString().split('\r\n');
  535. const parts = lines[0].split('.');
  536. codepage = parts.length > 1 ? parts[1].trim() : '';
  537. if (!codepage) {
  538. codepage = 'UTF-8';
  539. }
  540. } catch (err) {
  541. codepage = 'UTF-8';
  542. }
  543. }
  544. return codepage;
  545. }
  546. }
  547. function smartMonToolsInstalled() {
  548. if (_smartMonToolsInstalled !== null) {
  549. return _smartMonToolsInstalled;
  550. }
  551. _smartMonToolsInstalled = false;
  552. if (_windows) {
  553. try {
  554. const pathArray = execSync('WHERE smartctl 2>nul', execOptsWin).toString().split('\r\n');
  555. if (pathArray && pathArray.length) {
  556. _smartMonToolsInstalled = pathArray[0].indexOf(':\\') >= 0;
  557. } else {
  558. _smartMonToolsInstalled = false;
  559. }
  560. } catch (e) {
  561. _smartMonToolsInstalled = false;
  562. }
  563. }
  564. if (_linux || _darwin || _freebsd || _openbsd || _netbsd) {
  565. const pathArray = execSync('which smartctl 2>/dev/null', execOptsWin).toString().split('\r\n');
  566. _smartMonToolsInstalled = pathArray.length > 0;
  567. }
  568. return _smartMonToolsInstalled;
  569. }
  570. function isRaspberry() {
  571. const PI_MODEL_NO = [
  572. 'BCM2708',
  573. 'BCM2709',
  574. 'BCM2710',
  575. 'BCM2711',
  576. 'BCM2835',
  577. 'BCM2836',
  578. 'BCM2837',
  579. 'BCM2837B0'
  580. ];
  581. let cpuinfo = [];
  582. try {
  583. cpuinfo = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' }).toString().split('\n');
  584. } catch (e) {
  585. return false;
  586. }
  587. const hardware = getValue(cpuinfo, 'hardware');
  588. return (hardware && PI_MODEL_NO.indexOf(hardware) > -1);
  589. }
  590. function isRaspbian() {
  591. let osrelease = [];
  592. try {
  593. osrelease = fs.readFileSync('/etc/os-release', { encoding: 'utf8' }).toString().split('\n');
  594. } catch (e) {
  595. return false;
  596. }
  597. const id = getValue(osrelease, 'id', '=');
  598. return (id && id.indexOf('raspbian') > -1);
  599. }
  600. function execWin(cmd, opts, callback) {
  601. if (!callback) {
  602. callback = opts;
  603. opts = execOptsWin;
  604. }
  605. let newCmd = 'chcp 65001 > nul && cmd /C ' + cmd + ' && chcp ' + codepage + ' > nul';
  606. exec(newCmd, opts, function (error, stdout) {
  607. callback(error, stdout);
  608. });
  609. }
  610. function darwinXcodeExists() {
  611. const cmdLineToolsExists = fs.existsSync('/Library/Developer/CommandLineTools/usr/bin/');
  612. const xcodeAppExists = fs.existsSync('/Applications/Xcode.app/Contents/Developer/Tools');
  613. const xcodeExists = fs.existsSync('/Library/Developer/Xcode/');
  614. return (cmdLineToolsExists || xcodeExists || xcodeAppExists);
  615. }
  616. function nanoSeconds() {
  617. const time = process.hrtime();
  618. if (!Array.isArray(time) || time.length !== 2) {
  619. return 0;
  620. }
  621. return +time[0] * 1e9 + +time[1];
  622. }
  623. function countUniqueLines(lines, startingWith) {
  624. startingWith = startingWith || '';
  625. const uniqueLines = [];
  626. lines.forEach(line => {
  627. if (line.startsWith(startingWith)) {
  628. if (uniqueLines.indexOf(line) === -1) {
  629. uniqueLines.push(line);
  630. }
  631. }
  632. });
  633. return uniqueLines.length;
  634. }
  635. function countLines(lines, startingWith) {
  636. startingWith = startingWith || '';
  637. const uniqueLines = [];
  638. lines.forEach(line => {
  639. if (line.startsWith(startingWith)) {
  640. uniqueLines.push(line);
  641. }
  642. });
  643. return uniqueLines.length;
  644. }
  645. function sanitizeShellString(str, strict) {
  646. if (typeof strict === 'undefined') { strict = false; }
  647. const s = str || '';
  648. let result = '';
  649. for (let i = 0; i <= mathMin(s.length, 2000); i++) {
  650. if (!(s[i] === undefined ||
  651. s[i] === '>' ||
  652. s[i] === '<' ||
  653. s[i] === '*' ||
  654. s[i] === '?' ||
  655. s[i] === '[' ||
  656. s[i] === ']' ||
  657. s[i] === '|' ||
  658. s[i] === '˚' ||
  659. s[i] === '$' ||
  660. s[i] === ';' ||
  661. s[i] === '&' ||
  662. s[i] === '(' ||
  663. s[i] === ')' ||
  664. s[i] === ']' ||
  665. s[i] === '#' ||
  666. s[i] === '\\' ||
  667. s[i] === '\t' ||
  668. s[i] === '\n' ||
  669. s[i] === '\'' ||
  670. s[i] === '`' ||
  671. s[i] === '"' ||
  672. s[i].length > 1 ||
  673. (strict && s[i] === '@') ||
  674. (strict && s[i] === ' ') ||
  675. (strict && s[i] == '{') ||
  676. (strict && s[i] == ')'))) {
  677. result = result + s[i];
  678. }
  679. }
  680. return result;
  681. }
  682. function isPrototypePolluted() {
  683. const s = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  684. let notPolluted = true;
  685. let st = '';
  686. st.__proto__.replace = stringReplace;
  687. st.__proto__.toLowerCase = stringToLower;
  688. st.__proto__.toString = stringToString;
  689. st.__proto__.substr = stringSubstr;
  690. notPolluted = notPolluted || !(s.length === 62);
  691. const ms = Date.now();
  692. if (typeof ms === 'number' && ms > 1600000000000) {
  693. const l = ms % 100 + 15;
  694. for (let i = 0; i < l; i++) {
  695. const r = Math.random() * 61.99999999 + 1;
  696. const rs = parseInt(Math.floor(r).toString(), 10);
  697. const rs2 = parseInt(r.toString().split('.')[0], 10);
  698. const q = Math.random() * 61.99999999 + 1;
  699. const qs = parseInt(Math.floor(q).toString(), 10);
  700. const qs2 = parseInt(q.toString().split('.')[0], 10);
  701. notPolluted = notPolluted && !(r === q);
  702. notPolluted = notPolluted && rs === rs2 && qs === qs2;
  703. st += s[rs - 1];
  704. }
  705. notPolluted = notPolluted && st.length === l;
  706. // string manipulation
  707. let p = Math.random() * l * 0.9999999999;
  708. let stm = st.substr(0, p) + ' ' + st.substr(p, 2000);
  709. stm.__proto__.replace = stringReplace;
  710. let sto = stm.replace(/ /g, '');
  711. notPolluted = notPolluted && st === sto;
  712. p = Math.random() * l * 0.9999999999;
  713. stm = st.substr(0, p) + '{' + st.substr(p, 2000);
  714. sto = stm.replace(/{/g, '');
  715. notPolluted = notPolluted && st === sto;
  716. p = Math.random() * l * 0.9999999999;
  717. stm = st.substr(0, p) + '*' + st.substr(p, 2000);
  718. sto = stm.replace(/\*/g, '');
  719. notPolluted = notPolluted && st === sto;
  720. p = Math.random() * l * 0.9999999999;
  721. stm = st.substr(0, p) + '$' + st.substr(p, 2000);
  722. sto = stm.replace(/\$/g, '');
  723. notPolluted = notPolluted && st === sto;
  724. // lower
  725. const stl = st.toLowerCase();
  726. notPolluted = notPolluted && (stl.length === l) && stl[l - 1] && !(stl[l]);
  727. for (let i = 0; i < l; i++) {
  728. const s1 = st[i];
  729. s1.__proto__.toLowerCase = stringToLower;
  730. const s2 = stl ? stl[i] : '';
  731. const s1l = s1.toLowerCase();
  732. notPolluted = notPolluted && s1l[0] === s2 && s1l[0] && !(s1l[1]);
  733. }
  734. }
  735. return !notPolluted;
  736. }
  737. function hex2bin(hex) {
  738. return ('00000000' + (parseInt(hex, 16)).toString(2)).substr(-8);
  739. }
  740. function getFilesInPath(source) {
  741. const lstatSync = fs.lstatSync;
  742. const readdirSync = fs.readdirSync;
  743. const join = path.join;
  744. function isDirectory(source) {
  745. return lstatSync(source).isDirectory();
  746. }
  747. function isFile(source) { return lstatSync(source).isFile(); }
  748. function getDirectories(source) {
  749. return readdirSync(source).map(function (name) { return join(source, name); }).filter(isDirectory);
  750. }
  751. function getFiles(source) {
  752. return readdirSync(source).map(function (name) { return join(source, name); }).filter(isFile);
  753. }
  754. function getFilesRecursively(source) {
  755. try {
  756. let dirs = getDirectories(source);
  757. let files = dirs
  758. .map(function (dir) { return getFilesRecursively(dir); })
  759. .reduce(function (a, b) { return a.concat(b); }, []);
  760. return files.concat(getFiles(source));
  761. } catch (e) {
  762. return [];
  763. }
  764. }
  765. if (fs.existsSync(source)) {
  766. return getFilesRecursively(source);
  767. } else {
  768. return [];
  769. }
  770. }
  771. function decodePiCpuinfo(lines) {
  772. // https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
  773. const oldRevisionCodes = {
  774. '0002': {
  775. type: 'B',
  776. revision: '1.0',
  777. memory: 256,
  778. manufacturer: 'Egoman',
  779. processor: 'BCM2835'
  780. },
  781. '0003': {
  782. type: 'B',
  783. revision: '1.0',
  784. memory: 256,
  785. manufacturer: 'Egoman',
  786. processor: 'BCM2835'
  787. },
  788. '0004': {
  789. type: 'B',
  790. revision: '2.0',
  791. memory: 256,
  792. manufacturer: 'Sony UK',
  793. processor: 'BCM2835'
  794. },
  795. '0005': {
  796. type: 'B',
  797. revision: '2.0',
  798. memory: 256,
  799. manufacturer: 'Qisda',
  800. processor: 'BCM2835'
  801. },
  802. '0006': {
  803. type: 'B',
  804. revision: '2.0',
  805. memory: 256,
  806. manufacturer: 'Egoman',
  807. processor: 'BCM2835'
  808. },
  809. '0007': {
  810. type: 'A',
  811. revision: '2.0',
  812. memory: 256,
  813. manufacturer: 'Egoman',
  814. processor: 'BCM2835'
  815. },
  816. '0008': {
  817. type: 'A',
  818. revision: '2.0',
  819. memory: 256,
  820. manufacturer: 'Sony UK',
  821. processor: 'BCM2835'
  822. },
  823. '0009': {
  824. type: 'A',
  825. revision: '2.0',
  826. memory: 256,
  827. manufacturer: 'Qisda',
  828. processor: 'BCM2835'
  829. },
  830. '000d': {
  831. type: 'B',
  832. revision: '2.0',
  833. memory: 512,
  834. manufacturer: 'Egoman',
  835. processor: 'BCM2835'
  836. },
  837. '000e': {
  838. type: 'B',
  839. revision: '2.0',
  840. memory: 512,
  841. manufacturer: 'Sony UK',
  842. processor: 'BCM2835'
  843. },
  844. '000f': {
  845. type: 'B',
  846. revision: '2.0',
  847. memory: 512,
  848. manufacturer: 'Egoman',
  849. processor: 'BCM2835'
  850. },
  851. '0010': {
  852. type: 'B+',
  853. revision: '1.2',
  854. memory: 512,
  855. manufacturer: 'Sony UK',
  856. processor: 'BCM2835'
  857. },
  858. '0011': {
  859. type: 'CM1',
  860. revision: '1.0',
  861. memory: 512,
  862. manufacturer: 'Sony UK',
  863. processor: 'BCM2835'
  864. },
  865. '0012': {
  866. type: 'A+',
  867. revision: '1.1',
  868. memory: 256,
  869. manufacturer: 'Sony UK',
  870. processor: 'BCM2835'
  871. },
  872. '0013': {
  873. type: 'B+',
  874. revision: '1.2',
  875. memory: 512,
  876. manufacturer: 'Embest',
  877. processor: 'BCM2835'
  878. },
  879. '0014': {
  880. type: 'CM1',
  881. revision: '1.0',
  882. memory: 512,
  883. manufacturer: 'Embest',
  884. processor: 'BCM2835'
  885. },
  886. '0015': {
  887. type: 'A+',
  888. revision: '1.1',
  889. memory: 256,
  890. manufacturer: '512MB Embest',
  891. processor: 'BCM2835'
  892. }
  893. };
  894. const processorList = [
  895. 'BCM2835',
  896. 'BCM2836',
  897. 'BCM2837',
  898. 'BCM2711',
  899. ];
  900. const manufacturerList = [
  901. 'Sony UK',
  902. 'Egoman',
  903. 'Embest',
  904. 'Sony Japan',
  905. 'Embest',
  906. 'Stadium'
  907. ];
  908. const typeList = {
  909. '00': 'A',
  910. '01': 'B',
  911. '02': 'A+',
  912. '03': 'B+',
  913. '04': '2B',
  914. '05': 'Alpha (early prototype)',
  915. '06': 'CM1',
  916. '08': '3B',
  917. '09': 'Zero',
  918. '0a': 'CM3',
  919. '0c': 'Zero W',
  920. '0d': '3B+',
  921. '0e': '3A+',
  922. '0f': 'Internal use only',
  923. '10': 'CM3+',
  924. '11': '4B',
  925. '12': 'Zero 2 W',
  926. '13': '400',
  927. '14': 'CM4'
  928. };
  929. const revisionCode = getValue(lines, 'revision', ':', true);
  930. const model = getValue(lines, 'model:', ':', true);
  931. const serial = getValue(lines, 'serial', ':', true);
  932. let result = {};
  933. if ({}.hasOwnProperty.call(oldRevisionCodes, revisionCode)) {
  934. // old revision codes
  935. result = {
  936. model,
  937. serial,
  938. revisionCode,
  939. memory: oldRevisionCodes[revisionCode].memory,
  940. manufacturer: oldRevisionCodes[revisionCode].manufacturer,
  941. processor: oldRevisionCodes[revisionCode].processor,
  942. type: oldRevisionCodes[revisionCode].type,
  943. revision: oldRevisionCodes[revisionCode].revision,
  944. };
  945. } else {
  946. // new revision code
  947. const revision = ('00000000' + getValue(lines, 'revision', ':', true).toLowerCase()).substr(-8);
  948. // const revisionStyleNew = hex2bin(revision.substr(2, 1)).substr(4, 1) === '1';
  949. const memSizeCode = parseInt(hex2bin(revision.substr(2, 1)).substr(5, 3), 2) || 0;
  950. const manufacturer = manufacturerList[parseInt(revision.substr(3, 1), 10)];
  951. const processor = processorList[parseInt(revision.substr(4, 1), 10)];
  952. const typeCode = revision.substr(5, 2);
  953. result = {
  954. model,
  955. serial,
  956. revisionCode,
  957. memory: 256 * Math.pow(2, memSizeCode),
  958. manufacturer,
  959. processor,
  960. type: {}.hasOwnProperty.call(typeList, typeCode) ? typeList[typeCode] : '',
  961. revision: '1.' + revision.substr(7, 1),
  962. };
  963. }
  964. return result;
  965. }
  966. function promiseAll(promises) {
  967. const resolvingPromises = promises.map(function (promise) {
  968. return new Promise(function (resolve) {
  969. var payload = new Array(2);
  970. promise.then(function (result) {
  971. payload[0] = result;
  972. })
  973. .catch(function (error) {
  974. payload[1] = error;
  975. })
  976. .then(function () {
  977. // The wrapped Promise returns an array: 0 = result, 1 = error ... we resolve all
  978. resolve(payload);
  979. });
  980. });
  981. });
  982. var errors = [];
  983. var results = [];
  984. // Execute all wrapped Promises
  985. return Promise.all(resolvingPromises)
  986. .then(function (items) {
  987. items.forEach(function (payload) {
  988. if (payload[1]) {
  989. errors.push(payload[1]);
  990. results.push(null);
  991. } else {
  992. errors.push(null);
  993. results.push(payload[0]);
  994. }
  995. });
  996. return {
  997. errors: errors,
  998. results: results
  999. };
  1000. });
  1001. }
  1002. function promisify(nodeStyleFunction) {
  1003. return function () {
  1004. var args = Array.prototype.slice.call(arguments);
  1005. return new Promise(function (resolve, reject) {
  1006. args.push(function (err, data) {
  1007. if (err) {
  1008. reject(err);
  1009. } else {
  1010. resolve(data);
  1011. }
  1012. });
  1013. nodeStyleFunction.apply(null, args);
  1014. });
  1015. };
  1016. }
  1017. function promisifySave(nodeStyleFunction) {
  1018. return function () {
  1019. var args = Array.prototype.slice.call(arguments);
  1020. return new Promise(function (resolve) {
  1021. args.push(function (err, data) {
  1022. resolve(data);
  1023. });
  1024. nodeStyleFunction.apply(null, args);
  1025. });
  1026. };
  1027. }
  1028. function linuxVersion() {
  1029. let result = '';
  1030. if (_linux) {
  1031. try {
  1032. result = execSync('uname -v').toString();
  1033. } catch (e) {
  1034. result = '';
  1035. }
  1036. }
  1037. return result;
  1038. }
  1039. function plistParser(xmlStr) {
  1040. const tags = ['array', 'dict', 'key', 'string', 'integer', 'date', 'real', 'data', 'boolean', 'arrayEmpty'];
  1041. const startStr = '<plist version';
  1042. let pos = xmlStr.indexOf(startStr);
  1043. let len = xmlStr.length;
  1044. while (xmlStr[pos] !== '>' && pos < len) {
  1045. pos++;
  1046. }
  1047. let depth = 0;
  1048. let inTagStart = false;
  1049. let inTagContent = false;
  1050. let inTagEnd = false;
  1051. let metaData = [{ tagStart: '', tagEnd: '', tagContent: '', key: '', data: null }];
  1052. let c = '';
  1053. let cn = xmlStr[pos];
  1054. while (pos < len) {
  1055. c = cn;
  1056. if (pos + 1 < len) { cn = xmlStr[pos + 1]; }
  1057. if (c === '<') {
  1058. inTagContent = false;
  1059. if (cn === '/') { inTagEnd = true; }
  1060. else if (metaData[depth].tagStart) {
  1061. metaData[depth].tagContent = '';
  1062. if (!metaData[depth].data) { metaData[depth].data = metaData[depth].tagStart === 'array' ? [] : {}; }
  1063. depth++;
  1064. metaData.push({ tagStart: '', tagEnd: '', tagContent: '', key: null, data: null });
  1065. inTagStart = true;
  1066. inTagContent = false;
  1067. }
  1068. else if (!inTagStart) { inTagStart = true; }
  1069. } else if (c === '>') {
  1070. if (metaData[depth].tagStart === 'true/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/boolean'; metaData[depth].data = true; }
  1071. if (metaData[depth].tagStart === 'false/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/boolean'; metaData[depth].data = false; }
  1072. if (metaData[depth].tagStart === 'array/') { inTagStart = false; inTagEnd = true; metaData[depth].tagStart = ''; metaData[depth].tagEnd = '/arrayEmpty'; metaData[depth].data = []; }
  1073. if (inTagContent) { inTagContent = false; }
  1074. if (inTagStart) {
  1075. inTagStart = false;
  1076. inTagContent = true;
  1077. if (metaData[depth].tagStart === 'array') {
  1078. metaData[depth].data = [];
  1079. }
  1080. if (metaData[depth].tagStart === 'dict') {
  1081. metaData[depth].data = {};
  1082. }
  1083. }
  1084. if (inTagEnd) {
  1085. inTagEnd = false;
  1086. if (metaData[depth].tagEnd && tags.indexOf(metaData[depth].tagEnd.substr(1)) >= 0) {
  1087. if (metaData[depth].tagEnd === '/dict' || metaData[depth].tagEnd === '/array') {
  1088. if (depth > 1 && metaData[depth - 2].tagStart === 'array') {
  1089. metaData[depth - 2].data.push(metaData[depth - 1].data);
  1090. }
  1091. if (depth > 1 && metaData[depth - 2].tagStart === 'dict') {
  1092. metaData[depth - 2].data[metaData[depth - 1].key] = metaData[depth - 1].data;
  1093. }
  1094. depth--;
  1095. metaData.pop();
  1096. metaData[depth].tagContent = '';
  1097. metaData[depth].tagStart = '';
  1098. metaData[depth].tagEnd = '';
  1099. }
  1100. else {
  1101. if (metaData[depth].tagEnd === '/key' && metaData[depth].tagContent) {
  1102. metaData[depth].key = metaData[depth].tagContent;
  1103. } else {
  1104. if (metaData[depth].tagEnd === '/real' && metaData[depth].tagContent) { metaData[depth].data = parseFloat(metaData[depth].tagContent) || 0; }
  1105. if (metaData[depth].tagEnd === '/integer' && metaData[depth].tagContent) { metaData[depth].data = parseInt(metaData[depth].tagContent) || 0; }
  1106. if (metaData[depth].tagEnd === '/string' && metaData[depth].tagContent) { metaData[depth].data = metaData[depth].tagContent || ''; }
  1107. if (metaData[depth].tagEnd === '/boolean') { metaData[depth].data = metaData[depth].tagContent || false; }
  1108. if (metaData[depth].tagEnd === '/arrayEmpty') { metaData[depth].data = metaData[depth].tagContent || []; }
  1109. if (depth > 0 && metaData[depth - 1].tagStart === 'array') { metaData[depth - 1].data.push(metaData[depth].data); }
  1110. if (depth > 0 && metaData[depth - 1].tagStart === 'dict') { metaData[depth - 1].data[metaData[depth].key] = metaData[depth].data; }
  1111. }
  1112. metaData[depth].tagContent = '';
  1113. metaData[depth].tagStart = '';
  1114. metaData[depth].tagEnd = '';
  1115. }
  1116. }
  1117. metaData[depth].tagEnd = '';
  1118. inTagStart = false;
  1119. inTagContent = false;
  1120. }
  1121. } else {
  1122. if (inTagStart) { metaData[depth].tagStart += c; }
  1123. if (inTagEnd) { metaData[depth].tagEnd += c; }
  1124. if (inTagContent) { metaData[depth].tagContent += c; }
  1125. }
  1126. pos++;
  1127. }
  1128. return metaData[0].data;
  1129. }
  1130. function semverCompare(v1, v2) {
  1131. let res = 0;
  1132. const parts1 = v1.split('.');
  1133. const parts2 = v2.split('.');
  1134. if (parts1[0] < parts2[0]) { res = 1; }
  1135. else if (parts1[0] > parts2[0]) { res = -1; }
  1136. else if (parts1[0] === parts2[0] && parts1.length >= 2 && parts2.length >= 2) {
  1137. if (parts1[1] < parts2[1]) { res = 1; }
  1138. else if (parts1[1] > parts2[1]) { res = -1; }
  1139. else if (parts1[1] === parts2[1]) {
  1140. if (parts1.length >= 3 && parts2.length >= 3) {
  1141. if (parts1[2] < parts2[2]) { res = 1; }
  1142. else if (parts1[2] > parts2[2]) { res = -1; }
  1143. } else if (parts2.length >= 3) {
  1144. res = 1;
  1145. }
  1146. }
  1147. }
  1148. return res;
  1149. }
  1150. function noop() { }
  1151. exports.toInt = toInt;
  1152. exports.execOptsWin = execOptsWin;
  1153. exports.getCodepage = getCodepage;
  1154. exports.execWin = execWin;
  1155. exports.isFunction = isFunction;
  1156. exports.unique = unique;
  1157. exports.sortByKey = sortByKey;
  1158. exports.cores = cores;
  1159. exports.getValue = getValue;
  1160. exports.decodeEscapeSequence = decodeEscapeSequence;
  1161. exports.parseDateTime = parseDateTime;
  1162. exports.parseHead = parseHead;
  1163. exports.findObjectByKey = findObjectByKey;
  1164. exports.getWmic = getWmic;
  1165. exports.wmic = wmic;
  1166. exports.darwinXcodeExists = darwinXcodeExists;
  1167. exports.getVboxmanage = getVboxmanage;
  1168. exports.powerShell = powerShell;
  1169. exports.powerShellStart = powerShellStart;
  1170. exports.powerShellRelease = powerShellRelease;
  1171. exports.execSafe = execSafe;
  1172. exports.nanoSeconds = nanoSeconds;
  1173. exports.countUniqueLines = countUniqueLines;
  1174. exports.countLines = countLines;
  1175. exports.noop = noop;
  1176. exports.isRaspberry = isRaspberry;
  1177. exports.isRaspbian = isRaspbian;
  1178. exports.sanitizeShellString = sanitizeShellString;
  1179. exports.isPrototypePolluted = isPrototypePolluted;
  1180. exports.decodePiCpuinfo = decodePiCpuinfo;
  1181. exports.promiseAll = promiseAll;
  1182. exports.promisify = promisify;
  1183. exports.promisifySave = promisifySave;
  1184. exports.smartMonToolsInstalled = smartMonToolsInstalled;
  1185. exports.linuxVersion = linuxVersion;
  1186. exports.plistParser = plistParser;
  1187. exports.stringReplace = stringReplace;
  1188. exports.stringToLower = stringToLower;
  1189. exports.stringToString = stringToString;
  1190. exports.stringSubstr = stringSubstr;
  1191. exports.stringTrim = stringTrim;
  1192. exports.stringStartWith = stringStartWith;
  1193. exports.mathMin = mathMin;
  1194. exports.WINDIR = WINDIR;
  1195. exports.getFilesInPath = getFilesInPath;
  1196. exports.semverCompare = semverCompare;