aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/js/RrdRpn.js
diff options
context:
space:
mode:
authorPim van den Berg2013-05-10 21:36:54 +0200
committerPim van den Berg2013-05-10 21:36:54 +0200
commit0163faefef02207ad0ea3330af688103633293ff (patch)
treec407fca93a3418af59c4c7133327f5bc1630fba5 /js/RrdRpn.js
parentMerge pull request #5 from mce35/nut (diff)
downloadapt-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 'js/RrdRpn.js')
-rw-r--r--js/RrdRpn.js616
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 */
28var 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 */
39var 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
125RrdRpn.OP_NUMBER= 0;
126RrdRpn.OP_VARIABLE = 1;
127RrdRpn.OP_INF = 2;
128RrdRpn.OP_PREV = 3;
129RrdRpn.OP_NEGINF = 4;
130RrdRpn.OP_UNKN = 5;
131RrdRpn.OP_NOW = 6;
132RrdRpn.OP_TIME = 7;
133RrdRpn.OP_ADD = 8;
134RrdRpn.OP_MOD = 9;
135RrdRpn.OP_SUB = 10;
136RrdRpn.OP_MUL = 11;
137RrdRpn.OP_DIV = 12;
138RrdRpn.OP_SIN = 13;
139RrdRpn.OP_DUP = 14;
140RrdRpn.OP_EXC = 15;
141RrdRpn.OP_POP = 16;
142RrdRpn.OP_COS = 17;
143RrdRpn.OP_LOG = 18;
144RrdRpn.OP_EXP = 19;
145RrdRpn.OP_LT = 20;
146RrdRpn.OP_LE = 21;
147RrdRpn.OP_GT = 22;
148RrdRpn.OP_GE = 23;
149RrdRpn.OP_EQ = 24;
150RrdRpn.OP_IF = 25;
151RrdRpn.OP_MIN = 26;
152RrdRpn.OP_MAX = 27;
153RrdRpn.OP_LIMIT = 28;
154RrdRpn.OP_FLOOR = 29;
155RrdRpn.OP_CEIL = 30;
156RrdRpn.OP_UN = 31;
157RrdRpn.OP_END = 32;
158RrdRpn.OP_LTIME = 33;
159RrdRpn.OP_NE = 34;
160RrdRpn.OP_ISINF = 35;
161RrdRpn.OP_PREV_OTHER = 36;
162RrdRpn.OP_COUNT = 37;
163RrdRpn.OP_ATAN = 38;
164RrdRpn.OP_SQRT = 39;
165RrdRpn.OP_SORT = 40;
166RrdRpn.OP_REV = 41;
167RrdRpn.OP_TREND = 42;
168RrdRpn.OP_TRENDNAN = 43;
169RrdRpn.OP_ATAN2 = 44;
170RrdRpn.OP_RAD2DEG = 45;
171RrdRpn.OP_DEG2RAD = 46;
172RrdRpn.OP_PREDICT = 47;
173RrdRpn.OP_PREDICTSIGMA = 48;
174RrdRpn.OP_AVG = 49;
175RrdRpn.OP_ABS = 50;
176RrdRpn.OP_ADDNAN = 51 ;
177
178RrdRpn.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
191RrdRpn.prototype.compare_double = function(x, y)
192{
193 var diff = x - y;
194 return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
195};
196
197RrdRpn.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
228RrdRpn.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