diff options
| author | Pim van den Berg | 2013-05-10 21:36:54 +0200 | 
|---|---|---|
| committer | Pim van den Berg | 2013-05-10 21:36:54 +0200 | 
| commit | 0163faefef02207ad0ea3330af688103633293ff (patch) | |
| tree | c407fca93a3418af59c4c7133327f5bc1630fba5 /js/RrdRpn.js | |
| parent | Merge pull request #5 from mce35/nut (diff) | |
| download | apt-panopticon_cgp-0163faefef02207ad0ea3330af688103633293ff.zip apt-panopticon_cgp-0163faefef02207ad0ea3330af688103633293ff.tar.gz apt-panopticon_cgp-0163faefef02207ad0ea3330af688103633293ff.tar.bz2 apt-panopticon_cgp-0163faefef02207ad0ea3330af688103633293ff.tar.xz  | |
import js directory from jsrrdgraph for client side graph rendering
Source: https://github.com/manuelluis/jsrrdgraph@276b880
Diffstat (limited to '')
| -rw-r--r-- | js/RrdRpn.js | 616 | 
1 files changed, 616 insertions, 0 deletions
diff --git a/js/RrdRpn.js b/js/RrdRpn.js new file mode 100644 index 0000000..cbb5e8f --- /dev/null +++ b/js/RrdRpn.js  | |||
| @@ -0,0 +1,616 @@ | |||
| 1 | /** | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or modify it | ||
| 4 | * under the terms of the GNU General Public License as published by the Free | ||
| 5 | * Software Foundation; either version 2 of the License, or (at your option) | ||
| 6 | * any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | |||
| 13 | * You should have received a copy of the GNU General Public License along | ||
| 14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
| 15 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 16 | |||
| 17 | * RRDtool 1.4.5 Copyright by Tobi Oetiker, 1997-2010 | ||
| 18 | * | ||
| 19 | * Convert to javascript: Manuel Sanmartin <manuel.luis at gmail.com> | ||
| 20 | **/ | ||
| 21 | |||
| 22 | "use strict"; | ||
| 23 | |||
| 24 | /** | ||
| 25 | * RrdRpnError | ||
| 26 | * @constructor | ||
| 27 | */ | ||
| 28 | var RrdRpnError = function (message) | ||
| 29 | { | ||
| 30 | this.prototype = Error.prototype; | ||
| 31 | this.name = "RrdRpnError"; | ||
| 32 | this.message = (message) ? message : "RPN stack underflow"; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * RrdRpn | ||
| 37 | * @constructor | ||
| 38 | */ | ||
| 39 | var RrdRpn = function (str_expr, gdes) /* parser */ | ||
| 40 | { | ||
| 41 | var steps = -1; | ||
| 42 | var expr; | ||
| 43 | var exprs = str_expr.split(','); | ||
| 44 | |||
| 45 | this.rpnexpr = str_expr; | ||
| 46 | this.rpnp = []; | ||
| 47 | this.rpnstack = null; | ||
| 48 | |||
| 49 | for(var i=0, len=exprs.length; i < len; i++) { | ||
| 50 | expr=exprs[i].toUpperCase(); | ||
| 51 | |||
| 52 | steps++; | ||
| 53 | this.rpnp[steps] = {}; | ||
| 54 | |||
| 55 | if (!isNaN(expr)) { | ||
| 56 | this.rpnp[steps].op = RrdRpn.OP_NUMBER; | ||
| 57 | this.rpnp[steps].val = parseFloat(expr); | ||
| 58 | } | ||
| 59 | else if (expr === '+') this.rpnp[steps].op = RrdRpn.OP_ADD; | ||
| 60 | else if (expr === '-') this.rpnp[steps].op = RrdRpn.OP_SUB; | ||
| 61 | else if (expr === '*') this.rpnp[steps].op = RrdRpn.OP_MUL; | ||
| 62 | else if (expr === '/') this.rpnp[steps].op = RrdRpn.OP_DIV; | ||
| 63 | else if (expr === '%') this.rpnp[steps].op = RrdRpn.OP_MOD; | ||
| 64 | else if (expr === 'SIN') this.rpnp[steps].op = RrdRpn.OP_SIN; | ||
| 65 | else if (expr === 'COS') this.rpnp[steps].op = RrdRpn.OP_COS; | ||
| 66 | else if (expr === 'LOG') this.rpnp[steps].op = RrdRpn.OP_LOG; | ||
| 67 | else if (expr === 'FLOOR') this.rpnp[steps].op = RrdRpn.OP_FLOOR; | ||
| 68 | else if (expr === 'CEIL') this.rpnp[steps].op = RrdRpn.OP_CEIL; | ||
| 69 | else if (expr === 'EXP') this.rpnp[steps].op = RrdRpn.OP_EXP; | ||
| 70 | else if (expr === 'DUP') this.rpnp[steps].op = RrdRpn.OP_DUP; | ||
| 71 | else if (expr === 'EXC') this.rpnp[steps].op = RrdRpn.OP_EXC; | ||
| 72 | else if (expr === 'POP') this.rpnp[steps].op = RrdRpn.OP_POP; | ||
| 73 | else if (expr === 'LTIME') this.rpnp[steps].op = RrdRpn.OP_LTIME; | ||
| 74 | else if (expr === 'LT') this.rpnp[steps].op = RrdRpn.OP_LT; | ||
| 75 | else if (expr === 'LE') this.rpnp[steps].op = RrdRpn.OP_LE; | ||
| 76 | else if (expr === 'GT') this.rpnp[steps].op = RrdRpn.OP_GT; | ||
| 77 | else if (expr === 'GE') this.rpnp[steps].op = RrdRpn.OP_GE; | ||
| 78 | else if (expr === 'EQ') this.rpnp[steps].op = RrdRpn.OP_EQ; | ||
| 79 | else if (expr === 'IF') this.rpnp[steps].op = RrdRpn.OP_IF; | ||
| 80 | else if (expr === 'MIN') this.rpnp[steps].op = RrdRpn.OP_MIN; | ||
| 81 | else if (expr === 'MAX') this.rpnp[steps].op = RrdRpn.OP_MAX; | ||
| 82 | else if (expr === 'LIMIT') this.rpnp[steps].op = RrdRpn.OP_LIMIT; | ||
| 83 | else if (expr === 'UNKN') this.rpnp[steps].op = RrdRpn.OP_UNKN; | ||
| 84 | else if (expr === 'UN') this.rpnp[steps].op = RrdRpn.OP_UN; | ||
| 85 | else if (expr === 'NEGINF') this.rpnp[steps].op = RrdRpn.OP_NEGINF; | ||
| 86 | else if (expr === 'NE') this.rpnp[steps].op = RrdRpn.OP_NE; | ||
| 87 | else if (expr === 'COUNT') this.rpnp[steps].op = RrdRpn.OP_COUNT; | ||
| 88 | else if (/PREV\([-_A-Za-z0-9]+\)/.test(expr)) { | ||
| 89 | var match = exprs[i].match(/PREV\(([-_A-Za-z0-9]+)\)/i); | ||
| 90 | if (match.length == 2) { | ||
| 91 | this.rpnp[steps].op = RrdRpn.OP_PREV_OTHER; | ||
| 92 | this.rpnp[steps].ptr = this.find_var(gdes, match[1]); // FIXME if -1 | ||
| 93 | } | ||
| 94 | } | ||
| 95 | else if (expr === 'PREV') this.rpnp[steps].op = RrdRpn.OP_PREV; | ||
| 96 | else if (expr === 'INF') this.rpnp[steps].op = RrdRpn.OP_INF; | ||
| 97 | else if (expr === 'ISINF') this.rpnp[steps].op = RrdRpn.OP_ISINF; | ||
| 98 | else if (expr === 'NOW') this.rpnp[steps].op = RrdRpn.OP_NOW; | ||
| 99 | else if (expr === 'TIME') this.rpnp[steps].op = RrdRpn.OP_TIME; | ||
| 100 | else if (expr === 'ATAN2') this.rpnp[steps].op = RrdRpn.OP_ATAN2; | ||
| 101 | else if (expr === 'ATAN') this.rpnp[steps].op = RrdRpn.OP_ATAN; | ||
| 102 | else if (expr === 'SQRT') this.rpnp[steps].op = RrdRpn.OP_SQRT; | ||
| 103 | else if (expr === 'SORT') this.rpnp[steps].op = RrdRpn.OP_SORT; | ||
| 104 | else if (expr === 'REV') this.rpnp[steps].op = RrdRpn.OP_REV; | ||
| 105 | else if (expr === 'TREND') this.rpnp[steps].op = RrdRpn.OP_TREND; | ||
| 106 | else if (expr === 'TRENDNAN') this.rpnp[steps].op = RrdRpn.OP_TRENDNAN; | ||
| 107 | else if (expr === 'PREDICT') this.rpnp[steps].op = RrdRpn.OP_PREDICT; | ||
| 108 | else if (expr === 'PREDICTSIGMA') this.rpnp[steps].op = RrdRpn.OP_PREDICTSIGMA; | ||
| 109 | else if (expr === 'RAD2DEG') this.rpnp[steps].op = RrdRpn.OP_RAD2DEG; | ||
| 110 | else if (expr === 'DEG2RAD') this.rpnp[steps].op = RrdRpn.OP_DEG2RAD; | ||
| 111 | else if (expr === 'AVG') this.rpnp[steps].op = RrdRpn.OP_AVG; | ||
| 112 | else if (expr === 'ABS') this.rpnp[steps].op = RrdRpn.OP_ABS; | ||
| 113 | else if (expr === 'ADDNAN') this.rpnp[steps].op = RrdRpn.OP_ADDNAN; | ||
| 114 | else if (/[-_A-Za-z0-9]+/.test(expr)) { | ||
| 115 | this.rpnp[steps].ptr = this.find_var(gdes, exprs[i]); // FIXME if -1 | ||
| 116 | this.rpnp[steps].op = RrdRpn.OP_VARIABLE; | ||
| 117 | } else { | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | this.rpnp[steps + 1] = {}; | ||
| 122 | this.rpnp[steps + 1].op = RrdRpn.OP_END; | ||
| 123 | }; | ||
| 124 | |||
| 125 | RrdRpn.OP_NUMBER= 0; | ||
| 126 | RrdRpn.OP_VARIABLE = 1; | ||
| 127 | RrdRpn.OP_INF = 2; | ||
| 128 | RrdRpn.OP_PREV = 3; | ||
| 129 | RrdRpn.OP_NEGINF = 4; | ||
| 130 | RrdRpn.OP_UNKN = 5; | ||
| 131 | RrdRpn.OP_NOW = 6; | ||
| 132 | RrdRpn.OP_TIME = 7; | ||
| 133 | RrdRpn.OP_ADD = 8; | ||
| 134 | RrdRpn.OP_MOD = 9; | ||
| 135 | RrdRpn.OP_SUB = 10; | ||
| 136 | RrdRpn.OP_MUL = 11; | ||
| 137 | RrdRpn.OP_DIV = 12; | ||
| 138 | RrdRpn.OP_SIN = 13; | ||
| 139 | RrdRpn.OP_DUP = 14; | ||
| 140 | RrdRpn.OP_EXC = 15; | ||
| 141 | RrdRpn.OP_POP = 16; | ||
| 142 | RrdRpn.OP_COS = 17; | ||
| 143 | RrdRpn.OP_LOG = 18; | ||
| 144 | RrdRpn.OP_EXP = 19; | ||
| 145 | RrdRpn.OP_LT = 20; | ||
| 146 | RrdRpn.OP_LE = 21; | ||
| 147 | RrdRpn.OP_GT = 22; | ||
| 148 | RrdRpn.OP_GE = 23; | ||
| 149 | RrdRpn.OP_EQ = 24; | ||
| 150 | RrdRpn.OP_IF = 25; | ||
| 151 | RrdRpn.OP_MIN = 26; | ||
| 152 | RrdRpn.OP_MAX = 27; | ||
| 153 | RrdRpn.OP_LIMIT = 28; | ||
| 154 | RrdRpn.OP_FLOOR = 29; | ||
| 155 | RrdRpn.OP_CEIL = 30; | ||
| 156 | RrdRpn.OP_UN = 31; | ||
| 157 | RrdRpn.OP_END = 32; | ||
| 158 | RrdRpn.OP_LTIME = 33; | ||
| 159 | RrdRpn.OP_NE = 34; | ||
| 160 | RrdRpn.OP_ISINF = 35; | ||
| 161 | RrdRpn.OP_PREV_OTHER = 36; | ||
| 162 | RrdRpn.OP_COUNT = 37; | ||
| 163 | RrdRpn.OP_ATAN = 38; | ||
| 164 | RrdRpn.OP_SQRT = 39; | ||
| 165 | RrdRpn.OP_SORT = 40; | ||
| 166 | RrdRpn.OP_REV = 41; | ||
| 167 | RrdRpn.OP_TREND = 42; | ||
| 168 | RrdRpn.OP_TRENDNAN = 43; | ||
| 169 | RrdRpn.OP_ATAN2 = 44; | ||
| 170 | RrdRpn.OP_RAD2DEG = 45; | ||
| 171 | RrdRpn.OP_DEG2RAD = 46; | ||
| 172 | RrdRpn.OP_PREDICT = 47; | ||
| 173 | RrdRpn.OP_PREDICTSIGMA = 48; | ||
| 174 | RrdRpn.OP_AVG = 49; | ||
| 175 | RrdRpn.OP_ABS = 50; | ||
| 176 | RrdRpn.OP_ADDNAN = 51 ; | ||
| 177 | |||
| 178 | RrdRpn.prototype.find_var = function(gdes, key) | ||
| 179 | { | ||
| 180 | for (var ii = 0, gdes_c = gdes.length; ii < gdes_c; ii++) { | ||
| 181 | if ((gdes[ii].gf == RrdGraphDesc.GF_DEF || | ||
| 182 | gdes[ii].gf == RrdGraphDesc.GF_VDEF || | ||
| 183 | gdes[ii].gf == RrdGraphDesc.GF_CDEF) | ||
| 184 | && gdes[ii].vname == key) { | ||
| 185 | return ii; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | return -1; | ||
| 189 | }; | ||
| 190 | |||
| 191 | RrdRpn.prototype.compare_double = function(x, y) | ||
| 192 | { | ||
| 193 | var diff = x - y; | ||
| 194 | return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; | ||
| 195 | }; | ||
| 196 | |||
| 197 | RrdRpn.prototype.fmod = function (x, y) | ||
| 198 | { | ||
| 199 | // http://kevin.vanzonneveld.net | ||
| 200 | // + original by: Onno Marsman | ||
| 201 | // + input by: Brett Zamir (http://brett-zamir.me) | ||
| 202 | // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) | ||
| 203 | // * example 1: fmod(5.7, 1.3); | ||
| 204 | // * returns 1: 0.5 | ||
| 205 | var tmp, tmp2, p = 0, | ||
| 206 | pY = 0, | ||
| 207 | l = 0.0, | ||
| 208 | l2 = 0.0; | ||
| 209 | |||
| 210 | tmp = x.toExponential().match(/^.\.?(.*)e(.+)$/); | ||
| 211 | p = parseInt(tmp[2], 10) - (tmp[1] + '').length; | ||
| 212 | tmp = y.toExponential().match(/^.\.?(.*)e(.+)$/); | ||
| 213 | pY = parseInt(tmp[2], 10) - (tmp[1] + '').length; | ||
| 214 | |||
| 215 | if (pY > p) p = pY; | ||
| 216 | |||
| 217 | tmp2 = (x % y); | ||
| 218 | |||
| 219 | if (p < -100 || p > 20) { | ||
| 220 | l = Math.round(Math.log(tmp2) / Math.log(10)); | ||
| 221 | l2 = Math.pow(10, l); | ||
| 222 | return (tmp2 / l2).toFixed(l - p) * l2; | ||
| 223 | } else { | ||
| 224 | return parseFloat(tmp2.toFixed(-p)); | ||
| 225 | } | ||
| 226 | }; | ||
| 227 | |||
| 228 | RrdRpn.prototype.calc = function (data_idx, output, output_idx) | ||
| 229 | { | ||
| 230 | var stptr = -1; | ||
| 231 | |||
| 232 | this.rpnstack = []; | ||
| 233 | |||
| 234 | for (var rpi = 0; this.rpnp[rpi].op != RrdRpn.OP_END; rpi++) { | ||
| 235 | switch (this.rpnp[rpi].op) { | ||
| 236 | case RrdRpn.OP_NUMBER: | ||
| 237 | this.rpnstack[++stptr] = this.rpnp[rpi].val; | ||
| 238 | break; | ||
| 239 | case RrdRpn.OP_VARIABLE: | ||
| 240 | case RrdRpn.OP_PREV_OTHER: | ||
| 241 | if (this.rpnp[rpi].ds_cnt == 0) { | ||
| 242 | throw new RrdRpnError("VDEF made it into rpn_calc... aborting"); | ||
| 243 | } else { | ||
| 244 | if (this.rpnp[rpi].op == RrdRpn.OP_VARIABLE) { | ||
| 245 | this.rpnstack[++stptr] = this.rpnp[rpi].data[this.rpnp[rpi].pdata]; | ||
| 246 | } else { | ||
| 247 | if ((output_idx) <= 0) this.rpnstack[++stptr] = Number.NaN; | ||
| 248 | else this.rpnstack[++stptr] = this.rpnp[rpi].data[this.rpnp[rpi].pdata - this.rpnp[rpi].ds_cnt]; | ||
| 249 | } | ||
| 250 | if (data_idx % this.rpnp[rpi].step == 0) { | ||
| 251 | this.rpnp[rpi].pdata += this.rpnp[rpi].ds_cnt; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | break; | ||
| 255 | case RrdRpn.OP_COUNT: | ||
| 256 | this.rpnstack[++stptr] = (output_idx + 1); /* Note: Counter starts at 1 */ | ||
| 257 | break; | ||
| 258 | case RrdRpn.OP_PREV: | ||
| 259 | if ((output_idx) <= 0) this.rpnstack[++stptr] = Number.NaN; | ||
| 260 | else this.rpnstack[++stptr] = output[output_idx - 1]; | ||
| 261 | break; | ||
| 262 | case RrdRpn.OP_UNKN: | ||
| 263 | this.rpnstack[++stptr] = Number.NaN; | ||
| 264 | break; | ||
| 265 | case RrdRpn.OP_INF: | ||
| 266 | this.rpnstack[++stptr] = Infinity; | ||
| 267 | break; | ||
| 268 | case RrdRpn.OP_NEGINF: | ||
| 269 | this.rpnstack[++stptr] = -Infinity; | ||
| 270 | break; | ||
| 271 | case RrdRpn.OP_NOW: | ||
| 272 | this.rpnstack[++stptr] = Math.round((new Date()).getTime() / 1000); | ||
| 273 | break; | ||
| 274 | case RrdRpn.OP_TIME: | ||
| 275 | this.rpnstack[++stptr] = data_idx; | ||
| 276 | break; | ||
| 277 | case RrdRpn.OP_LTIME: | ||
| 278 | var date = new Date(data_idx*1000); // FIXME XXX | ||
| 279 | this.rpnstack[++stptr] = date.getTimezoneOffset() * 60 + data_idx; | ||
| 280 | break; | ||
| 281 | case RrdRpn.OP_ADD: | ||
| 282 | if(stptr < 1) throw new RrdRpnError(); | ||
| 283 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] + this.rpnstack[stptr]; | ||
| 284 | stptr--; | ||
| 285 | break; | ||
| 286 | case RrdRpn.OP_ADDNAN: | ||
| 287 | if(stptr < 1) throw new RrdRpnError(); | ||
| 288 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 289 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 290 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 291 | /* NOOP */ | ||
| 292 | /* this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1]; */ | ||
| 293 | } else { | ||
| 294 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] + this.rpnstack[stptr]; | ||
| 295 | } | ||
| 296 | stptr--; | ||
| 297 | break; | ||
| 298 | case RrdRpn.OP_SUB: | ||
| 299 | if(stptr < 1) throw new RrdRpnError(); | ||
| 300 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] - this.rpnstack[stptr]; | ||
| 301 | stptr--; | ||
| 302 | break; | ||
| 303 | case RrdRpn.OP_MUL: | ||
| 304 | if(stptr < 1) throw new RrdRpnError(); | ||
| 305 | this.rpnstack[stptr - 1] = (this.rpnstack[stptr - 1]) * (this.rpnstack[stptr]); | ||
| 306 | stptr--; | ||
| 307 | break; | ||
| 308 | case RrdRpn.OP_DIV: | ||
| 309 | if(stptr < 1) throw new RrdRpnError(); | ||
| 310 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] / this.rpnstack[stptr]; | ||
| 311 | stptr--; | ||
| 312 | break; | ||
| 313 | case RrdRpn.OP_MOD: | ||
| 314 | if(stptr < 1) throw new RrdRpnError(); | ||
| 315 | this.rpnstack[stptr - 1] = this.fmod(this.rpnstack[stptr - 1] , this.rpnstack[stptr]); | ||
| 316 | stptr--; | ||
| 317 | break; | ||
| 318 | case RrdRpn.OP_SIN: | ||
| 319 | if(stptr < 0) throw new RrdRpnError(); | ||
| 320 | this.rpnstack[stptr] = Math.sin(this.rpnstack[stptr]); | ||
| 321 | break; | ||
| 322 | case RrdRpn.OP_ATAN: | ||
| 323 | if(stptr < 0) throw new RrdRpnError(); | ||
| 324 | this.rpnstack[stptr] = Math.atan(this.rpnstack[stptr]); | ||
| 325 | break; | ||
| 326 | case RrdRpn.OP_RAD2DEG: | ||
| 327 | if(stptr < 0) throw new RrdRpnError(); | ||
| 328 | this.rpnstack[stptr] = 57.29577951 * this.rpnstack[stptr]; | ||
| 329 | break; | ||
| 330 | case RrdRpn.OP_DEG2RAD: | ||
| 331 | if(stptr < 0) throw new RrdRpnError(); | ||
| 332 | this.rpnstack[stptr] = 0.0174532952 * this.rpnstack[stptr]; | ||
| 333 | break; | ||
| 334 | case RrdRpn.OP_ATAN2: | ||
| 335 | if(stptr < 1) throw new RrdRpnError(); | ||
| 336 | this.rpnstack[stptr - 1] = Math.atan2(this.rpnstack[stptr - 1], this.rpnstack[stptr]); | ||
| 337 | stptr--; | ||
| 338 | break; | ||
| 339 | case RrdRpn.OP_COS: | ||
| 340 | if(stptr < 0) throw new RrdRpnError(); | ||
| 341 | this.rpnstack[stptr] = Math.cos(this.rpnstack[stptr]); | ||
| 342 | break; | ||
| 343 | case RrdRpn.OP_CEIL: | ||
| 344 | if(stptr < 0) throw new RrdRpnError(); | ||
| 345 | this.rpnstack[stptr] = Math.ceil(this.rpnstack[stptr]); | ||
| 346 | break; | ||
| 347 | case RrdRpn.OP_FLOOR: | ||
| 348 | if(stptr < 0) throw new RrdRpnError(); | ||
| 349 | this.rpnstack[stptr] = Math.floor(this.rpnstack[stptr]); | ||
| 350 | break; | ||
| 351 | case RrdRpn.OP_LOG: | ||
| 352 | if(stptr < 0) throw new RrdRpnError(); | ||
| 353 | this.rpnstack[stptr] = Math.log(this.rpnstack[stptr]); | ||
| 354 | break; | ||
| 355 | case RrdRpn.OP_DUP: | ||
| 356 | if(stptr < 0) throw new RrdRpnError(); | ||
| 357 | this.rpnstack[stptr + 1] = this.rpnstack[stptr]; | ||
| 358 | stptr++; | ||
| 359 | break; | ||
| 360 | case RrdRpn.OP_POP: | ||
| 361 | if(stptr < 0) throw new RrdRpnError(); | ||
| 362 | stptr--; | ||
| 363 | break; | ||
| 364 | case RrdRpn.OP_EXC: | ||
| 365 | if(stptr < 1) throw new RrdRpnError(); { | ||
| 366 | var dummy = this.rpnstack[stptr]; | ||
| 367 | this.rpnstack[stptr] = this.rpnstack[stptr - 1]; | ||
| 368 | this.rpnstack[stptr - 1] = dummy; | ||
| 369 | } | ||
| 370 | break; | ||
| 371 | case RrdRpn.OP_EXP: | ||
| 372 | if(stptr < 0) throw new RrdRpnError(); | ||
| 373 | this.rpnstack[stptr] = Math.exp(this.rpnstack[stptr]); | ||
| 374 | break; | ||
| 375 | case RrdRpn.OP_LT: | ||
| 376 | if(stptr < 1) throw new RrdRpnError(); | ||
| 377 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 378 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 379 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 380 | } else { | ||
| 381 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] < this.rpnstack[stptr] ? 1.0 : 0.0; | ||
| 382 | } | ||
| 383 | stptr--; | ||
| 384 | break; | ||
| 385 | case RrdRpn.OP_LE: | ||
| 386 | if(stptr < 1) throw new RrdRpnError(); | ||
| 387 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 388 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 389 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 390 | } else { | ||
| 391 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] <= this.rpnstack[stptr] ? 1.0 : 0.0; | ||
| 392 | } | ||
| 393 | stptr--; | ||
| 394 | break; | ||
| 395 | case RrdRpn.OP_GT: | ||
| 396 | if(stptr < 1) throw new RrdRpnError(); | ||
| 397 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 398 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 399 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 400 | } else { | ||
| 401 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] > this.rpnstack[stptr] ? 1.0 : 0.0; | ||
| 402 | } | ||
| 403 | stptr--; | ||
| 404 | break; | ||
| 405 | case RrdRpn.OP_GE: | ||
| 406 | if(stptr < 1) throw new RrdRpnError(); | ||
| 407 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 408 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 409 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 410 | } else { | ||
| 411 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] >= this.rpnstack[stptr] ? 1.0 : 0.0; | ||
| 412 | } | ||
| 413 | stptr--; | ||
| 414 | break; | ||
| 415 | case RrdRpn.OP_NE: | ||
| 416 | if(stptr < 1) throw new RrdRpnError(); | ||
| 417 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 418 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 419 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 420 | } else { | ||
| 421 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] == this.rpnstack[stptr] ? 0.0 : 1.0; | ||
| 422 | } | ||
| 423 | stptr--; | ||
| 424 | break; | ||
| 425 | case RrdRpn.OP_EQ: | ||
| 426 | if(stptr < 1) throw new RrdRpnError(); | ||
| 427 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 428 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 429 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 430 | } else { | ||
| 431 | this.rpnstack[stptr - 1] = this.rpnstack[stptr - 1] == this.rpnstack[stptr] ? 1.0 : 0.0; | ||
| 432 | } | ||
| 433 | stptr--; | ||
| 434 | break; | ||
| 435 | case RrdRpn.OP_IF: | ||
| 436 | if(stptr < 2) throw new RrdRpnError(); | ||
| 437 | this.rpnstack[stptr - 2] = (isNaN(this.rpnstack[stptr - 2]) || this.rpnstack[stptr - 2] == 0.0) ? this.rpnstack[stptr] : this.rpnstack[stptr - 1]; | ||
| 438 | stptr--; | ||
| 439 | stptr--; | ||
| 440 | break; | ||
| 441 | case RrdRpn.OP_MIN: | ||
| 442 | if(stptr < 1) throw new RrdRpnError(); | ||
| 443 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 444 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 445 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 446 | } else if (this.rpnstack[stptr - 1] > this.rpnstack[stptr]) { | ||
| 447 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 448 | } | ||
| 449 | stptr--; | ||
| 450 | break; | ||
| 451 | case RrdRpn.OP_MAX: | ||
| 452 | if(stptr < 1) throw new RrdRpnError(); | ||
| 453 | if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 454 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 455 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 456 | } else if (this.rpnstack[stptr - 1] < this.rpnstack[stptr]) { | ||
| 457 | this.rpnstack[stptr - 1] = this.rpnstack[stptr]; | ||
| 458 | } | ||
| 459 | stptr--; | ||
| 460 | break; | ||
| 461 | case RrdRpn.OP_LIMIT: | ||
| 462 | if(stptr < 2) throw new RrdRpnError(); | ||
| 463 | if (isNaN(this.rpnstack[stptr - 2])) { | ||
| 464 | } else if (isNaN(this.rpnstack[stptr - 1])) { | ||
| 465 | this.rpnstack[stptr - 2] = this.rpnstack[stptr - 1]; | ||
| 466 | } else if (isNaN(this.rpnstack[stptr])) { | ||
| 467 | this.rpnstack[stptr - 2] = this.rpnstack[stptr]; | ||
| 468 | } else if (this.rpnstack[stptr - 2] < this.rpnstack[stptr - 1]) { | ||
| 469 | this.rpnstack[stptr - 2] = Number.NaN; | ||
| 470 | } else if (this.rpnstack[stptr - 2] > this.rpnstack[stptr]) { | ||
| 471 | this.rpnstack[stptr - 2] = Number.NaN; | ||
| 472 | } | ||
| 473 | stptr -= 2; | ||
| 474 | break; | ||
| 475 | case RrdRpn.OP_UN: | ||
| 476 | if(stptr < 0) throw new RrdRpnError(); | ||
| 477 | this.rpnstack[stptr] = isNaN(this.rpnstack[stptr]) ? 1.0 : 0.0; | ||
| 478 | break; | ||
| 479 | case RrdRpn.OP_ISINF: | ||
| 480 | if(stptr < 0) throw new RrdRpnError(); | ||
| 481 | this.rpnstack[stptr] = isInfinite(this.rpnstack[stptr]) ? 1.0 : 0.0; | ||
| 482 | break; | ||
| 483 | case RrdRpn.OP_SQRT: | ||
| 484 | if(stptr < 0) throw new RrdRpnError(); | ||
| 485 | this.rpnstack[stptr] = Math.sqrt(this.rpnstack[stptr]); | ||
| 486 | break; | ||
| 487 | case RrdRpn.OP_SORT: | ||
| 488 | if(stptr < 0) throw new RrdRpnError(); | ||
| 489 | var spn = this.rpnstack[stptr--]; | ||
| 490 | if(stptr < spn - 1) throw new RrdRpnError(); | ||
| 491 | var array = this.rpnstack.slice(stptr - spn + 1, stptr +1); | ||
| 492 | array.sort(this.compare_double); | ||
| 493 | for (var i=stptr - spn + 1, ii=0; i < (stptr +1) ; i++, ii++) | ||
| 494 | this.rpnstack[i] = array[ii]; | ||
| 495 | // qsort(this.rpnstack + stptr - spn + 1, spn, sizeof(double), rpn_compare_double); | ||
| 496 | break; | ||
| 497 | case RrdRpn.OP_REV: | ||
| 498 | if(stptr < 0) throw new RrdRpnError(); | ||
| 499 | var spn = this.rpnstack[stptr--]; | ||
| 500 | if(stptr < spn - 1) throw new RrdRpnError(); | ||
| 501 | var array = this.rpnstack.slice(stptr - spn + 1, stptr +1); | ||
| 502 | array.reverse(); | ||
| 503 | for (var i=stptr - spn + 1, ii=0; i < (stptr +1) ; i++, ii++) | ||
| 504 | this.rpnstack[i] = array[ii]; | ||
| 505 | break; | ||
| 506 | case RrdRpn.OP_PREDICT: | ||
| 507 | case RrdRpn.OP_PREDICTSIGMA: | ||
| 508 | if(stptr < 2) throw new RrdRpnError(); | ||
| 509 | var locstepsize = this.rpnstack[--stptr]; | ||
| 510 | var shifts = this.rpnstack[--stptr]; | ||
| 511 | if(stptr < shifts) throw new RrdRpnError(); | ||
| 512 | if (shifts<0) stptr--; | ||
| 513 | else stptr-=shifts; | ||
| 514 | var val=Number.NaN; | ||
| 515 | var dsstep = this.rpnp[rpi - 1].step; | ||
| 516 | var dscount = this.rpnp[rpi - 1].ds_cnt; | ||
| 517 | var locstep = Math.ceil(locstepsize/dsstep); | ||
| 518 | var sum = 0; | ||
| 519 | var sum2 = 0; | ||
| 520 | var count = 0; | ||
| 521 | /* now loop for each position */ | ||
| 522 | var doshifts=shifts; | ||
| 523 | if (shifts<0) doshifts=-shifts; | ||
| 524 | for(var loop=0;loop<doshifts;loop++) { | ||
| 525 | var shiftstep=1; | ||
| 526 | if (shifts<0) shiftstep = loop*this.rpnstack[stptr]; | ||
| 527 | else shiftstep = this.rpnstack[stptr+loop]; | ||
| 528 | if(shiftstep <0) { | ||
| 529 | throw new RrdRpnError("negative shift step not allowed: "+shiftstep); | ||
| 530 | } | ||
| 531 | shiftstep=Math.ceil(shiftstep/dsstep); | ||
| 532 | for(var i=0;i<=locstep;i++) { | ||
| 533 | var offset=shiftstep+i; | ||
| 534 | if ((offset>=0)&&(offset<output_idx)) { | ||
| 535 | val = this.rpnp[rpi - 1].data[-dscount * offset]; | ||
| 536 | if (! isNaN(val)) { | ||
| 537 | sum+=val; | ||
| 538 | sum2+=val*val; | ||
| 539 | count++; | ||
| 540 | } | ||
| 541 | } | ||
| 542 | } | ||
| 543 | } | ||
| 544 | val=Number.NaN; | ||
| 545 | if (this.rpnp[rpi].op == RrdRpn.OP_PREDICT) { | ||
| 546 | if (count>0) val = sum/count; | ||
| 547 | } else { | ||
| 548 | if (count>1) { | ||
| 549 | val=count*sum2-sum*sum; | ||
| 550 | if (val<0) { | ||
| 551 | val=Number.NaN; | ||
| 552 | } else { | ||
| 553 | val=Math.sqrt(val/(count*(count-1.0))); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | } | ||
| 557 | this.rpnstack[stptr] = val; | ||
| 558 | break; | ||
| 559 | case RrdRpn.OP_TREND: | ||
| 560 | case RrdRpn.OP_TRENDNAN: | ||
| 561 | if(stptr < 1) throw new RrdRpnError(); | ||
| 562 | if ((rpi < 2) || (this.rpnp[rpi - 2].op != RrdRpn.OP_VARIABLE)) { | ||
| 563 | throw new RrdRpnError("malformed trend arguments"); | ||
| 564 | } else { | ||
| 565 | var dur = this.rpnstack[stptr]; | ||
| 566 | var step = this.rpnp[rpi - 2].step; | ||
| 567 | |||
| 568 | if (output_idx + 1 >= Math.ceil(dur / step)) { | ||
| 569 | var ignorenan = (this.rpnp[rpi].op == RrdRpn.OP_TREND); | ||
| 570 | var accum = 0.0; | ||
| 571 | var i = 0; | ||
| 572 | var count = 0; | ||
| 573 | |||
| 574 | do { | ||
| 575 | var val = this.rpnp[rpi - 2].data[this.rpnp[rpi - 2].ds_cnt * i--]; | ||
| 576 | if (ignorenan || !isNaN(val)) { | ||
| 577 | accum += val; | ||
| 578 | ++count; | ||
| 579 | } | ||
| 580 | dur -= step; | ||
| 581 | } while (dur > 0); | ||
| 582 | |||
| 583 | this.rpnstack[--stptr] = (count == 0) ? Number.NaN : (accum / count); | ||
| 584 | } else this.rpnstack[--stptr] = Number.NaN; | ||
| 585 | } | ||
| 586 | break; | ||
| 587 | case RrdRpn.OP_AVG: | ||
| 588 | if(stptr < 0) throw new RrdRpnError(); | ||
| 589 | var i = this.rpnstack[stptr--]; | ||
| 590 | var sum = 0; | ||
| 591 | var count = 0; | ||
| 592 | |||
| 593 | if(stptr < i - 1) throw new RrdRpnError(); | ||
| 594 | while (i > 0) { | ||
| 595 | var val = this.rpnstack[stptr--]; | ||
| 596 | i--; | ||
| 597 | if (isNaN(val)) continue; | ||
| 598 | count++; | ||
| 599 | sum += val; | ||
| 600 | } | ||
| 601 | if (count > 0) this.rpnstack[++stptr] = sum / count; | ||
| 602 | else this.rpnstack[++stptr] = Number.NaN; | ||
| 603 | break; | ||
| 604 | case RrdRpn.OP_ABS: | ||
| 605 | if(stptr < 0) throw new RrdRpnError(); | ||
| 606 | this.rpnstack[stptr] = fabs(this.rpnstack[stptr]); | ||
| 607 | break; | ||
| 608 | case RrdRpn.OP_END: | ||
| 609 | break; | ||
| 610 | } | ||
| 611 | } | ||
| 612 | if (stptr != 0) throw new RrdRpnError("RPN final stack size != 1"); | ||
| 613 | output[output_idx] = this.rpnstack[0]; | ||
| 614 | return 0; | ||
| 615 | }; | ||
| 616 | |||
