├── .gitignore
├── LICENSE.md
├── README.md
├── app.js
├── monitor.js
├── monitors
├── cpu.js
├── memory.js
├── network.js
├── processes.js
├── temps.js
└── uptime.js
├── package-lock.json
├── package.json
└── public
├── css
├── darkmode.css
├── light.css
└── style.css
├── index.html
└── js
├── lib
├── Chart.min.js
└── moment.min.js
├── script.js
├── theme.js
└── widgets
├── basechartwidget.js
├── basepiewidget.js
├── basewidget.js
├── cpuchart.js
├── cpuusage.js
├── freemem.js
├── memory.js
├── network.js
├── processcpu.js
├── processmemory.js
├── temps.js
└── uptime.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | up.sh
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright (c) 2015 Kevin Bedi
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mintr
2 |
3 | 
4 |
5 | Mintr is a simple unix monitoring tool. It intentially avoids authentication, and thus does not monitor or display any private information, nor does it allow any actions to be taken from the web interface.
6 |
7 | It, quite simply, shows a few graphs that should help indicate the current status of your server, as well as the status over the past hour.
8 |
9 | Currently it shows
10 |
11 | * Memory usage
12 | * CPU Usage
13 | * Network activity
14 | * Process memory usage & CPU usage
15 | * Temperature Sensors
16 |
17 | # Installation & Usage
18 |
19 | ```
20 | npm install -g mintr
21 | mintr
22 | ```
23 |
24 | If you do not have nodejs/npm, you'll need to install that first. See https://nodejs.org/ for instructions on this.
25 |
26 | `mintr` takes an optional parameter which is the port it runs on, so you can run `mintr 1337` if you want to run it on port `1337`. The default port is `3000`.
27 | You can run `mintr` in a screen/tmux, add it to your system's startup, or anything else you please.
28 | Then go to `http://your-server.com:3000`, or replace `3000` with the correct port.
29 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var express = require('express');
4 | var app = express();
5 |
6 | var server = require('http').Server(app);
7 | var io = require('socket.io')(server);
8 |
9 | var monitor = require('./monitor');
10 | monitor.on('data', function(data) {
11 | io.emit('data', data);
12 | });
13 |
14 | app.use(express.static(__dirname + '/public'));
15 |
16 | var port = parseInt(process.argv[2]) || 3000;
17 | server.listen(port);
18 | console.log("Mintr is listening on port " + port);
19 |
20 | var sockets = {};
21 |
22 | io.on('connection', function (socket) {
23 | sockets[socket.id] = socket;
24 |
25 | var history = monitor.getHistory();
26 | socket.emit('history', history);
27 |
28 | socket.on('disconnect', function() {
29 | delete sockets[socket.id];
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/monitor.js:
--------------------------------------------------------------------------------
1 | // Dependencies
2 | var os = require('os');
3 | var async = require('async');
4 |
5 | // Constants
6 | var EMPTY_CALLBACK = function (callback) {
7 | callback();
8 | };
9 |
10 | // Monitors
11 | var monitors = {
12 | memory: require('./monitors/memory'),
13 | uptime: require('./monitors/uptime'),
14 | network: require('./monitors/network'),
15 | processes: require('./monitors/processes'),
16 | cpu: require('./monitors/cpu'),
17 | temps: require('./monitors/temps'),
18 | };
19 |
20 | // XXX: Hacky way to prevent us from having to call the callback
21 | // with (null, result) from within the monitors
22 | for (var key in monitors) {
23 | var monitor = monitors[key];
24 |
25 | (function (monitor) {
26 | monitor._asyncMonitor = function (history, callback) {
27 | monitor.monitor(history, function (result) {
28 | callback(null, result);
29 | });
30 | };
31 | })(monitor);
32 | }
33 |
34 | var monitorArray = [];
35 | for (var key in monitors) {
36 | var monitor = monitors[key];
37 |
38 | monitorArray.push({
39 | monitor: monitor,
40 | key: key,
41 | });
42 | }
43 |
44 | monitors = monitorArray;
45 |
46 | // Event stuff
47 | var _eventHandlers = {};
48 | var _trigger = function (eventName, data) {
49 | if (!_eventHandlers[eventName]) {
50 | return;
51 | }
52 |
53 | _eventHandlers[eventName].forEach(function (callback) {
54 | callback && callback(data);
55 | });
56 | };
57 |
58 | // Main
59 | var Monitor = function () {
60 | this._history = {
61 | memory: [],
62 | network: [],
63 | processes: [],
64 | temps: [],
65 | };
66 |
67 | monitors.forEach(function (monitor) {
68 | if (monitor.monitor.history) {
69 | this._history[monitor.key] = [];
70 | }
71 | }, this);
72 |
73 | this._numData = 0;
74 |
75 | this._monitor();
76 | };
77 |
78 | Monitor.prototype.on = function (eventName, callback) {
79 | _eventHandlers[eventName] = _eventHandlers[eventName] || [];
80 | _eventHandlers[eventName].push(callback);
81 | };
82 |
83 | Monitor.prototype._getData = function (callback) {
84 | var numData = this._numData++;
85 |
86 | var data = {};
87 |
88 | var monitorAsyncFuncs = monitors.map(function (monitor) {
89 | if (numData % monitor.monitor.frequency === 0) {
90 | return monitor.monitor._asyncMonitor.bind(
91 | null,
92 | this._history[monitor.key]
93 | );
94 | } else {
95 | return EMPTY_CALLBACK;
96 | }
97 | }, this);
98 |
99 | async.parallel(monitorAsyncFuncs, function (error, results) {
100 | results.forEach(function (result, index) {
101 | if (result === undefined || result === null) {
102 | return;
103 | }
104 |
105 | var monitor = monitors[index];
106 | var key = monitors[index].key;
107 | monitor = monitor.monitor;
108 |
109 | data[key] = result;
110 | data[key].timestamp = Date.now();
111 |
112 | if (monitor.history) {
113 | this._history[key].push(result);
114 | } else {
115 | this._history[key] = result;
116 | }
117 |
118 | var maxNumHistoryElements = (monitor.maxHistory / monitor.frequency);
119 | if (this._history[key].length > maxNumHistoryElements) {
120 | this._history[key].splice(0, 1);
121 | }
122 | }, this);
123 | callback(data);
124 | }.bind(this));
125 | };
126 |
127 | Monitor.prototype.getHistory = function () {
128 | return this._history;
129 | };
130 |
131 | Monitor.prototype._monitor = function () {
132 | this._getData(function (data) {
133 | _trigger('data', data);
134 | });
135 |
136 | setTimeout(this._monitor.bind(this), 1000);
137 | };
138 |
139 | module.exports = new Monitor();
140 |
--------------------------------------------------------------------------------
/monitors/cpu.js:
--------------------------------------------------------------------------------
1 | var exec = require('child_process').exec;
2 | var os = require('os');
3 |
4 | var CPU = {};
5 |
6 | CPU.monitor = function(history, callback) {
7 | exec('ps aux', function(error, result) {
8 | var cpu = 0;
9 |
10 | var lines = result.split('\n');
11 | lines.splice(0, 1);
12 |
13 | for (var x = 0; x < lines.length; x++) {
14 | if (!lines[x].trim()) {
15 | continue;
16 | }
17 | cpu += parseFloat(lines[x].split(/\s+/)[2]);
18 | }
19 |
20 | // Also record a normalized CPU usage per thread
21 | var normalized = cpu / os.cpus().length;
22 |
23 | callback({
24 | cpu: cpu,
25 | normalized: normalized,
26 | timestamp: Date.now(),
27 | });
28 | });
29 | };
30 |
31 | CPU.history = true;
32 | CPU.maxHistory = 3600;
33 | CPU.frequency = 20;
34 |
35 | module.exports = CPU;
36 |
--------------------------------------------------------------------------------
/monitors/memory.js:
--------------------------------------------------------------------------------
1 | var os = require('os');
2 |
3 | var Memory = {};
4 |
5 | Memory.monitor = function(history, callback) {
6 | callback({
7 | total: os.totalmem(),
8 | free: os.freemem(),
9 | });
10 | };
11 |
12 | Memory.history = true;
13 | Memory.maxHistory = 3600;
14 | Memory.frequency = 20;
15 |
16 | module.exports = Memory;
17 |
--------------------------------------------------------------------------------
/monitors/network.js:
--------------------------------------------------------------------------------
1 | var exec = require('child_process').exec;
2 | var async = require('async');
3 | var os = require('os');
4 |
5 | var Memory = {};
6 |
7 | Memory.monitor = function(history, callback) {
8 | exec('ip -s link', function(error, result) {
9 | if (error) {
10 | console.log(
11 | 'Mintr uses `ip` to get network information, which your ' +
12 | 'OS does not support.'
13 | );
14 | console.log(error);
15 | callback({});
16 | return;
17 | }
18 |
19 | var data = {
20 | in: 0,
21 | out: 0,
22 | };
23 |
24 | var rx = result.match(/\d+:\s+\w+:\s+[\S\s]*?RX:\s+[\S\s]*?(\d+)/g);
25 | var tx = result.match(/\d+:\s+\w+:\s+[\S\s]*?TX:\s+[\S\s]*?(\d+)/g);
26 |
27 | for (var x = 0; x < rx.length; x++) {
28 | var localAmt = rx[x];
29 | if (localAmt.indexOf('lo:') !== -1) {
30 | continue;
31 | }
32 |
33 | data.in += parseInt(localAmt.substring(localAmt.lastIndexOf('\n') + 1));
34 | }
35 |
36 | for (var x = 0; x < rx.length; x++) {
37 | var localAmt = tx[x];
38 | if (localAmt.indexOf('lo:') !== -1) {
39 | continue;
40 | }
41 |
42 | data.out += parseInt(localAmt.substring(localAmt.lastIndexOf('\n') + 1));
43 | }
44 |
45 | data.timestamp = Date.now();
46 |
47 | // Now calculate speeds
48 | if (history.length > 0) {
49 | var amountBack = 1;
50 | var index = history.length - amountBack;
51 | var lastTimestamp = history[index].timestamp;
52 | var lastOut = history[index].out;
53 | var lastIn = history[index].in;
54 |
55 | var elapsedTime = data.timestamp - lastTimestamp;
56 | var deltaOut = data.out - lastOut;
57 | var deltaIn = data.in - lastIn;
58 |
59 | data.outSpeed = deltaOut / elapsedTime * 1000;
60 | data.inSpeed = deltaIn / elapsedTime * 1000;
61 | } else {
62 | data.outSpeed = 0;
63 | data.inSpeed = 0;
64 | }
65 |
66 | callback(data);
67 | });
68 | };
69 |
70 | Memory.history = true;
71 | Memory.maxHistory = 3600;
72 | Memory.frequency = 20;
73 |
74 | module.exports = Memory;
75 |
--------------------------------------------------------------------------------
/monitors/processes.js:
--------------------------------------------------------------------------------
1 | var exec = require('child_process').exec;
2 |
3 | var MAX_NAME_LENGTH = 40;
4 |
5 | var Processes = {};
6 |
7 | Processes.monitor = function(history, callback) {
8 | exec('ps aux', function(error, result) {
9 | var processes = [];
10 |
11 | var lines = result.split('\n');
12 | lines.splice(0, 1);
13 |
14 | for (var x = 0; x < lines.length; x++) {
15 | var line = lines[x];
16 | if (!line.trim()) {
17 | continue;
18 | }
19 | var process = {};
20 | var words = line.split(/\s+/);
21 | process.user = words[0];
22 | process.pid = parseInt(words[1]);
23 | process.cpu = parseFloat(words[2]);
24 | process.mem = parseFloat(words[3]);
25 | var name = words[10];
26 | for (var y = 11; y < words.length; y++) {
27 | name += ' ' + words[y];
28 | }
29 | process.name = name && name.substring(0, MAX_NAME_LENGTH);
30 |
31 | processes.push(process);
32 | }
33 |
34 | var topCPU = processes.sort(function(a, b) {
35 | return b.cpu - a.cpu;
36 | }).slice(0, 5);
37 | var topMem = processes.sort(function(a, b) {
38 | return b.mem - a.mem;
39 | }).slice(0, 5);
40 |
41 | var topProcesses = [];
42 | var topPIDs = {};
43 | for (var x = 0; x < topCPU.length; x++) {
44 | topPIDs[topCPU[x].pid] = true;
45 | topProcesses.push(topCPU[x]);
46 | if (!topPIDs[topMem[x].pid]) {
47 | topPIDs[topMem[x].pid] = true;
48 | topProcesses.push(topMem[x]);
49 | }
50 | }
51 |
52 | callback(topProcesses);
53 | });
54 | };
55 |
56 | Processes.history = false;
57 | Processes.frequency = 20;
58 |
59 | module.exports = Processes;
60 |
--------------------------------------------------------------------------------
/monitors/temps.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | var Temps = {};
4 |
5 | Temps.monitor = function (history, callback) {
6 | if (!fs.existsSync('/sys/class/thermal')) {
7 | callback({});
8 | return;
9 | }
10 |
11 | const tempSensorDirs = fs.readdirSync('/sys/class/thermal')
12 | .filter(x => x.startsWith('thermal'));
13 |
14 | const temps = tempSensorDirs.map(dir => {
15 | const dirType = fs.readFileSync('/sys/class/thermal/' + dir + '/type', { encoding: 'utf8' });
16 | const dirTemp = fs.readFileSync('/sys/class/thermal/' + dir + '/temp', { encoding: 'utf8' });
17 |
18 | return { type: dirType.trim(), temp: parseInt(dirTemp.trim()) };
19 | });
20 |
21 | callback(temps);
22 | };
23 |
24 | Temps.history = false;
25 | Temps.frequency = 20;
26 |
27 | module.exports = Temps;
28 |
--------------------------------------------------------------------------------
/monitors/uptime.js:
--------------------------------------------------------------------------------
1 | var os = require('os');
2 | var exec = require('child_process').exec;
3 |
4 | var Uptime = {};
5 |
6 | Uptime.monitor = function(history, callback) {
7 | exec('ps -eo lstart,args | grep /sbin/init', function(error, result) {
8 | var processTextIndex = result.indexOf('/sbin/init');
9 | var dateText = result.substring(0, processTextIndex);
10 | var uptime = Date.now() - new Date(dateText).getTime();
11 |
12 | callback(uptime);
13 | });
14 | };
15 |
16 | Uptime.history = false;
17 | Uptime.frequency = 1;
18 |
19 | module.exports = Uptime;
20 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mintr",
3 | "version": "0.0.12",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "mintr",
9 | "version": "0.0.12",
10 | "license": "MIT",
11 | "dependencies": {
12 | "async": "^0.9.0",
13 | "express": "^4.19.2",
14 | "socket.io": "^4.6.2"
15 | },
16 | "bin": {
17 | "mintr": "app.js"
18 | }
19 | },
20 | "node_modules/@socket.io/component-emitter": {
21 | "version": "3.1.0",
22 | "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
23 | "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
24 | },
25 | "node_modules/@types/cookie": {
26 | "version": "0.4.1",
27 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
28 | "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
29 | },
30 | "node_modules/@types/cors": {
31 | "version": "2.8.17",
32 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
33 | "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
34 | "dependencies": {
35 | "@types/node": "*"
36 | }
37 | },
38 | "node_modules/@types/node": {
39 | "version": "20.14.11",
40 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
41 | "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==",
42 | "dependencies": {
43 | "undici-types": "~5.26.4"
44 | }
45 | },
46 | "node_modules/accepts": {
47 | "version": "1.3.8",
48 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
49 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
50 | "dependencies": {
51 | "mime-types": "~2.1.34",
52 | "negotiator": "0.6.3"
53 | },
54 | "engines": {
55 | "node": ">= 0.6"
56 | }
57 | },
58 | "node_modules/array-flatten": {
59 | "version": "1.1.1",
60 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
61 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
62 | },
63 | "node_modules/async": {
64 | "version": "0.9.2",
65 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
66 | "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw=="
67 | },
68 | "node_modules/base64id": {
69 | "version": "2.0.0",
70 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
71 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
72 | "engines": {
73 | "node": "^4.5.0 || >= 5.9"
74 | }
75 | },
76 | "node_modules/body-parser": {
77 | "version": "1.20.2",
78 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
79 | "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
80 | "dependencies": {
81 | "bytes": "3.1.2",
82 | "content-type": "~1.0.5",
83 | "debug": "2.6.9",
84 | "depd": "2.0.0",
85 | "destroy": "1.2.0",
86 | "http-errors": "2.0.0",
87 | "iconv-lite": "0.4.24",
88 | "on-finished": "2.4.1",
89 | "qs": "6.11.0",
90 | "raw-body": "2.5.2",
91 | "type-is": "~1.6.18",
92 | "unpipe": "1.0.0"
93 | },
94 | "engines": {
95 | "node": ">= 0.8",
96 | "npm": "1.2.8000 || >= 1.4.16"
97 | }
98 | },
99 | "node_modules/bytes": {
100 | "version": "3.1.2",
101 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
102 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
103 | "engines": {
104 | "node": ">= 0.8"
105 | }
106 | },
107 | "node_modules/call-bind": {
108 | "version": "1.0.7",
109 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
110 | "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
111 | "dependencies": {
112 | "es-define-property": "^1.0.0",
113 | "es-errors": "^1.3.0",
114 | "function-bind": "^1.1.2",
115 | "get-intrinsic": "^1.2.4",
116 | "set-function-length": "^1.2.1"
117 | },
118 | "engines": {
119 | "node": ">= 0.4"
120 | },
121 | "funding": {
122 | "url": "https://github.com/sponsors/ljharb"
123 | }
124 | },
125 | "node_modules/content-disposition": {
126 | "version": "0.5.4",
127 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
128 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
129 | "dependencies": {
130 | "safe-buffer": "5.2.1"
131 | },
132 | "engines": {
133 | "node": ">= 0.6"
134 | }
135 | },
136 | "node_modules/content-type": {
137 | "version": "1.0.5",
138 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
139 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
140 | "engines": {
141 | "node": ">= 0.6"
142 | }
143 | },
144 | "node_modules/cookie": {
145 | "version": "0.6.0",
146 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
147 | "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
148 | "engines": {
149 | "node": ">= 0.6"
150 | }
151 | },
152 | "node_modules/cookie-signature": {
153 | "version": "1.0.6",
154 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
155 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
156 | },
157 | "node_modules/cors": {
158 | "version": "2.8.5",
159 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
160 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
161 | "dependencies": {
162 | "object-assign": "^4",
163 | "vary": "^1"
164 | },
165 | "engines": {
166 | "node": ">= 0.10"
167 | }
168 | },
169 | "node_modules/debug": {
170 | "version": "2.6.9",
171 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
172 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
173 | "dependencies": {
174 | "ms": "2.0.0"
175 | }
176 | },
177 | "node_modules/define-data-property": {
178 | "version": "1.1.4",
179 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
180 | "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
181 | "dependencies": {
182 | "es-define-property": "^1.0.0",
183 | "es-errors": "^1.3.0",
184 | "gopd": "^1.0.1"
185 | },
186 | "engines": {
187 | "node": ">= 0.4"
188 | },
189 | "funding": {
190 | "url": "https://github.com/sponsors/ljharb"
191 | }
192 | },
193 | "node_modules/depd": {
194 | "version": "2.0.0",
195 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
196 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
197 | "engines": {
198 | "node": ">= 0.8"
199 | }
200 | },
201 | "node_modules/destroy": {
202 | "version": "1.2.0",
203 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
204 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
205 | "engines": {
206 | "node": ">= 0.8",
207 | "npm": "1.2.8000 || >= 1.4.16"
208 | }
209 | },
210 | "node_modules/ee-first": {
211 | "version": "1.1.1",
212 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
213 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
214 | },
215 | "node_modules/encodeurl": {
216 | "version": "1.0.2",
217 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
218 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
219 | "engines": {
220 | "node": ">= 0.8"
221 | }
222 | },
223 | "node_modules/engine.io": {
224 | "version": "6.5.5",
225 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
226 | "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
227 | "dependencies": {
228 | "@types/cookie": "^0.4.1",
229 | "@types/cors": "^2.8.12",
230 | "@types/node": ">=10.0.0",
231 | "accepts": "~1.3.4",
232 | "base64id": "2.0.0",
233 | "cookie": "~0.4.1",
234 | "cors": "~2.8.5",
235 | "debug": "~4.3.1",
236 | "engine.io-parser": "~5.2.1",
237 | "ws": "~8.17.1"
238 | },
239 | "engines": {
240 | "node": ">=10.2.0"
241 | }
242 | },
243 | "node_modules/engine.io-parser": {
244 | "version": "5.2.3",
245 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
246 | "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
247 | "engines": {
248 | "node": ">=10.0.0"
249 | }
250 | },
251 | "node_modules/engine.io/node_modules/cookie": {
252 | "version": "0.4.2",
253 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
254 | "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
255 | "engines": {
256 | "node": ">= 0.6"
257 | }
258 | },
259 | "node_modules/engine.io/node_modules/debug": {
260 | "version": "4.3.5",
261 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
262 | "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
263 | "dependencies": {
264 | "ms": "2.1.2"
265 | },
266 | "engines": {
267 | "node": ">=6.0"
268 | },
269 | "peerDependenciesMeta": {
270 | "supports-color": {
271 | "optional": true
272 | }
273 | }
274 | },
275 | "node_modules/engine.io/node_modules/ms": {
276 | "version": "2.1.2",
277 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
278 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
279 | },
280 | "node_modules/es-define-property": {
281 | "version": "1.0.0",
282 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
283 | "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
284 | "dependencies": {
285 | "get-intrinsic": "^1.2.4"
286 | },
287 | "engines": {
288 | "node": ">= 0.4"
289 | }
290 | },
291 | "node_modules/es-errors": {
292 | "version": "1.3.0",
293 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
294 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
295 | "engines": {
296 | "node": ">= 0.4"
297 | }
298 | },
299 | "node_modules/escape-html": {
300 | "version": "1.0.3",
301 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
302 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
303 | },
304 | "node_modules/etag": {
305 | "version": "1.8.1",
306 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
307 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
308 | "engines": {
309 | "node": ">= 0.6"
310 | }
311 | },
312 | "node_modules/express": {
313 | "version": "4.19.2",
314 | "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
315 | "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
316 | "dependencies": {
317 | "accepts": "~1.3.8",
318 | "array-flatten": "1.1.1",
319 | "body-parser": "1.20.2",
320 | "content-disposition": "0.5.4",
321 | "content-type": "~1.0.4",
322 | "cookie": "0.6.0",
323 | "cookie-signature": "1.0.6",
324 | "debug": "2.6.9",
325 | "depd": "2.0.0",
326 | "encodeurl": "~1.0.2",
327 | "escape-html": "~1.0.3",
328 | "etag": "~1.8.1",
329 | "finalhandler": "1.2.0",
330 | "fresh": "0.5.2",
331 | "http-errors": "2.0.0",
332 | "merge-descriptors": "1.0.1",
333 | "methods": "~1.1.2",
334 | "on-finished": "2.4.1",
335 | "parseurl": "~1.3.3",
336 | "path-to-regexp": "0.1.7",
337 | "proxy-addr": "~2.0.7",
338 | "qs": "6.11.0",
339 | "range-parser": "~1.2.1",
340 | "safe-buffer": "5.2.1",
341 | "send": "0.18.0",
342 | "serve-static": "1.15.0",
343 | "setprototypeof": "1.2.0",
344 | "statuses": "2.0.1",
345 | "type-is": "~1.6.18",
346 | "utils-merge": "1.0.1",
347 | "vary": "~1.1.2"
348 | },
349 | "engines": {
350 | "node": ">= 0.10.0"
351 | }
352 | },
353 | "node_modules/finalhandler": {
354 | "version": "1.2.0",
355 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
356 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
357 | "dependencies": {
358 | "debug": "2.6.9",
359 | "encodeurl": "~1.0.2",
360 | "escape-html": "~1.0.3",
361 | "on-finished": "2.4.1",
362 | "parseurl": "~1.3.3",
363 | "statuses": "2.0.1",
364 | "unpipe": "~1.0.0"
365 | },
366 | "engines": {
367 | "node": ">= 0.8"
368 | }
369 | },
370 | "node_modules/forwarded": {
371 | "version": "0.2.0",
372 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
373 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
374 | "engines": {
375 | "node": ">= 0.6"
376 | }
377 | },
378 | "node_modules/fresh": {
379 | "version": "0.5.2",
380 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
381 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
382 | "engines": {
383 | "node": ">= 0.6"
384 | }
385 | },
386 | "node_modules/function-bind": {
387 | "version": "1.1.2",
388 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
389 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
390 | "funding": {
391 | "url": "https://github.com/sponsors/ljharb"
392 | }
393 | },
394 | "node_modules/get-intrinsic": {
395 | "version": "1.2.4",
396 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
397 | "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
398 | "dependencies": {
399 | "es-errors": "^1.3.0",
400 | "function-bind": "^1.1.2",
401 | "has-proto": "^1.0.1",
402 | "has-symbols": "^1.0.3",
403 | "hasown": "^2.0.0"
404 | },
405 | "engines": {
406 | "node": ">= 0.4"
407 | },
408 | "funding": {
409 | "url": "https://github.com/sponsors/ljharb"
410 | }
411 | },
412 | "node_modules/gopd": {
413 | "version": "1.0.1",
414 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
415 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
416 | "dependencies": {
417 | "get-intrinsic": "^1.1.3"
418 | },
419 | "funding": {
420 | "url": "https://github.com/sponsors/ljharb"
421 | }
422 | },
423 | "node_modules/has-property-descriptors": {
424 | "version": "1.0.2",
425 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
426 | "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
427 | "dependencies": {
428 | "es-define-property": "^1.0.0"
429 | },
430 | "funding": {
431 | "url": "https://github.com/sponsors/ljharb"
432 | }
433 | },
434 | "node_modules/has-proto": {
435 | "version": "1.0.3",
436 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
437 | "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
438 | "engines": {
439 | "node": ">= 0.4"
440 | },
441 | "funding": {
442 | "url": "https://github.com/sponsors/ljharb"
443 | }
444 | },
445 | "node_modules/has-symbols": {
446 | "version": "1.0.3",
447 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
448 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
449 | "engines": {
450 | "node": ">= 0.4"
451 | },
452 | "funding": {
453 | "url": "https://github.com/sponsors/ljharb"
454 | }
455 | },
456 | "node_modules/hasown": {
457 | "version": "2.0.2",
458 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
459 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
460 | "dependencies": {
461 | "function-bind": "^1.1.2"
462 | },
463 | "engines": {
464 | "node": ">= 0.4"
465 | }
466 | },
467 | "node_modules/http-errors": {
468 | "version": "2.0.0",
469 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
470 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
471 | "dependencies": {
472 | "depd": "2.0.0",
473 | "inherits": "2.0.4",
474 | "setprototypeof": "1.2.0",
475 | "statuses": "2.0.1",
476 | "toidentifier": "1.0.1"
477 | },
478 | "engines": {
479 | "node": ">= 0.8"
480 | }
481 | },
482 | "node_modules/iconv-lite": {
483 | "version": "0.4.24",
484 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
485 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
486 | "dependencies": {
487 | "safer-buffer": ">= 2.1.2 < 3"
488 | },
489 | "engines": {
490 | "node": ">=0.10.0"
491 | }
492 | },
493 | "node_modules/inherits": {
494 | "version": "2.0.4",
495 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
496 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
497 | },
498 | "node_modules/ipaddr.js": {
499 | "version": "1.9.1",
500 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
501 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
502 | "engines": {
503 | "node": ">= 0.10"
504 | }
505 | },
506 | "node_modules/media-typer": {
507 | "version": "0.3.0",
508 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
509 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
510 | "engines": {
511 | "node": ">= 0.6"
512 | }
513 | },
514 | "node_modules/merge-descriptors": {
515 | "version": "1.0.1",
516 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
517 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
518 | },
519 | "node_modules/methods": {
520 | "version": "1.1.2",
521 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
522 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
523 | "engines": {
524 | "node": ">= 0.6"
525 | }
526 | },
527 | "node_modules/mime": {
528 | "version": "1.6.0",
529 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
530 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
531 | "bin": {
532 | "mime": "cli.js"
533 | },
534 | "engines": {
535 | "node": ">=4"
536 | }
537 | },
538 | "node_modules/mime-db": {
539 | "version": "1.52.0",
540 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
541 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
542 | "engines": {
543 | "node": ">= 0.6"
544 | }
545 | },
546 | "node_modules/mime-types": {
547 | "version": "2.1.35",
548 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
549 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
550 | "dependencies": {
551 | "mime-db": "1.52.0"
552 | },
553 | "engines": {
554 | "node": ">= 0.6"
555 | }
556 | },
557 | "node_modules/ms": {
558 | "version": "2.0.0",
559 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
560 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
561 | },
562 | "node_modules/negotiator": {
563 | "version": "0.6.3",
564 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
565 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
566 | "engines": {
567 | "node": ">= 0.6"
568 | }
569 | },
570 | "node_modules/object-assign": {
571 | "version": "4.1.1",
572 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
573 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
574 | "engines": {
575 | "node": ">=0.10.0"
576 | }
577 | },
578 | "node_modules/object-inspect": {
579 | "version": "1.13.2",
580 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
581 | "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
582 | "engines": {
583 | "node": ">= 0.4"
584 | },
585 | "funding": {
586 | "url": "https://github.com/sponsors/ljharb"
587 | }
588 | },
589 | "node_modules/on-finished": {
590 | "version": "2.4.1",
591 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
592 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
593 | "dependencies": {
594 | "ee-first": "1.1.1"
595 | },
596 | "engines": {
597 | "node": ">= 0.8"
598 | }
599 | },
600 | "node_modules/parseurl": {
601 | "version": "1.3.3",
602 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
603 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
604 | "engines": {
605 | "node": ">= 0.8"
606 | }
607 | },
608 | "node_modules/path-to-regexp": {
609 | "version": "0.1.7",
610 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
611 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
612 | },
613 | "node_modules/proxy-addr": {
614 | "version": "2.0.7",
615 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
616 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
617 | "dependencies": {
618 | "forwarded": "0.2.0",
619 | "ipaddr.js": "1.9.1"
620 | },
621 | "engines": {
622 | "node": ">= 0.10"
623 | }
624 | },
625 | "node_modules/qs": {
626 | "version": "6.11.0",
627 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
628 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
629 | "dependencies": {
630 | "side-channel": "^1.0.4"
631 | },
632 | "engines": {
633 | "node": ">=0.6"
634 | },
635 | "funding": {
636 | "url": "https://github.com/sponsors/ljharb"
637 | }
638 | },
639 | "node_modules/range-parser": {
640 | "version": "1.2.1",
641 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
642 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
643 | "engines": {
644 | "node": ">= 0.6"
645 | }
646 | },
647 | "node_modules/raw-body": {
648 | "version": "2.5.2",
649 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
650 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
651 | "dependencies": {
652 | "bytes": "3.1.2",
653 | "http-errors": "2.0.0",
654 | "iconv-lite": "0.4.24",
655 | "unpipe": "1.0.0"
656 | },
657 | "engines": {
658 | "node": ">= 0.8"
659 | }
660 | },
661 | "node_modules/safe-buffer": {
662 | "version": "5.2.1",
663 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
664 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
665 | "funding": [
666 | {
667 | "type": "github",
668 | "url": "https://github.com/sponsors/feross"
669 | },
670 | {
671 | "type": "patreon",
672 | "url": "https://www.patreon.com/feross"
673 | },
674 | {
675 | "type": "consulting",
676 | "url": "https://feross.org/support"
677 | }
678 | ]
679 | },
680 | "node_modules/safer-buffer": {
681 | "version": "2.1.2",
682 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
683 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
684 | },
685 | "node_modules/send": {
686 | "version": "0.18.0",
687 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
688 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
689 | "dependencies": {
690 | "debug": "2.6.9",
691 | "depd": "2.0.0",
692 | "destroy": "1.2.0",
693 | "encodeurl": "~1.0.2",
694 | "escape-html": "~1.0.3",
695 | "etag": "~1.8.1",
696 | "fresh": "0.5.2",
697 | "http-errors": "2.0.0",
698 | "mime": "1.6.0",
699 | "ms": "2.1.3",
700 | "on-finished": "2.4.1",
701 | "range-parser": "~1.2.1",
702 | "statuses": "2.0.1"
703 | },
704 | "engines": {
705 | "node": ">= 0.8.0"
706 | }
707 | },
708 | "node_modules/send/node_modules/ms": {
709 | "version": "2.1.3",
710 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
711 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
712 | },
713 | "node_modules/serve-static": {
714 | "version": "1.15.0",
715 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
716 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
717 | "dependencies": {
718 | "encodeurl": "~1.0.2",
719 | "escape-html": "~1.0.3",
720 | "parseurl": "~1.3.3",
721 | "send": "0.18.0"
722 | },
723 | "engines": {
724 | "node": ">= 0.8.0"
725 | }
726 | },
727 | "node_modules/set-function-length": {
728 | "version": "1.2.2",
729 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
730 | "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
731 | "dependencies": {
732 | "define-data-property": "^1.1.4",
733 | "es-errors": "^1.3.0",
734 | "function-bind": "^1.1.2",
735 | "get-intrinsic": "^1.2.4",
736 | "gopd": "^1.0.1",
737 | "has-property-descriptors": "^1.0.2"
738 | },
739 | "engines": {
740 | "node": ">= 0.4"
741 | }
742 | },
743 | "node_modules/setprototypeof": {
744 | "version": "1.2.0",
745 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
746 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
747 | },
748 | "node_modules/side-channel": {
749 | "version": "1.0.6",
750 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
751 | "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
752 | "dependencies": {
753 | "call-bind": "^1.0.7",
754 | "es-errors": "^1.3.0",
755 | "get-intrinsic": "^1.2.4",
756 | "object-inspect": "^1.13.1"
757 | },
758 | "engines": {
759 | "node": ">= 0.4"
760 | },
761 | "funding": {
762 | "url": "https://github.com/sponsors/ljharb"
763 | }
764 | },
765 | "node_modules/socket.io": {
766 | "version": "4.7.5",
767 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz",
768 | "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==",
769 | "dependencies": {
770 | "accepts": "~1.3.4",
771 | "base64id": "~2.0.0",
772 | "cors": "~2.8.5",
773 | "debug": "~4.3.2",
774 | "engine.io": "~6.5.2",
775 | "socket.io-adapter": "~2.5.2",
776 | "socket.io-parser": "~4.2.4"
777 | },
778 | "engines": {
779 | "node": ">=10.2.0"
780 | }
781 | },
782 | "node_modules/socket.io-adapter": {
783 | "version": "2.5.5",
784 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
785 | "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
786 | "dependencies": {
787 | "debug": "~4.3.4",
788 | "ws": "~8.17.1"
789 | }
790 | },
791 | "node_modules/socket.io-adapter/node_modules/debug": {
792 | "version": "4.3.5",
793 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
794 | "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
795 | "dependencies": {
796 | "ms": "2.1.2"
797 | },
798 | "engines": {
799 | "node": ">=6.0"
800 | },
801 | "peerDependenciesMeta": {
802 | "supports-color": {
803 | "optional": true
804 | }
805 | }
806 | },
807 | "node_modules/socket.io-adapter/node_modules/ms": {
808 | "version": "2.1.2",
809 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
810 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
811 | },
812 | "node_modules/socket.io-parser": {
813 | "version": "4.2.4",
814 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
815 | "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
816 | "dependencies": {
817 | "@socket.io/component-emitter": "~3.1.0",
818 | "debug": "~4.3.1"
819 | },
820 | "engines": {
821 | "node": ">=10.0.0"
822 | }
823 | },
824 | "node_modules/socket.io-parser/node_modules/debug": {
825 | "version": "4.3.4",
826 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
827 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
828 | "dependencies": {
829 | "ms": "2.1.2"
830 | },
831 | "engines": {
832 | "node": ">=6.0"
833 | },
834 | "peerDependenciesMeta": {
835 | "supports-color": {
836 | "optional": true
837 | }
838 | }
839 | },
840 | "node_modules/socket.io-parser/node_modules/ms": {
841 | "version": "2.1.2",
842 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
843 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
844 | },
845 | "node_modules/socket.io/node_modules/debug": {
846 | "version": "4.3.4",
847 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
848 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
849 | "dependencies": {
850 | "ms": "2.1.2"
851 | },
852 | "engines": {
853 | "node": ">=6.0"
854 | },
855 | "peerDependenciesMeta": {
856 | "supports-color": {
857 | "optional": true
858 | }
859 | }
860 | },
861 | "node_modules/socket.io/node_modules/ms": {
862 | "version": "2.1.2",
863 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
864 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
865 | },
866 | "node_modules/statuses": {
867 | "version": "2.0.1",
868 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
869 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
870 | "engines": {
871 | "node": ">= 0.8"
872 | }
873 | },
874 | "node_modules/toidentifier": {
875 | "version": "1.0.1",
876 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
877 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
878 | "engines": {
879 | "node": ">=0.6"
880 | }
881 | },
882 | "node_modules/type-is": {
883 | "version": "1.6.18",
884 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
885 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
886 | "dependencies": {
887 | "media-typer": "0.3.0",
888 | "mime-types": "~2.1.24"
889 | },
890 | "engines": {
891 | "node": ">= 0.6"
892 | }
893 | },
894 | "node_modules/undici-types": {
895 | "version": "5.26.5",
896 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
897 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
898 | },
899 | "node_modules/unpipe": {
900 | "version": "1.0.0",
901 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
902 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
903 | "engines": {
904 | "node": ">= 0.8"
905 | }
906 | },
907 | "node_modules/utils-merge": {
908 | "version": "1.0.1",
909 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
910 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
911 | "engines": {
912 | "node": ">= 0.4.0"
913 | }
914 | },
915 | "node_modules/vary": {
916 | "version": "1.1.2",
917 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
918 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
919 | "engines": {
920 | "node": ">= 0.8"
921 | }
922 | },
923 | "node_modules/ws": {
924 | "version": "8.17.1",
925 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
926 | "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
927 | "engines": {
928 | "node": ">=10.0.0"
929 | },
930 | "peerDependencies": {
931 | "bufferutil": "^4.0.1",
932 | "utf-8-validate": ">=5.0.2"
933 | },
934 | "peerDependenciesMeta": {
935 | "bufferutil": {
936 | "optional": true
937 | },
938 | "utf-8-validate": {
939 | "optional": true
940 | }
941 | }
942 | }
943 | }
944 | }
945 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mintr",
3 | "author": "Kevin Bedi",
4 | "version": "0.0.12",
5 | "description": "A simple unix monitor",
6 | "main": "app.js",
7 | "bin": "./app.js",
8 | "license": "MIT",
9 | "dependencies": {
10 | "async": "^0.9.0",
11 | "express": "^4.19.2",
12 | "socket.io": "^4.6.2"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/public/css/darkmode.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #060606;
3 | }
4 |
5 | .theme-button::after {
6 | content: "🌙";
7 | }
8 |
9 | .header {
10 | background: #000;
11 | box-shadow: 0 0 5px #444;
12 | }
13 |
14 | .widget {
15 | background: #000;
16 | border: 1px solid #0f0f0f;
17 | box-shadow: 0 0 5px #111;
18 | }
19 |
20 | .widget-title {
21 | background: #111;
22 | color: #aaa;
23 | border-bottom: 1px solid #444;
24 | }
25 |
26 | .tooltip {
27 | background: #000;
28 | color: #fff;
29 | box-shadow: 0 2px 6px -4px #111;
30 | }
--------------------------------------------------------------------------------
/public/css/light.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #fafafa;
3 | }
4 |
5 | .theme-button::after {
6 | content: "🌞";
7 | }
8 |
9 | .header {
10 | background: white;
11 | box-shadow: 0 0 5px #888;
12 | }
13 |
14 | .widget {
15 | background: #fff;
16 | border: 1px solid #f0f0f0;
17 | box-shadow: 0 0 5px #ccc;
18 | }
19 |
20 | .widget-title {
21 | background: #f5f5f5;
22 | color: #aaa;
23 | border-bottom: 1px solid #eee;
24 | }
25 |
26 | .tooltip {
27 | background: #f9f9f9;
28 | color: #000;
29 | box-shadow: 0 2px 6px -4px #444;
30 | }
--------------------------------------------------------------------------------
/public/css/style.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --transition: all ease-in-out 200ms;
3 | }
4 |
5 | * {
6 | margin: 0;
7 | padding: 0;
8 | box-sizing: border-box;
9 | }
10 |
11 | body {
12 | font-family: "Open Sans", sans-serif;
13 | font-weight: 300;
14 | transition: var(--transition);
15 | }
16 |
17 | .theme-button {
18 | cursor: pointer;
19 | }
20 |
21 | .header {
22 | color: #2196f3;
23 | padding: 20px;
24 | font-size: 22px;
25 | font-weight: bold;
26 | position: fixed;
27 | width: 100%;
28 | top: 0;
29 | left: 0;
30 | z-index: 1;
31 | transition: var(--transition);
32 | }
33 |
34 | .container {
35 | width: 960px;
36 | margin: 0 auto;
37 | padding: 80px 0 0 10px;
38 | }
39 |
40 | .widget {
41 | margin: 0 10px 10px 0;
42 | text-align: center;
43 | display: inline-block;
44 | width: 100%;
45 | vertical-align: top;
46 | float: left;
47 | border-radius: 8px;
48 | overflow: hidden;
49 | transition: var(--transition);
50 | }
51 |
52 | .widget-content {
53 | padding: 20px;
54 | color: #2196f3;
55 | font-weight: 500;
56 | position: relative;
57 | }
58 |
59 | .widget-content .pie {
60 | text-align: left;
61 | color: #888;
62 | }
63 |
64 | .widget-content .legend {
65 | display: inline-block;
66 | margin-left: 40px;
67 | vertical-align: top;
68 | max-width: 292px;
69 | white-space: nowrap;
70 | overflow: hidden;
71 | }
72 |
73 | .widget-content .legend ul {
74 | list-style-type: none;
75 | line-height: 56px;
76 | cursor: default;
77 | }
78 |
79 | .widget-content .legend ul li span {
80 | width: 40px;
81 | height: 5px;
82 | display: inline-block;
83 | margin-right: 15px;
84 | vertical-align: middle;
85 | }
86 |
87 | .widget-content .legend ul li {
88 | position: relative;
89 | }
90 |
91 | .widget.one {
92 | width: 306px;
93 | }
94 |
95 | .widget.two {
96 | width: 624px;
97 | }
98 |
99 | .widget.three {
100 | width: 940px;
101 | }
102 |
103 | .widget-title {
104 | font-weight: 500;
105 | font-size: 18px;
106 | text-transform: uppercase;
107 | text-align: left;
108 | padding: 14px 20px;
109 | transition: var(--transition);
110 | }
111 |
112 | .title-container {
113 | width: 960px;
114 | margin: 0 auto;
115 | padding: 0 10px;
116 | display: flex;
117 | justify-content: space-between;
118 | }
119 |
120 | .tooltip {
121 | position: absolute;
122 | top: 190px;
123 | left: 610px;
124 | padding: 5px 10px;
125 | border-radius: 2px;
126 | white-space: nowrap;
127 | pointer-events: none;
128 | display: none;
129 | line-height: normal;
130 | max-width: 800px;
131 | white-space: pre-wrap;
132 | word-wrap: break-word;
133 | transition: var(--transition);
134 | }
135 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Mintr
5 |
6 |
11 |
12 |
13 |
20 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/public/js/lib/moment.min.js:
--------------------------------------------------------------------------------
1 | //! moment.js
2 | //! version : 2.9.0
3 | //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4 | //! license : MIT
5 | //! momentjs.com
6 | (function(a){function b(a,b,c){switch(arguments.length){case 2:return null!=a?a:b;case 3:return null!=a?a:null!=b?b:c;default:throw new Error("Implement me")}}function c(a,b){return Bb.call(a,b)}function d(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function e(a){vb.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+a)}function f(a,b){var c=!0;return o(function(){return c&&(e(a),c=!1),b.apply(this,arguments)},b)}function g(a,b){sc[a]||(e(b),sc[a]=!0)}function h(a,b){return function(c){return r(a.call(this,c),b)}}function i(a,b){return function(c){return this.localeData().ordinal(a.call(this,c),b)}}function j(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function k(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function l(){}function m(a,b){b!==!1&&H(a),p(this,a),this._d=new Date(+a._d),uc===!1&&(uc=!0,vb.updateOffset(this),uc=!1)}function n(a){var b=A(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+36e5*h,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=vb.localeData(),this._bubble()}function o(a,b){for(var d in b)c(b,d)&&(a[d]=b[d]);return c(b,"toString")&&(a.toString=b.toString),c(b,"valueOf")&&(a.valueOf=b.valueOf),a}function p(a,b){var c,d,e;if("undefined"!=typeof b._isAMomentObject&&(a._isAMomentObject=b._isAMomentObject),"undefined"!=typeof b._i&&(a._i=b._i),"undefined"!=typeof b._f&&(a._f=b._f),"undefined"!=typeof b._l&&(a._l=b._l),"undefined"!=typeof b._strict&&(a._strict=b._strict),"undefined"!=typeof b._tzm&&(a._tzm=b._tzm),"undefined"!=typeof b._isUTC&&(a._isUTC=b._isUTC),"undefined"!=typeof b._offset&&(a._offset=b._offset),"undefined"!=typeof b._pf&&(a._pf=b._pf),"undefined"!=typeof b._locale&&(a._locale=b._locale),Kb.length>0)for(c in Kb)d=Kb[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function q(a){return 0>a?Math.ceil(a):Math.floor(a)}function r(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthd;d++)(c&&a[d]!==b[d]||!c&&C(a[d])!==C(b[d]))&&g++;return g+f}function z(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=lc[a]||mc[b]||b}return a}function A(a){var b,d,e={};for(d in a)c(a,d)&&(b=z(d),b&&(e[b]=a[d]));return e}function B(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}vb[b]=function(e,f){var g,h,i=vb._locale[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=vb().utc().set(d,a);return i.call(vb._locale,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function C(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function D(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function E(a,b,c){return jb(vb([a,11,31+b-c]),b,c).week}function F(a){return G(a)?366:365}function G(a){return a%4===0&&a%100!==0||a%400===0}function H(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[Db]<0||a._a[Db]>11?Db:a._a[Eb]<1||a._a[Eb]>D(a._a[Cb],a._a[Db])?Eb:a._a[Fb]<0||a._a[Fb]>24||24===a._a[Fb]&&(0!==a._a[Gb]||0!==a._a[Hb]||0!==a._a[Ib])?Fb:a._a[Gb]<0||a._a[Gb]>59?Gb:a._a[Hb]<0||a._a[Hb]>59?Hb:a._a[Ib]<0||a._a[Ib]>999?Ib:-1,a._pf._overflowDayOfYear&&(Cb>b||b>Eb)&&(b=Eb),a._pf.overflow=b)}function I(b){return null==b._isValid&&(b._isValid=!isNaN(b._d.getTime())&&b._pf.overflow<0&&!b._pf.empty&&!b._pf.invalidMonth&&!b._pf.nullInput&&!b._pf.invalidFormat&&!b._pf.userInvalidated,b._strict&&(b._isValid=b._isValid&&0===b._pf.charsLeftOver&&0===b._pf.unusedTokens.length&&b._pf.bigHour===a)),b._isValid}function J(a){return a?a.toLowerCase().replace("_","-"):a}function K(a){for(var b,c,d,e,f=0;f0;){if(d=L(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&y(e,c,!0)>=b-1)break;b--}f++}return null}function L(a){var b=null;if(!Jb[a]&&Lb)try{b=vb.locale(),require("./locale/"+a),vb.locale(b)}catch(c){}return Jb[a]}function M(a,b){var c,d;return b._isUTC?(c=b.clone(),d=(vb.isMoment(a)||x(a)?+a:+vb(a))-+c,c._d.setTime(+c._d+d),vb.updateOffset(c,!1),c):vb(a).local()}function N(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function O(a){var b,c,d=a.match(Pb);for(b=0,c=d.length;c>b;b++)d[b]=rc[d[b]]?rc[d[b]]:N(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function P(a,b){return a.isValid()?(b=Q(b,a.localeData()),nc[b]||(nc[b]=O(b)),nc[b](a)):a.localeData().invalidDate()}function Q(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Qb.lastIndex=0;d>=0&&Qb.test(a);)a=a.replace(Qb,c),Qb.lastIndex=0,d-=1;return a}function R(a,b){var c,d=b._strict;switch(a){case"Q":return _b;case"DDDD":return bc;case"YYYY":case"GGGG":case"gggg":return d?cc:Tb;case"Y":case"G":case"g":return ec;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?dc:Ub;case"S":if(d)return _b;case"SS":if(d)return ac;case"SSS":if(d)return bc;case"DDD":return Sb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Wb;case"a":case"A":return b._locale._meridiemParse;case"x":return Zb;case"X":return $b;case"Z":case"ZZ":return Xb;case"T":return Yb;case"SSSS":return Vb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?ac:Rb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Rb;case"Do":return d?b._locale._ordinalParse:b._locale._ordinalParseLenient;default:return c=new RegExp($(Z(a.replace("\\","")),"i"))}}function S(a){a=a||"";var b=a.match(Xb)||[],c=b[b.length-1]||[],d=(c+"").match(jc)||["-",0,0],e=+(60*d[1])+C(d[2]);return"+"===d[0]?e:-e}function T(a,b,c){var d,e=c._a;switch(a){case"Q":null!=b&&(e[Db]=3*(C(b)-1));break;case"M":case"MM":null!=b&&(e[Db]=C(b)-1);break;case"MMM":case"MMMM":d=c._locale.monthsParse(b,a,c._strict),null!=d?e[Db]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[Eb]=C(b));break;case"Do":null!=b&&(e[Eb]=C(parseInt(b.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=C(b));break;case"YY":e[Cb]=vb.parseTwoDigitYear(b);break;case"YYYY":case"YYYYY":case"YYYYYY":e[Cb]=C(b);break;case"a":case"A":c._meridiem=b;break;case"h":case"hh":c._pf.bigHour=!0;case"H":case"HH":e[Fb]=C(b);break;case"m":case"mm":e[Gb]=C(b);break;case"s":case"ss":e[Hb]=C(b);break;case"S":case"SS":case"SSS":case"SSSS":e[Ib]=C(1e3*("0."+b));break;case"x":c._d=new Date(C(b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=S(b);break;case"dd":case"ddd":case"dddd":d=c._locale.weekdaysParse(b),null!=d?(c._w=c._w||{},c._w.d=d):c._pf.invalidWeekday=b;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":a=a.substr(0,1);case"gggg":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=C(b));break;case"gg":case"GG":c._w=c._w||{},c._w[a]=vb.parseTwoDigitYear(b)}}function U(a){var c,d,e,f,g,h,i;c=a._w,null!=c.GG||null!=c.W||null!=c.E?(g=1,h=4,d=b(c.GG,a._a[Cb],jb(vb(),1,4).year),e=b(c.W,1),f=b(c.E,1)):(g=a._locale._week.dow,h=a._locale._week.doy,d=b(c.gg,a._a[Cb],jb(vb(),g,h).year),e=b(c.w,1),null!=c.d?(f=c.d,g>f&&++e):f=null!=c.e?c.e+g:g),i=kb(d,e,f,h,g),a._a[Cb]=i.year,a._dayOfYear=i.dayOfYear}function V(a){var c,d,e,f,g=[];if(!a._d){for(e=X(a),a._w&&null==a._a[Eb]&&null==a._a[Db]&&U(a),a._dayOfYear&&(f=b(a._a[Cb],e[Cb]),a._dayOfYear>F(f)&&(a._pf._overflowDayOfYear=!0),d=fb(f,0,a._dayOfYear),a._a[Db]=d.getUTCMonth(),a._a[Eb]=d.getUTCDate()),c=0;3>c&&null==a._a[c];++c)a._a[c]=g[c]=e[c];for(;7>c;c++)a._a[c]=g[c]=null==a._a[c]?2===c?1:0:a._a[c];24===a._a[Fb]&&0===a._a[Gb]&&0===a._a[Hb]&&0===a._a[Ib]&&(a._nextDay=!0,a._a[Fb]=0),a._d=(a._useUTC?fb:eb).apply(null,g),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[Fb]=24)}}function W(a){var b;a._d||(b=A(a._i),a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],V(a))}function X(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function Y(b){if(b._f===vb.ISO_8601)return void ab(b);b._a=[],b._pf.empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Q(b._f,b._locale).match(Pb)||[],c=0;c0&&b._pf.unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),rc[f]?(d?b._pf.empty=!1:b._pf.unusedTokens.push(f),T(f,d,b)):b._strict&&!d&&b._pf.unusedTokens.push(f);b._pf.charsLeftOver=i-j,h.length>0&&b._pf.unusedInput.push(h),b._pf.bigHour===!0&&b._a[Fb]<=12&&(b._pf.bigHour=a),b._a[Fb]=k(b._locale,b._a[Fb],b._meridiem),V(b),H(b)}function Z(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function $(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function _(a){var b,c,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;fg)&&(e=g,c=b));o(a,c||b)}function ab(a){var b,c,d=a._i,e=fc.exec(d);if(e){for(a._pf.iso=!0,b=0,c=hc.length;c>b;b++)if(hc[b][1].exec(d)){a._f=hc[b][0]+(e[6]||" ");break}for(b=0,c=ic.length;c>b;b++)if(ic[b][1].exec(d)){a._f+=ic[b][0];break}d.match(Xb)&&(a._f+="Z"),Y(a)}else a._isValid=!1}function bb(a){ab(a),a._isValid===!1&&(delete a._isValid,vb.createFromInputFallback(a))}function cb(a,b){var c,d=[];for(c=0;ca&&h.setFullYear(a),h}function fb(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function gb(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function hb(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function ib(a,b,c){var d=vb.duration(a).abs(),e=Ab(d.as("s")),f=Ab(d.as("m")),g=Ab(d.as("h")),h=Ab(d.as("d")),i=Ab(d.as("M")),j=Ab(d.as("y")),k=e0,k[4]=c,hb.apply({},k)}function jb(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=vb(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function kb(a,b,c,d,e){var f,g,h=fb(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:F(a-1)+g}}function lb(b){var c,d=b._i,e=b._f;return b._locale=b._locale||vb.localeData(b._l),null===d||e===a&&""===d?vb.invalid({nullInput:!0}):("string"==typeof d&&(b._i=d=b._locale.preparse(d)),vb.isMoment(d)?new m(d,!0):(e?w(e)?_(b):Y(b):db(b),c=new m(b),c._nextDay&&(c.add(1,"d"),c._nextDay=a),c))}function mb(a,b){var c,d;if(1===b.length&&w(b[0])&&(b=b[0]),!b.length)return vb();for(c=b[0],d=1;d=0?"+":"-";return b+r(Math.abs(a),6)},gg:function(){return r(this.weekYear()%100,2)},gggg:function(){return r(this.weekYear(),4)},ggggg:function(){return r(this.weekYear(),5)},GG:function(){return r(this.isoWeekYear()%100,2)},GGGG:function(){return r(this.isoWeekYear(),4)},GGGGG:function(){return r(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return C(this.milliseconds()/100)},SS:function(){return r(C(this.milliseconds()/10),2)},SSS:function(){return r(this.milliseconds(),3)},SSSS:function(){return r(this.milliseconds(),3)},Z:function(){var a=this.utcOffset(),b="+";return 0>a&&(a=-a,b="-"),b+r(C(a/60),2)+":"+r(C(a)%60,2)},ZZ:function(){var a=this.utcOffset(),b="+";return 0>a&&(a=-a,b="-"),b+r(C(a/60),2)+r(C(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},sc={},tc=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"],uc=!1;pc.length;)xb=pc.pop(),rc[xb+"o"]=i(rc[xb],xb);for(;qc.length;)xb=qc.pop(),rc[xb+xb]=h(rc[xb],2);rc.DDDD=h(rc.DDD,3),o(l.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a,b,c){var d,e,f;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;12>d;d++){if(e=vb.utc([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=vb([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},longDateFormat:function(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.apply(b,[c]):d},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(a){return a},postformat:function(a){return a},week:function(a){return jb(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},firstDayOfWeek:function(){return this._week.dow},firstDayOfYear:function(){return this._week.doy},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),vb=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._i=b,g._f=c,g._l=e,g._strict=f,g._isUTC=!1,g._pf=d(),lb(g)},vb.suppressDeprecationWarnings=!1,vb.createFromInputFallback=f("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),vb.min=function(){var a=[].slice.call(arguments,0);return mb("isBefore",a)},vb.max=function(){var a=[].slice.call(arguments,0);return mb("isAfter",a)},vb.utc=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._useUTC=!0,g._isUTC=!0,g._l=e,g._i=b,g._f=c,g._strict=f,g._pf=d(),lb(g).utc()},vb.unix=function(a){return vb(1e3*a)},vb.duration=function(a,b){var d,e,f,g,h=a,i=null;return vb.isDuration(a)?h={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(h={},b?h[b]=a:h.milliseconds=a):(i=Nb.exec(a))?(d="-"===i[1]?-1:1,h={y:0,d:C(i[Eb])*d,h:C(i[Fb])*d,m:C(i[Gb])*d,s:C(i[Hb])*d,ms:C(i[Ib])*d}):(i=Ob.exec(a))?(d="-"===i[1]?-1:1,f=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*d},h={y:f(i[2]),M:f(i[3]),d:f(i[4]),h:f(i[5]),m:f(i[6]),s:f(i[7]),w:f(i[8])}):null==h?h={}:"object"==typeof h&&("from"in h||"to"in h)&&(g=t(vb(h.from),vb(h.to)),h={},h.ms=g.milliseconds,h.M=g.months),e=new n(h),vb.isDuration(a)&&c(a,"_locale")&&(e._locale=a._locale),e},vb.version=yb,vb.defaultFormat=gc,vb.ISO_8601=function(){},vb.momentProperties=Kb,vb.updateOffset=function(){},vb.relativeTimeThreshold=function(b,c){return oc[b]===a?!1:c===a?oc[b]:(oc[b]=c,!0)},vb.lang=f("moment.lang is deprecated. Use moment.locale instead.",function(a,b){return vb.locale(a,b)}),vb.locale=function(a,b){var c;return a&&(c="undefined"!=typeof b?vb.defineLocale(a,b):vb.localeData(a),c&&(vb.duration._locale=vb._locale=c)),vb._locale._abbr},vb.defineLocale=function(a,b){return null!==b?(b.abbr=a,Jb[a]||(Jb[a]=new l),Jb[a].set(b),vb.locale(a),Jb[a]):(delete Jb[a],null)},vb.langData=f("moment.langData is deprecated. Use moment.localeData instead.",function(a){return vb.localeData(a)}),vb.localeData=function(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return vb._locale;if(!w(a)){if(b=L(a))return b;a=[a]}return K(a)},vb.isMoment=function(a){return a instanceof m||null!=a&&c(a,"_isAMomentObject")},vb.isDuration=function(a){return a instanceof n};for(xb=tc.length-1;xb>=0;--xb)B(tc[xb]);vb.normalizeUnits=function(a){return z(a)},vb.invalid=function(a){var b=vb.utc(0/0);return null!=a?o(b._pf,a):b._pf.userInvalidated=!0,b},vb.parseZone=function(){return vb.apply(null,arguments).parseZone()},vb.parseTwoDigitYear=function(a){return C(a)+(C(a)>68?1900:2e3)},vb.isDate=x,o(vb.fn=m.prototype,{clone:function(){return vb(this)},valueOf:function(){return+this._d-6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=vb(this).utc();return 00:!1},parsingFlags:function(){return o({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(a){return this.utcOffset(0,a)},local:function(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(this._dateUtcOffset(),"m")),this},format:function(a){var b=P(this,a||vb.defaultFormat);return this.localeData().postformat(b)},add:u(1,"add"),subtract:u(-1,"subtract"),diff:function(a,b,c){var d,e,f=M(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=z(b),"year"===b||"month"===b||"quarter"===b?(e=j(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:q(e)},from:function(a,b){return vb.duration({to:this,from:a}).locale(this.locale()).humanize(!b)},fromNow:function(a){return this.from(vb(),a)},calendar:function(a){var b=a||vb(),c=M(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this,vb(b)))},isLeapYear:function(){return G(this.year())},isDST:function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},day:function(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=gb(a,this.localeData()),this.add(a-b,"d")):b},month:qb("Month",!0),startOf:function(a){switch(a=z(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a?this.weekday(0):"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this},endOf:function(b){return b=z(b),b===a||"millisecond"===b?this:this.startOf(b).add(1,"isoWeek"===b?"week":b).subtract(1,"ms")},isAfter:function(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=vb.isMoment(a)?a:vb(a),+this>+a):(c=vb.isMoment(a)?+a:+vb(a),c<+this.clone().startOf(b))},isBefore:function(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=vb.isMoment(a)?a:vb(a),+a>+this):(c=vb.isMoment(a)?+a:+vb(a),+this.clone().endOf(b)a?this:a}),max:f("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(a){return a=vb.apply(null,arguments),a>this?this:a}),zone:f("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",function(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}),utcOffset:function(a,b){var c,d=this._offset||0;return null!=a?("string"==typeof a&&(a=S(a)),Math.abs(a)<16&&(a=60*a),!this._isUTC&&b&&(c=this._dateUtcOffset()),this._offset=a,this._isUTC=!0,null!=c&&this.add(c,"m"),d!==a&&(!b||this._changeInProgress?v(this,vb.duration(a-d,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,vb.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?d:this._dateUtcOffset()},isLocal:function(){return!this._isUTC},isUtcOffset:function(){return this._isUTC},isUtc:function(){return this._isUTC&&0===this._offset},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(S(this._i)),this},hasAlignedHourOffset:function(a){return a=a?vb(a).utcOffset():0,(this.utcOffset()-a)%60===0},daysInMonth:function(){return D(this.year(),this.month())},dayOfYear:function(a){var b=Ab((vb(this).startOf("day")-vb(this).startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")},quarter:function(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)},weekYear:function(a){var b=jb(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")},isoWeekYear:function(a){var b=jb(this,1,4).year;return null==a?b:this.add(a-b,"y")},week:function(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")},isoWeek:function(a){var b=jb(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")},weekday:function(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},isoWeeksInYear:function(){return E(this.year(),1,4)},weeksInYear:function(){var a=this.localeData()._week;return E(this.year(),a.dow,a.doy)},get:function(a){return a=z(a),this[a]()},set:function(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else a=z(a),"function"==typeof this[a]&&this[a](b);return this},locale:function(b){var c;return b===a?this._locale._abbr:(c=vb.localeData(b),null!=c&&(this._locale=c),this)},lang:f("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(b){return b===a?this.localeData():this.locale(b)}),localeData:function(){return this._locale},_dateUtcOffset:function(){return 15*-Math.round(this._d.getTimezoneOffset()/15)}}),vb.fn.millisecond=vb.fn.milliseconds=qb("Milliseconds",!1),vb.fn.second=vb.fn.seconds=qb("Seconds",!1),vb.fn.minute=vb.fn.minutes=qb("Minutes",!1),vb.fn.hour=vb.fn.hours=qb("Hours",!0),vb.fn.date=qb("Date",!0),vb.fn.dates=f("dates accessor is deprecated. Use date instead.",qb("Date",!0)),vb.fn.year=qb("FullYear",!0),vb.fn.years=f("years accessor is deprecated. Use year instead.",qb("FullYear",!0)),vb.fn.days=vb.fn.day,vb.fn.months=vb.fn.month,vb.fn.weeks=vb.fn.week,vb.fn.isoWeeks=vb.fn.isoWeek,vb.fn.quarters=vb.fn.quarter,vb.fn.toJSON=vb.fn.toISOString,vb.fn.isUTC=vb.fn.isUtc,o(vb.duration.fn=n.prototype,{_bubble:function(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;g.milliseconds=d%1e3,a=q(d/1e3),g.seconds=a%60,b=q(a/60),g.minutes=b%60,c=q(b/60),g.hours=c%24,e+=q(c/24),h=q(rb(e)),e-=q(sb(h)),f+=q(e/30),e%=30,h+=q(f/12),f%=12,g.days=e,g.months=f,g.years=h},abs:function(){return this._milliseconds=Math.abs(this._milliseconds),this._days=Math.abs(this._days),this._months=Math.abs(this._months),this._data.milliseconds=Math.abs(this._data.milliseconds),this._data.seconds=Math.abs(this._data.seconds),this._data.minutes=Math.abs(this._data.minutes),this._data.hours=Math.abs(this._data.hours),this._data.months=Math.abs(this._data.months),this._data.years=Math.abs(this._data.years),this},weeks:function(){return q(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*C(this._months/12)
7 | },humanize:function(a){var b=ib(this,!a,this.localeData());return a&&(b=this.localeData().pastFuture(+this,b)),this.localeData().postformat(b)},add:function(a,b){var c=vb.duration(a,b);return this._milliseconds+=c._milliseconds,this._days+=c._days,this._months+=c._months,this._bubble(),this},subtract:function(a,b){var c=vb.duration(a,b);return this._milliseconds-=c._milliseconds,this._days-=c._days,this._months-=c._months,this._bubble(),this},get:function(a){return a=z(a),this[a.toLowerCase()+"s"]()},as:function(a){var b,c;if(a=z(a),"month"===a||"year"===a)return b=this._days+this._milliseconds/864e5,c=this._months+12*rb(b),"month"===a?c:c/12;switch(b=this._days+Math.round(sb(this._months/12)),a){case"week":return b/7+this._milliseconds/6048e5;case"day":return b+this._milliseconds/864e5;case"hour":return 24*b+this._milliseconds/36e5;case"minute":return 24*b*60+this._milliseconds/6e4;case"second":return 24*b*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*b*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+a)}},lang:vb.fn.lang,locale:vb.fn.locale,toIsoString:f("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var a=Math.abs(this.years()),b=Math.abs(this.months()),c=Math.abs(this.days()),d=Math.abs(this.hours()),e=Math.abs(this.minutes()),f=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"},localeData:function(){return this._locale},toJSON:function(){return this.toISOString()}}),vb.duration.fn.toString=vb.duration.fn.toISOString;for(xb in kc)c(kc,xb)&&tb(xb.toLowerCase());vb.duration.fn.asMilliseconds=function(){return this.as("ms")},vb.duration.fn.asSeconds=function(){return this.as("s")},vb.duration.fn.asMinutes=function(){return this.as("m")},vb.duration.fn.asHours=function(){return this.as("h")},vb.duration.fn.asDays=function(){return this.as("d")},vb.duration.fn.asWeeks=function(){return this.as("weeks")},vb.duration.fn.asMonths=function(){return this.as("M")},vb.duration.fn.asYears=function(){return this.as("y")},vb.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===C(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),Lb?module.exports=vb:"function"==typeof define&&define.amd?(define(function(a,b,c){return c.config&&c.config()&&c.config().noGlobal===!0&&(zb.moment=wb),vb}),ub(!0)):ub()}).call(this);
--------------------------------------------------------------------------------
/public/js/script.js:
--------------------------------------------------------------------------------
1 | var socket = io();
2 |
3 | window.moveTooltip = function (tooltip, element, middleX) {
4 | var $tooltip = $('.tooltip');
5 | if (!tooltip) {
6 | $tooltip.hide();
7 | return;
8 | }
9 |
10 | if (!$tooltip.length) {
11 | $tooltip = $("").addClass("tooltip");
12 | }
13 |
14 | if (element) {
15 | element.appendChild($tooltip[0]);
16 | } else {
17 | tooltip.chart.canvas.parentNode.appendChild($tooltip[0]);
18 | }
19 |
20 | $tooltip.html('');
21 |
22 | var values = tooltip.labels.map(function (label, index) {
23 | return {
24 | label: label,
25 | datasetLabel: tooltip.datasetLabels && tooltip.datasetLabels[index],
26 | color: tooltip.colors[index],
27 | };
28 | });
29 |
30 | values.sort(function (a, b) {
31 | return parseInt(b.label) - parseInt(a.label);
32 | });
33 |
34 | values.forEach(function (value) {
35 | var label = value.label;
36 | if (value.datasetLabel) {
37 | label = value.datasetLabel + ': ' + label;
38 | }
39 |
40 | var $label = $('
')
41 | .text(label)
42 | .css({
43 | color: value.color,
44 | });
45 | $tooltip.append($label);
46 | });
47 |
48 | $tooltip.css({
49 | top: tooltip.y - 20 * (values && values.length || 1),
50 | left: tooltip.x + 20 -
51 | (tooltip.x > (middleX || 500) ? $tooltip.width() + 20 : 0),
52 | });
53 |
54 | $tooltip.show();
55 | };
56 |
57 | $(function () {
58 | Chart.defaults.global.animation = false;
59 |
60 | var container = document.getElementsByClassName('container')[0];
61 |
62 | var createWidget = function (Widget) {
63 | var widget = document.createElement('div');
64 | container.appendChild(widget);
65 |
66 | var widgetObj = new Widget(widget);
67 |
68 | widget.className = 'widget ' + widgetObj.getWidthClass();
69 |
70 | var titleEle = document.createElement('div');
71 | titleEle.className = 'widget-title';
72 |
73 | titleEle.innerText = widgetObj.getTitle();
74 |
75 | var contEle = document.createElement('div');
76 | contEle.className = 'widget-content';
77 |
78 | widget.appendChild(titleEle);
79 | widget.appendChild(contEle);
80 |
81 | contEle.appendChild(widgetObj.getElement());
82 |
83 | return widgetObj;
84 | };
85 |
86 | var widgetClasses = [
87 | CPUChartWidget,
88 | FreememWidget,
89 | NetworkWidget,
90 | ProcessCPUWidget,
91 | MemoryWidget,
92 | UptimeWidget,
93 | CPUUsageWidget,
94 | ProcessMemoryWidget,
95 | TempsWidget,
96 | ];
97 |
98 | var widgets = widgetClasses.map(function (Widget) {
99 | return createWidget(Widget);
100 | });
101 |
102 | socket.on('history', function (history) {
103 | widgets.forEach(function (widget) {
104 | widget.initialize(history);
105 | });
106 | });
107 |
108 | socket.on('data', function (data) {
109 | widgets.forEach(function (widget) {
110 | widget.addData(data);
111 | });
112 | });
113 |
114 | // Legend tooltips
115 | $(".legend").on("mouseover", "li", function (event) {
116 | var rect = this.getClientRects()[0];
117 | window.moveTooltip({
118 | labels: [this.textContent],
119 | colors: [$(this).find("span").css("background-color")],
120 | x: rect.left + 30,
121 | y: rect.top + 30 + window.scrollY,
122 | }, document.body, 10000);
123 | });
124 |
125 | $(".legend").on("mouseout", "li", function (event) {
126 | $(".tooltip").hide();
127 | });
128 | });
129 |
--------------------------------------------------------------------------------
/public/js/theme.js:
--------------------------------------------------------------------------------
1 | const themes = ["light", "darkmode"];
2 |
3 | $(function () {
4 | let currentTheme = window.localStorage.getItem("theme") ?? themes[0];
5 |
6 | const setTheme = (theme) => {
7 | currentTheme = theme;
8 | window.localStorage.setItem("theme", currentTheme);
9 |
10 | document.getElementById("theme").href = "./css/" + currentTheme + ".css";
11 | };
12 |
13 | setTheme(currentTheme);
14 |
15 | $(".theme-button").on("click", () => {
16 | const curThemeIdx = themes.findIndex((x) => x === currentTheme);
17 | const newThemeIdx = (curThemeIdx + 1) % themes.length;
18 |
19 | setTheme(themes[newThemeIdx]);
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/public/js/widgets/basechartwidget.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var BaseChartWidget = function(widget) {
3 | this.canvas = document.createElement('canvas');
4 | this.canvas.width = widget.clientWidth - 40;
5 | this.canvas.height = 280;
6 | this.ctx = this.canvas.getContext('2d');
7 |
8 | this.numPoints = 0;
9 | };
10 | BaseChartWidget.prototype = Object.create(BaseWidget.prototype);
11 |
12 | BaseChartWidget.prototype.getElement = function() {
13 | return this.canvas;
14 | };
15 |
16 | BaseChartWidget.prototype.getColors = function() {
17 | return ['#000000'];
18 | },
19 |
20 | BaseChartWidget.prototype.getFillColors = function() {
21 | return ['#AAAAAA'];
22 | };
23 |
24 | BaseChartWidget.prototype.getLabels = function() {
25 | return ['Label'];
26 | };
27 |
28 | /*
29 | * Override to specify a suffix on the values in the chart
30 | * such as MB, or kB/s
31 | */
32 | BaseChartWidget.prototype.getSuffix = function() {
33 | return "";
34 | };
35 |
36 | /*
37 | * Should return an object like:
38 | * {
39 | * values: [[1, 2, 3], [2, 6, 1]],
40 | * labels: ['', 'test', ''],
41 | * }
42 | */
43 | BaseChartWidget.prototype.getPointsFromHistory = function(history) {
44 | throw "Children must override";
45 | };
46 |
47 | /*
48 | * Should return an integer
49 | */
50 | BaseChartWidget.prototype.getValuesFromData = function(data) {
51 | throw "Children must override";
52 | };
53 |
54 | BaseChartWidget.prototype.getLabelFromData = function(data) {
55 | return "";
56 | }
57 |
58 | BaseChartWidget.prototype.initialize = function(history) {
59 | var dataPoints = this.getPointsFromHistory(history);
60 | var labels = dataPoints.labels;
61 |
62 | var datasets = dataPoints.values.map(function(dataset, index) {
63 | return {
64 | fillColor: this.getFillColors()[index],
65 | strokeColor: this.getColors()[index],
66 | pointColor: 'rgba(0,0,0,0)',
67 | pointStrokeColor: 'rgba(0,0,0,0)',
68 | data: dataset,
69 | };
70 | }, this);
71 |
72 | var chartData = {
73 | labels: labels,
74 | datasets: datasets,
75 | };
76 |
77 | this.chart = new Chart(this.ctx).Line(chartData, {
78 | bezierCurveTension: 0.3,
79 | animationSteps: 30,
80 | scaleLabel: "<%= value %> " + this.getSuffix(),
81 | pointDotRadius: 4,
82 | scaleShowVerticalLines: false,
83 | showTooltips: false,
84 | });
85 |
86 | $(this.canvas).on('mousemove', function(event) {
87 | var mouseX = event.originalEvent.offsetX || event.originalEvent.layerX;
88 | var mouseY = event.originalEvent.offsetY || event.originalEvent.layerY;
89 |
90 | this.chart.datasets.forEach(function(dataset) {
91 | dataset.points.forEach(function(point) {
92 | point.fillColor = 'rgba(0,0,0,0)';
93 | });
94 | });
95 |
96 | var points = this.chart.datasets[0].points;
97 | var sortedPoints = points.map(function(point, index) {
98 | return {
99 | point: point,
100 | index: index,
101 | };
102 | });
103 |
104 | sortedPoints.sort(function(a, b) {
105 | var aDist = Math.abs(mouseX - a.point.x);
106 | var bDist = Math.abs(mouseX - b.point.x);
107 |
108 | return aDist - bDist;
109 | });
110 |
111 | var closestPoint = sortedPoints[0];
112 |
113 | this.chart.datasets.forEach(function(dataset, datasetIndex) {
114 | var index = sortedPoints[0].index;
115 | dataset.points[index].fillColor = this.getColors()[datasetIndex];
116 | }, this);
117 |
118 | this.chart.render(true);
119 |
120 | var labels = this.chart.datasets.map(function(dataset) {
121 | return dataset.points[closestPoint.index].value +
122 | ' ' + this.getSuffix();
123 | }, this);
124 |
125 | moveTooltip({
126 | chart: this.chart.chart,
127 | labels: labels,
128 | colors: this.getColors(),
129 | datasetLabels: this.getLabels(),
130 | x: closestPoint.point.x,
131 | y: closestPoint.point.y,
132 | });
133 | }.bind(this));
134 |
135 |
136 | $(this.canvas).on('mouseout', function() {
137 | // Reset all datasets
138 | this.chart.datasets.forEach(function(dataset) {
139 | dataset.points.forEach(function(point) {
140 | point.fillColor = 'rgba(0,0,0,0)';
141 | });
142 | });
143 |
144 | this.chart.render(true);
145 |
146 | moveTooltip(false);
147 | }.bind(this));
148 | };
149 |
150 | BaseChartWidget.prototype.addData = function(data) {
151 | var values = this.getValuesFromData(data);
152 |
153 | if (!values) {
154 | return;
155 | }
156 |
157 | var index = this.numPoints++;
158 |
159 | this.chart.addData(
160 | values,
161 | index % 5 === 0 ? this.getLabelFromData(data) : ''
162 | );
163 | };
164 |
165 | window.BaseChartWidget = BaseChartWidget;
166 | })();
167 |
--------------------------------------------------------------------------------
/public/js/widgets/basepiewidget.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var COLORS = ['#F44336', '#3F51B5', '#4CAF50', '#00BCD4', '#FFEB3B'];
3 |
4 | var BasePieWidget = function(widget) {
5 | this.div = document.createElement('div');
6 | this.div.className = 'pie';
7 |
8 | this.canvas = document.createElement('canvas');
9 | this.canvas.width = 250;
10 | this.canvas.height = 250;
11 | this.ctx = this.canvas.getContext('2d');
12 |
13 | this.legendDiv = document.createElement('div');
14 | this.legendDiv.className = 'legend';
15 |
16 | this.div.appendChild(this.canvas);
17 | this.div.appendChild(this.legendDiv);
18 |
19 | this.numPoints = 0;
20 | };
21 | BasePieWidget.prototype = Object.create(BaseWidget.prototype);
22 |
23 | BasePieWidget.prototype.getElement = function() {
24 | return this.div;
25 | };
26 |
27 | BasePieWidget.prototype.getWidthClass = function() {
28 | return "two";
29 | };
30 |
31 | /*
32 | * Override to specify a suffix on the values in the chart
33 | * such as MB, or kB/s
34 | */
35 | BasePieWidget.prototype.getSuffix = function() {
36 | return "";
37 | };
38 |
39 | BasePieWidget.prototype.initialize = function(history) {
40 | this.addData(history);
41 | };
42 |
43 | BasePieWidget.prototype.getChartData = function(data) {
44 | throw "Children must override";
45 | };
46 |
47 | BasePieWidget.prototype.addData = function(data) {
48 | var index = this.numPoints++;
49 |
50 | var data = this.getChartData(data);
51 |
52 | if (!data) {
53 | return;
54 | }
55 |
56 | this.chart && this.chart.destroy();
57 |
58 | this.chart = new Chart(this.ctx).Doughnut(data, {
59 | animateScale: index === 0,
60 | animateRotate : index === 0,
61 | tooltipTemplate: "<%= fillColor %>|<%= label %>: <%= value %>"
62 | + this.getSuffix(),
63 | customTooltips: function(tooltip) {
64 | if (!tooltip) {
65 | $(".tooltip").hide();
66 | return;
67 | }
68 |
69 | var textSplit = tooltip.text.split("|");
70 | var color = textSplit[0];
71 |
72 | tooltip.labels = [textSplit[1]];
73 | // tooltip.datasetLabels = [''];
74 | tooltip.colors = [color];
75 |
76 | window.moveTooltip(tooltip);
77 | }.bind(this),
78 | legendTemplate:
79 | '
-legend\">' +
80 | '<% for (var i=0; i' +
81 | '- ' +
82 | '\">' +
83 | '' +
84 | '<%=segments[i].value%>' + this.getSuffix() +
85 | ': <%=segments[i].label%>' +
86 | '
' +
87 | '<%}%>' +
88 | '
'
89 | });
90 |
91 | this.legendDiv.innerHTML = this.chart.generateLegend();
92 | };
93 |
94 |
95 | window.BasePieWidget = BasePieWidget;
96 | })();
97 |
--------------------------------------------------------------------------------
/public/js/widgets/basewidget.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var BaseWidget = function(widget) {
3 | this.div = document.createElement('div');
4 | };
5 |
6 | BaseWidget.prototype.getTitle = function() {
7 | return "Base Widget";
8 | };
9 |
10 | BaseWidget.prototype.getWidthClass = function() {
11 | return "one";
12 | };
13 |
14 | BaseWidget.prototype.getElement = function() {
15 | return this.div;
16 | };
17 |
18 | BaseWidget.prototype.initialize = function(history) {
19 | };
20 |
21 | BaseWidget.prototype.addData = function(data) {
22 | };
23 |
24 | window.BaseWidget = BaseWidget;
25 | })();
26 |
--------------------------------------------------------------------------------
/public/js/widgets/cpuchart.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var CPUChartWidget = function(widget) {
3 | BaseChartWidget.call(this, widget);
4 | };
5 | CPUChartWidget.prototype = Object.create(BaseChartWidget.prototype);
6 |
7 | CPUChartWidget.prototype.getTitle = function() {
8 | return "CPU Usage";
9 | };
10 |
11 | CPUChartWidget.prototype.getWidthClass = function() {
12 | return "three";
13 | };
14 |
15 | CPUChartWidget.prototype.getColors = function() {
16 | return ['#4CAF50', '#1B5E20'];
17 | },
18 |
19 | CPUChartWidget.prototype.getFillColors = function() {
20 | return ['rgba(76,175,80,0.05)', 'rgba(27,94,32, 0.05)'];
21 | };
22 |
23 | CPUChartWidget.prototype.getLabels = function() {
24 | return ['CPU Usage', 'CPU Usage Per Thread'];
25 | };
26 |
27 | CPUChartWidget.prototype.getSuffix = function() {
28 | return "%";
29 | };
30 |
31 | CPUChartWidget.prototype.getPointsFromHistory = function(history) {
32 | var dataPoints = [];
33 | var normalizedDataPoints = [];
34 | var labels = [];
35 |
36 | history.cpu.forEach(function(data, index) {
37 | this.numPoints++;
38 |
39 | dataPoints.push(data.cpu.toFixed(2));
40 | normalizedDataPoints.push(data.normalized.toFixed(2));
41 | labels.push(
42 | index % 5 === 0
43 | ? moment(data.timestamp).format('h:mm:ss')
44 | : ''
45 | );
46 | }, this);
47 |
48 | return {
49 | values: [dataPoints, normalizedDataPoints],
50 | labels: labels,
51 | };
52 | };
53 |
54 | CPUChartWidget.prototype.getValuesFromData = function(data) {
55 | if (!data.cpu) {
56 | return;
57 | }
58 |
59 | return [data.cpu.cpu.toFixed(2), data.cpu.normalized.toFixed(2)];
60 | };
61 |
62 | CPUChartWidget.prototype.getLabelFromData = function(data) {
63 | return moment(data.cpu.timestamp).format('h:mm:ss');
64 | };
65 |
66 | window.CPUChartWidget = CPUChartWidget;
67 | })();
68 |
--------------------------------------------------------------------------------
/public/js/widgets/cpuusage.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var CPUUsageWidget = function(widget) {
3 | BaseWidget.call(this, widget);
4 | this.topDiv = document.createElement('div');
5 | this.bottomDiv = document.createElement('div');
6 | this.div.appendChild(this.topDiv);
7 | this.div.appendChild(this.bottomDiv);
8 | };
9 | CPUUsageWidget.prototype = Object.create(BaseWidget.prototype);
10 |
11 | CPUUsageWidget.prototype.getTitle = function() {
12 | return "CPU Load";
13 | };
14 |
15 | CPUUsageWidget.prototype.getWidthClass = function() {
16 | return "one";
17 | };
18 |
19 | CPUUsageWidget.prototype.initialize = function(history) {
20 | this.addData(history);
21 | };
22 |
23 | CPUUsageWidget.prototype.addData = function(data) {
24 | if (!data.cpu) {
25 | return false;
26 | }
27 |
28 | if (data.cpu.length) {
29 | var cpu = data.cpu[data.cpu.length - 1].cpu;
30 | var normalized = data.cpu[data.cpu.length - 1].normalized;
31 | } else {
32 | cpu = data.cpu.cpu;
33 | normalized = data.cpu.normalized;
34 | }
35 |
36 | this.topDiv.innerText =
37 | "CPU Load: " + cpu.toFixed(2) + "%";
38 | this.bottomDiv.innerText =
39 | "Normalized: " + normalized.toFixed(2) + "% per thread";
40 | };
41 |
42 | window.CPUUsageWidget = CPUUsageWidget;
43 | })();
44 |
--------------------------------------------------------------------------------
/public/js/widgets/freemem.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var FreememWidget = function(widget) {
3 | BaseChartWidget.call(this, widget);
4 | };
5 | FreememWidget.prototype = Object.create(BaseChartWidget.prototype);
6 |
7 | FreememWidget.prototype.getTitle = function() {
8 | return "Used Memory";
9 | };
10 |
11 | FreememWidget.prototype.getWidthClass = function() {
12 | return "three";
13 | };
14 |
15 | FreememWidget.prototype.getColors = function() {
16 | return ['#1E88E5'];
17 | },
18 |
19 | FreememWidget.prototype.getFillColors = function() {
20 | return ['rgba(30,136,229,0.05)'];
21 | };
22 |
23 | FreememWidget.prototype.getLabels = function() {
24 | return ['Used Memory'];
25 | };
26 |
27 | FreememWidget.prototype.getSuffix = function() {
28 | return "MB";
29 | };
30 |
31 | FreememWidget.prototype.getPointsFromHistory = function(history) {
32 | var dataPoints = []
33 | var labels = [];
34 | history.memory.forEach(function(data, index) {
35 | this.numPoints++;
36 |
37 | dataPoints.push(Math.floor((data.total - data.free) / 1000000));
38 | labels.push(
39 | index % 5 === 0
40 | ? moment(data.timestamp).format('h:mm:ss')
41 | : ''
42 | );
43 | }, this);
44 |
45 | return {
46 | values: [dataPoints],
47 | labels: labels,
48 | };
49 | };
50 |
51 | FreememWidget.prototype.getValuesFromData = function(data) {
52 | if (!data.memory) {
53 | return;
54 | }
55 |
56 | return [Math.floor((data.memory.total - data.memory.free) / 1000000)];
57 | };
58 |
59 | FreememWidget.prototype.getLabelFromData = function(data) {
60 | return moment(data.memory.timestamp).format('h:mm:ss');
61 | };
62 |
63 | window.FreememWidget = FreememWidget;
64 | })();
65 |
--------------------------------------------------------------------------------
/public/js/widgets/memory.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var MemoryWidget = function(widget) {
3 | BaseWidget.call(this, widget);
4 | };
5 | MemoryWidget.prototype = Object.create(BaseWidget.prototype);
6 |
7 | MemoryWidget.prototype.getTitle = function() {
8 | return "Used Memory";
9 | };
10 |
11 | MemoryWidget.prototype.getWidthClass = function() {
12 | return "one";
13 | };
14 |
15 | MemoryWidget.prototype.initialize = function(history) {
16 | this.addData({
17 | memory: history.memory[history.memory.length - 1]
18 | });
19 | };
20 |
21 | MemoryWidget.prototype.addData = function(data) {
22 | if (!data.memory) {
23 | return;
24 | }
25 |
26 | var usedMemMB =
27 | Math.floor((data.memory.total - data.memory.free) / 1000000);
28 | var totalMemMB = Math.floor(data.memory.total / 1000000);
29 |
30 | this.div.innerText =
31 | "Used Memory: " + usedMemMB + "MB / " + totalMemMB + "MB";
32 | };
33 |
34 | window.MemoryWidget = MemoryWidget;
35 | })();
36 |
--------------------------------------------------------------------------------
/public/js/widgets/network.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var NetworkWidget = function(widget) {
3 | BaseChartWidget.call(this, widget);
4 | };
5 | NetworkWidget.prototype = Object.create(BaseChartWidget.prototype);
6 |
7 | NetworkWidget.prototype.getTitle = function() {
8 | return "Network Activity";
9 | };
10 |
11 | NetworkWidget.prototype.getWidthClass = function() {
12 | return "three";
13 | };
14 |
15 | NetworkWidget.prototype.getColors = function() {
16 | return ['#F44336', '#B71C1C'];
17 | },
18 |
19 | NetworkWidget.prototype.getFillColors = function() {
20 | return ['rgba(244,67,54,0.05)', 'rgba(183,28,28,0.05)'];
21 | };
22 |
23 | NetworkWidget.prototype.getLabels = function() {
24 | return ['Incoming Speed', 'Outgoing Speed'];
25 | };
26 |
27 | NetworkWidget.prototype.getSuffix = function() {
28 | return "kB/s";
29 | };
30 |
31 | NetworkWidget.prototype.getPointsFromHistory = function(history) {
32 | var inDataPoints = [];
33 | var outDataPoints = [];
34 | var labels = [];
35 |
36 | history.network.forEach(function(data, index) {
37 | this.numPoints++;
38 |
39 | inDataPoints.push(Math.floor(data.inSpeed / 1000));
40 | outDataPoints.push(Math.floor(data.outSpeed / 1000));
41 | labels.push(
42 | index % 5 === 0
43 | ? moment(data.timestamp).format('h:mm:ss')
44 | : ''
45 | );
46 | }, this);
47 |
48 | return {
49 | values: [inDataPoints, outDataPoints],
50 | labels: labels,
51 | };
52 | };
53 |
54 | NetworkWidget.prototype.getValuesFromData = function(data) {
55 | if (!data.network) {
56 | return;
57 | }
58 |
59 | return [
60 | Math.floor(data.network.inSpeed / 1000),
61 | Math.floor(data.network.outSpeed / 1000)
62 | ];
63 | };
64 |
65 | NetworkWidget.prototype.getLabelFromData = function(data) {
66 | return moment(data.network.timestamp).format('h:mm:ss');
67 | };
68 |
69 | window.NetworkWidget = NetworkWidget;
70 | })();
71 |
--------------------------------------------------------------------------------
/public/js/widgets/processcpu.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var COLORS = ['#F44336', '#3F51B5', '#4CAF50', '#00BCD4', '#FF9800'];
3 |
4 | var ProcessCPUWidget = function(widget) {
5 | BasePieWidget.call(this, widget);
6 | };
7 | ProcessCPUWidget.prototype = Object.create(BasePieWidget.prototype);
8 |
9 | ProcessCPUWidget.prototype.getTitle = function() {
10 | return "Process CPU Usage";
11 | };
12 |
13 | ProcessCPUWidget.prototype.getSuffix = function() {
14 | return "% CPU";
15 | };
16 |
17 | ProcessCPUWidget.prototype.getChartData = function(data) {
18 | if (!data.processes) {
19 | return false;
20 | }
21 |
22 | var processes = data.processes;
23 |
24 | processes.sort(function(a, b) {
25 | return b.cpu - a.cpu;
26 | });
27 |
28 | processes = processes.slice(0, 5);
29 |
30 | var chartData = [];
31 | processes.forEach(function(process, index) {
32 | chartData.push({
33 | value: process.cpu,
34 | color: COLORS[index],
35 | label: process.name,
36 | });
37 | });
38 |
39 | return chartData;
40 | };
41 |
42 | window.ProcessCPUWidget = ProcessCPUWidget;
43 | })();
44 |
--------------------------------------------------------------------------------
/public/js/widgets/processmemory.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var COLORS = ['#F44336', '#3F51B5', '#4CAF50', '#00BCD4', '#FF9800'];
3 |
4 | var ProcessMemoryWidget = function(widget) {
5 | BasePieWidget.call(this, widget);
6 | };
7 | ProcessMemoryWidget.prototype = Object.create(BasePieWidget.prototype);
8 |
9 | ProcessMemoryWidget.prototype.getTitle = function() {
10 | return "Process Memory Usage";
11 | };
12 |
13 | ProcessMemoryWidget.prototype.getSuffix = function() {
14 | return "% Memory";
15 | };
16 |
17 | ProcessMemoryWidget.prototype.getChartData = function(data) {
18 | if (!data.processes) {
19 | return false;
20 | }
21 |
22 | var processes = data.processes;
23 |
24 | processes.sort(function(a, b) {
25 | return b.mem - a.mem;
26 | });
27 |
28 | processes = processes.slice(0, 5);
29 |
30 | var chartData = [];
31 | processes.forEach(function(process, index) {
32 | chartData.push({
33 | value: process.mem,
34 | color: COLORS[index],
35 | label: process.name,
36 | });
37 | });
38 |
39 | return chartData;
40 | };
41 |
42 | window.ProcessMemoryWidget = ProcessMemoryWidget;
43 | })();
44 |
--------------------------------------------------------------------------------
/public/js/widgets/temps.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | var TempsWidget = function (widget) {
3 | BaseWidget.call(this, widget);
4 |
5 | this.divs = [];
6 |
7 | // this.topDiv = document.createElement('div');
8 | // this.bottomDiv = document.createElement('div');
9 | // this.div.appendChild(this.topDiv);
10 | // this.div.appendChild(this.bottomDiv);
11 | };
12 | TempsWidget.prototype = Object.create(BaseWidget.prototype);
13 |
14 | TempsWidget.prototype.getTitle = function () {
15 | return "Temperature Sensors";
16 | };
17 |
18 | TempsWidget.prototype.getWidthClass = function () {
19 | return "one";
20 | };
21 |
22 | TempsWidget.prototype.initialize = function (history) {
23 | this.addData(history);
24 | };
25 |
26 | TempsWidget.prototype.addData = function (data) {
27 | if (!data.temps) {
28 | return false;
29 | }
30 |
31 | // const latestData = data.temps[data.temps.length - 1];
32 |
33 | console.log(data.temps);
34 |
35 | // TODO we might wanna support removing divs if the number of sensors goes
36 | // down somehow during runtime.
37 | if (this.divs.length < data.temps.length) {
38 | const numDivsToCreate = data.temps.length - this.divs.length;
39 | for (let x = 0; x < numDivsToCreate; x++) {
40 | const div = document.createElement('div');
41 | this.div.appendChild(div);
42 | this.divs.push(div);
43 | }
44 | }
45 |
46 | data.temps.forEach((tempData, idx) => {
47 | const tempC = tempData.temp / 1000;
48 | this.divs[idx].innerText = `${tempData.type}: ${tempC}°C`;
49 | });
50 | };
51 |
52 | window.TempsWidget = TempsWidget;
53 | })();
54 |
--------------------------------------------------------------------------------
/public/js/widgets/uptime.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var UptimeWidget = function(widget) {
3 | BaseWidget.call(this, widget);
4 | };
5 | UptimeWidget.prototype = Object.create(BaseWidget.prototype);
6 |
7 | UptimeWidget.prototype.getTitle = function() {
8 | return "Uptime Information";
9 | };
10 |
11 | UptimeWidget.prototype.getWidthClass = function() {
12 | return "one";
13 | };
14 |
15 | UptimeWidget.prototype.getElement = function() {
16 | return this.div;
17 | };
18 |
19 | UptimeWidget.prototype.initialize = function(history) {
20 | this.addData(history);
21 | };
22 |
23 | UptimeWidget.prototype.addData = function(data) {
24 | var uptimeMilli = data.uptime;
25 | var duration = moment.duration(uptimeMilli);
26 |
27 | var years = duration.years();
28 | var months = duration.months();
29 | var days = duration.days();
30 | var hours = duration.hours();
31 | var minutes = duration.minutes();
32 | var seconds = duration.seconds();
33 |
34 | var times = [
35 | [years, 'year'],
36 | [months, 'month'],
37 | [days, 'day'],
38 | [hours, 'hour'],
39 | [minutes, 'minute'],
40 | [seconds, 'second'],
41 | ];
42 |
43 | var display = "";
44 | for (var x = 0; x < times.length; x++) {
45 | var time = times[x];
46 | if (time[0]) {
47 | display += time[0] + ' ' + time[1] +
48 | (time[0] !== 1 ? 's' : '') +
49 | (x !== times.length - 1 ? ', ' : '');
50 | }
51 | }
52 |
53 | this.div.innerText = display;
54 | };
55 |
56 | window.UptimeWidget = UptimeWidget;
57 | })();
58 |
--------------------------------------------------------------------------------