text: 'use strict';
  // @ts-check
  // ==================================================================================
  // cpu.js
  // ----------------------------------------------------------------------------------
  // Description:   System Information - library
  //                for Node.js
  // Copyright:     (c) 2014 - 2020
  // Author:        Sebastian Hildebrandt
  // ----------------------------------------------------------------------------------
  // License:       MIT
  // ==================================================================================
  // 4. CPU
  // ----------------------------------------------------------------------------------
  
  const os = require('os');
  const exec = require('child_process').exec;
  const fs = require('fs');
  const util = require('./util');
  
  let _platform = process.platform;
  
  const _linux = (_platform === 'linux');
  const _darwin = (_platform === 'darwin');
  const _windows = (_platform === 'win32');
  const _freebsd = (_platform === 'freebsd');
  const _openbsd = (_platform === 'openbsd');
  const _netbsd = (_platform === 'netbsd');
  const _sunos = (_platform === 'sunos');
  
  let _cpu_speed = '0.00';
  let _current_cpu = {
    user: 0,
    nice: 0,
    system: 0,
    idle: 0,
    irq: 0,
    load: 0,
    tick: 0,
    ms: 0,
    currentload: 0,
    currentload_user: 0,
    currentload_system: 0,
    currentload_nice: 0,
    currentload_idle: 0,
    currentload_irq: 0,
    raw_currentload: 0,
    raw_currentload_user: 0,
    raw_currentload_system: 0,
    raw_currentload_nice: 0,
    raw_currentload_idle: 0,
    raw_currentload_irq: 0
  };
  let _cpus = [];
  let _corecount = 0;
  
  const AMDBaseFrequencies = {
    '8346': '1.8',
    '8347': '1.9',
    '8350': '2.0',
    '8354': '2.2',
    '8356|SE': '2.4',
    '8356': '2.3',
    '8360': '2.5',
    '2372': '2.1',
    '2373': '2.1',
    '2374': '2.2',
    '2376': '2.3',
    '2377': '2.3',
    '2378': '2.4',
    '2379': '2.4',
    '2380': '2.5',
    '2381': '2.5',
    '2382': '2.6',
    '2384': '2.7',
    '2386': '2.8',
    '2387': '2.8',
    '2389': '2.9',
    '2393': '3.1',
    '8374': '2.2',
    '8376': '2.3',
    '8378': '2.4',
    '8379': '2.4',
    '8380': '2.5',
    '8381': '2.5',
    '8382': '2.6',
    '8384': '2.7',
    '8386': '2.8',
    '8387': '2.8',
    '8389': '2.9',
    '8393': '3.1',
    '2419EE': '1.8',
    '2423HE': '2.0',
    '2425HE': '2.1',
    '2427': '2.2',
    '2431': '2.4',
    '2435': '2.6',
    '2439SE': '2.8',
    '8425HE': '2.1',
    '8431': '2.4',
    '8435': '2.6',
    '8439SE': '2.8',
    '4122': '2.2',
    '4130': '2.6',
    '4162EE': '1.7',
    '4164EE': '1.8',
    '4170HE': '2.1',
    '4174HE': '2.3',
    '4176HE': '2.4',
    '4180': '2.6',
    '4184': '2.8',
    '6124HE': '1.8',
    '6128HE': '2.0',
    '6132HE': '2.2',
    '6128': '2.0',
    '6134': '2.3',
    '6136': '2.4',
    '6140': '2.6',
    '6164HE': '1.7',
    '6166HE': '1.8',
    '6168': '1.9',
    '6172': '2.1',
    '6174': '2.2',
    '6176': '2.3',
    '6176SE': '2.3',
    '6180SE': '2.5',
    '3250': '2.5',
    '3260': '2.7',
    '3280': '2.4',
    '4226': '2.7',
    '4228': '2.8',
    '4230': '2.9',
    '4234': '3.1',
    '4238': '3.3',
    '4240': '3.4',
    '4256': '1.6',
    '4274': '2.5',
    '4276': '2.6',
    '4280': '2.8',
    '4284': '3.0',
    '6204': '3.3',
    '6212': '2.6',
    '6220': '3.0',
    '6234': '2.4',
    '6238': '2.6',
    '6262HE': '1.6',
    '6272': '2.1',
    '6274': '2.2',
    '6276': '2.3',
    '6278': '2.4',
    '6282SE': '2.6',
    '6284SE': '2.7',
    '6308': '3.5',
    '6320': '2.8',
    '6328': '3.2',
    '6338P': '2.3',
    '6344': '2.6',
    '6348': '2.8',
    '6366': '1.8',
    '6370P': '2.0',
    '6376': '2.3',
    '6378': '2.4',
    '6380': '2.5',
    '6386': '2.8',
    'FX|4100': '3.6',
    'FX|4120': '3.9',
    'FX|4130': '3.8',
    'FX|4150': '3.8',
    'FX|4170': '4.2',
    'FX|6100': '3.3',
    'FX|6120': '3.6',
    'FX|6130': '3.6',
    'FX|6200': '3.8',
    'FX|8100': '2.8',
    'FX|8120': '3.1',
    'FX|8140': '3.2',
    'FX|8150': '3.6',
    'FX|8170': '3.9',
    'FX|4300': '3.8',
    'FX|4320': '4.0',
    'FX|4350': '4.2',
    'FX|6300': '3.5',
    'FX|6350': '3.9',
    'FX|8300': '3.3',
    'FX|8310': '3.4',
    'FX|8320': '3.5',
    'FX|8350': '4.0',
    'FX|8370': '4.0',
    'FX|9370': '4.4',
    'FX|9590': '4.7',
    'FX|8320E': '3.2',
    'FX|8370E': '3.3',
    '1950X': '3.4',
    '1920X': '3.5',
    '1920': '3.2',
    '1900X': '3.8',
    '1800X': '3.6',
    '1700X': '3.4',
    'Pro 1700X': '3.5',
    '1700': '3.0',
    'Pro 1700': '3.0',
    '1600X': '3.6',
    '1600': '3.2',
    'Pro 1600': '3.2',
    '1500X': '3.5',
    'Pro 1500': '3.5',
    '1400': '3.2',
    '1300X': '3.5',
    'Pro 1300': '3.5',
    '1200': '3.1',
    'Pro 1200': '3.1',
    '2200U': '2.5',
    '2300U': '2.0',
    'Pro 2300U': '2.0',
    '2500U': '2.0',
    'Pro 2500U': '2.2',
    '2700U': '2.0',
    'Pro 2700U': '2.2',
    '2600H': '3.2',
    '2800H': '3.3',
    '7601': '2.2',
    '7551': '2.0',
    '7501': '2.0',
    '74501': '2.3',
    '7401': '2.0',
    '7351': '2.4',
    '7301': '2.2',
    '7281': '2.1',
    '7251': '2.1',
    '7551P': '2.0',
    '7401P': '2.0',
    '7351P': '2.4',
    '2300X': '3.5',
    '2500X': '3.6',
    '2600': '3.4',
    '2600E': '3.1',
    '2600X': '3.6',
    '2700': '3.2',
    '2700E': '2.8',
    '2700X': '3.7',
    'Pro 2700X': '3.6',
    '2920': '3.5',
    '2950': '3.5',
    '2970WX': '3.0',
    '2990WX': '3.0',
    '3200U': '2.6',
    '3300U': '2.1',
    '3500U': '2.1',
    '3550H': '2.1',
    '3580U': '2.1',
    '3700U': '2.3',
    '3750H': '2.3',
    '3780U': '2.3',
    '3500X': '3.6',
    '3600': '3.6',
    'Pro 3600': '3.6',
    '3600X': '3.8',
    'Pro 3700': '3.6',
    '3700X': '3.6',
    '3800X': '3.9',
    '3900': '3.1',
    'Pro 3900': '3.1',
    '3900X': '3.8',
    '3950X': '3.5',
    '3960X': '3.8',
    '3970X': '3.7',
    '7232P': '3.1',
    '7302P': '3.0',
    '7402P': '2.8',
    '7502P': '2.5',
    '7702P': '2.0',
    '7252': '3.1',
    '7262': '3.2',
    '7272': '2.9',
    '7282': '2.8',
    '7302': '3.0',
    '7352': '2.3',
    '7402': '2.8',
    '7452': '2.35',
    '7502': '2.5',
    '7542': '2.9',
    '7552': '2.2',
    '7642': '2.3',
    '7702': '2.0',
    '7742': '2.25',
    '7H12': '2.6'
  };
  
  const socketTypes = {
    1: 'Other',
    2: 'Unknown',
    3: 'Daughter Board',
    4: 'ZIF Socket',
    5: 'Replacement/Piggy Back',
    6: 'None',
    7: 'LIF Socket',
    8: 'Slot 1',
    9: 'Slot 2',
    10: '370 Pin Socket',
    11: 'Slot A',
    12: 'Slot M',
    13: '423',
    14: 'A (Socket 462)',
    15: '478',
    16: '754',
    17: '940',
    18: '939',
    19: 'mPGA604',
    20: 'LGA771',
    21: 'LGA775',
    22: 'S1',
    23: 'AM2',
    24: 'F (1207)',
    25: 'LGA1366',
    26: 'G34',
    27: 'AM3',
    28: 'C32',
    29: 'LGA1156',
    30: 'LGA1567',
    31: 'PGA988A',
    32: 'BGA1288',
    33: 'rPGA988B',
    34: 'BGA1023',
    35: 'BGA1224',
    36: 'LGA1155',
    37: 'LGA1356',
    38: 'LGA2011',
    39: 'FS1',
    40: 'FS2',
    41: 'FM1',
    42: 'FM2',
    43: 'LGA2011-3',
    44: 'LGA1356-3',
    45: 'LGA1150',
    46: 'BGA1168',
    47: 'BGA1234',
    48: 'BGA1364',
    49: 'AM4',
    50: 'LGA1151',
    51: 'BGA1356',
    52: 'BGA1440',
    53: 'BGA1515',
    54: 'LGA3647-1',
    55: 'SP3',
    56: 'SP3r2',
    57: 'LGA2066',
    58: 'BGA1392',
    59: 'BGA1510',
    60: 'BGA1528'
  };
  
  function cpuBrandManufacturer(res) {
    res.brand = res.brand.replace(/\(R\)+/g, '®').replace(/\s+/g, ' ').trim();
    res.brand = res.brand.replace(/\(TM\)+/g, '™').replace(/\s+/g, ' ').trim();
    res.brand = res.brand.replace(/\(C\)+/g, '©').replace(/\s+/g, ' ').trim();
    res.brand = res.brand.replace(/CPU+/g, '').replace(/\s+/g, ' ').trim();
    res.manufacturer = res.brand.split(' ')[0];
  
    let parts = res.brand.split(' ');
    parts.shift();
    res.brand = parts.join(' ');
    return res;
  }
  
  function getAMDSpeed(brand) {
    let result = '0.00';
    for (let key in AMDBaseFrequencies) {
      if ({}.hasOwnProperty.call(AMDBaseFrequencies, key)) {
        let parts = key.split('|');
        let found = 0;
        parts.forEach(item => {
          if (brand.indexOf(item) > -1) {
            found++;
          }
        });
        if (found === parts.length) {
          result = AMDBaseFrequencies[key];
        }
      }
    }
    return result;
  }
  
  // --------------------------
  // CPU - brand, speed
  
  function getCpu() {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        const UNKNOWN = 'unknown';
        let result = {
          manufacturer: UNKNOWN,
          brand: UNKNOWN,
          vendor: '',
          family: '',
          model: '',
          stepping: '',
          revision: '',
          voltage: '',
          speed: '0.00',
          speedmin: '',
          speedmax: '',
          governor: '',
          cores: util.cores(),
          physicalCores: util.cores(),
          processors: 1,
          socket: '',
          cache: {}
        };
        if (_darwin) {
          exec('sysctl machdep.cpu hw.cpufrequency_max hw.cpufrequency_min hw.packages hw.physicalcpu_max hw.ncpu', function (error, stdout) {
            // if (!error) {
            let lines = stdout.toString().split('\n');
            const modelline = util.getValue(lines, 'machdep.cpu.brand_string');
            const modellineParts = modelline.split('@');
            result.brand = modellineParts[0].trim();
            result.speed = modellineParts[1] ? modellineParts[1].trim() : '0';
            result.speed = parseFloat(result.speed.replace(/GHz+/g, '')).toFixed(2);
            _cpu_speed = result.speed;
            result = cpuBrandManufacturer(result);
            result.speedmin = (util.getValue(lines, 'hw.cpufrequency_min') / 1000000000.0).toFixed(2);
            result.speedmax = (util.getValue(lines, 'hw.cpufrequency_max') / 1000000000.0).toFixed(2);
            result.vendor = util.getValue(lines, 'machdep.cpu.vendor');
            result.family = util.getValue(lines, 'machdep.cpu.family');
            result.model = util.getValue(lines, 'machdep.cpu.model');
            result.stepping = util.getValue(lines, 'machdep.cpu.stepping');
            const countProcessors = util.getValue(lines, 'hw.packages');
            const countCores = util.getValue(lines, 'hw.physicalcpu_max');
            const countThreads = util.getValue(lines, 'hw.ncpu');
            if (countProcessors) {
              result.processors = parseInt(countProcessors) || 1;
            }
            if (countCores && countThreads) {
              result.cores = parseInt(countThreads) || util.cores();
              result.physicalCores = parseInt(countCores) || util.cores();
            }
            // }
            cpuCache().then(res => {
              result.cache = res;
              resolve(result);
            });
          });
        }
        if (_linux) {
          let modelline = '';
          let lines = [];
          if (os.cpus()[0] && os.cpus()[0].model) modelline = os.cpus()[0].model;
          exec('export LC_ALL=C; lscpu; echo -n "Governor: "; cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null; echo; unset LC_ALL', function (error, stdout) {
            if (!error) {
              lines = stdout.toString().split('\n');
            }
            modelline = util.getValue(lines, 'model name') || modelline;
            const modellineParts = modelline.split('@');
            result.brand = modellineParts[0].trim();
            result.speed = modellineParts[1] ? parseFloat(modellineParts[1].trim()).toFixed(2) : '0.00';
            if (result.speed === '0.00' && (result.brand.indexOf('AMD') > -1 || result.brand.toLowerCase().indexOf('ryzen') > -1)) {
              result.speed = getAMDSpeed(result.brand);
            }
            if (result.speed === '0.00') {
              let current = getCpuCurrentSpeedSync();
              if (current.avg !== 0) result.speed = current.avg.toFixed(2);
            }
            _cpu_speed = result.speed;
            result.speedmin = Math.round(parseFloat(util.getValue(lines, 'cpu min mhz').replace(/,/g, '.')) / 10.0) / 100;
            result.speedmin = result.speedmin ? parseFloat(result.speedmin).toFixed(2) : '';
            result.speedmax = Math.round(parseFloat(util.getValue(lines, 'cpu max mhz').replace(/,/g, '.')) / 10.0) / 100;
            result.speedmax = result.speedmax ? parseFloat(result.speedmax).toFixed(2) : '';
  
            result = cpuBrandManufacturer(result);
            result.vendor = util.getValue(lines, 'vendor id');
            // if (!result.vendor) { result.vendor = util.getValue(lines, 'anbieterkennung'); }
  
            result.family = util.getValue(lines, 'cpu family');
            // if (!result.family) { result.family = util.getValue(lines, 'prozessorfamilie'); }
            result.model = util.getValue(lines, 'model:');
            // if (!result.model) { result.model = util.getValue(lines, 'modell:'); }
            result.stepping = util.getValue(lines, 'stepping');
            result.revision = util.getValue(lines, 'cpu revision');
            result.cache.l1d = util.getValue(lines, 'l1d cache');
            if (result.cache.l1d) { result.cache.l1d = parseInt(result.cache.l1d) * (result.cache.l1d.indexOf('K') !== -1 ? 1024 : 1); }
            result.cache.l1i = util.getValue(lines, 'l1i cache');
            if (result.cache.l1i) { result.cache.l1i = parseInt(result.cache.l1i) * (result.cache.l1i.indexOf('K') !== -1 ? 1024 : 1); }
            result.cache.l2 = util.getValue(lines, 'l2 cache');
            if (result.cache.l2) { result.cache.l2 = parseInt(result.cache.l2) * (result.cache.l2.indexOf('K') !== -1 ? 1024 : 1); }
            result.cache.l3 = util.getValue(lines, 'l3 cache');
            if (result.cache.l3) { result.cache.l3 = parseInt(result.cache.l3) * (result.cache.l3.indexOf('K') !== -1 ? 1024 : 1); }
  
            const threadsPerCore = util.getValue(lines, 'thread(s) per core') || '1';
            // const coresPerSocketInt = parseInt(util.getValue(lines, 'cores(s) per socket') || '1', 10);
            const processors = util.getValue(lines, 'socket(s)') || '1';
            let threadsPerCoreInt = parseInt(threadsPerCore, 10);
            let processorsInt = parseInt(processors, 10);
            result.physicalCores = result.cores / threadsPerCoreInt;
            result.processors = processorsInt;
            result.governor = util.getValue(lines, 'governor') || '';
  
            // Test Raspberry
            if (result.vendor === 'ARM') {
              const linesRpi = fs.readFileSync('/proc/cpuinfo').toString().split('\n');
              const rPIRevision = util.decodePiCpuinfo(linesRpi);
              if (rPIRevision.model.toLowerCase().indexOf('raspberry') >= 0) {
                result.family = result.manufacturer;
                result.manufacturer = rPIRevision.manufacturer;
                result.brand = rPIRevision.processor;
                result.revision = rPIRevision.revisionCode;
                result.socket = 'SOC';
              }
            }
  
            // socket type
            let lines2 = [];
            exec('export LC_ALL=C; dmidecode –t 4 2>/dev/null | grep "Upgrade: Socket"; unset LC_ALL', function (error2, stdout2) {
              lines2 = stdout2.toString().split('\n');
              if (lines2 && lines2.length) {
                result.socket = util.getValue(lines2, 'Upgrade').replace('Socket', '').trim() || result.socket;
              }
              resolve(result);
            });
          });
        }
        if (_freebsd || _openbsd || _netbsd) {
          let modelline = '';
          let lines = [];
          if (os.cpus()[0] && os.cpus()[0].model) modelline = os.cpus()[0].model;
          exec('export LC_ALL=C; dmidecode -t 4; dmidecode -t 7 unset LC_ALL', function (error, stdout) {
            let cache = [];
            if (!error) {
              const data = stdout.toString().split('# dmidecode');
              const processor = data.length > 1 ? data[1] : '';
              cache = data.length > 2 ? data[2].split('Cache Information') : [];
  
              lines = processor.split('\n');
            }
            result.brand = modelline.split('@')[0].trim();
            result.speed = modelline.split('@')[1] ? parseFloat(modelline.split('@')[1].trim()).toFixed(2) : '0.00';
            if (result.speed === '0.00' && (result.brand.indexOf('AMD') > -1 || result.brand.toLowerCase().indexOf('ryzen') > -1)) {
              result.speed = getAMDSpeed(result.brand);
            }
            if (result.speed === '0.00') {
              let current = getCpuCurrentSpeedSync();
              if (current.avg !== 0) result.speed = current.avg.toFixed(2);
            }
            _cpu_speed = result.speed;
            result.speedmin = '';
            result.speedmax = Math.round(parseFloat(util.getValue(lines, 'max speed').replace(/Mhz/g, '')) / 10.0) / 100;
            result.speedmax = result.speedmax ? parseFloat(result.speedmax).toFixed(2) : '';
  
            result = cpuBrandManufacturer(result);
            result.vendor = util.getValue(lines, 'manufacturer');
            let sig = util.getValue(lines, 'signature');
            sig = sig.split(',');
            for (var i = 0; i < sig.length; i++) {
              sig[i] = sig[i].trim();
            }
            result.family = util.getValue(sig, 'Family', ' ', true);
            result.model = util.getValue(sig, 'Model', ' ', true);
            result.stepping = util.getValue(sig, 'Stepping', ' ', true);
            result.revision = '';
            const voltage = parseFloat(util.getValue(lines, 'voltage'));
            result.voltage = isNaN(voltage) ? '' : voltage.toFixed(2);
            for (let i = 0; i < cache.length; i++) {
              lines = cache[i].split('\n');
              let cacheType = util.getValue(lines, 'Socket Designation').toLowerCase().replace(' ', '-').split('-');
              cacheType = cacheType.length ? cacheType[0] : '';
              const sizeParts = util.getValue(lines, 'Installed Size').split(' ');
              let size = parseInt(sizeParts[0], 10);
              const unit = sizeParts.length > 1 ? sizeParts[1] : 'kb';
              size = size * (unit === 'kb' ? 1024 : (unit === 'mb' ? 1024 * 1024 : (unit === 'gb' ? 1024 * 1024 * 1024 : 1)));
              if (cacheType) {
                if (cacheType === 'l1') {
                  result.cache[cacheType + 'd'] = size / 2;
                  result.cache[cacheType + 'i'] = size / 2;
                } else {
                  result.cache[cacheType] = size;
                }
              }
            }
            // socket type
            result.socket = util.getValue(lines, 'Upgrade').replace('Socket', '').trim();
            // # threads / # cores
            const threadCount = util.getValue(lines, 'thread count').trim();
            const coreCount = util.getValue(lines, 'core count').trim();
            if (coreCount && threadCount) {
              result.cores = threadCount;
              result.physicalCores = coreCount;
            }
            resolve(result);
          });
        }
        if (_sunos) {
          resolve(result);
        }
        if (_windows) {
          try {
            util.wmic('cpu get /value').then((stdout, error) => {
              if (!error) {
                let lines = stdout.split('\r\n');
                let name = util.getValue(lines, 'name', '=') || '';
                if (name.indexOf('@') >= 0) {
                  result.brand = name.split('@')[0].trim();
                  result.speed = name.split('@')[1] ? parseFloat(name.split('@')[1].trim()).toFixed(2) : '0.00';
                  _cpu_speed = result.speed;
                } else {
                  result.brand = name.trim();
                  result.speed = '0.00';
                }
                result = cpuBrandManufacturer(result);
                result.revision = util.getValue(lines, 'revision', '=');
                result.cache.l1d = 0;
                result.cache.l1i = 0;
                result.cache.l2 = util.getValue(lines, 'l2cachesize', '=');
                result.cache.l3 = util.getValue(lines, 'l3cachesize', '=');
                if (result.cache.l2) { result.cache.l2 = parseInt(result.cache.l2, 10) * 1024; }
                if (result.cache.l3) { result.cache.l3 = parseInt(result.cache.l3, 10) * 1024; }
                result.vendor = util.getValue(lines, 'manufacturer', '=');
                result.speedmax = Math.round(parseFloat(util.getValue(lines, 'maxclockspeed', '=').replace(/,/g, '.')) / 10.0) / 100;
                result.speedmax = result.speedmax ? parseFloat(result.speedmax).toFixed(2) : '';
                if (result.speed === '0.00' && (result.brand.indexOf('AMD') > -1 || result.brand.toLowerCase().indexOf('ryzen') > -1)) {
                  result.speed = getAMDSpeed(result.brand);
                }
                if (result.speed === '0.00') {
                  result.speed = result.speedmax;
                }
  
                let description = util.getValue(lines, 'description', '=').split(' ');
                for (let i = 0; i < description.length; i++) {
                  if (description[i].toLowerCase().startsWith('family') && (i + 1) < description.length && description[i + 1]) {
                    result.family = description[i + 1];
                  }
                  if (description[i].toLowerCase().startsWith('model') && (i + 1) < description.length && description[i + 1]) {
                    result.model = description[i + 1];
                  }
                  if (description[i].toLowerCase().startsWith('stepping') && (i + 1) < description.length && description[i + 1]) {
                    result.stepping = description[i + 1];
                  }
                }
                // socket type
                const socketId = util.getValue(lines, 'UpgradeMethod', '=');
                if (socketTypes[socketId]) {
                  result.socket = socketTypes[socketId];
                }
                // # threads / # cores
                const countProcessors = util.countLines(lines, 'Caption');
                const countThreads = util.getValue(lines, 'NumberOfLogicalProcessors', '=');
                const countCores = util.getValue(lines, 'NumberOfCores', '=');
                if (countProcessors) {
                  result.processors = parseInt(countProcessors) || 1;
                }
                if (countCores && countThreads) {
                  result.cores = parseInt(countThreads) || util.cores();
                  result.physicalCores = parseInt(countCores) || util.cores();
                }
                if (countProcessors > 1) {
                  result.cores = result.cores * countProcessors;
                  result.physicalCores = result.physicalCores * countProcessors;
                }
              }
              util.wmic('path Win32_CacheMemory get CacheType,InstalledSize,Purpose').then((stdout, error) => {
                if (!error) {
                  let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
                  lines.forEach(function (line) {
                    if (line !== '') {
                      line = line.trim().split(/\s\s+/);
                      // L1 Instructions
                      if (line[2] === 'L1 Cache' && line[0] === '3') {
                        result.cache.l1i = parseInt(line[1], 10);
                      }
                      // L1 Data
                      if (line[2] === 'L1 Cache' && line[0] === '4') {
                        result.cache.l1d = parseInt(line[1], 10);
                      }
                    }
                  });
                }
                resolve(result);
              });
            });
          } catch (e) {
            resolve(result);
          }
        }
      });
    });
  }
  
  // --------------------------
  // CPU - Processor Data
  
  function cpu(callback) {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        getCpu().then(result => {
          if (callback) { callback(result); }
          resolve(result);
        });
      });
    });
  }
  
  exports.cpu = cpu;
  
  // --------------------------
  // CPU - current speed - in GHz
  
  function getCpuCurrentSpeedSync() {
  
    let cpus = os.cpus();
    let minFreq = 999999999;
    let maxFreq = 0;
    let avgFreq = 0;
    let cores = [];
  
    if (cpus && cpus.length) {
      for (let i in cpus) {
        if ({}.hasOwnProperty.call(cpus, i)) {
          avgFreq = avgFreq + cpus[i].speed;
          if (cpus[i].speed > maxFreq) maxFreq = cpus[i].speed;
          if (cpus[i].speed < minFreq) minFreq = cpus[i].speed;
        }
        cores.push(parseFloat(((cpus[i].speed + 1) / 1000).toFixed(2)));
      }
      avgFreq = avgFreq / cpus.length;
      return {
        min: parseFloat(((minFreq + 1) / 1000).toFixed(2)),
        max: parseFloat(((maxFreq + 1) / 1000).toFixed(2)),
        avg: parseFloat(((avgFreq + 1) / 1000).toFixed(2)),
        cores: cores
      };
    } else {
      return {
        min: 0,
        max: 0,
        avg: 0,
        cores: cores
      };
    }
  }
  
  function cpuCurrentspeed(callback) {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        let result = getCpuCurrentSpeedSync();
        if (result.avg === 0 && _cpu_speed !== '0.00') {
          const currCpuSpeed = parseFloat(_cpu_speed);
          result = {
            min: currCpuSpeed,
            max: currCpuSpeed,
            avg: currCpuSpeed,
            cores: []
          };
        }
        if (callback) { callback(result); }
        resolve(result);
      });
    });
  }
  
  exports.cpuCurrentspeed = cpuCurrentspeed;
  
  // --------------------------
  // CPU - temperature
  // if sensors are installed
  
  function cpuTemperature(callback) {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        let result = {
          main: -1.0,
          cores: [],
          max: -1.0
        };
        if (_linux) {
          const cmd = 'for mon in /sys/class/hwmon/hwmon*; do for label in "$mon"/temp*_label; do if [ -f $label ]; then value=$(echo $label | rev | cut -c 7- | rev)_input; if [ -f "$value" ]; then echo $(cat "$label")___$(cat "$value");  fi; fi; done; done;';
          try {
            exec(cmd, function (error, stdout) {
              let lines = stdout.toString().split('\n');
              lines.forEach(line => {
                const parts = line.split('___');
                const label = parts[0];
                const value = parts.length > 1 && parts[1] ? parts[1] : '0';
                if (value && (label === undefined || (label && label.toLowerCase().startsWith('core')))) {
                  result.cores.push(Math.round(parseInt(value, 10) / 100) / 10);
                } else if (value && label && result.main === -1) {
                  result.main = Math.round(parseInt(value, 10) / 100) / 10;
                }
              });
  
              if (result.cores.length > 0) {
                if (result.main === -1) {
                  result.main = Math.round(result.cores.reduce((a, b) => a + b, 0) / result.cores.length);
                }
                let maxtmp = Math.max.apply(Math, result.cores);
                result.max = (maxtmp > result.main) ? maxtmp : result.main;
              }
              if (result.main !== -1) {
                if (result.max === -1) {
                  result.max = result.main;
                }
                if (callback) { callback(result); }
                resolve(result);
                return;
              }
              // }
              exec('sensors', function (error, stdout) {
                if (!error) {
                  let lines = stdout.toString().split('\n');
                  let tdieTemp = -1;
                  lines.forEach(function (line) {
                    let regex = /[+-]([^°]*)/g;
                    let temps = line.match(regex);
                    let firstPart = line.split(':')[0].toUpperCase();
                    if (firstPart.indexOf('PHYSICAL') !== -1 || firstPart.indexOf('PACKAGE') !== -1) {
                      result.main = parseFloat(temps);
                    }
                    if (firstPart.indexOf('CORE ') !== -1) {
                      result.cores.push(parseFloat(temps));
                    }
                    if (firstPart.indexOf('TDIE') !== -1 && tdieTemp === -1) {
                      tdieTemp = parseFloat(temps);
                    }
                  });
                  if (result.cores.length > 0) {
                    if (result.main === -1) {
                      result.main = Math.round(result.cores.reduce((a, b) => a + b, 0) / result.cores.length);
                    }
                    let maxtmp = Math.max.apply(Math, result.cores);
                    result.max = (maxtmp > result.main) ? maxtmp : result.main;
                  } else {
                    if (result.main === -1 && tdieTemp !== -1) {
                      result.main = tdieTemp;
                      result.max = tdieTemp;
                    }
                  }
                  if (result.main !== -1.0 || result.max !== -1.0) {
                    if (callback) { callback(result); }
                    resolve(result);
                    return;
                  }
                }
                fs.stat('/sys/class/thermal/thermal_zone0/temp', function (err) {
                  if (err === null) {
                    fs.readFile('/sys/class/thermal/thermal_zone0/temp', function (error, stdout) {
                      if (!error) {
                        let lines = stdout.toString().split('\n');
                        if (lines.length > 0) {
                          result.main = parseFloat(lines[0]) / 1000.0;
                          result.max = result.main;
                        }
                      }
                      if (callback) { callback(result); }
                      resolve(result);
                    });
                  } else {
                    exec('/opt/vc/bin/vcgencmd measure_temp', function (error, stdout) {
                      if (!error) {
                        let lines = stdout.toString().split('\n');
                        if (lines.length > 0 && lines[0].indexOf('=')) {
                          result.main = parseFloat(lines[0].split('=')[1]);
                          result.max = result.main;
                        }
                      }
                      if (callback) { callback(result); }
                      resolve(result);
                    });
                  }
                });
              });
            });
          } catch (er) {
            if (callback) { callback(result); }
            resolve(result);
          }
        }
        if (_freebsd || _openbsd || _netbsd) {
          exec('sysctl dev.cpu | grep temp', function (error, stdout) {
            if (!error) {
              let lines = stdout.toString().split('\n');
              let sum = 0;
              lines.forEach(function (line) {
                const parts = line.split(':');
                if (parts.length > 1) {
                  const temp = parseFloat(parts[1].replace(',', '.'));
                  if (temp > result.max) result.max = temp;
                  sum = sum + temp;
                  result.cores.push(temp);
                }
              });
              if (result.cores.length) {
                result.main = Math.round(sum / result.cores.length * 100) / 100;
              }
            }
            if (callback) { callback(result); }
            resolve(result);
          });
        }
        if (_darwin) {
          let osxTemp = null;
          try {
            osxTemp = require('osx-temperature-sensor');
          } catch (er) {
            osxTemp = null;
          }
          if (osxTemp) {
            result = osxTemp.cpuTemperature();
          }
  
          if (callback) { callback(result); }
          resolve(result);
        }
        if (_sunos) {
          if (callback) { callback(result); }
          resolve(result);
        }
        if (_windows) {
          try {
            util.wmic('/namespace:\\\\root\\wmi PATH MSAcpi_ThermalZoneTemperature get CurrentTemperature').then((stdout, error) => {
              if (!error) {
                let sum = 0;
                let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
                lines.forEach(function (line) {
                  let value = (parseInt(line, 10) - 2732) / 10;
                  sum = sum + value;
                  if (value > result.max) result.max = value;
                  result.cores.push(value);
                });
                if (result.cores.length) {
                  result.main = sum / result.cores.length;
                }
              }
              if (callback) { callback(result); }
              resolve(result);
            });
          } catch (e) {
            if (callback) { callback(result); }
            resolve(result);
          }
        }
      });
    });
  }
  
  exports.cpuTemperature = cpuTemperature;
  
  // --------------------------
  // CPU Flags
  
  function cpuFlags(callback) {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        let result = '';
        if (_windows) {
          try {
            exec('reg query "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0" /v FeatureSet', util.execOptsWin, function (error, stdout) {
              if (!error) {
                let flag_hex = stdout.split('0x').pop().trim();
                let flag_bin_unpadded = parseInt(flag_hex, 16).toString(2);
                let flag_bin = '0'.repeat(32 - flag_bin_unpadded.length) + flag_bin_unpadded;
                // empty flags are the reserved fields in the CPUID feature bit list
                // as found on wikipedia:
                // https://en.wikipedia.org/wiki/CPUID
                let all_flags = [
                  'fpu', 'vme', 'de', 'pse', 'tsc', 'msr', 'pae', 'mce', 'cx8', 'apic',
                  '', 'sep', 'mtrr', 'pge', 'mca', 'cmov', 'pat', 'pse-36', 'psn', 'clfsh',
                  '', 'ds', 'acpi', 'mmx', 'fxsr', 'sse', 'sse2', 'ss', 'htt', 'tm', 'ia64', 'pbe'
                ];
                for (let f = 0; f < all_flags.length; f++) {
                  if (flag_bin[f] === '1' && all_flags[f] !== '') {
                    result += ' ' + all_flags[f];
                  }
                }
                result = result.trim();
              }
              if (callback) { callback(result); }
              resolve(result);
            });
          } catch (e) {
            if (callback) { callback(result); }
            resolve(result);
          }
        }
        if (_linux) {
          try {
  
            exec('export LC_ALL=C; lscpu; unset LC_ALL', function (error, stdout) {
              if (!error) {
                let lines = stdout.toString().split('\n');
                lines.forEach(function (line) {
                  if (line.split(':')[0].toUpperCase().indexOf('FLAGS') !== -1) {
                    result = line.split(':')[1].trim().toLowerCase();
                  }
                });
              }
              if (!result) {
                fs.readFile('/proc/cpuinfo', function (error, stdout) {
                  if (!error) {
                    let lines = stdout.toString().split('\n');
                    result = util.getValue(lines, 'features', ':', true).toLowerCase();
                  }
                  if (callback) { callback(result); }
                  resolve(result);
                });
              } else {
                if (callback) { callback(result); }
                resolve(result);
              }
            });
          } catch (e) {
            if (callback) { callback(result); }
            resolve(result);
          }
        }
        if (_freebsd || _openbsd || _netbsd) {
          exec('export LC_ALL=C; dmidecode -t 4 2>/dev/null; unset LC_ALL', function (error, stdout) {
            let flags = [];
            if (!error) {
              let parts = stdout.toString().split('\tFlags:');
              const lines = parts.length > 1 ? parts[1].split('\tVersion:')[0].split['\n'] : [];
              lines.forEach(function (line) {
                let flag = (line.indexOf('(') ? line.split('(')[0].toLowerCase() : '').trim().replace(/\t/g, '');
                if (flag) {
                  flags.push(flag);
                }
              });
            }
            result = flags.join(' ').trim();
            if (callback) { callback(result); }
            resolve(result);
          });
        }
        if (_darwin) {
          exec('sysctl machdep.cpu.features', function (error, stdout) {
            if (!error) {
              let lines = stdout.toString().split('\n');
              if (lines.length > 0 && lines[0].indexOf('machdep.cpu.features:') !== -1) {
                result = lines[0].split(':')[1].trim().toLowerCase();
              }
            }
            if (callback) { callback(result); }
            resolve(result);
          });
        }
        if (_sunos) {
          if (callback) { callback(result); }
          resolve(result);
        }
      });
    });
  }
  
  exports.cpuFlags = cpuFlags;
  
  // --------------------------
  // CPU Cache
  
  function cpuCache(callback) {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
  
        let result = {
          l1d: -1,
          l1i: -1,
          l2: -1,
          l3: -1,
        };
        if (_linux) {
          try {
            exec('export LC_ALL=C; lscpu; unset LC_ALL', function (error, stdout) {
              if (!error) {
                let lines = stdout.toString().split('\n');
                lines.forEach(function (line) {
                  let parts = line.split(':');
                  if (parts[0].toUpperCase().indexOf('L1D CACHE') !== -1) {
                    result.l1d = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                  }
                  if (parts[0].toUpperCase().indexOf('L1I CACHE') !== -1) {
                    result.l1i = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                  }
                  if (parts[0].toUpperCase().indexOf('L2 CACHE') !== -1) {
                    result.l2 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                  }
                  if (parts[0].toUpperCase().indexOf('L3 CACHE') !== -1) {
                    result.l3 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                  }
                });
              }
              if (callback) { callback(result); }
              resolve(result);
            });
          } catch (e) {
            if (callback) { callback(result); }
            resolve(result);
          }
        }
        if (_freebsd || _openbsd || _netbsd) {
          exec('export LC_ALL=C; dmidecode -t 7 2>/dev/null; unset LC_ALL', function (error, stdout) {
            let cache = [];
            if (!error) {
              const data = stdout.toString();
              cache = data.split('Cache Information');
              cache.shift();
            }
            for (let i = 0; i < cache.length; i++) {
              const lines = cache[i].split('\n');
              let cacheType = util.getValue(lines, 'Socket Designation').toLowerCase().replace(' ', '-').split('-');
              cacheType = cacheType.length ? cacheType[0] : '';
              const sizeParts = util.getValue(lines, 'Installed Size').split(' ');
              let size = parseInt(sizeParts[0], 10);
              const unit = sizeParts.length > 1 ? sizeParts[1] : 'kb';
              size = size * (unit === 'kb' ? 1024 : (unit === 'mb' ? 1024 * 1024 : (unit === 'gb' ? 1024 * 1024 * 1024 : 1)));
              if (cacheType) {
                if (cacheType === 'l1') {
                  result.cache[cacheType + 'd'] = size / 2;
                  result.cache[cacheType + 'i'] = size / 2;
                } else {
                  result.cache[cacheType] = size;
                }
              }
            }
            if (callback) { callback(result); }
            resolve(result);
          });
        }
        if (_darwin) {
          exec('sysctl hw.l1icachesize hw.l1dcachesize hw.l2cachesize hw.l3cachesize', function (error, stdout) {
            if (!error) {
              let lines = stdout.toString().split('\n');
              lines.forEach(function (line) {
                let parts = line.split(':');
                if (parts[0].toLowerCase().indexOf('hw.l1icachesize') !== -1) {
                  result.l1d = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                }
                if (parts[0].toLowerCase().indexOf('hw.l1dcachesize') !== -1) {
                  result.l1i = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                }
                if (parts[0].toLowerCase().indexOf('hw.l2cachesize') !== -1) {
                  result.l2 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                }
                if (parts[0].toLowerCase().indexOf('hw.l3cachesize') !== -1) {
                  result.l3 = parseInt(parts[1].trim()) * (parts[1].indexOf('K') !== -1 ? 1024 : 1);
                }
              });
            }
            if (callback) { callback(result); }
            resolve(result);
          });
        }
        if (_sunos) {
          if (callback) { callback(result); }
          resolve(result);
        }
        if (_windows) {
          try {
            util.wmic('cpu get l2cachesize, l3cachesize /value').then((stdout, error) => {
              if (!error) {
                let lines = stdout.split('\r\n');
                result.l1d = 0;
                result.l1i = 0;
                result.l2 = util.getValue(lines, 'l2cachesize', '=');
                result.l3 = util.getValue(lines, 'l3cachesize', '=');
                if (result.l2) { result.l2 = parseInt(result.l2, 10) * 1024; }
                if (result.l3) { result.l3 = parseInt(result.l3, 10) * 1024; }
              }
              util.wmic('path Win32_CacheMemory get CacheType,InstalledSize,Purpose').then((stdout, error) => {
                if (!error) {
                  let lines = stdout.split('\r\n').filter(line => line.trim() !== '').filter((line, idx) => idx > 0);
                  lines.forEach(function (line) {
                    if (line !== '') {
                      line = line.trim().split(/\s\s+/);
                      // L1 Instructions
                      if (line[2] === 'L1 Cache' && line[0] === '3') {
                        result.l1i = parseInt(line[1], 10);
                      }
                      // L1 Data
                      if (line[2] === 'L1 Cache' && line[0] === '4') {
                        result.l1d = parseInt(line[1], 10);
                      }
                    }
                  });
                }
                if (callback) { callback(result); }
                resolve(result);
              });
            });
          } catch (e) {
            if (callback) { callback(result); }
            resolve(result);
          }
        }
      });
    });
  }
  
  exports.cpuCache = cpuCache;
  
  // --------------------------
  // CPU - current load - in %
  
  function getLoad() {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        let loads = os.loadavg().map(function (x) { return x / util.cores(); });
        let avgload = parseFloat((Math.max.apply(Math, loads)).toFixed(2));
        let result = {};
  
        let now = Date.now() - _current_cpu.ms;
        if (now >= 200) {
          _current_cpu.ms = Date.now();
          const cpus = os.cpus();
          let totalUser = 0;
          let totalSystem = 0;
          let totalNice = 0;
          let totalIrq = 0;
          let totalIdle = 0;
          let cores = [];
          _corecount = (cpus && cpus.length) ? cpus.length : 0;
  
          for (let i = 0; i < _corecount; i++) {
            const cpu = cpus[i].times;
            totalUser += cpu.user;
            totalSystem += cpu.sys;
            totalNice += cpu.nice;
            totalIdle += cpu.idle;
            totalIrq += cpu.irq;
            let tmp_tick = (_cpus && _cpus[i] && _cpus[i].totalTick ? _cpus[i].totalTick : 0);
            let tmp_load = (_cpus && _cpus[i] && _cpus[i].totalLoad ? _cpus[i].totalLoad : 0);
            let tmp_user = (_cpus && _cpus[i] && _cpus[i].user ? _cpus[i].user : 0);
            let tmp_system = (_cpus && _cpus[i] && _cpus[i].sys ? _cpus[i].sys : 0);
            let tmp_nice = (_cpus && _cpus[i] && _cpus[i].nice ? _cpus[i].nice : 0);
            let tmp_idle = (_cpus && _cpus[i] && _cpus[i].idle ? _cpus[i].idle : 0);
            let tmp_irq = (_cpus && _cpus[i] && _cpus[i].irq ? _cpus[i].irq : 0);
            _cpus[i] = cpu;
            _cpus[i].totalTick = _cpus[i].user + _cpus[i].sys + _cpus[i].nice + _cpus[i].irq + _cpus[i].idle;
            _cpus[i].totalLoad = _cpus[i].user + _cpus[i].sys + _cpus[i].nice + _cpus[i].irq;
            _cpus[i].currentTick = _cpus[i].totalTick - tmp_tick;
            _cpus[i].load = (_cpus[i].totalLoad - tmp_load);
            _cpus[i].load_user = (_cpus[i].user - tmp_user);
            _cpus[i].load_system = (_cpus[i].sys - tmp_system);
            _cpus[i].load_nice = (_cpus[i].nice - tmp_nice);
            _cpus[i].load_idle = (_cpus[i].idle - tmp_idle);
            _cpus[i].load_irq = (_cpus[i].irq - tmp_irq);
            cores[i] = {};
            cores[i].load = _cpus[i].load / _cpus[i].currentTick * 100;
            cores[i].load_user = _cpus[i].load_user / _cpus[i].currentTick * 100;
            cores[i].load_system = _cpus[i].load_system / _cpus[i].currentTick * 100;
            cores[i].load_nice = _cpus[i].load_nice / _cpus[i].currentTick * 100;
            cores[i].load_idle = _cpus[i].load_idle / _cpus[i].currentTick * 100;
            cores[i].load_irq = _cpus[i].load_irq / _cpus[i].currentTick * 100;
            cores[i].raw_load = _cpus[i].load;
            cores[i].raw_load_user = _cpus[i].load_user;
            cores[i].raw_load_system = _cpus[i].load_system;
            cores[i].raw_load_nice = _cpus[i].load_nice;
            cores[i].raw_load_idle = _cpus[i].load_idle;
            cores[i].raw_load_irq = _cpus[i].load_irq;
          }
          let totalTick = totalUser + totalSystem + totalNice + totalIrq + totalIdle;
          let totalLoad = totalUser + totalSystem + totalNice + totalIrq;
          let currentTick = totalTick - _current_cpu.tick;
          result = {
            avgload: avgload,
            currentload: (totalLoad - _current_cpu.load) / currentTick * 100,
            currentload_user: (totalUser - _current_cpu.user) / currentTick * 100,
            currentload_system: (totalSystem - _current_cpu.system) / currentTick * 100,
            currentload_nice: (totalNice - _current_cpu.nice) / currentTick * 100,
            currentload_idle: (totalIdle - _current_cpu.idle) / currentTick * 100,
            currentload_irq: (totalIrq - _current_cpu.irq) / currentTick * 100,
            raw_currentload: (totalLoad - _current_cpu.load),
            raw_currentload_user: (totalUser - _current_cpu.user),
            raw_currentload_system: (totalSystem - _current_cpu.system),
            raw_currentload_nice: (totalNice - _current_cpu.nice),
            raw_currentload_idle: (totalIdle - _current_cpu.idle),
            raw_currentload_irq: (totalIrq - _current_cpu.irq),
            cpus: cores
          };
          _current_cpu = {
            user: totalUser,
            nice: totalNice,
            system: totalSystem,
            idle: totalIdle,
            irq: totalIrq,
            tick: totalTick,
            load: totalLoad,
            ms: _current_cpu.ms,
            currentload: result.currentload,
            currentload_user: result.currentload_user,
            currentload_system: result.currentload_system,
            currentload_nice: result.currentload_nice,
            currentload_idle: result.currentload_idle,
            currentload_irq: result.currentload_irq,
            raw_currentload: result.raw_currentload,
            raw_currentload_user: result.raw_currentload_user,
            raw_currentload_system: result.raw_currentload_system,
            raw_currentload_nice: result.raw_currentload_nice,
            raw_currentload_idle: result.raw_currentload_idle,
            raw_currentload_irq: result.raw_currentload_irq,
          };
        } else {
          let cores = [];
          for (let i = 0; i < _corecount; i++) {
            cores[i] = {};
            cores[i].load = _cpus[i].load / _cpus[i].currentTick * 100;
            cores[i].load_user = _cpus[i].load_user / _cpus[i].currentTick * 100;
            cores[i].load_system = _cpus[i].load_system / _cpus[i].currentTick * 100;
            cores[i].load_nice = _cpus[i].load_nice / _cpus[i].currentTick * 100;
            cores[i].load_idle = _cpus[i].load_idle / _cpus[i].currentTick * 100;
            cores[i].load_irq = _cpus[i].load_irq / _cpus[i].currentTick * 100;
            cores[i].raw_load = _cpus[i].load;
            cores[i].raw_load_user = _cpus[i].load_user;
            cores[i].raw_load_system = _cpus[i].load_system;
            cores[i].raw_load_nice = _cpus[i].load_nice;
            cores[i].raw_load_idle = _cpus[i].load_idle;
            cores[i].raw_load_irq = _cpus[i].load_irq;
          }
          result = {
            avgload: avgload,
            currentload: _current_cpu.currentload,
            currentload_user: _current_cpu.currentload_user,
            currentload_system: _current_cpu.currentload_system,
            currentload_nice: _current_cpu.currentload_nice,
            currentload_idle: _current_cpu.currentload_idle,
            currentload_irq: _current_cpu.currentload_irq,
            raw_currentload: _current_cpu.raw_currentload,
            raw_currentload_user: _current_cpu.raw_currentload_user,
            raw_currentload_system: _current_cpu.raw_currentload_system,
            raw_currentload_nice: _current_cpu.raw_currentload_nice,
            raw_currentload_idle: _current_cpu.raw_currentload_idle,
            raw_currentload_irq: _current_cpu.raw_currentload_irq,
            cpus: cores
          };
        }
        resolve(result);
      });
    });
  }
  
  function currentLoad(callback) {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        getLoad().then(result => {
          if (callback) { callback(result); }
          resolve(result);
        });
      });
    });
  }
  
  exports.currentLoad = currentLoad;
  
  // --------------------------
  // PS - full load
  // since bootup
  
  function getFullLoad() {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
  
        const cpus = os.cpus();
        let totalUser = 0;
        let totalSystem = 0;
        let totalNice = 0;
        let totalIrq = 0;
        let totalIdle = 0;
  
        let result = 0;
  
        if (cpus && cpus.length) {
          for (let i = 0, len = cpus.length; i < len; i++) {
            const cpu = cpus[i].times;
            totalUser += cpu.user;
            totalSystem += cpu.sys;
            totalNice += cpu.nice;
            totalIrq += cpu.irq;
            totalIdle += cpu.idle;
          }
          let totalTicks = totalIdle + totalIrq + totalNice + totalSystem + totalUser;
          result = (totalTicks - totalIdle) / totalTicks * 100.0;
  
        } else {
          result = 0;
        }
        resolve(result);
      });
    });
  }
  
  function fullLoad(callback) {
  
    return new Promise((resolve) => {
      process.nextTick(() => {
        getFullLoad().then(result => {
          if (callback) { callback(result); }
          resolve(result);
        });
      });
    });
  }
  
  exports.fullLoad = fullLoad;
  
  