UNPKG

swstats

Version:
852 lines (745 loc) 23.7 kB
"use strict"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } (function e(t, n, r) { function s(o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == "function" && require;if (!u && a) return a(o, !0);if (i) return i(o, !0);var f = new Error("Cannot find module '" + o + "'");throw f.code = "MODULE_NOT_FOUND", f; }var l = n[o] = { exports: {} };t[o][0].call(l.exports, function (e) { var n = t[o][1][e];return s(n ? n : e); }, l, l.exports, e, t, n, r); }return n[o].exports; }var i = typeof require == "function" && require;for (var o = 0; o < r.length; o++) { s(r[o]); }return s; })({ 1: [function (require, module, exports) { "use strict"; (function ($) { var SWindow = require("./index"); $.SWindow = SWindow; })(window); }, { "./index": 2 }], 2: [function (require, module, exports) { var Operation = require("./lib/ops"), TimeStats = require("./lib/timestats"), SizeStats = require("./lib/sizestats"); module.exports = { TimeStats: TimeStats, SizeStats: SizeStats, Operation: Operation, register: Operation.register }; }, { "./lib/ops": 4, "./lib/sizestats": 6, "./lib/timestats": 7 }], 3: [function (require, module, exports) { module.exports = { sum: function sum(currval, newitems, olditems, allitems, newstats, oldstats) { currval = currval === undefined ? {} : currval; var ln = newitems.length, lo = olditems.length; for (var i = 0; i < ln; i++) { for (var j in newitems[i].v) { currval[j] = currval[j] || 0; currval[j] += newitems[i].v[j]; } } for (var _i = 0; _i < lo; _i++) { for (var _j in olditems[_i].v) { currval[_j] = currval[_j] || 0; currval[_j] -= olditems[_i].v[_j]; } } return currval; }, freq: function freq(currval, newitems, olditems, allitems, newstats, oldstats) { var sums = newstats.sum; var total = 0, res = {}; for (var i in sums) { total += sums[i]; }for (var _i2 in sums) { res[_i2] = sums[_i2] / total; }return res; }, mode: function mode(currval, newitems, olditems, allitems, newstats, oldstats) { var sums = newstats.sum; var map = []; for (var i in sums) { map.push({ k: i, t: sums[i] }); }map.sort(function (a, b) { return a.t - b.t; }); return (map.pop() || {}).k; } }; }, {}], 4: [function (require, module, exports) { var NOps = require("./nops"), COps = require("./cops"); // Default operations var DEF_OPS = { numeric: ["count", "sum", "max", "min", "avg", "stdev"], category: ["sum", "freq", "mode"] }; // Stats function type constants var TYPES = { numeric: "numeric", category: "category" }; // Registered operations var OPS = { numeric: { "count": { fn: NOps.count, deps: [] }, "sum": { fn: NOps.sum, deps: [] }, "max": { fn: NOps.max, deps: [] }, "min": { fn: NOps.min, deps: [] }, "avg": { fn: NOps.avg, deps: [] }, "stdev": { fn: NOps.stdev, deps: ["avg"] } }, category: { "sum": { fn: COps.sum, deps: [] }, "freq": { fn: COps.freq, deps: ["sum"] }, "mode": { fn: COps.mode, deps: ["sum"] } } }; /** * Registers a new operation * @param type [TYPES.numeric / TYPES.category] * @param name The name of the stat function * @param deps Array of dependency names * @param fn Stats function to be called, in the form of * fn(currval,newitems,olditems,allitems,newstats,oldstats) * @param def Use by default. */ function register(type, name, deps, fn, def) { OPS[type][name] = { fn: fn, deps: deps }; if (def) DEF_OPS[type].push(name); } module.exports = { NOps: NOps, COps: COps, RXOps: OPS, DEFOps: DEF_OPS, Types: TYPES, register: register }; }, { "./cops": 3, "./nops": 5 }], 5: [function (require, module, exports) { var OPS = { count: function count(currval, newitems, olditems, allitems, newstats, oldstats) { var t = 0, len = allitems.length; for (var i = 0; i < len; i++) { t += allitems[i].l || 1; }return t; }, sum: function sum(currval, newitems, olditems, allitems, newstats, oldstats) { currval = currval === undefined ? 0 : currval; var ln = newitems.length, lo = olditems.length; for (var i = 0; i < ln; i++) { currval += newitems[i].v; }for (var _i3 = 0; _i3 < lo; _i3++) { currval -= olditems[_i3].v; }return currval; }, max: function max(currval, newitems, olditems, allitems, newstats, oldstats) { var max = -Infinity, len = allitems.length; for (var i = 0; i < len; i++) { max = Math.max(max, allitems[i].max); }return max; }, min: function min(currval, newitems, olditems, allitems, newstats, oldstats) { var min = Infinity, len = allitems.length; for (var i = 0; i < len; i++) { min = Math.min(min, allitems[i].min); }return min; }, avg: function avg(currval, newitems, olditems, allitems, newstats, oldstats) { var ln = OPS.count(0, 0, 0, newitems), lo = OPS.count(0, 0, 0, olditems), nvl = OPS.count(0, 0, 0, allitems), ovl = nvl - ln + lo; currval = currval === undefined ? 0 : currval; currval = currval * ovl; for (var i = 0; i < newitems.length; i++) { currval += newitems[i].v; }for (var _i4 = 0; _i4 < olditems.length; _i4++) { currval -= olditems[_i4].v; }currval = currval / nvl; return isNaN(currval) ? 0 : currval; }, stdev: function stdev(currval, newitems, olditems, allitems, newstats, oldstats) { oldstats.stdev = oldstats.stdev || { avg: 1, sqsum: 0, sum: 0, stdev: 0 }; var ln = OPS.count(0, 0, 0, newitems), lo = OPS.count(0, 0, 0, olditems), nvl = OPS.count(0, 0, 0, allitems), ovl = nvl - ln + lo, len = allitems.length, oavg = oldstats.avg || 0; var oldavg = oldstats.stdev.avg; var oldsqsum = oldstats.stdev.sqsum; var oldsum = oldstats.stdev.sum; var newavg = newstats.avg || 0; var newsqsum = oldsqsum; var newsum = oldsum; for (var i = 0; i < olditems.length; i++) { var it = olditems[i].v / (olditems[i].l || 1); newsqsum -= it * it; newsum -= it; } for (var _i5 = 0; _i5 < newitems.length; _i5++) { var _it = newitems[_i5].v / (newitems[_i5].l || 1); newsqsum += _it * _it; newsum += _it; } var stdev = Math.sqrt((newsqsum - 2 * newavg * newsum + len * newavg * newavg) / len); return { avg: newavg, sqsum: newsqsum, sum: newsum, stdev: stdev }; } }; module.exports = OPS; }, {}], 6: [function (require, module, exports) { var Operation = require("./ops"), Util = require("./util"), Types = Operation.Types, RXOps = Operation.RXOps, DEFOps = Operation.DEFOps; // Default options var DEF_OPTIONS = { type: Types.numeric, ops: DEFOps.numeric, step: 1000 }; /** * SizeStats Slide Window * @class */ var SizeStats = function () { /** * @param {numeric} size Number of maximum slots before slide * @param {[type]} options Options */ function SizeStats(size, options) { _classCallCheck(this, SizeStats); options = options || DEF_OPTIONS; this._options = options; this._arr = []; this._size = size || 1000; this._type = options.type || DEF_OPTIONS.type; this._ops = options.ops || DEFOps[this._type]; this.stats = Util.clone(options.stats || {}); Util.sortOps(this._ops, this._type); } _createClass(SizeStats, [{ key: "clean", value: function clean() { this._arr = []; this._oldstats = {}; this.stats = Util.clone(this._options.stats || {}); } }, { key: "push", value: function push(vals) { vals = vals instanceof Array ? vals : [vals]; return this._type == Types.numeric ? this._pushNum(vals) : this._pushCat(vals); } }, { key: "_pushNum", value: function _pushNum(vals) { var _this = this; var arr = this._arr, old = []; var type = this._type; var oldstats = Util.clone(this.stats); vals = vals.map(function (v) { return { v: v, l: 1, max: v, min: v }; }); vals.forEach(function (v) { return _this._arr.push(v); }); while (this._arr.length > this._size) { old.push(this._arr.shift()); } this._ops.forEach(function (op) { _this.stats[op] = RXOps[type][op].fn(_this.stats[op], vals, old, arr, _this.stats, oldstats); }); return this; } }, { key: "_pushCat", value: function _pushCat(vals) { var _this2 = this; var arr = this._arr, old = []; var type = this._type; var oldstats = Util.clone(this.stats); var map = { v: {} }; vals.forEach(function (v) { map.v[v] = map.v[v] || 0; map.v[v]++; }); this._arr.push(map); while (this._arr.length > this._size) { old.push(this._arr.shift()); } this._ops.forEach(function (op) { _this2.stats[op] = RXOps[type][op].fn(_this2.stats[op], [map], old, arr, _this2.stats, oldstats); }); return this; } }, { key: "length", get: function get() { return this._arr.length; } }, { key: "window", get: function get() { var _this3 = this; var type = this._type; var win = this._arr.map(function (slot) { var ops = {}; _this3._ops.forEach(function (op) { ops[op] = RXOps[type][op].fn(undefined, [slot], [], [slot], ops, {}); }); return ops; }); return win; } }]); return SizeStats; }(); module.exports = SizeStats; }, { "./ops": 4, "./util": 8 }], 7: [function (require, module, exports) { var Operation = require("./ops"), Util = require("./util"), Types = Operation.Types, RXOps = Operation.RXOps, DEFOps = Operation.DEFOps; // Default options var DEF_OPTIONS = { type: Types.numeric, ops: DEFOps.numeric, step: 1000 }; var IVAL = 1000; // Slide window interval var LIST = []; // Active window instances /** * Slide time window interval */ setInterval(function () { var now = Date.now(); // For each stat created object LIST.filter(function (sws) { return !sws._pause; }).forEach(function (sws) { var arr = sws._arr, time = sws._time; var type = sws._type; var old = []; var oldstats = Util.clone(sws.stats); // Remove slots whose date has expired while (arr.length && now - arr[0].t > time) { old.push(arr.shift()); } // Execute each stat operation over the remaining slots sws._ops.forEach(function (op) { sws.stats[op] = RXOps[type][op].fn(sws.stats[op], [], old, sws._arr, sws.stats, oldstats); }); }); }, IVAL); /** * TimeStats Slide Window * @class */ var TimeStats = function () { _createClass(TimeStats, null, [{ key: "TS", get: function get() { return { ABSOLUTE: "absolute", RELATIVE: "relative" }; } /** * @param {numeric} time Time (ms) of the duration of the window, before slide * @param {object} options options */ }]); function TimeStats(time, options) { _classCallCheck(this, TimeStats); options = options || DEF_OPTIONS; this._options = options; this._arr = []; this._time = time || 10000; this._tst = options.timestamp || TimeStats.TS.ABSOLUTE; this._type = options.type || DEF_OPTIONS.type; this._ops = options.ops || DEFOps[this._type]; this._step = options.step || DEF_OPTIONS.step; this._pause = false; this._active = true; this._oldstats = {}; this._mints = Infinity; this._maxts = -Infinity; this.stats = Util.clone(options.stats || {}); Util.sortOps(this._ops, this._type); if (this._tst == TimeStats.TS.ABSOLUTE) LIST.push(this); } _createClass(TimeStats, [{ key: "clean", value: function clean() { this._arr = []; this._oldstats = {}; this.stats = Util.clone(this._options.stats || {}); } }, { key: "push", value: function push(vals) { if (!this._active || this._pause) return; vals = vals instanceof Array ? vals : [vals]; if (this._tst == TimeStats.TS.ABSOLUTE) { return this._type == Types.numeric ? this._pushNum(vals) : this._pushCat(vals); } else { return this._type == Types.numeric ? this._pushNumRel(vals) : this._pushCatRel(vals); } } }, { key: "pause", value: function pause() { this._pause = true; } }, { key: "resume", value: function resume(shift) { var arr = this._arr; if (shift && arr.length) { var now = Date.now(); var last = arr[arr.length].t; var diff = now - last; arr.length.forEach(function (v) { return v.t += diff; }); } this._pause = false; } }, { key: "destroy", value: function destroy() { var idx = LIST.indexOf(this); if (idx >= 0) LIST.splice(idx, 1); this._active = false; } }, { key: "_pushNum", value: function _pushNum(vals) { var _this4 = this; var now = Date.now(), arr = this._arr, type = this._type, oldstats = Util.clone(this.stats); // Map values to stat object vals = vals.map(function (v) { return { t: now, v: v, l: 1, max: v, min: v }; }); // First slot in array if (!arr.length) arr.push({ t: now, v: 0, l: 0, max: -Infinity, min: Infinity }); // Get last slot var last = arr[arr.length - 1]; // Value fits in current slot if (now - last.t < this._step) { // Clone the current slot to make the diff last = Util.clone(last); // Acumulate on the slot copy vals.forEach(function (v) { last.v += v.v;last.l += 1; last.max = Math.max(last.max, v.v), last.min = Math.min(last.min, v.v); }); // Remove the original slot and push the copy var oa = [arr.pop()], na = [last]; arr.push(last); // Apply operations this._ops.forEach(function (op) { _this4.stats[op] = RXOps[type][op].fn(_this4.stats[op], na, oa, arr, _this4.stats, oldstats); }); } else { vals.forEach(function (v) { arr.push(v); }); this._ops.forEach(function (op) { _this4.stats[op] = RXOps[type][op].fn(_this4.stats[op], vals, [], arr, _this4.stats, oldstats); }); } return this; } }, { key: "_pushNumRel", value: function _pushNumRel(vals) { var _this5 = this; var now = Date.now(), arr = this._arr, type = this._type, oldstats = Util.clone(this.stats); vals = vals.map(function (v) { return { t: v.t || now, v: v.v, l: 1, max: v.v, min: v.v }; }); vals.forEach(function (v) { // First element if (!arr.length) { arr.push(v); _this5._mints = v.t; _this5._maxts = v.t; return; } // Ignore values older than current time window var tsdist = _this5._maxts - v.t; if (tsdist > _this5._time) return; // Find the closest slot by time difference var tss = arr.map(function (slot, i) { return { dt: Math.abs(slot.t - v.t), i: i }; }).sort(function (a, b) { return b.dt - a.dt; }).pop(); var slot = arr[tss.i]; // Value fits in this slot if (Math.abs(v.t - slot.t) < _this5._step) { var cloned = Util.clone(slot); cloned.v += v.v;cloned.l += 1; cloned.max = Math.max(cloned.max, v.v), cloned.min = Math.min(cloned.min, v.v // Remove the original slot and push the copy );var oa = arr.splice(tss.i, 1), na = [cloned]; arr.push(cloned); // Apply operations _this5._ops.forEach(function (op) { _this5.stats[op] = RXOps[type][op].fn(_this5.stats[op], na, oa, arr, _this5.stats, oldstats); }); } // Create a new slot else { arr.push(v); _this5._ops.forEach(function (op) { _this5.stats[op] = RXOps[type][op].fn(_this5.stats[op], [v], [], arr, _this5.stats, oldstats); }); } // Update window time range _this5._mints = Math.min(v.t, _this5._mints); _this5._maxts = Math.max(v.t, _this5._maxts); oldstats = Util.clone(_this5.stats); }); // Sort window arr.sort(function (a, b) { return a.t - b.t; }); // Remove old slots var old = []; while (Math.abs(this._mints - this._maxts) > this._time) { old.push(arr.shift()); this._mints = arr[0].t; } // Refresh operations if (old.length) { this._ops.forEach(function (op) { _this5.stats[op] = RXOps[type][op].fn(_this5.stats[op], [], old, arr, _this5.stats, oldstats); }); } return this; } }, { key: "_pushCat", value: function _pushCat(vals) { var _this6 = this; var now = Date.now(); var arr = this._arr; var type = this._type; var oldstats = Util.clone(this.stats); var map = {}; vals.forEach(function (v) { map[v] = map[v] || 0; map[v]++; }); if (!arr.length) arr.push({ t: now, v: {} }); var last = Util.clone(arr[arr.length - 1]); if (now - last.t < this._step) { for (var i in map) { last.v[i] = last.v[i] || 0; last.v[i] += map[i]; } var oa = [arr.pop()], na = [last]; arr.push(last); this._ops.forEach(function (op) { _this6.stats[op] = RXOps[type][op].fn(_this6.stats[op], na, oa, arr, _this6.stats, oldstats); }); } else { var item = { t: now, v: map }; arr.push(item); this._ops.forEach(function (op) { _this6.stats[op] = RXOps[type][op].fn(_this6.stats[op], [item], [], arr, _this6.stats, oldstats); }); } return this; } }, { key: "_pushCatRel", value: function _pushCatRel(vals) { var _this7 = this; var arr = this._arr, type = this._type, oldstats = Util.clone(this.stats); vals.forEach(function (v) { // First element if (!arr.length) { arr.push({ t: v.t, v: _defineProperty({}, v.v, 1) }); _this7._mints = v.t; _this7._maxts = v.t; return; } // Ignore values older than current time window var tsdist = _this7._maxts - v.t; if (tsdist > _this7._time) return; // Find the closest slot by time difference var tss = arr.map(function (slot, i) { return { dt: Math.abs(slot.t - v.t), i: i }; }).sort(function (a, b) { return b.dt - a.dt; }).pop(); var slot = arr[tss.i]; // Value fits in this slot if (Math.abs(v.t - slot.t) < _this7._step) { var cloned = Util.clone(slot); cloned.v[v.v] = cloned.v[v.v] || 0; cloned.v[v.v] += 1; // Remove the original slot and push the copy var oa = arr.splice(tss.i, 1), na = [cloned]; arr.push(cloned); // Apply operations _this7._ops.forEach(function (op) { _this7.stats[op] = RXOps[type][op].fn(_this7.stats[op], na, oa, arr, _this7.stats, oldstats); }); } // Create a new slot else { var newslot = { t: v.t, v: _defineProperty({}, v.v, 1) }; arr.push(newslot); _this7._ops.forEach(function (op) { _this7.stats[op] = RXOps[type][op].fn(_this7.stats[op], newslot, [], arr, _this7.stats, oldstats); }); } // Update window time range _this7._mints = Math.min(v.t, _this7._mints); _this7._maxts = Math.max(v.t, _this7._maxts); oldstats = Util.clone(_this7.stats); }); // Sort window arr.sort(function (a, b) { return a.t - b.t; }); // Remove old slots var old = []; while (Math.abs(this._mints - this._maxts) > this._time) { old.push(arr.shift()); this._mints = arr[0].t; } // Refresh operations if (old.length) { this._ops.forEach(function (op) { _this7.stats[op] = RXOps[type][op].fn(_this7.stats[op], [], old, arr, _this7.stats, oldstats); }); } return this; } }, { key: "length", get: function get() { return this._arr.length; } }, { key: "window", get: function get() { var _this8 = this; var type = this._type; var win = this._arr.map(function (slot) { var ops = { t: slot.t }; _this8._ops.forEach(function (op) { ops[op] = RXOps[type][op].fn(undefined, [slot], [], [slot], ops, {}); }); return ops; }); return win; } }]); return TimeStats; }(); module.exports = TimeStats; }, { "./ops": 4, "./util": 8 }], 8: [function (require, module, exports) { var RXOps = require("./ops").RXOps; /** * Simple object clone function */ function clone(obj) { if ((typeof obj === "undefined" ? "undefined" : _typeof(obj)) != "object") { return obj; } else { var o = {}; for (var i in obj) { o[i] = clone(obj[i]); }return o; } } function depends(a, b, type) { var deps = RXOps[type][a].deps; if (!deps.length) return false;else if (deps.indexOf(b) >= 0) return true;else { return deps.reduce(function (curr, val) { return curr || depends(val, b, type); }, false); } } /** * Sorts category operations by its dependencies */ function sortOps(ops, type) { var map = {}, n = false; ops.forEach(function (op) { return map[op] = true; }); do { n = false; ops.forEach(function (op) { RXOps[type][op].deps.forEach(function (dep) { if (!map[dep]) { map[dep] = true; ops.push(dep); n = true; }; }); }); } while (n); // Stupid sort because Array.sort will not work with dependency sorting if (ops.length > 1) { var tmp = null, it = false; do { it = false; for (var i = 0; i < ops.length; i++) { for (var j = i; j < ops.length; j++) { if (depends(ops[i], ops[j], type)) { tmp = ops[i]; ops[i] = ops[j]; ops[j] = tmp; it = true; } } } } while (it); } } module.exports = { clone: clone, depends: depends, sortOps: sortOps }; }, { "./ops": 4 }] }, {}, [1]); //# sourceMappingURL=swstats.js.map