[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = space\nindent_size = 2\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nend_of_line = lf\n# editorconfig-tools is unable to ignore longs strings or urls\nmax_line_length = null\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "PRs are welcome, please make sure that your changes are well tested\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "#### Environment\n\n- OS:\n- Node version: (`$ node --version`)\n- gtop version: (`$ npm info gtop version`)\n\n#### Description\n\n*A description of the issue*\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Node.js CI\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    branches:\n      - master\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Use Node.js 17.x\n        uses: actions/setup-node@v2\n        with:\n          node-version: '17.x'\n      - name: Install dependencies\n        run: npm ci\n      - name: Lint check\n        run: npm run lint-check\n      - name: Test\n        run: npm test\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Node.js Package\non:\n  release:\n    types: [created]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      # Setup .npmrc file to publish to npm\n      - uses: actions/setup-node@v2\n        with:\n          node-version: '17.x'\n          registry-url: 'https://registry.npmjs.org'\n      - run: npm install\n      - run: npm publish\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Typescript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n"
  },
  {
    "path": ".npmignore",
    "content": ".git*\ntest/\nimg/\nnode_modules/\n*.gif\n*.png\n.github/\nsnap/"
  },
  {
    "path": "CLI.md",
    "content": "GTOP\n=====\n\n> gtop - System monitoring dashboard for terminal\n\n## SYNOPSIS\n\n`gtop`\n\n\n## DESCRIPTION\n\ngtop is a system monitoring dashboard for terminal much like htop, top, etc...\n\n## INTERACTIVE COMMANDS\n\nThe following commands are supported while in gtop:\n\n- `p` sort the process table by Process Id\n- `c` sort the process table by CPU usage\n- `m` sort the process table by Memory usage\n\n\n## Website\n\nhttps://github.com/aksakalli/gtop\n\n## BUGS\n\nPlease report any bugs to https://github.com/aksakalli/gtop.\n\n\n## LICENSE\n\nCopyright (c) 2017, Can Güney Aksakalli (MIT License).\n\n\n## SEE ALSO\n\nnode.js(1),"
  },
  {
    "path": "Dockerfile",
    "content": "FROM node:15-alpine\n\nRUN apk --no-cache add procps\nENV LANG=en_US.utf8 \\\n    TERM=xterm-256color\n\nCOPY lib lib\nCOPY bin bin\nCOPY package.json .\nCOPY package-lock.json .\n\nRUN npm install --production\nENTRYPOINT [\"./bin/gtop\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Can Güney Aksakalli\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# gtop\n\n![screen record](https://raw.githubusercontent.com/aksakalli/gtop/master/img/demo.gif)\n\nSystem monitoring dashboard for terminal.\n\n  [![NPM Version](https://img.shields.io/npm/v/gtop.svg)](https://npmjs.org/package/gtop)\n  [![NPM Downloads](https://img.shields.io/npm/dm/gtop.svg)](https://npmjs.org/package/gtop)\n  [![Snap Status](https://snapcraft.io/gtop/badge.svg)](https://snapcraft.io/gtop)\n  [![Docker Pulls](https://img.shields.io/docker/pulls/aksakalli/gtop)](https://hub.docker.com/r/aksakalli/gtop)\n  [![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/aksakalli/gtop)](https://hub.docker.com/r/aksakalli/gtop/builds)\n\n### Requirements\n\n* Linux / OSX / Windows (partial support)\n* Node.js >= v8\n\n### Installation\n\n```sh\n$ npm install gtop -g\n```\n\n#### Docker\n\nYou need to assign host `net` and `pid` to access the metrics in the host machine.\n\n```sh\n$ docker run --rm -it \\\n    --name gtop \\\n    --net=\"host\" \\\n    --pid=\"host\" \\\n    aksakalli/gtop\n```\n\n### Usage\n\nStart gtop with the `gtop` command\n\n```sh\n$ gtop\n```\n\nTo stop gtop use `q`, or `ctrl+c` in most shell environments.\n\nYou can sort the process table by pressing\n\n* `p`: Process Id\n* `c`: CPU usage\n* `m`: Memory usage\n\n### Troubleshooting\n\nIf you see question marks or other different characters, try to run it with these environment variables:\n\n```sh\n$ LANG=en_US.utf8 TERM=xterm-256color gtop\n```\n\n## License\n\nReleased under [the MIT license](LICENSE).\n"
  },
  {
    "path": "bin/gtop",
    "content": "#!/usr/bin/env node\n\nrequire('../lib/gtop').init()\n"
  },
  {
    "path": "index.js",
    "content": "module.exports = require('./lib/gtop');\n"
  },
  {
    "path": "lib/gtop.js",
    "content": "var blessed = require('blessed'),\n  contrib = require('blessed-contrib'),\n  monitor = require('./monitor');\n\nvar screen = blessed.screen();\nvar grid = new contrib.grid({\n  rows: 12,\n  cols: 12,\n  screen: screen,\n});\n\nvar cpuLine = grid.set(0, 0, 4, 12, contrib.line, {\n  showNthLabel: 5,\n  maxY: 100,\n  label: 'CPU History',\n  showLegend: true,\n});\n\nvar memLine = grid.set(4, 0, 4, 8, contrib.line, {\n  showNthLabel: 5,\n  maxY: 100,\n  label: 'Memory and Swap History',\n  showLegend: true,\n  legend: {\n    width: 10,\n  },\n});\n\nvar memDonut = grid.set(4, 8, 2, 4, contrib.donut, {\n  radius: 8,\n  arcWidth: 3,\n  yPadding: 2,\n  remainColor: 'black',\n  label: 'Memory',\n});\n\nvar swapDonut = grid.set(6, 8, 2, 4, contrib.donut, {\n  radius: 8,\n  arcWidth: 3,\n  yPadding: 2,\n  remainColor: 'black',\n  label: 'Swap',\n});\n\nvar netSpark = grid.set(8, 0, 2, 6, contrib.sparkline, {\n  label: 'Network History',\n  tags: true,\n  style: {\n    fg: 'blue',\n  },\n});\n\nvar diskDonut = grid.set(10, 0, 2, 6, contrib.donut, {\n  radius: 8,\n  arcWidth: 3,\n  yPadding: 2,\n  remainColor: 'black',\n  label: 'Disk usage',\n});\n\nvar procTable = grid.set(8, 6, 4, 6, contrib.table, {\n  keys: true,\n  label: 'Processes',\n  columnSpacing: 1,\n  columnWidth: [7, 24, 7, 7],\n});\n\nprocTable.focus();\n\nscreen.render();\nscreen.on('resize', function(a) {\n  cpuLine.emit('attach');\n  memLine.emit('attach');\n  memDonut.emit('attach');\n  swapDonut.emit('attach');\n  netSpark.emit('attach');\n  diskDonut.emit('attach');\n  procTable.emit('attach');\n});\n\nscreen.key(['escape', 'q', 'C-c'], function(ch, key) {\n  return process.exit(0);\n});\n\nfunction init() {\n  new monitor.Cpu(cpuLine); //no Windows support\n  new monitor.Mem(memLine, memDonut, swapDonut);\n  new monitor.Net(netSpark);\n  new monitor.Disk(diskDonut);\n  new monitor.Proc(procTable); // no Windows support\n}\n\nprocess.on('uncaughtException', function(err) {\n  // avoid exiting due to unsupported system resources in Windows\n});\n\nmodule.exports = {\n  init: init,\n  monitor: monitor,\n};\n"
  },
  {
    "path": "lib/monitor/cpu.js",
    "content": "var si = require('systeminformation'),\n  utils = require('../utils');\n\nvar colors = utils.colors;\n\nfunction Cpu(line) {\n  this.line = line;\n  si.currentLoad(data => {\n    this.cpuData = data.cpus.map((cpu, i) => {\n      return {\n        title: 'CPU' + (i + 1),\n        style: {\n          line: colors[i % colors.length],\n        },\n        x: Array(61)\n          .fill()\n          .map((_, i) => 60 - i),\n        y: Array(61).fill(0),\n      };\n    });\n    this.updateData(data);\n    this.interval = setInterval(() => {\n      si.currentLoad(data => {\n        this.updateData(data);\n      });\n    }, 1000);\n  });\n}\n\nCpu.prototype.updateData = function(data) {\n  data.cpus.forEach((cpu, i) => {\n    var loadString = cpu.load.toFixed(1).toString();\n    while (loadString.length < 6) {\n      loadString = ' ' + loadString;\n    }\n    loadString = loadString + '%';\n\n    this.cpuData[i].title = 'CPU' + (i + 1) + loadString;\n    this.cpuData[i].y.shift();\n    this.cpuData[i].y.push(cpu.load);\n  });\n\n  this.line.setData(this.cpuData);\n  this.line.screen.render();\n};\n\nmodule.exports = Cpu;\n"
  },
  {
    "path": "lib/monitor/disk.js",
    "content": "var si = require('systeminformation'),\n  utils = require('../utils');\n\nvar colors = utils.colors;\n\nfunction Disk(donut) {\n  this.donut = donut;\n\n  si.fsSize(data => {\n    this.updateData(data);\n  });\n\n  this.interval = setInterval(() => {\n    si.fsSize(data => {\n      this.updateData(data);\n    });\n  }, 10000);\n}\n\nDisk.prototype.updateData = function(data) {\n  var disk = data[0];\n\n  var label =\n    utils.humanFileSize(disk.used, true) +\n    ' of ' +\n    utils.humanFileSize(disk.size, true);\n\n  this.donut.setData([\n    {\n      percent: disk.use / 100,\n      label: label,\n      color: colors[5],\n    },\n  ]);\n  this.donut.screen.render();\n};\n\nmodule.exports = Disk;\n"
  },
  {
    "path": "lib/monitor/index.js",
    "content": "module.exports = {\n  Cpu: require('./cpu'),\n  Mem: require('./mem'),\n  Net: require('./net'),\n  Disk: require('./disk'),\n  Proc: require('./proc'),\n};\n"
  },
  {
    "path": "lib/monitor/mem.js",
    "content": "var si = require('systeminformation'),\n  utils = require('../utils');\n\nvar colors = utils.colors;\n\nfunction Mem(line, memDonut, swapDonut) {\n  this.line = line;\n  this.memDonut = memDonut;\n  this.swapDonut = swapDonut;\n\n  si.mem(data => {\n    this.memData = [\n      {\n        title: 'Memory',\n        style: {\n          line: colors[0],\n        },\n        x: Array(61)\n          .fill()\n          .map((_, i) => 60 - i),\n        y: Array(61).fill(0),\n      },\n      {\n        title: 'Swap',\n        style: {\n          line: colors[1],\n        },\n        x: Array(61)\n          .fill()\n          .map((_, i) => 60 - i),\n        y: Array(61).fill(0),\n      },\n    ];\n    this.updateData(data);\n    this.interval = setInterval(() => {\n      si.mem(data => {\n        this.updateData(data);\n      });\n    }, 1000);\n  });\n}\n\nMem.prototype.updateData = function(data) {\n  var memPer = (100 * (1 - data.available / data.total)).toFixed();\n  var swapPer = (100 * (1 - data.swapfree / data.swaptotal)).toFixed();\n\n  swapPer = isNaN(swapPer) ? 0 : swapPer;\n\n  this.memData[0].y.shift();\n  this.memData[0].y.push(memPer);\n\n  this.memData[1].y.shift();\n  this.memData[1].y.push(swapPer);\n\n  var memTitle =\n    utils.humanFileSize(data.total - data.available) +\n    ' of ' +\n    utils.humanFileSize(data.total);\n\n  var swapTitle =\n    utils.humanFileSize(data.swaptotal - data.swapfree) +\n    ' of ' +\n    utils.humanFileSize(data.swaptotal);\n\n  this.line.setData(this.memData);\n  this.memDonut.setData([\n    {\n      percent: memPer / 100,\n      label: memTitle,\n      color: colors[0],\n    },\n  ]);\n  this.swapDonut.setData([\n    {\n      percent: swapPer / 100,\n      label: swapTitle,\n      color: colors[1],\n    },\n  ]);\n  this.line.screen.render();\n};\n\nmodule.exports = Mem;\n"
  },
  {
    "path": "lib/monitor/net.js",
    "content": "var si = require('systeminformation'),\n  utils = require('../utils');\n\nvar colors = utils.colors;\n\nfunction Net(sparkline) {\n  this.sparkline = sparkline;\n  this.netData = [Array(61).fill(0), Array(61).fill(0)];\n\n  si.networkInterfaceDefault(iface => {\n    var that = this;\n    var updater = function() {\n      si.networkStats(iface, data => {\n        that.updateData(data[0]);\n      });\n    };\n    updater();\n    this.interval = setInterval(updater, 1000);\n  });\n}\n\nNet.prototype.updateData = function(data) {\n  var rx_sec = Math.max(0, data['rx_sec']);\n  var tx_sec = Math.max(0, data['tx_sec']);\n\n  this.netData[0].shift();\n  this.netData[0].push(rx_sec);\n\n  this.netData[1].shift();\n  this.netData[1].push(tx_sec);\n\n  rx_label =\n    'Receiving:      ' +\n    utils.humanFileSize(rx_sec) +\n    '/s \\nTotal received: ' +\n    utils.humanFileSize(data['rx_bytes']);\n\n  tx_label =\n    'Transferring:      ' +\n    utils.humanFileSize(tx_sec) +\n    '/s \\nTotal transferred: ' +\n    utils.humanFileSize(data['tx_bytes']);\n\n  this.sparkline.setData([rx_label, tx_label], this.netData);\n  this.sparkline.screen.render();\n};\n\nmodule.exports = Net;\n"
  },
  {
    "path": "lib/monitor/proc.js",
    "content": "var si = require('systeminformation'),\n  utils = require('../utils');\n\nvar colors = utils.colors;\n\nvar pars = {\n  p: 'pid',\n  c: 'cpu',\n  m: 'mem',\n};\n\nfunction Proc(table) {\n  this.table = table;\n\n  this.pSort = pars.c;\n  this.reIndex = false;\n  this.reverse = false;\n\n  var that = this;\n\n  var updater = function() {\n    si.processes(data => {\n      that.updateData(data);\n    });\n  };\n  updater();\n  this.interval = setInterval(updater, 3000);\n  this.table.screen.key(['m', 'c', 'p'], function(ch, key) {\n    if (pars[ch] == that.pSort) {\n      that.reverse = !that.reverse;\n    } else {\n      that.pSort = pars[ch] || that.pSort;\n    }\n\n    that.reIndex = true;\n    updater();\n  });\n}\n\nProc.prototype.updateData = function(data) {\n  var par = this.pSort;\n\n  var data = data.list\n    .sort(function(a, b) {\n      return b[par] - a[par];\n    })\n    .map(p => {\n      return [\n        p.pid,\n        p.command, //.slice(0,10),\n        ' ' + p.cpu.toFixed(1),\n        p.mem.toFixed(1),\n      ];\n    });\n\n  var headers = ['PID', 'Command', '%CPU', '%MEM'];\n\n  headers[\n    {\n      pid: 0,\n      cpu: 2,\n      mem: 3,\n    }[this.pSort]\n  ] += this.reverse ? '▲' : '▼';\n\n  this.table.setData({\n    headers: headers,\n    data: this.reverse ? data.reverse() : data,\n  });\n\n  if (this.reIndex) {\n    this.table.rows.select(0);\n    this.reIndex = false;\n  }\n\n  this.table.screen.render();\n};\n\nmodule.exports = Proc;\n"
  },
  {
    "path": "lib/utils.js",
    "content": "var utils = {};\n\nutils.humanFileSize = function(bytes, isDecimal) {\n  isDecimal = typeof isDecimal !== 'undefined' ? isDecimal : false;\n  if (bytes == 0) {\n    return '0.00 B';\n  }\n  var base = isDecimal ? 1000 : 1024;\n  var e = Math.floor(Math.log(bytes) / Math.log(base));\n  return (\n    (bytes / Math.pow(base, e)).toFixed(2) +\n    ' ' +\n    ' KMGTP'.charAt(e) +\n    (isDecimal || e == 0 ? '' : 'i') +\n    'B'\n  );\n};\n\nutils.colors = ['magenta', 'cyan', 'blue', 'yellow', 'green', 'red'];\n\nmodule.exports = utils;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"gtop\",\n  \"version\": \"1.1.5\",\n  \"description\": \"graphic top\",\n  \"main\": \"./index.js\",\n  \"bin\": {\n    \"gtop\": \"./bin/gtop\"\n  },\n  \"scripts\": {\n    \"test\": \"echo \\\"Test will be implemented.\\\" && exit 0\",\n    \"start\": \"./bin/gtop\",\n    \"lint\": \"prettier --single-quote --trailing-comma es5 --write 'lib/**/*.js'\",\n    \"lint-check\": \"prettier --check --single-quote --trailing-comma es5 'lib/**/*.js'\",\n    \"prepublishOnly\": \"marked-man --version $npm_package_version --manual 'Gtop Help' --section 1 ./CLI.md > gtop.1\"\n  },\n  \"man\": [\"./gtop.1\"],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/aksakalli/gtop.git\"\n  },\n  \"keywords\": [\n    \"system\",\n    \"monitoring\",\n    \"top\",\n    \"chart\",\n    \"monitor\",\n    \"dashboard\",\n    \"os\"\n  ],\n  \"author\": \"aksakalli\",\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/aksakalli/gtop/issues\"\n  },\n  \"homepage\": \"https://github.com/aksakalli/gtop#readme\",\n  \"dependencies\": {\n    \"blessed\": \"^0.1.81\",\n    \"blessed-contrib\": \"^4.11.0\",\n    \"systeminformation\": \"^5.18.15\"\n  },\n  \"engines\": {\n    \"node\": \">=4.0.0\"\n  },\n  \"devDependencies\": {\n    \"marked-man\": \"^1.3.3\",\n    \"prettier\": \"1.19.1\"\n  }\n}\n"
  },
  {
    "path": "snap/snapcraft.yaml",
    "content": "name: gtop\nsummary: System monitoring dashboard for terminal\ndescription: |\n  System monitoring dashboard for terminal\nversion: v1.1.5\nbase: core22\ngrade: stable\n\nconfinement: classic\n\napps:\n  gtop:\n    command: bin/gtop\n\nparts:\n  gtop:\n    source: https://github.com/aksakalli/gtop.git\n    source-tag: ${SNAPCRAFT_PROJECT_VERSION}\n    plugin: npm\n    npm-include-node: true\n    npm-node-version: \"17.3.0\"\n"
  }
]