summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES2
-rw-r--r--doc/smokeping_install.pod16
-rw-r--r--etc/basepage.html.dist40
-rw-r--r--htdocs/js/idrag.js588
-rw-r--r--htdocs/js/iutil.js13
-rw-r--r--htdocs/js/jquery.js11
-rw-r--r--htdocs/js/smokeping_iselect.js287
-rw-r--r--htdocs/js/smokeping_zoom.js181
-rw-r--r--lib/Smokeping.pm27
9 files changed, 1152 insertions, 13 deletions
diff --git a/CHANGES b/CHANGES
index 7bb8005..88e4789 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+* Integrated interactive Graph zoomer -- Roman Plessl rplessl oetiker.ch
+
* first drop of the master/slave code added. now the debugging beginns. -- tobi
* fix uses of uninitialized value in the loss_background code
diff --git a/doc/smokeping_install.pod b/doc/smokeping_install.pod
index 9e82e1a..0fe1f14 100644
--- a/doc/smokeping_install.pod
+++ b/doc/smokeping_install.pod
@@ -107,11 +107,11 @@ recommend using the F<suexec> system for running CGI scripts. Often it is
sufficient to change the F<suexec> binary to setuid root and restart Apache.
Using F<suexec> allow to run cgi scripts under proper user accounts.
-=item Perl 5.6.1
+=item Perl 5.8.8
L<http://www.perl.com>
-I guess you will get away with older versions of perl. I am using 5.6.1 here
+I guess you will get away with older versions of perl. I am using 5.8.8 here
and it works fine.
=item SpeedyCGI
@@ -170,7 +170,13 @@ Edit the F<smokeping.cgi> analog to the F<smokeping> script above. Make sure
the first line of the script is pointing to your freshly installed copy of
Speedy CGI. Store the script in a directory of your weberver where CGIs get
executed. You also have to edit the B<use lib> line similar to what you did
-to F<smokeping>
+to F<smokeping>.
+
+=item F<htdocs/js/*>
+
+To make the interactive graph-zoomer work, you have to place the relevant
+files somewhere on your webserver and adapt the links in F<basepage.html>
+(see below).
=item F<etc/config>
@@ -181,7 +187,9 @@ L<smokeping_config> for details.
=item F<etc/basepage.html>
Edit the html template to your likings. Please do not remove the link to the
-SmokePing counter and my name from the template.
+SmokePing counter and my name from the template. The content of the template
+will be renderd by the smokeping.cgi. This means that all embeded links must
+be relative to smokeping.cgi.
=item F<etc/smokemail>
diff --git a/etc/basepage.html.dist b/etc/basepage.html.dist
index 2daea0d..bcf7025 100644
--- a/etc/basepage.html.dist
+++ b/etc/basepage.html.dist
@@ -39,10 +39,50 @@ a.menulink:hover {
color: #e0e0ff;
}
+.selectableitem {
+ border:2px solid #FFFFFF;
+ float:left;
+ height:140px;
+ margin:10px;
+ padding:10px;
+ text-align:center;
+ width:160px;
+}
+
+.selectableitem p {
+ font-weight:bold;
+}
+
+.selectableitem div {
+ height:120px;
+ line-height:120px;
+}
+
+.selecteditem {
+ border:2px solid #999999;
+}
+
+.selecthelper {
+ background-color:#000000;
+ opacity:0.3;
+}
+
+.zoom {
+ height:330px;
+ overflow:auto;
+ width:700px;
+}
-->
</STYLE>
+<script type="text/javascript" src="js/jquery.js"></script>
+<script type="text/javascript" src="js/idrag.js"></script>
+<script type="text/javascript" src="js/smokeping_iselect.js"></script>
+<script type="text/javascript" src="js/iutil.js"></script>
+<script type="text/javascript" src="js/smokeping_zoom.js"></script>
+
+
</HEAD>
<BODY bgcolor="white">
<TABLE border="0" cellpadding="10" cellspacing="0">
diff --git a/htdocs/js/idrag.js b/htdocs/js/idrag.js
new file mode 100644
index 0000000..d4b2c72
--- /dev/null
+++ b/htdocs/js/idrag.js
@@ -0,0 +1,588 @@
+/**
+ * Interface Elements for jQuery
+ * Draggable
+ *
+ * http://interface.eyecon.ro
+ *
+ * Copyright (c) 2006 Stefan Petre
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ */
+
+/**
+ * Create a draggable element with a number of advanced options including callback, Google Maps type draggables,
+ * reversion, ghosting, and grid dragging.
+ *
+ * @name Draggable
+ * @descr Creates draggable elements that can be moved across the page.
+ * @param Hash hash A hash of parameters. All parameters are optional.
+ * @option String handle (optional) The jQuery selector matching the handle that starts the draggable
+ * @option DOMElement handle (optional) The DOM Element of the handle that starts the draggable
+ * @option Boolean revert (optional) When true, on stop-drag the element returns to initial position
+ * @option Boolean ghosting (optional) When true, a copy of the element is moved
+ * @option Integer zIndex (optional) zIndex depth for the element while it is being dragged
+ * @option Float opacity (optional) A number between 0 and 1 that indicates the opacity of the element while being dragged
+ * @option Integer grid (optional) (optional) A number of pixels indicating the grid that the element should snap to
+ * @option Array grid (optional) A number of x-pixels and y-pixels indicating the grid that the element should snap to
+ * @option Integer fx (optional) Duration for the effect (like ghosting or revert) applied to the draggable
+ * @option String containment (optional) Define the zone where the draggable can be moved. 'parent' moves it inside parent
+ * element, while 'document' prevents it from leaving the document and forcing additional
+ * scrolling
+ * @option Array containment An 4-element array (left, top, width, height) indicating the containment of the element
+ * @option String axis (optional) Set an axis: vertical (with 'vertically') or horizontal (with 'horizontally')
+ * @option Function onStart (optional) Callback function triggered when the dragging starts
+ * @option Function onStop (optional) Callback function triggered when the dragging stops
+ * @option Function onChange (optional) Callback function triggered when the dragging stop *and* the element was moved at least
+ * one pixel
+ * @option Function onDrag (optional) Callback function triggered while the element is dragged. Receives two parameters: x and y
+ * coordinates. You can return an object with new coordinates {x: x, y: y} so this way you can
+ * interact with the dragging process (for instance, build your containment)
+ * @option Boolean insideParent Forces the element to remain inside its parent when being dragged (like Google Maps)
+ * @option Integer snapDistance (optional) The element is not moved unless it is dragged more than snapDistance. You can prevent
+ * accidental dragging and keep regular clicking enabled (for links or form elements,
+ * for instance)
+ * @option Object cursorAt (optional) The dragged element is moved to the cursor position with the offset specified. Accepts value
+ * for top, left, right and bottom offset. Basically, this forces the cursor to a particular
+ * position during the entire drag operation.
+ * @option Boolean autoSize (optional) When true, the drag helper is resized to its content, instead of the dragged element's sizes
+ * @option String frameClass (optional) When is set the cloned element is hidden so only a frame is dragged
+ * @type jQuery
+ * @cat Plugins/Interface
+ * @author Stefan Petre
+ */
+
+jQuery.iDrag = {
+ helper : null,
+ dragged: null,
+ destroy : function()
+ {
+ return this.each(
+ function ()
+ {
+ if (this.isDraggable) {
+ this.dragCfg.dhe.unbind('mousedown', jQuery.iDrag.draginit);
+ this.dragCfg = null;
+ this.isDraggable = false;
+ if(jQuery.browser.msie) {
+ this.unselectable = "off";
+ } else {
+ this.style.MozUserSelect = '';
+ this.style.KhtmlUserSelect = '';
+ this.style.userSelect = '';
+ }
+ }
+ }
+ );
+ },
+ draginit : function (e)
+ {
+ if (jQuery.iDrag.dragged != null) {
+ jQuery.iDrag.dragstop(e);
+ return false;
+ }
+ var elm = this.dragElem;
+ jQuery(document)
+ .bind('mousemove', jQuery.iDrag.dragmove)
+ .bind('mouseup', jQuery.iDrag.dragstop);
+ elm.dragCfg.pointer = jQuery.iUtil.getPointer(e);
+ elm.dragCfg.currentPointer = elm.dragCfg.pointer;
+ elm.dragCfg.init = false;
+ elm.dragCfg.fromHandler = this != this.dragElem;
+ jQuery.iDrag.dragged = elm;
+ if (elm.dragCfg.si && this != this.dragElem) {
+ parentPos = jQuery.iUtil.getPosition(elm.parentNode);
+ sliderSize = jQuery.iUtil.getSize(elm);
+ sliderPos = {
+ x : parseInt(jQuery.css(elm,'left')) || 0,
+ y : parseInt(jQuery.css(elm,'top')) || 0
+ };
+ dx = elm.dragCfg.currentPointer.x - parentPos.x - sliderSize.wb/2 - sliderPos.x;
+ dy = elm.dragCfg.currentPointer.y - parentPos.y - sliderSize.hb/2 - sliderPos.y;
+ jQuery.iSlider.dragmoveBy(elm, [dx, dy]);
+ }
+ return jQuery.selectKeyHelper||false;
+ },
+
+ dragstart : function(e)
+ {
+ var elm = jQuery.iDrag.dragged;
+ elm.dragCfg.init = true;
+
+ var dEs = elm.style;
+
+ elm.dragCfg.oD = jQuery.css(elm,'display');
+ elm.dragCfg.oP = jQuery.css(elm,'position');
+ if (!elm.dragCfg.initialPosition)
+ elm.dragCfg.initialPosition = elm.dragCfg.oP;
+
+ elm.dragCfg.oR = {
+ x : parseInt(jQuery.css(elm,'left')) || 0,
+ y : parseInt(jQuery.css(elm,'top')) || 0
+ };
+ elm.dragCfg.diffX = 0;
+ elm.dragCfg.diffY = 0;
+ if (jQuery.browser.msie) {
+ var oldBorder = jQuery.iUtil.getBorder(elm, true);
+ elm.dragCfg.diffX = oldBorder.l||0;
+ elm.dragCfg.diffY = oldBorder.t||0;
+ }
+
+ elm.dragCfg.oC = jQuery.extend(
+ jQuery.iUtil.getPosition(elm),
+ jQuery.iUtil.getSize(elm)
+ );
+ if (elm.dragCfg.oP != 'relative' && elm.dragCfg.oP != 'absolute') {
+ dEs.position = 'relative';
+ }
+
+ jQuery.iDrag.helper.empty();
+ var clonedEl = elm.cloneNode(true);
+
+ jQuery(clonedEl).css(
+ {
+ display: 'block',
+ left: '0px',
+ top: '0px'
+ }
+ );
+ clonedEl.style.marginTop = '0';
+ clonedEl.style.marginRight = '0';
+ clonedEl.style.marginBottom = '0';
+ clonedEl.style.marginLeft = '0';
+ jQuery.iDrag.helper.append(clonedEl);
+
+ var dhs = jQuery.iDrag.helper.get(0).style;
+
+ if (elm.dragCfg.autoSize) {
+ dhs.width = 'auto';
+ dhs.height = 'auto';
+ } else {
+ dhs.height = elm.dragCfg.oC.hb + 'px';
+ dhs.width = elm.dragCfg.oC.wb + 'px';
+ }
+
+ dhs.display = 'block';
+ dhs.marginTop = '0px';
+ dhs.marginRight = '0px';
+ dhs.marginBottom = '0px';
+ dhs.marginLeft = '0px';
+
+ //remeasure the clone to check if the size was changed by user's functions
+ jQuery.extend(
+ elm.dragCfg.oC,
+ jQuery.iUtil.getSize(clonedEl)
+ );
+
+ if (elm.dragCfg.cursorAt) {
+ if (elm.dragCfg.cursorAt.left) {
+ elm.dragCfg.oR.x += elm.dragCfg.pointer.x - elm.dragCfg.oC.x - elm.dragCfg.cursorAt.left;
+ elm.dragCfg.oC.x = elm.dragCfg.pointer.x - elm.dragCfg.cursorAt.left;
+ }
+ if (elm.dragCfg.cursorAt.top) {
+ elm.dragCfg.oR.y += elm.dragCfg.pointer.y - elm.dragCfg.oC.y - elm.dragCfg.cursorAt.top;
+ elm.dragCfg.oC.y = elm.dragCfg.pointer.y - elm.dragCfg.cursorAt.top;
+ }
+ if (elm.dragCfg.cursorAt.right) {
+ elm.dragCfg.oR.x += elm.dragCfg.pointer.x - elm.dragCfg.oC.x -elm.dragCfg.oC.hb + elm.dragCfg.cursorAt.right;
+ elm.dragCfg.oC.x = elm.dragCfg.pointer.x - elm.dragCfg.oC.wb + elm.dragCfg.cursorAt.right;
+ }
+ if (elm.dragCfg.cursorAt.bottom) {
+ elm.dragCfg.oR.y += elm.dragCfg.pointer.y - elm.dragCfg.oC.y - elm.dragCfg.oC.hb + elm.dragCfg.cursorAt.bottom;
+ elm.dragCfg.oC.y = elm.dragCfg.pointer.y - elm.dragCfg.oC.hb + elm.dragCfg.cursorAt.bottom;
+ }
+ }
+ elm.dragCfg.nx = elm.dragCfg.oR.x;
+ elm.dragCfg.ny = elm.dragCfg.oR.y;
+
+ if (elm.dragCfg.insideParent || elm.dragCfg.containment == 'parent') {
+ parentBorders = jQuery.iUtil.getBorder(elm.parentNode, true);
+ elm.dragCfg.oC.x = elm.offsetLeft + (jQuery.browser.msie ? 0 : jQuery.browser.opera ? -parentBorders.l : parentBorders.l);
+ elm.dragCfg.oC.y = elm.offsetTop + (jQuery.browser.msie ? 0 : jQuery.browser.opera ? -parentBorders.t : parentBorders.t);
+ jQuery(elm.parentNode).append(jQuery.iDrag.helper.get(0));
+ }
+ if (elm.dragCfg.containment) {
+ jQuery.iDrag.getContainment(elm);
+ elm.dragCfg.onDragModifier.containment = jQuery.iDrag.fitToContainer;
+ }
+
+ if (elm.dragCfg.si) {
+ jQuery.iSlider.modifyContainer(elm);
+ }
+
+ dhs.left = elm.dragCfg.oC.x - elm.dragCfg.diffX + 'px';
+ dhs.top = elm.dragCfg.oC.y - elm.dragCfg.diffY + 'px';
+ //resize the helper to fit the clone
+ dhs.width = elm.dragCfg.oC.wb + 'px';
+ dhs.height = elm.dragCfg.oC.hb + 'px';
+
+ jQuery.iDrag.dragged.dragCfg.prot = false;
+
+ if (elm.dragCfg.gx) {
+ elm.dragCfg.onDragModifier.grid = jQuery.iDrag.snapToGrid;
+ }
+ if (elm.dragCfg.zIndex != false) {
+ jQuery.iDrag.helper.css('zIndex', elm.dragCfg.zIndex);
+ }
+ if (elm.dragCfg.opacity) {
+ jQuery.iDrag.helper.css('opacity', elm.dragCfg.opacity);
+ if (window.ActiveXObject) {
+ jQuery.iDrag.helper.css('filter', 'alpha(opacity=' + elm.dragCfg.opacity * 100 + ')');
+ }
+ }
+
+ if(elm.dragCfg.frameClass) {
+ jQuery.iDrag.helper.addClass(elm.dragCfg.frameClass);
+ jQuery.iDrag.helper.get(0).firstChild.style.display = 'none';
+ }
+ if (elm.dragCfg.onStart)
+ elm.dragCfg.onStart.apply(elm, [clonedEl, elm.dragCfg.oR.x, elm.dragCfg.oR.y]);
+ if (jQuery.iDrop && jQuery.iDrop.count > 0 ){
+ jQuery.iDrop.highlight(elm);
+ }
+ if (elm.dragCfg.ghosting == false) {
+ dEs.display = 'none';
+ }
+ return false;
+ },
+
+ getContainment : function(elm)
+ {
+ if (elm.dragCfg.containment.constructor == String) {
+ if (elm.dragCfg.containment == 'parent') {
+ elm.dragCfg.cont = jQuery.extend(
+ {x:0,y:0},
+ jQuery.iUtil.getSize(elm.parentNode)
+ );
+ var contBorders = jQuery.iUtil.getBorder(elm.parentNode, true);
+ elm.dragCfg.cont.w = elm.dragCfg.cont.wb - contBorders.l - contBorders.r;
+ elm.dragCfg.cont.h = elm.dragCfg.cont.hb - contBorders.t - contBorders.b;
+ } else if (elm.dragCfg.containment == 'document') {
+ var clnt = jQuery.iUtil.getClient();
+ elm.dragCfg.cont = {
+ x : 0,
+ y : 0,
+ w : clnt.w,
+ h : clnt.h
+ };
+ }
+ } else if (elm.dragCfg.containment.constructor == Array) {
+ elm.dragCfg.cont = {
+ x : parseInt(elm.dragCfg.containment[0])||0,
+ y : parseInt(elm.dragCfg.containment[1])||0,
+ w : parseInt(elm.dragCfg.containment[2])||0,
+ h : parseInt(elm.dragCfg.containment[3])||0
+ };
+ }
+ elm.dragCfg.cont.dx = elm.dragCfg.cont.x - elm.dragCfg.oC.x;
+ elm.dragCfg.cont.dy = elm.dragCfg.cont.y - elm.dragCfg.oC.y;
+ },
+
+ hidehelper : function(dragged)
+ {
+ if (dragged.dragCfg.insideParent || dragged.dragCfg.containment == 'parent') {
+ jQuery('body', document).append(jQuery.iDrag.helper.get(0));
+ }
+ jQuery.iDrag.helper.empty().hide().css('opacity', 1);
+ if (window.ActiveXObject) {
+ jQuery.iDrag.helper.css('filter', 'alpha(opacity=100)');
+ }
+ },
+
+ dragstop : function(e)
+ {
+
+ jQuery(document)
+ .unbind('mousemove', jQuery.iDrag.dragmove)
+ .unbind('mouseup', jQuery.iDrag.dragstop);
+
+ if (jQuery.iDrag.dragged == null) {
+ return;
+ }
+ var dragged = jQuery.iDrag.dragged;
+
+ jQuery.iDrag.dragged = null;
+
+ if (dragged.dragCfg.init == false) {
+ return false;
+ }
+ if (dragged.dragCfg.so == true) {
+ jQuery(dragged).css('position', dragged.dragCfg.oP);
+ }
+ var dEs = dragged.style;
+
+ if (dragged.si) {
+ jQuery.iDrag.helper.css('cursor', 'move');
+ }
+ if(dragged.dragCfg.frameClass) {
+ jQuery.iDrag.helper.removeClass(dragged.dragCfg.frameClass);
+ }
+
+ if (dragged.dragCfg.revert == false) {
+ if (dragged.dragCfg.fx > 0) {
+ if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'horizontally') {
+ var x = new jQuery.fx(dragged,{duration:dragged.dragCfg.fx}, 'left');
+ x.custom(dragged.dragCfg.oR.x,dragged.dragCfg.nRx);
+ }
+ if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'vertically') {
+ var y = new jQuery.fx(dragged,{duration:dragged.dragCfg.fx}, 'top');
+ y.custom(dragged.dragCfg.oR.y,dragged.dragCfg.nRy);
+ }
+ } else {
+ if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'horizontally')
+ dragged.style.left = dragged.dragCfg.nRx + 'px';
+ if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'vertically')
+ dragged.style.top = dragged.dragCfg.nRy + 'px';
+ }
+ jQuery.iDrag.hidehelper(dragged);
+ if (dragged.dragCfg.ghosting == false) {
+ jQuery(dragged).css('display', dragged.dragCfg.oD);
+ }
+ } else if (dragged.dragCfg.fx > 0) {
+ dragged.dragCfg.prot = true;
+ var dh = false;
+ if(jQuery.iDrop && jQuery.iSort && dragged.dragCfg.so) {
+ dh = jQuery.iUtil.getPosition(jQuery.iSort.helper.get(0));
+ }
+ jQuery.iDrag.helper.animate(
+ {
+ left : dh ? dh.x : dragged.dragCfg.oC.x,
+ top : dh ? dh.y : dragged.dragCfg.oC.y
+ },
+ dragged.dragCfg.fx,
+ function()
+ {
+ dragged.dragCfg.prot = false;
+ if (dragged.dragCfg.ghosting == false) {
+ dragged.style.display = dragged.dragCfg.oD;
+ }
+ jQuery.iDrag.hidehelper(dragged);
+ }
+ );
+ } else {
+ jQuery.iDrag.hidehelper(dragged);
+ if (dragged.dragCfg.ghosting == false) {
+ jQuery(dragged).css('display', dragged.dragCfg.oD);
+ }
+ }
+
+ if (jQuery.iDrop && jQuery.iDrop.count > 0 ){
+ jQuery.iDrop.checkdrop(dragged);
+ }
+ if (jQuery.iSort && dragged.dragCfg.so) {
+ jQuery.iSort.check(dragged);
+ }
+ if (dragged.dragCfg.onChange && (dragged.dragCfg.nRx != dragged.dragCfg.oR.x || dragged.dragCfg.nRy != dragged.dragCfg.oR.y)){
+ dragged.dragCfg.onChange.apply(dragged, dragged.dragCfg.lastSi||[0,0,dragged.dragCfg.nRx,dragged.dragCfg.nRy]);
+ }
+ if (dragged.dragCfg.onStop)
+ dragged.dragCfg.onStop.apply(dragged);
+ return false;
+ },
+
+ snapToGrid : function(x, y, dx, dy)
+ {
+ if (dx != 0)
+ dx = parseInt((dx + (this.dragCfg.gx * dx/Math.abs(dx))/2)/this.dragCfg.gx) * this.dragCfg.gx;
+ if (dy != 0)
+ dy = parseInt((dy + (this.dragCfg.gy * dy/Math.abs(dy))/2)/this.dragCfg.gy) * this.dragCfg.gy;
+ return {
+ dx : dx,
+ dy : dy,
+ x: 0,
+ y: 0
+ };
+ },
+
+ fitToContainer : function(x, y, dx, dy)
+ {
+ dx = Math.min(
+ Math.max(dx,this.dragCfg.cont.dx),
+ this.dragCfg.cont.w + this.dragCfg.cont.dx - this.dragCfg.oC.wb
+ );
+ dy = Math.min(
+ Math.max(dy,this.dragCfg.cont.dy),
+ this.dragCfg.cont.h + this.dragCfg.cont.dy - this.dragCfg.oC.hb
+ );
+
+ return {
+ dx : dx,
+ dy : dy,
+ x: 0,
+ y: 0
+ }
+ },
+
+ dragmove : function(e)
+ {
+ if (jQuery.iDrag.dragged == null || jQuery.iDrag.dragged.dragCfg.prot == true) {
+ return;
+ }
+
+ var dragged = jQuery.iDrag.dragged;
+
+ dragged.dragCfg.currentPointer = jQuery.iUtil.getPointer(e);
+ if (dragged.dragCfg.init == false) {
+ distance = Math.sqrt(Math.pow(dragged.dragCfg.pointer.x - dragged.dragCfg.currentPointer.x, 2) + Math.pow(dragged.dragCfg.pointer.y - dragged.dragCfg.currentPointer.y, 2));
+ if (distance < dragged.dragCfg.snapDistance){
+ return;
+ } else {
+ jQuery.iDrag.dragstart(e);
+ }
+ }
+
+ var dx = dragged.dragCfg.currentPointer.x - dragged.dragCfg.pointer.x;
+ var dy = dragged.dragCfg.currentPointer.y - dragged.dragCfg.pointer.y;
+
+ for (var i in dragged.dragCfg.onDragModifier) {
+ var newCoords = dragged.dragCfg.onDragModifier[i].apply(dragged, [dragged.dragCfg.oR.x + dx, dragged.dragCfg.oR.y + dy, dx, dy]);
+ if (newCoords && newCoords.constructor == Object) {
+ dx = i != 'user' ? newCoords.dx : (newCoords.x - dragged.dragCfg.oR.x);
+ dy = i != 'user' ? newCoords.dy : (newCoords.y - dragged.dragCfg.oR.y);
+ }
+ }
+
+ dragged.dragCfg.nx = dragged.dragCfg.oC.x + dx - dragged.dragCfg.diffX;
+ dragged.dragCfg.ny = dragged.dragCfg.oC.y + dy - dragged.dragCfg.diffY;
+
+ if (dragged.dragCfg.si && (dragged.dragCfg.onSlide || dragged.dragCfg.onChange)) {
+ jQuery.iSlider.onSlide(dragged, dragged.dragCfg.nx, dragged.dragCfg.ny);
+ }
+
+ if(dragged.dragCfg.onDrag)
+ dragged.dragCfg.onDrag.apply(dragged, [dragged.dragCfg.oR.x + dx, dragged.dragCfg.oR.y + dy]);
+
+ if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'horizontally') {
+ dragged.dragCfg.nRx = dragged.dragCfg.oR.x + dx;
+ jQuery.iDrag.helper.get(0).style.left = dragged.dragCfg.nx + 'px';
+ }
+ if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'vertically') {
+ dragged.dragCfg.nRy = dragged.dragCfg.oR.y + dy;
+ jQuery.iDrag.helper.get(0).style.top = dragged.dragCfg.ny + 'px';
+ }
+
+ if (jQuery.iDrop && jQuery.iDrop.count > 0 ){
+ jQuery.iDrop.checkhover(dragged);
+ }
+ return false;
+ },
+
+ build : function(o)
+ {
+ if (!jQuery.iDrag.helper) {
+ jQuery('body',document).append('<div id="dragHelper"></div>');
+ jQuery.iDrag.helper = jQuery('#dragHelper');
+ var el = jQuery.iDrag.helper.get(0);
+ var els = el.style;
+ els.position = 'absolute';
+ els.display = 'none';
+ els.cursor = 'move';
+ els.listStyle = 'none';
+ els.overflow = 'hidden';
+ if (window.ActiveXObject) {
+ el.unselectable = "on";
+ } else {
+ els.mozUserSelect = 'none';
+ els.userSelect = 'none';
+ els.KhtmlUserSelect = 'none';
+ }
+ }
+ if (!o) {
+ o = {};
+ }
+ return this.each(
+ function()
+ {
+ if (this.isDraggable || !jQuery.iUtil)
+ return;
+ if (window.ActiveXObject) {
+ this.onselectstart = function(){return false;};
+ this.ondragstart = function(){return false;};
+ }
+ var el = this;
+ var dhe = o.handle ? jQuery(this).find(o.handle) : jQuery(this);
+ if(jQuery.browser.msie) {
+ dhe.each(
+ function()
+ {
+ this.unselectable = "on";
+ }
+ );
+ } else {
+ dhe.css('-moz-user-select', 'none');
+ dhe.css('user-select', 'none');
+ dhe.css('-khtml-user-select', 'none');
+ }
+ this.dragCfg = {
+ dhe: dhe,
+ revert : o.revert ? true : false,
+ ghosting : o.ghosting ? true : false,
+ so : o.so ? o.so : false,
+ si : o.si ? o.si : false,
+ insideParent : o.insideParent ? o.insideParent : false,
+ zIndex : o.zIndex ? parseInt(o.zIndex)||0 : false,
+ opacity : o.opacity ? parseFloat(o.opacity) : false,
+ fx : parseInt(o.fx)||null,
+ hpc : o.hpc ? o.hpc : false,
+ onDragModifier : {},
+ pointer : {},
+ onStart : o.onStart && o.onStart.constructor == Function ? o.onStart : false,
+ onStop : o.onStop && o.onStop.constructor == Function ? o.onStop : false,
+ onChange : o.onChange && o.onChange.constructor == Function ? o.onChange : false,
+ axis : /vertically|horizontally/.test(o.axis) ? o.axis : false,
+ snapDistance : o.snapDistance ? parseInt(o.snapDistance)||0 : 0,
+ cursorAt: o.cursorAt ? o.cursorAt : false,
+ autoSize : o.autoSize ? true : false,
+ frameClass : o.frameClass || false
+
+ };
+ if (o.onDragModifier && o.onDragModifier.constructor == Function)
+ this.dragCfg.onDragModifier.user = o.onDragModifier;
+ if (o.onDrag && o.onDrag.constructor == Function)
+ this.dragCfg.onDrag = o.onDrag;
+ if (o.containment && ((o.containment.constructor == String && (o.containment == 'parent' || o.containment == 'document')) || (o.containment.constructor == Array && o.containment.length == 4) )) {
+ this.dragCfg.containment = o.containment;
+ }
+ if(o.fractions) {
+ this.dragCfg.fractions = o.fractions;
+ }
+ if(o.grid){
+ if(typeof o.grid == 'number'){
+ this.dragCfg.gx = parseInt(o.grid)||1;
+ this.dragCfg.gy = parseInt(o.grid)||1;
+ } else if (o.grid.length == 2) {
+ this.dragCfg.gx = parseInt(o.grid[0])||1;
+ this.dragCfg.gy = parseInt(o.grid[1])||1;
+ }
+ }
+ if (o.onSlide && o.onSlide.constructor == Function) {
+ this.dragCfg.onSlide = o.onSlide;
+ }
+
+ this.isDraggable = true;
+ dhe.each(
+ function(){
+ this.dragElem = el;
+ }
+ );
+ dhe.bind('mousedown', jQuery.iDrag.draginit);
+ }
+ )
+ }
+};
+
+/**
+ * Destroy an existing draggable on a collection of elements
+ *
+ * @name DraggableDestroy
+ * @descr Destroy a draggable
+ * @type jQuery
+ * @cat Plugins/Interface
+ * @example $('#drag2').DraggableDestroy();
+ */
+
+jQuery.fn.extend(
+ {
+ DraggableDestroy : jQuery.iDrag.destroy,
+ Draggable : jQuery.iDrag.build
+ }
+); \ No newline at end of file
diff --git a/htdocs/js/iutil.js b/htdocs/js/iutil.js
new file mode 100644
index 0000000..05a5b04
--- /dev/null
+++ b/htdocs/js/iutil.js
@@ -0,0 +1,13 @@
+/**
+ * Interface Elements for jQuery
+ * utility function
+ *
+ * http://interface.eyecon.ro
+ *
+ * Copyright (c) 2006 Stefan Petre
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ *
+ */
+eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('9.J={1C:6(e){4 x=0;4 y=0;4 7=e.Y;4 12=1H;c(9(e).8(\'A\')==\'T\'){4 N=7.B;4 Q=7.z;12=1f;7.B=\'1r\';7.A=\'1q\';7.z=\'1d\'}4 3=e;R(3){x+=3.1h+(3.O&&!9.1m.1i?d(3.O.17)||0:0);y+=3.1n+(3.O&&!9.1m.1i?d(3.O.18)||0:0);3=3.1t}3=e;R(3&&3.1e&&3.1e.16()!=\'f\'){x-=3.u||0;y-=3.F||0;3=3.1D}c(12==1f){7.A=\'T\';7.z=Q;7.B=N}a{x:x,y:y}},1B:6(3){4 x=0,y=0;R(3){x+=3.1h||0;y+=3.1n||0;3=3.1t}a{x:x,y:y}},1s:6(e){4 w=9.8(e,\'1E\');4 h=9.8(e,\'1G\');4 o=0;4 q=0;4 7=e.Y;c(9(e).8(\'A\')!=\'T\'){o=e.V;q=e.U}p{4 N=7.B;4 Q=7.z;7.B=\'1r\';7.A=\'1q\';7.z=\'1d\';o=e.V;q=e.U;7.A=\'T\';7.z=Q;7.B=N}a{w:w,h:h,o:o,q:q}},1F:6(3){a{o:3.V||0,q:3.U||0}},1I:6(e){4 h,w,C;c(e){w=e.I;h=e.G}p{C=5.j;w=1c.14||P.14||(C&&C.I)||5.f.I;h=1c.10||P.10||(C&&C.G)||5.f.G}a{w:w,h:h}},1p:6(e){4 t=0,l=0,w=0,h=0,s=0,E=0;c(e&&e.1u.16()!=\'f\'){t=e.F;l=e.u;w=e.15;h=e.W;s=0;E=0}p{c(5.j){t=5.j.F;l=5.j.u;w=5.j.15;h=5.j.W}p c(5.f){t=5.f.F;l=5.f.u;w=5.f.15;h=5.f.W}s=P.14||5.j.I||5.f.I||0;E=P.10||5.j.G||5.f.G||0}a{t:t,l:l,w:w,h:h,s:s,E:E}},1v:6(e,D){4 3=9(e);4 t=3.8(\'1w\')||\'\';4 r=3.8(\'1x\')||\'\';4 b=3.8(\'1A\')||\'\';4 l=3.8(\'1z\')||\'\';c(D)a{t:d(t)||0,r:d(r)||0,b:d(b)||0,l:d(l)};p a{t:t,r:r,b:b,l:l}},1y:6(e,D){4 3=9(e);4 t=3.8(\'1J\')||\'\';4 r=3.8(\'1M\')||\'\';4 b=3.8(\'27\')||\'\';4 l=3.8(\'28\')||\'\';c(D)a{t:d(t)||0,r:d(r)||0,b:d(b)||0,l:d(l)};p a{t:t,r:r,b:b,l:l}},26:6(e,D){4 3=9(e);4 t=3.8(\'18\')||\'\';4 r=3.8(\'22\')||\'\';4 b=3.8(\'23\')||\'\';4 l=3.8(\'17\')||\'\';c(D)a{t:d(t)||0,r:d(r)||0,b:d(b)||0,l:d(l)||0};p a{t:t,r:r,b:b,l:l}},2e:6(L){4 x=L.2d||(L.2b+(5.j.u||5.f.u))||0;4 y=L.2c||(L.29+(5.j.F||5.f.F))||0;a{x:x,y:y}},X:6(g,13){13(g);g=g.1O;R(g){9.J.X(g,13);g=g.1L}},1N:6(g){9.J.X(g,6(3){19(4 Z 1T 3){c(1Z 3[Z]===\'6\'){3[Z]=1a}}})},1X:6(3,H){4 k=9.J.1p();4 11=9.J.1s(3);c(!H||H==\'1W\')9(3).8({1U:k.t+((1g.1o(k.h,k.E)-k.t-11.q)/2)+\'1j\'});c(!H||H==\'20\')9(3).8({1Y:k.l+((1g.1o(k.w,k.s)-k.l-11.o)/2)+\'1j\'})},2f:6(3,1l){4 1k=9(\'25[@M*="S"]\',3||5),S;1k.24(6(){S=K.M;K.M=1l;K.Y.2a="21:1R.1P.1V(M=\'"+S+"\')"})}};[].1b||(1S.1Q.1b=6(v,n){n=(n==1a)?0:n;4 m=K.1K;19(4 i=n;i<m;i++)c(K[i]==v)a i;a-1});',62,140,'|||el|var|document|function|es|css|jQuery|return||if|parseInt||body|nodeEl|||documentElement|clientScroll||||wb|else|hb||iw||scrollLeft|||||position|display|visibility|de|toInteger|ih|scrollTop|clientHeight|axis|clientWidth|iUtil|this|event|src|oldVisibility|currentStyle|self|oldPosition|while|png|none|offsetHeight|offsetWidth|scrollHeight|traverseDOM|style|attr|innerHeight|windowSize|restoreStyles|func|innerWidth|scrollWidth|toLowerCase|borderLeftWidth|borderTopWidth|for|null|indexOf|window|absolute|tagName|true|Math|offsetLeft|opera|px|images|emptyGIF|browser|offsetTop|max|getScroll|block|hidden|getSize|offsetParent|nodeName|getMargins|marginTop|marginRight|getPadding|marginLeft|marginBottom|getPositionLite|getPosition|parentNode|width|getSizeLite|height|false|getClient|paddingTop|length|nextSibling|paddingRight|purgeEvents|firstChild|Microsoft|prototype|DXImageTransform|Array|in|top|AlphaImageLoader|vertically|centerEl|left|typeof|horizontally|progid|borderRightWidth|borderBottomWidth|each|img|getBorder|paddingBottom|paddingLeft|clientY|filter|clientX|pageY|pageX|getPointer|fixPNG'.split('|'),0,{}))
diff --git a/htdocs/js/jquery.js b/htdocs/js/jquery.js
new file mode 100644
index 0000000..f364720
--- /dev/null
+++ b/htdocs/js/jquery.js
@@ -0,0 +1,11 @@
+/*
+ * jQuery 1.1.3.1 - New Wave Javascript
+ *
+ * Copyright (c) 2007 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2007-07-05 00:43:24 -0400 (Thu, 05 Jul 2007) $
+ * $Rev: 2243 $
+ */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('7(1g 18.6=="I"){18.I=18.I;u 6=q(a,c){7(18==9||!9.3X)v 14 6(a,c);v 9.3X(a,c)};7(1g $!="I")6.1I$=$;u $=6;6.11=6.8r={3X:q(a,c){a=a||P;7(6.16(a))v 14 6(P)[6.11.1G?"1G":"1W"](a);7(1g a=="1s"){u m=/^[^<]*(<(.|\\s)+>)[^>]*$/.1V(a);7(m)a=6.31([m[1]]);B v 14 6(c).1L(a)}v 9.4E(a.15==2b&&a||(a.3C||a.C&&a!=18&&!a.1q&&a[0]!=I&&a[0].1q)&&6.2L(a)||[a])},3C:"1.1.3.1",7W:q(){v 9.C},C:0,1M:q(a){v a==I?6.2L(9):9[a]},1Z:q(a){u b=6(a);b.5q=9;v b},4E:q(a){9.C=0;[].R.O(9,a);v 9},F:q(a,b){v 6.F(9,a,b)},2p:q(a){u b=-1;9.F(q(i){7(9==a)b=i});v b},1b:q(f,d,e){u c=f;7(f.15==33)7(d==I)v 9.C&&6[e||"1b"](9[0],f)||I;B{c={};c[f]=d}v 9.F(q(a){E(u b V c)6.1b(e?9.T:9,b,6.4H(9,c[b],e,a,b))})},1f:q(b,a){v 9.1b(b,a,"2z")},2A:q(e){7(1g e=="1s")v 9.2Y().3e(P.66(e));u t="";6.F(e||9,q(){6.F(9.2S,q(){7(9.1q!=8)t+=9.1q!=1?9.5R:6.11.2A([9])})});v t},8b:q(){u a,1S=19;v 9.F(q(){7(!a)a=6.31(1S,9.2O);u b=a[0].3s(K);9.L.2K(b,9);1v(b.1d)b=b.1d;b.4g(9)})},3e:q(){v 9.2F(19,K,1,q(a){9.4g(a)})},5w:q(){v 9.2F(19,K,-1,q(a){9.2K(a,9.1d)})},5t:q(){v 9.2F(19,N,1,q(a){9.L.2K(a,9)})},5s:q(){v 9.2F(19,N,-1,q(a){9.L.2K(a,9.1X)})},2U:q(){v 9.5q||6([])},1L:q(t){u b=6.3k(9,q(a){v 6.1L(t,a)});v 9.1Z(/[^+>] [^+>]/.17(t)||t.J("..")>-1?6.5g(b):b)},7x:q(e){u d=9.1A(9.1L("*"));d.F(q(){9.1I$1a={};E(u a V 9.$1a)9.1I$1a[a]=6.1c({},9.$1a[a])}).3U();u r=9.1Z(6.3k(9,q(a){v a.3s(e!=I?e:K)}));d.F(q(){u b=9.1I$1a;E(u a V b)E(u c V b[a])6.S.1A(9,a,b[a][c],b[a][c].W);9.1I$1a=H});v r},1i:q(t){v 9.1Z(6.16(t)&&6.2s(9,q(b,a){v t.O(b,[a])})||6.2x(t,9))},4Y:q(t){v 9.1Z(t.15==33&&6.2x(t,9,K)||6.2s(9,q(a){v(t.15==2b||t.3C)?6.2w(a,t)<0:a!=t}))},1A:q(t){v 9.1Z(6.1T(9.1M(),t.15==33?6(t).1M():t.C!=I&&(!t.Q||t.Q=="6Z")?t:[t]))},37:q(a){v a?6.2x(a,9).C>0:N},6R:q(a){v a==I?(9.C?9[0].2v:H):9.1b("2v",a)},3F:q(a){v a==I?(9.C?9[0].27:H):9.2Y().3e(a)},2F:q(f,d,g,e){u c=9.C>1,a;v 9.F(q(){7(!a){a=6.31(f,9.2O);7(g<0)a.6E()}u b=9;7(d&&6.Q(9,"1r")&&6.Q(a[0],"2V"))b=9.3R("1z")[0]||9.4g(P.5h("1z"));6.F(a,q(){e.O(b,[c?9.3s(K):9])})})}};6.1c=6.11.1c=q(){u c=19[0],a=1;7(19.C==1){c=9;a=0}u b;1v((b=19[a++])!=H)E(u i V b)c[i]=b[i];v c};6.1c({6n:q(){7(6.1I$)$=6.1I$;v 6},16:q(a){v!!a&&1g a!="1s"&&!a.Q&&a.15!=2b&&/q/i.17(a+"")},40:q(a){v a.4z&&a.2O&&!a.2O.4y},Q:q(b,a){v b.Q&&b.Q.1D()==a.1D()},F:q(a,b,c){7(a.C==I)E(u i V a)b.O(a[i],c||[i,a[i]]);B E(u i=0,4x=a.C;i<4x;i++)7(b.O(a[i],c||[i,a[i]])===N)1F;v a},4H:q(c,b,d,e,a){7(6.16(b))b=b.3D(c,[e]);u f=/z-?2p|5Y-?8p|1e|5U|8i-?1u/i;v b&&b.15==3y&&d=="2z"&&!f.17(a)?b+"4o":b},12:{1A:q(b,c){6.F(c.2R(/\\s+/),q(i,a){7(!6.12.3w(b.12,a))b.12+=(b.12?" ":"")+a})},1E:q(b,c){b.12=c!=I?6.2s(b.12.2R(/\\s+/),q(a){v!6.12.3w(c,a)}).5M(" "):""},3w:q(t,c){v 6.2w(c,(t.12||t).3v().2R(/\\s+/))>-1}},4m:q(e,o,f){E(u i V o){e.T["2N"+i]=e.T[i];e.T[i]=o[i]}f.O(e,[]);E(u i V o)e.T[i]=e.T["2N"+i]},1f:q(e,p){7(p=="1u"||p=="29"){u b={},3r,3p,d=["83","81","80","7Y"];6.F(d,q(){b["7V"+9]=0;b["7T"+9+"7S"]=0});6.4m(e,b,q(){7(6(e).37(\':4f\')){3r=e.7Q;3p=e.7O}B{e=6(e.3s(K)).1L(":4b").5v("2B").2U().1f({48:"1y",3i:"7L",U:"2h",7K:"0",7I:"0"}).5o(e.L)[0];u a=6.1f(e.L,"3i")||"3n";7(a=="3n")e.L.T.3i="7G";3r=e.7E;3p=e.7D;7(a=="3n")e.L.T.3i="3n";e.L.3q(e)}});v p=="1u"?3r:3p}v 6.2z(e,p)},2z:q(e,a,d){u g;7(a=="1e"&&6.M.1h){g=6.1b(e.T,"1e");v g==""?"1":g}7(a.3t(/3x/i))a=6.1U;7(!d&&e.T[a])g=e.T[a];B 7(P.3f&&P.3f.3Y){7(a.3t(/3x/i))a="3x";a=a.1o(/([A-Z])/g,"-$1").2H();u b=P.3f.3Y(e,H);7(b)g=b.57(a);B 7(a=="U")g="1P";B 6.4m(e,{U:"2h"},q(){u c=P.3f.3Y(9,"");g=c&&c.57(a)||""})}B 7(e.3S){u f=a.1o(/\\-(\\w)/g,q(m,c){v c.1D()});g=e.3S[a]||e.3S[f]}v g},31:q(a,c){u r=[];c=c||P;6.F(a,q(i,b){7(!b)v;7(b.15==3y)b=b.3v();7(1g b=="1s"){u s=6.2C(b).2H(),1x=c.5h("1x"),1N=[];u a=!s.J("<1H")&&[1,"<2y>","</2y>"]||!s.J("<7g")&&[1,"<52>","</52>"]||(!s.J("<7c")||!s.J("<1z")||!s.J("<7a")||!s.J("<78"))&&[1,"<1r>","</1r>"]||!s.J("<2V")&&[2,"<1r><1z>","</1z></1r>"]||(!s.J("<75")||!s.J("<74"))&&[3,"<1r><1z><2V>","</2V></1z></1r>"]||!s.J("<73")&&[2,"<1r><4W>","</4W></1r>"]||[0,"",""];1x.27=a[1]+b+a[2];1v(a[0]--)1x=1x.1d;7(6.M.1h){7(!s.J("<1r")&&s.J("<1z")<0)1N=1x.1d&&1x.1d.2S;B 7(a[1]=="<1r>"&&s.J("<1z")<0)1N=1x.2S;E(u n=1N.C-1;n>=0;--n)7(6.Q(1N[n],"1z")&&!1N[n].2S.C)1N[n].L.3q(1N[n])}b=6.2L(1x.2S)}7(0===b.C&&(!6.Q(b,"34")&&!6.Q(b,"2y")))v;7(b[0]==I||6.Q(b,"34")||b.71)r.R(b);B r=6.1T(r,b)});v r},1b:q(c,d,a){u e=6.40(c)?{}:6.3H;7(e[d]){7(a!=I)c[e[d]]=a;v c[e[d]]}B 7(a==I&&6.M.1h&&6.Q(c,"34")&&(d=="70"||d=="6Y"))v c.6W(d).5R;B 7(c.4z){7(a!=I)c.6U(d,a);7(6.M.1h&&/4M|2u/.17(d)&&!6.40(c))v c.35(d,2);v c.35(d)}B{7(d=="1e"&&6.M.1h){7(a!=I){c.5U=1;c.1i=(c.1i||"").1o(/4L\\([^)]*\\)/,"")+(39(a).3v()=="6M"?"":"4L(1e="+a*4X+")")}v c.1i?(39(c.1i.3t(/1e=([^)]*)/)[1])/4X).3v():""}d=d.1o(/-([a-z])/6K,q(z,b){v b.1D()});7(a!=I)c[d]=a;v c[d]}},2C:q(t){v t.1o(/^\\s+|\\s+$/g,"")},2L:q(a){u r=[];7(1g a!="6I")E(u i=0,26=a.C;i<26;i++)r.R(a[i]);B r=a.51(0);v r},2w:q(b,a){E(u i=0,26=a.C;i<26;i++)7(a[i]==b)v i;v-1},1T:q(a,b){E(u i=0;b[i];i++)a.R(b[i]);v a},5g:q(a){u r=[],3P=6.1k++;E(u i=0,4G=a.C;i<4G;i++)7(3P!=a[i].1k){a[i].1k=3P;r.R(a[i])}v r},1k:0,2s:q(c,b,d){7(1g b=="1s")b=14 45("a","i","v "+b);u a=[];E(u i=0,30=c.C;i<30;i++)7(!d&&b(c[i],i)||d&&!b(c[i],i))a.R(c[i]);v a},3k:q(c,b){7(1g b=="1s")b=14 45("a","v "+b);u d=[];E(u i=0,30=c.C;i<30;i++){u a=b(c[i],i);7(a!==H&&a!=I){7(a.15!=2b)a=[a];d=d.6v(a)}}v d}});14 q(){u b=6u.6t.2H();6.M={4D:(b.3t(/.+(?:6s|6q|6o|6m)[\\/: ]([\\d.]+)/)||[])[1],20:/5l/.17(b),2a:/2a/.17(b),1h:/1h/.17(b)&&!/2a/.17(b),3j:/3j/.17(b)&&!/(6h|5l)/.17(b)};6.6g=!6.M.1h||P.6f=="6c";6.1U=6.M.1h?"1U":"5x",6.3H={"E":"68","67":"12","3x":6.1U,5x:6.1U,1U:6.1U,27:"27",12:"12",2v:"2v",2r:"2r",2B:"2B",65:"63",2T:"2T",62:"5Z"}};6.F({4v:"a.L",4p:"6.4p(a)",8o:"6.22(a,2,\'1X\')",8n:"6.22(a,2,\'4t\')",8k:"6.4q(a.L.1d,a)",8h:"6.4q(a.1d)"},q(i,n){6.11[i]=q(a){u b=6.3k(9,n);7(a&&1g a=="1s")b=6.2x(a,b);v 9.1Z(b)}});6.F({5o:"3e",8g:"5w",2K:"5t",8f:"5s"},q(i,n){6.11[i]=q(){u a=19;v 9.F(q(){E(u j=0,26=a.C;j<26;j++)6(a[j])[n](9)})}});6.F({5v:q(a){6.1b(9,a,"");9.8d(a)},8c:q(c){6.12.1A(9,c)},88:q(c){6.12.1E(9,c)},87:q(c){6.12[6.12.3w(9,c)?"1E":"1A"](9,c)},1E:q(a){7(!a||6.1i(a,[9]).r.C)9.L.3q(9)},2Y:q(){1v(9.1d)9.3q(9.1d)}},q(i,n){6.11[i]=q(){v 9.F(n,19)}});6.F(["5Q","5P","5O","5N"],q(i,n){6.11[n]=q(a,b){v 9.1i(":"+n+"("+a+")",b)}});6.F(["1u","29"],q(i,n){6.11[n]=q(h){v h==I?(9.C?6.1f(9[0],n):H):9.1f(n,h.15==33?h:h+"4o")}});6.1c({4n:{"":"m[2]==\'*\'||6.Q(a,m[2])","#":"a.35(\'2m\')==m[2]",":":{5P:"i<m[3]-0",5O:"i>m[3]-0",22:"m[3]-0==i",5Q:"m[3]-0==i",2Q:"i==0",2P:"i==r.C-1",5L:"i%2==0",5K:"i%2","2Q-3u":"a.L.3R(\'*\')[0]==a","2P-3u":"6.22(a.L.5J,1,\'4t\')==a","86-3u":"!6.22(a.L.5J,2,\'4t\')",4v:"a.1d",2Y:"!a.1d",5N:"(a.5H||a.85||\'\').J(m[3])>=0",4f:\'"1y"!=a.G&&6.1f(a,"U")!="1P"&&6.1f(a,"48")!="1y"\',1y:\'"1y"==a.G||6.1f(a,"U")=="1P"||6.1f(a,"48")=="1y"\',84:"!a.2r",2r:"a.2r",2B:"a.2B",2T:"a.2T||6.1b(a,\'2T\')",2A:"\'2A\'==a.G",4b:"\'4b\'==a.G",5F:"\'5F\'==a.G",4l:"\'4l\'==a.G",5E:"\'5E\'==a.G",4k:"\'4k\'==a.G",5D:"\'5D\'==a.G",5C:"\'5C\'==a.G",1J:\'"1J"==a.G||6.Q(a,"1J")\',5B:"/5B|2y|82|1J/i.17(a.Q)"},"[":"6.1L(m[2],a).C"},5A:[/^\\[ *(@)([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(\\[)\\s*(.*?(\\[.*?\\])?[^[]*?)\\s*\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,14 3o("^([:.#]*)("+(6.2J=6.M.20&&6.M.4D<"3.0.0"?"\\\\w":"(?:[\\\\w\\7Z-\\7X*1I-]|\\\\\\\\.)")+"+)")],2x:q(a,c,b){u d,1K=[];1v(a&&a!=d){d=a;u f=6.1i(a,c,b);a=f.t.1o(/^\\s*,\\s*/,"");1K=b?c=f.r:6.1T(1K,f.r)}v 1K},1L:q(t,l){7(1g t!="1s")v[t];7(l&&!l.1q)l=H;l=l||P;7(!t.J("//")){l=l.4h;t=t.2G(2,t.C)}B 7(!t.J("/")&&!l.2O){l=l.4h;t=t.2G(1,t.C);7(t.J("/")>=1)t=t.2G(t.J("/"),t.C)}u b=[l],2j=[],2P;1v(t&&2P!=t){u r=[];2P=t;t=6.2C(t).1o(/^\\/\\//,"");u k=N;u g=14 3o("^[/>]\\\\s*("+6.2J+"+)");u m=g.1V(t);7(m){u o=m[1].1D();E(u i=0;b[i];i++)E(u c=b[i].1d;c;c=c.1X)7(c.1q==1&&(o=="*"||c.Q.1D()==o.1D()))r.R(c);b=r;t=t.1o(g,"");7(t.J(" ")==0)7R;k=K}B{g=/^((\\/?\\.\\.)|([>\\/+~]))\\s*([a-z]*)/i;7((m=g.1V(t))!=H){r=[];u o=m[4],1k=6.1k++;m=m[1];E(u j=0,2e=b.C;j<2e;j++)7(m.J("..")<0){u n=m=="~"||m=="+"?b[j].1X:b[j].1d;E(;n;n=n.1X)7(n.1q==1){7(m=="~"&&n.1k==1k)1F;7(!o||n.Q.1D()==o.1D()){7(m=="~")n.1k=1k;r.R(n)}7(m=="+")1F}}B r.R(b[j].L);b=r;t=6.2C(t.1o(g,""));k=K}}7(t&&!k){7(!t.J(",")){7(l==b[0])b.4e();2j=6.1T(2j,b);r=b=[l];t=" "+t.2G(1,t.C)}B{u h=14 3o("^("+6.2J+"+)(#)("+6.2J+"+)");u m=h.1V(t);7(m){m=[0,m[2],m[3],m[1]]}B{h=14 3o("^([#.]?)("+6.2J+"*)");m=h.1V(t)}m[2]=m[2].1o(/\\\\/g,"");u f=b[b.C-1];7(m[1]=="#"&&f&&f.4d){u p=f.4d(m[2]);7((6.M.1h||6.M.2a)&&p&&1g p.2m=="1s"&&p.2m!=m[2])p=6(\'[@2m="\'+m[2]+\'"]\',f)[0];b=r=p&&(!m[3]||6.Q(p,m[3]))?[p]:[]}B{E(u i=0;b[i];i++){u a=m[1]!=""||m[0]==""?"*":m[2];7(a=="*"&&b[i].Q.2H()=="7P")a="2E";r=6.1T(r,b[i].3R(a))}7(m[1]==".")r=6.4c(r,m[2]);7(m[1]=="#"){u e=[];E(u i=0;r[i];i++)7(r[i].35("2m")==m[2]){e=[r[i]];1F}r=e}b=r}t=t.1o(h,"")}}7(t){u d=6.1i(t,r);b=r=d.r;t=6.2C(d.t)}}7(t)b=[];7(b&&l==b[0])b.4e();2j=6.1T(2j,b);v 2j},4c:q(r,m,a){m=" "+m+" ";u b=[];E(u i=0;r[i];i++){u c=(" "+r[i].12+" ").J(m)>=0;7(!a&&c||a&&!c)b.R(r[i])}v b},1i:q(t,r,h){u d;1v(t&&t!=d){d=t;u p=6.5A,m;E(u i=0;p[i];i++){m=p[i].1V(t);7(m){t=t.7N(m[0].C);m[2]=m[2].1o(/\\\\/g,"");1F}}7(!m)1F;7(m[1]==":"&&m[2]=="4Y")r=6.1i(m[3],r,K).r;B 7(m[1]==".")r=6.4c(r,m[2],h);B 7(m[1]=="@"){u g=[],G=m[3];E(u i=0,2e=r.C;i<2e;i++){u a=r[i],z=a[6.3H[m[2]]||m[2]];7(z==H||/4M|2u/.17(m[2]))z=6.1b(a,m[2])||\'\';7((G==""&&!!z||G=="="&&z==m[5]||G=="!="&&z!=m[5]||G=="^="&&z&&!z.J(m[5])||G=="$="&&z.2G(z.C-m[5].C)==m[5]||(G=="*="||G=="~=")&&z.J(m[5])>=0)^h)g.R(a)}r=g}B 7(m[1]==":"&&m[2]=="22-3u"){u e=6.1k++,g=[],17=/(\\d*)n\\+?(\\d*)/.1V(m[3]=="5L"&&"2n"||m[3]=="5K"&&"2n+1"||!/\\D/.17(m[3])&&"n+"+m[3]||m[3]),2Q=(17[1]||1)-0,d=17[2]-0;E(u i=0,2e=r.C;i<2e;i++){u j=r[i],L=j.L;7(e!=L.1k){u c=1;E(u n=L.1d;n;n=n.1X)7(n.1q==1)n.4a=c++;L.1k=e}u b=N;7(2Q==1){7(d==0||j.4a==d)b=K}B 7((j.4a+d)%2Q==0)b=K;7(b^h)g.R(j)}r=g}B{u f=6.4n[m[1]];7(1g f!="1s")f=6.4n[m[1]][m[2]];49("f = q(a,i){v "+f+"}");r=6.2s(r,f,h)}}v{r:r,t:t}},4p:q(c){u b=[];u a=c.L;1v(a&&a!=P){b.R(a);a=a.L}v b},22:q(a,e,c,b){e=e||1;u d=0;E(;a;a=a[c])7(a.1q==1&&++d==e)1F;v a},4q:q(n,a){u r=[];E(;n;n=n.1X){7(n.1q==1&&(!a||n!=a))r.R(n)}v r}});6.S={1A:q(d,e,c,b){7(6.M.1h&&d.3m!=I)d=18;7(!c.1Q)c.1Q=9.1Q++;7(b!=I){u f=c;c=q(){v f.O(9,19)};c.W=b;c.1Q=f.1Q}7(!d.$1a)d.$1a={};7(!d.$1p)d.$1p=q(){u a;7(1g 6=="I"||6.S.47)v a;a=6.S.1p.O(d,19);v a};u g=d.$1a[e];7(!g){g=d.$1a[e]={};7(d.46)d.46(e,d.$1p,N);B d.7M("5r"+e,d.$1p)}g[c.1Q]=c;7(!9.Y[e])9.Y[e]=[];7(6.2w(d,9.Y[e])==-1)9.Y[e].R(d)},1Q:1,Y:{},1E:q(b,c,a){u d=b.$1a,1Y,2p;7(d){7(c&&c.G){a=c.44;c=c.G}7(!c){E(c V d)9.1E(b,c)}B 7(d[c]){7(a)3l d[c][a.1Q];B E(a V b.$1a[c])3l d[c][a];E(1Y V d[c])1F;7(!1Y){7(b.43)b.43(c,b.$1p,N);B b.7J("5r"+c,b.$1p);1Y=H;3l d[c];1v(9.Y[c]&&((2p=6.2w(b,9.Y[c]))>=0))3l 9.Y[c][2p]}}E(1Y V d)1F;7(!1Y)b.$1p=b.$1a=H}},1t:q(c,b,d){b=6.2L(b||[]);7(!d)6.F(9.Y[c]||[],q(){6.S.1t(c,b,9)});B{u a,1Y,11=6.16(d[c]||H);b.5p(9.42({G:c,1O:d}));7(6.16(d.$1p)&&(a=d.$1p.O(d,b))!==N)9.47=K;7(11&&a!==N&&!6.Q(d,\'a\'))d[c]();9.47=N}},1p:q(b){u a;b=6.S.42(b||18.S||{});u c=9.$1a&&9.$1a[b.G],1S=[].51.3D(19,1);1S.5p(b);E(u j V c){1S[0].44=c[j];1S[0].W=c[j].W;7(c[j].O(9,1S)===N){b.2d();b.2D();a=N}}7(6.M.1h)b.1O=b.2d=b.2D=b.44=b.W=H;v a},42:q(c){u a=c;c=6.1c({},a);c.2d=q(){7(a.2d)v a.2d();a.7H=N};c.2D=q(){7(a.2D)v a.2D();a.7F=K};7(!c.1O&&c.5n)c.1O=c.5n;7(6.M.20&&c.1O.1q==3)c.1O=a.1O.L;7(!c.41&&c.4j)c.41=c.4j==c.1O?c.7C:c.4j;7(c.5k==H&&c.5j!=H){u e=P.4h,b=P.4y;c.5k=c.5j+(e&&e.5i||b.5i);c.7z=c.7y+(e&&e.5f||b.5f)}7(!c.3h&&(c.5e||c.5d))c.3h=c.5e||c.5d;7(!c.5c&&c.5b)c.5c=c.5b;7(!c.3h&&c.1J)c.3h=(c.1J&1?1:(c.1J&2?3:(c.1J&4?2:0)));v c}};6.11.1c({3g:q(c,a,b){v c=="3z"?9.3Z(c,a,b):9.F(q(){6.S.1A(9,c,b||a,b&&a)})},3Z:q(d,b,c){v 9.F(q(){6.S.1A(9,d,q(a){6(9).3U(a);v(c||b).O(9,19)},c&&b)})},3U:q(a,b){v 9.F(q(){6.S.1E(9,a,b)})},1t:q(a,b){v 9.F(q(){6.S.1t(a,b,9)})},1R:q(){u a=19;v 9.5a(q(e){9.4u=0==9.4u?1:0;e.2d();v a[9.4u].O(9,[e])||N})},7w:q(f,g){q 3W(e){u p=e.41;1v(p&&p!=9)2g{p=p.L}25(e){p=9};7(p==9)v N;v(e.G=="3V"?f:g).O(9,[e])}v 9.3V(3W).59(3W)},1G:q(f){7(6.3d)f.O(P,[6]);B 6.2q.R(q(){v f.O(9,[6])});v 9}});6.1c({3d:N,2q:[],1G:q(){7(!6.3d){6.3d=K;7(6.2q){6.F(6.2q,q(){9.O(P)});6.2q=H}7(6.M.3j||6.M.2a)P.43("58",6.1G,N);7(!18.7v.C)6(18).1W(q(){6("#3T").1E()})}}});14 q(){6.F(("7u,7t,1W,7s,7r,3z,5a,7q,"+"7p,7o,7n,3V,59,7m,2y,"+"4k,7l,7k,7j,2c").2R(","),q(i,o){6.11[o]=q(f){v f?9.3g(o,f):9.1t(o)}});7(6.M.3j||6.M.2a)P.46("58",6.1G,N);B 7(6.M.1h){P.7i("<7h"+"7f 2m=3T 7e=K "+"2u=//:><\\/3b>");u a=P.4d("3T");7(a)a.7d=q(){7(9.3a!="1n")v;6.1G()};a=H}B 7(6.M.20)6.3N=3m(q(){7(P.3a=="79"||P.3a=="1n"){3M(6.3N);6.3N=H;6.1G()}},10);6.S.1A(18,"1W",6.1G)};7(6.M.1h)6(18).3Z("3z",q(){u a=6.S.Y;E(u b V a){u c=a[b],i=c.C;7(i&&b!=\'3z\')77 c[i-1]&&6.S.1E(c[i-1],b);1v(--i)}});6.11.1c({76:q(c,b,a){9.1W(c,b,a,1)},1W:q(g,d,c,e){7(6.16(g))v 9.3g("1W",g);c=c||q(){};u f="3K";7(d)7(6.16(d)){c=d;d=H}B{d=6.2E(d);f="50"}u h=9;6.2Z({1C:g,G:f,W:d,2t:e,1n:q(a,b){7(b=="28"||!e&&b=="4V")h.1b("27",a.3c).3J().F(c,[a.3c,b,a]);B c.O(h,[a.3c,b,a])}});v 9},72:q(){v 6.2E(9)},3J:q(){v 9.1L("3b").F(q(){7(9.2u)6.4U(9.2u);B 6.3I(9.2A||9.5H||9.27||"")}).2U()}});6.F("4T,4I,4S,4R,4Q,4P".2R(","),q(i,o){6.11[o]=q(f){v 9.3g(o,f)}});6.1c({1M:q(e,c,a,d,b){7(6.16(c)){a=c;c=H}v 6.2Z({G:"3K",1C:e,W:c,28:a,3G:d,2t:b})},6X:q(d,b,a,c){v 6.1M(d,b,a,c,1)},4U:q(b,a){v 6.1M(b,H,a,"3b")},6V:q(c,b,a){v 6.1M(c,b,a,"4N")},6T:q(d,b,a,c){7(6.16(b)){a=b;b={}}v 6.2Z({G:"50",1C:d,W:b,28:a,3G:c})},6S:q(a){6.36.21=a},6Q:q(a){6.1c(6.36,a)},36:{Y:K,G:"3K",21:0,4O:"6P/x-6O-34-6N",4K:K,38:K,W:H},32:{},2Z:q(s){s=6.1c({},6.36,s);7(s.W){7(s.4K&&1g s.W!="1s")s.W=6.2E(s.W);7(s.G.2H()=="1M"){s.1C+=((s.1C.J("?")>-1)?"&":"?")+s.W;s.W=H}}7(s.Y&&!6.3L++)6.S.1t("4T");u f=N;u h=18.4Z?14 4Z("6L.6J"):14 4J();h.7b(s.G,s.1C,s.38);7(s.W)h.3Q("6H-6G",s.4O);7(s.2t)h.3Q("6F-3O-6D",6.32[s.1C]||"6C, 6B 6A 6z 4r:4r:4r 6y");h.3Q("X-6x-6w","4J");7(s.56)s.56(h);7(s.Y)6.S.1t("4P",[h,s]);u g=q(d){7(h&&(h.3a==4||d=="21")){f=K;7(i){3M(i);i=H}u c;2g{c=6.54(h)&&d!="21"?s.2t&&6.4F(h,s.1C)?"4V":"28":"2c";7(c!="2c"){u b;2g{b=h.3E("53-3O")}25(e){}7(s.2t&&b)6.32[s.1C]=b;u a=6.55(h,s.3G);7(s.28)s.28(a,c);7(s.Y)6.S.1t("4Q",[h,s])}B 6.2X(s,h,c)}25(e){c="2c";6.2X(s,h,c,e)}7(s.Y)6.S.1t("4S",[h,s]);7(s.Y&&!--6.3L)6.S.1t("4I");7(s.1n)s.1n(h,c);7(s.38)h=H}};u i=3m(g,13);7(s.21>0)4C(q(){7(h){h.6r();7(!f)g("21")}},s.21);2g{h.6p(s.W)}25(e){6.2X(s,h,H,e)}7(!s.38)g();v h},2X:q(s,a,b,e){7(s.2c)s.2c(a,b,e);7(s.Y)6.S.1t("4R",[a,s,e])},3L:0,54:q(r){2g{v!r.23&&7A.7B=="4l:"||(r.23>=5u&&r.23<6l)||r.23==5m||6.M.20&&r.23==I}25(e){}v N},4F:q(a,c){2g{u b=a.3E("53-3O");v a.23==5m||b==6.32[c]||6.M.20&&a.23==I}25(e){}v N},55:q(r,b){u c=r.3E("6k-G");u a=!b&&c&&c.J("4B")>=0;a=b=="4B"||a?r.6j:r.3c;7(b=="3b")6.3I(a);7(b=="4N")a=49("("+a+")");7(b=="3F")6("<1x>").3F(a).3J();v a},2E:q(a){u s=[];7(a.15==2b||a.3C)6.F(a,q(){s.R(2l(9.6i)+"="+2l(9.2v))});B E(u j V a)7(a[j]&&a[j].15==2b)6.F(a[j],q(){s.R(2l(j)+"="+2l(9))});B s.R(2l(j)+"="+2l(a[j]));v s.5M("&")},3I:q(a){7(18.4A)18.4A(a);B 7(6.M.20)18.4C(a,0);B 49.3D(18,a)}});6.11.1c({1m:q(b,a){v b?9.1w({1u:"1m",29:"1m",1e:"1m"},b,a):9.1i(":1y").F(q(){9.T.U=9.2i?9.2i:"";7(6.1f(9,"U")=="1P")9.T.U="2h"}).2U()},1j:q(b,a){v b?9.1w({1u:"1j",29:"1j",1e:"1j"},b,a):9.1i(":4f").F(q(){9.2i=9.2i||6.1f(9,"U");7(9.2i=="1P")9.2i="2h";9.T.U="1P"}).2U()},5G:6.11.1R,1R:q(a,b){v 6.16(a)&&6.16(b)?9.5G(a,b):a?9.1w({1u:"1R",29:"1R",1e:"1R"},a,b):9.F(q(){6(9)[6(9).37(":1y")?"1m":"1j"]()})},6e:q(b,a){v 9.1w({1u:"1m"},b,a)},6d:q(b,a){v 9.1w({1u:"1j"},b,a)},6b:q(b,a){v 9.1w({1u:"1R"},b,a)},6a:q(b,a){v 9.1w({1e:"1m"},b,a)},69:q(b,a){v 9.1w({1e:"1j"},b,a)},7U:q(c,a,b){v 9.1w({1e:a},c,b)},1w:q(d,h,f,g){v 9.1l(q(){u c=6(9).37(":1y"),1H=6.5z(h,f,g),5y=9;E(u p V d){7(d[p]=="1j"&&c||d[p]=="1m"&&!c)v 6.16(1H.1n)&&1H.1n.O(9);7(p=="1u"||p=="29"){1H.U=6.1f(9,"U");1H.2f=9.T.2f}}7(1H.2f!=H)9.T.2f="1y";9.2k=6.1c({},d);6.F(d,q(a,b){u e=14 6.2M(5y,1H,a);7(b.15==3y)e.2W(e.1K(),b);B e[b=="1R"?c?"1m":"1j":b](d)})})},1l:q(a,b){7(!b){b=a;a="2M"}v 9.F(q(){7(!9.1l)9.1l={};7(!9.1l[a])9.1l[a]=[];9.1l[a].R(b);7(9.1l[a].C==1)b.O(9)})}});6.1c({5z:q(b,a,c){u d=b&&b.15==64?b:{1n:c||!c&&a||6.16(b)&&b,1B:b,2I:c&&a||a&&a.15!=45&&a||(6.2I.4i?"4i":"4w")};d.1B=(d.1B&&d.1B.15==3y?d.1B:{61:60,89:5u}[d.1B])||8a;d.2N=d.1n;d.1n=q(){6.5I(9,"2M");7(6.16(d.2N))d.2N.O(9)};v d},2I:{4w:q(p,n,b,a){v b+a*p},4i:q(p,n,b,a){v((-5W.5X(p*5W.8e)/2)+0.5)*a+b}},1l:{},5I:q(b,a){a=a||"2M";7(b.1l&&b.1l[a]){b.1l[a].4e();u f=b.1l[a][0];7(f)f.O(b)}},3B:[],2M:q(f,e,g){u z=9;u y=f.T;z.a=q(){7(e.3A)e.3A.O(f,[z.2o]);7(g=="1e")6.1b(y,"1e",z.2o);B{y[g]=8m(z.2o)+"4o";y.U="2h"}};z.5V=q(){v 39(6.1f(f,g))};z.1K=q(){u r=39(6.2z(f,g));v r&&r>-8l?r:z.5V()};z.2W=q(c,b){z.4s=(14 5T()).5S();z.2o=c;z.a();6.3B.R(q(){v z.3A(c,b)});7(6.3B.C==1){u d=3m(q(){u a=6.3B;E(u i=0;i<a.C;i++)7(!a[i]())a.8j(i--,1);7(!a.C)3M(d)},13)}};z.1m=q(){7(!f.24)f.24={};f.24[g]=6.1b(f.T,g);e.1m=K;z.2W(0,9.1K());7(g!="1e")y[g]="8q";6(f).1m()};z.1j=q(){7(!f.24)f.24={};f.24[g]=6.1b(f.T,g);e.1j=K;z.2W(9.1K(),0)};z.3A=q(a,c){u t=(14 5T()).5S();7(t>e.1B+z.4s){z.2o=c;z.a();7(f.2k)f.2k[g]=K;u b=K;E(u i V f.2k)7(f.2k[i]!==K)b=N;7(b){7(e.U!=H){y.2f=e.2f;y.U=e.U;7(6.1f(f,"U")=="1P")y.U="2h"}7(e.1j)y.U="1P";7(e.1j||e.1m)E(u p V f.2k)6.1b(y,p,f.24[p])}7(b&&6.16(e.1n))e.1n.O(f);v N}B{u n=t-9.4s;u p=n/e.1B;z.2o=6.2I[e.2I](p,n,a,(c-a),e.1B);z.a()}v K}}})}',62,524,'||||||jQuery|if||this|||||||||||||||||function||||var|return||||||else|length||for|each|type|null|undefined|indexOf|true|parentNode|browser|false|apply|document|nodeName|push|event|style|display|in|data||global|||fn|className||new|constructor|isFunction|test|window|arguments|events|attr|extend|firstChild|opacity|css|typeof|msie|filter|hide|mergeNum|queue|show|complete|replace|handle|nodeType|table|string|trigger|height|while|animate|div|hidden|tbody|add|duration|url|toUpperCase|remove|break|ready|opt|_|button|cur|find|get|tb|target|none|guid|toggle|args|merge|styleFloat|exec|load|nextSibling|ret|pushStack|safari|timeout|nth|status|orig|catch|al|innerHTML|success|width|opera|Array|error|preventDefault|rl|overflow|try|block|oldblock|done|curAnim|encodeURIComponent|id||now|index|readyList|disabled|grep|ifModified|src|value|inArray|multiFilter|select|curCSS|text|checked|trim|stopPropagation|param|domManip|substr|toLowerCase|easing|chars|insertBefore|makeArray|fx|old|ownerDocument|last|first|split|childNodes|selected|end|tr|custom|handleError|empty|ajax|el|clean|lastModified|String|form|getAttribute|ajaxSettings|is|async|parseFloat|readyState|script|responseText|isReady|append|defaultView|bind|which|position|mozilla|map|delete|setInterval|static|RegExp|oWidth|removeChild|oHeight|cloneNode|match|child|toString|has|float|Number|unload|step|timers|jquery|call|getResponseHeader|html|dataType|props|globalEval|evalScripts|GET|active|clearInterval|safariTimer|Modified|num|setRequestHeader|getElementsByTagName|currentStyle|__ie_init|unbind|mouseover|handleHover|init|getComputedStyle|one|isXMLDoc|relatedTarget|fix|removeEventListener|handler|Function|addEventListener|triggered|visibility|eval|nodeIndex|radio|classFilter|getElementById|shift|visible|appendChild|documentElement|swing|fromElement|submit|file|swap|expr|px|parents|sibling|00|startTime|previousSibling|lastToggle|parent|linear|ol|body|tagName|execScript|xml|setTimeout|version|setArray|httpNotModified|fl|prop|ajaxStop|XMLHttpRequest|processData|alpha|href|json|contentType|ajaxSend|ajaxSuccess|ajaxError|ajaxComplete|ajaxStart|getScript|notmodified|colgroup|100|not|ActiveXObject|POST|slice|fieldset|Last|httpSuccess|httpData|beforeSend|getPropertyValue|DOMContentLoaded|mouseout|click|ctrlKey|metaKey|keyCode|charCode|scrollTop|unique|createElement|scrollLeft|clientX|pageX|webkit|304|srcElement|appendTo|unshift|prevObject|on|after|before|200|removeAttr|prepend|cssFloat|self|speed|parse|input|reset|image|password|checkbox|_toggle|textContent|dequeue|lastChild|odd|even|join|contains|gt|lt|eq|nodeValue|getTime|Date|zoom|max|Math|cos|font|maxLength|600|slow|maxlength|readOnly|Object|readonly|createTextNode|class|htmlFor|fadeOut|fadeIn|slideToggle|CSS1Compat|slideUp|slideDown|compatMode|boxModel|compatible|name|responseXML|content|300|ie|noConflict|ra|send|it|abort|rv|userAgent|navigator|concat|With|Requested|GMT|1970|Jan|01|Thu|Since|reverse|If|Type|Content|array|XMLHTTP|ig|Microsoft|NaN|urlencoded|www|application|ajaxSetup|val|ajaxTimeout|post|setAttribute|getJSON|getAttributeNode|getIfModified|method|FORM|action|options|serialize|col|th|td|loadIfModified|do|colg|loaded|tfoot|open|thead|onreadystatechange|defer|ipt|leg|scr|write|keyup|keypress|keydown|change|mousemove|mouseup|mousedown|dblclick|scroll|resize|focus|blur|frames|hover|clone|clientY|pageY|location|protocol|toElement|clientWidth|clientHeight|cancelBubble|relative|returnValue|left|detachEvent|right|absolute|attachEvent|substring|offsetWidth|object|offsetHeight|continue|Width|border|fadeTo|padding|size|uFFFF|Left|u0128|Right|Bottom|textarea|Top|enabled|innerText|only|toggleClass|removeClass|fast|400|wrap|addClass|removeAttribute|PI|insertAfter|prependTo|children|line|splice|siblings|10000|parseInt|prev|next|weight|1px|prototype'.split('|'),0,{})) \ No newline at end of file
diff --git a/htdocs/js/smokeping_iselect.js b/htdocs/js/smokeping_iselect.js
new file mode 100644
index 0000000..905b8c3
--- /dev/null
+++ b/htdocs/js/smokeping_iselect.js
@@ -0,0 +1,287 @@
+/**
+ * Interface Elements for jQuery
+ * Selectables
+ *
+ * http://interface.eyecon.ro
+ *
+ * Copyright (c) 2006 Stefan Petre
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * Modified for smokeping ... we hacked in the call
+ * we need after the area is selected. Yes there is
+ * certainly a much better way todo this! Let us know!
+ *
+ */
+
+jQuery.selectHelper = null;
+jQuery.selectKeyHelper = false;
+jQuery.selectdrug = null;
+jQuery.selectCurrent = []; // For current selection
+jQuery.selectKeyDown = function(e) {
+ var pressedKey = e.charCode || e.keyCode || -1;
+ if (pressedKey == 17 || pressedKey == 16) {
+ jQuery.selectKeyHelper = true;
+ }
+};
+jQuery.selectKeyUp = function(e) {
+ jQuery.selectKeyHelper = false;
+};
+jQuery.selectstart = function(e) {
+ this.f.pointer = jQuery.iUtil.getPointer(e);
+ this.f.pos = jQuery.extend(
+ jQuery.iUtil.getPosition(this),
+ jQuery.iUtil.getSize(this)
+ );
+
+ this.f.scr = jQuery.iUtil.getScroll(this);
+ this.f.pointer.x -= this.f.pos.x;
+ this.f.pointer.y -= this.f.pos.y;
+ jQuery(this).append(jQuery.selectHelper.get(0));
+ if (this.f.hc)
+ jQuery.selectHelper.addClass(this.f.hc).css('display','block');
+ jQuery.selectHelper.css(
+ {
+ display: 'block',
+ width: '0px',
+ height: '0px'
+ }
+ );
+ if (this.f.o) {
+ jQuery.selectHelper.css('opacity', this.f.o);
+ }
+
+ jQuery.selectdrug = this;
+ jQuery.selectedone = false;
+ jQuery.selectCurrent = []; // For current selection state
+ this.f.el.each(
+ function ()
+ {
+ this.pos = {
+ x: this.offsetLeft + (this.currentStyle && !jQuery.browser.opera ?parseInt(this.currentStyle.borderLeftWidth)||0:0) + (jQuery.selectdrug.scrollLeft||0),
+ y: this.offsetTop + (this.currentStyle && !jQuery.browser.opera ?parseInt(this.currentStyle.borderTopWidth)||0:0) + (jQuery.selectdrug.scrollTop||0),
+ wb: this.offsetWidth,
+ hb: this.offsetHeight
+ };
+ if (this.s == true) {
+ if (jQuery.selectKeyHelper == false) {
+ this.s = false;
+ jQuery(this).removeClass(jQuery.selectdrug.f.sc);
+ } else {
+ jQuery.selectedone = true;
+
+ // Save current state
+ jQuery.selectCurrent[jQuery.selectCurrent.length] = jQuery.attr(this,'id');
+ }
+ }
+ }
+ );
+ jQuery.selectcheck.apply(this, [e]);
+ jQuery(document)
+ .bind('mousemove', jQuery.selectcheck)
+ .bind('mouseup', jQuery.selectstop);
+ return false;
+};
+jQuery.selectcheck = function(e)
+{
+ if(!jQuery.selectdrug)
+ return;
+ jQuery.selectcheckApply.apply(jQuery.selectdrug, [e]);
+};
+jQuery.selectcheckApply = function(e)
+{
+ if(!jQuery.selectdrug)
+ return;
+ var pointer = jQuery.iUtil.getPointer(e);
+
+ var scr = jQuery.iUtil.getScroll(jQuery.selectdrug);
+ pointer.x += scr.l - this.f.scr.l - this.f.pos.x;
+ pointer.y += scr.t - this.f.scr.t - this.f.pos.y;
+
+ var sx = Math.min(pointer.x, this.f.pointer.x);
+ var sw = Math.min(Math.abs(pointer.x - this.f.pointer.x), Math.abs(this.f.scr.w - sx));
+ var sy = Math.min(pointer.y, this.f.pointer.y);
+ var sh = Math.min(Math.abs(pointer.y - this.f.pointer.y), Math.abs(this.f.scr.h - sy));
+ if (this.scrollTop > 0 && pointer.y - 20 < this.scrollTop) {
+ var diff = Math.min(scr.t, 10);
+ sy -= diff;
+ sh += diff;
+ this.scrollTop -= diff;
+ } else if (this.scrollTop+ this.f.pos.h < this.f.scr.h && pointer.y + 20 > this.scrollTop + this.f.pos.h) {
+ var diff = Math.min(this.f.scr.h - this.scrollTop, 10);
+ this.scrollTop += diff;
+ if (this.scrollTop != scr.t)
+ sh += diff;
+ }
+ if (this.scrollLeft > 0 && pointer.x - 20 < this.scrollLeft) {
+ var diff = Math.min(scr.l, 10);
+ sx -= diff;
+ sw += diff;
+ this.scrollLeft -= diff;
+ } else if (this.scrollLeft+ this.f.pos.w < this.f.scr.w && pointer.x + 20 > this.scrollLeft + this.f.pos.w) {
+ var diff = Math.min(this.f.scr.w - this.scrollLeft, 10);
+ this.scrollLeft += diff;
+ if (this.scrollLeft != scr.l)
+ sw += diff;
+ }
+ jQuery.selectHelper.css(
+ {
+ left: sx + 'px',
+ top: sy + 'px',
+ width: sw + 'px',
+ height: sh + 'px'
+ }
+ );
+ jQuery.selectHelper.l = sx + this.f.scr.l;
+ jQuery.selectHelper.t = sy + this.f.scr.t;
+ jQuery.selectHelper.r = jQuery.selectHelper.l + sw;
+ jQuery.selectHelper.b = jQuery.selectHelper.t + sh;
+
+ jQuery.selectedone = false;
+ this.f.el.each(
+ function () {
+ // Locate the current element in the current selection
+ iIndex = jQuery.selectCurrent.indexOf(jQuery.attr(this, 'id'));
+ // In case we are currently OVER an item
+ if (
+ ! ( this.pos.x > jQuery.selectHelper.r
+ || (this.pos.x + this.pos.wb) < jQuery.selectHelper.l
+ || this.pos.y > jQuery.selectHelper.b
+ || (this.pos.y + this.pos.hb) < jQuery.selectHelper.t
+ )
+ )
+ {
+ jQuery.selectedone = true;
+ if (this.s != true) {
+ this.s = true;
+ jQuery(this).addClass(jQuery.selectdrug.f.sc);
+ }
+
+ // Check to see if this item was previously selected, if so, unselect it
+ if (iIndex != -1) {
+ this.s = false;
+ jQuery(this).removeClass(jQuery.selectdrug.f.sc);
+ }
+ } else if (
+ (this.s == true) &&
+ (iIndex == -1)
+ ) {
+ // If the item was marked as selected, but it was not selected when you started dragging unselect it.
+ this.s = false;
+ jQuery(this).removeClass(jQuery.selectdrug.f.sc);
+ } else if (
+ (!this.s) &&
+ (jQuery.selectKeyHelper == true) &&
+ (iIndex != -1)
+ ) {
+ // Reselect the item if:
+ // - we ARE multiselecting,
+ // - dragged over an allready selected object (so it got unselected)
+ // - But then dragged the selection out of it again.
+ this.s = true;
+ jQuery(this).addClass(jQuery.selectdrug.f.sc);
+ }
+ }
+ );
+ return false;
+};
+jQuery.selectstop = function(e)
+{
+ if(!jQuery.selectdrug)
+ return;
+ jQuery.selectstopApply.apply(jQuery.selectdrug, [e]);
+};
+jQuery.selectstopApply = function(e)
+{
+ jQuery(document)
+ .unbind('mousemove', jQuery.selectcheck)
+ .unbind('mouseup', jQuery.selectstop);
+ if(!jQuery.selectdrug)
+ return;
+ jQuery.selectHelper.css('display','none');
+ if (this.f.hc)
+ jQuery.selectHelper.removeClass(this.f.hc);
+ jQuery.selectdrug = false;
+ jQuery('body').append(jQuery.selectHelper.get(0));
+
+ /* added by Roman Plessl -- rp */
+ mySelectTop = jQuery.selectHelper.t;
+ mySelectLeft = jQuery.selectHelper.l;
+ mySelectRight = jQuery.selectHelper.r;
+ mySelectBottom = jQuery.selectHelper.b;
+
+ changeRRDImage();
+
+ // In case we have selected some new items..
+ if (jQuery.selectedone == true) {
+ if (this.f.onselect)
+ this.f.onselect(jQuery.Selectserialize(jQuery.attr(this,'id')));
+ } else {
+ if (this.f.onselectstop)
+ this.f.onselectstop(jQuery.Selectserialize(jQuery.attr(this,'id')));
+ }
+ // Reset current selection
+ jQuery.selectCurrent = [];
+};
+
+jQuery.Selectserialize = function(s)
+{
+ var h = '';
+ var o = [];
+ if (a = jQuery('#' + s)) {
+ a.get(0).f.el.each(
+ function ()
+ {
+ if (this.s == true) {
+ if (h.length > 0) {
+ h += '&';
+ }
+ h += s + '[]=' + jQuery.attr(this,'id');
+ o[o.length] = jQuery.attr(this,'id');
+ }
+ }
+ );
+ }
+ return {hash:h, o:o};
+};
+jQuery.fn.Selectable = function(o)
+{
+ if (!jQuery.selectHelper) {
+ jQuery('body',document).append('<div id="selectHelper"></div>').bind('keydown', jQuery.selectKeyDown).bind('keyup', jQuery.selectKeyUp);
+ jQuery.selectHelper = jQuery('#selectHelper');
+ jQuery.selectHelper.css(
+ {
+ position: 'absolute',
+ display: 'none'
+ }
+ );
+
+ if (window.event) {
+ jQuery('body',document).bind('keydown', jQuery.selectKeyDown).bind('keyup', jQuery.selectKeyUp);
+ } else {
+ jQuery(document).bind('keydown', jQuery.selectKeyDown).bind('keyup', jQuery.selectKeyUp);
+ }
+ }
+
+ if (!o) {
+ o = {};
+ }
+ return this.each(
+ function()
+ {
+ if (this.isSelectable)
+ return;
+ this.isSelectable = true;
+ this.f = {
+ a : o.accept,
+ o : o.opacity ? parseFloat(o.opacity) : false,
+ sc : o.selectedclass ? o.selectedclass : false,
+ hc : o.helperclass ? o.helperclass : false,
+ onselect : o.onselect ? o.onselect : false,
+ onselectstop : o.onselectstop ? o.onselectstop : false
+ };
+ this.f.el = jQuery('.' + o.accept);
+ jQuery(this).bind('mousedown', jQuery.selectstart).css('position', 'relative');
+ }
+ );
+};
diff --git a/htdocs/js/smokeping_zoom.js b/htdocs/js/smokeping_zoom.js
new file mode 100644
index 0000000..3f19db5
--- /dev/null
+++ b/htdocs/js/smokeping_zoom.js
@@ -0,0 +1,181 @@
+<!--
+
+/*
+ * This code replaces images in the smokeping website with ajax
+ *
+ * The jquery toolkit (version 1.1.3.1) was used for platform
+ * independency. The URL parsing part was taken from the
+ * bonsaj.js script.
+ *
+ * Copyright (c) 2007 Roman Plessl <roman.plessl@oetiker.ch>
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2007-08-15 17:14:56 +0200 $
+ * $Rev: 36 $
+ *
+ */
+
+/*++ from bonsai.js ++ urlObj +++++++++++++++++++++++++++++++++++++++++*/
+function urlObj(url) {
+ var urlBaseAndParameters;
+
+ urlBaseAndParameters = url.split("?");
+ this.urlBase = urlBaseAndParameters[0];
+ this.urlParameters = urlBaseAndParameters[1].split(";");
+
+ this.getUrlBase = urlObjGetUrlBase;
+ this.getUrlParameterValue = urlObjGetUrlParameterValue;
+}
+
+/*++ from bonsai.js ++ urlObjGetUrlBase +++++++++++++++++++++++++++++++*/
+
+function urlObjGetUrlBase() {
+ return this.urlBase;
+}
+
+/*++ form bonsai.js ++ urlObjGetUrlParameterValue +++++++++++++++++++++*/
+
+function urlObjGetUrlParameterValue(parameter) {
+ var i;
+ var fieldAndValue;
+ var value;
+
+ i = 0;
+ while (this.urlParameters [i] != undefined) {
+ fieldAndValue = this.urlParameters[i].split("=");
+ if (fieldAndValue[0] == parameter) {
+ value = fieldAndValue[1];
+ }
+ i++;
+ }
+ return value;
+}
+
+/*++++++++++++++++++++ isoDateToJS +++++++++++++++++++++++++++++++++++++*/
+function ISODateToJS(rawisodate) {
+ var decode = decodeURI(rawisodate);
+ if (decode == "now") {
+ return new Date();
+ }
+ else {
+ var M = decode.match(/(\d\d\d\d).(\d\d).(\d\d).(\d\d).(\d\d)/)
+ var date = new Date(M[1], M[2]-1, M[3], M[4], M[5], "00")
+ return date;
+ }
+}
+
+/*++++++++++++++++++++++ JSToisoDate ++++++++++++++++++++++++++++++++++++++*/
+function JSToISODate(mydate) {
+ var isodate = mydate.getFullYear() + "-";
+ if ((mydate.getMonth() + 1) < 10) { isodate = isodate + "0"; }
+ isodate = isodate + (mydate.getMonth() + 1) + "-";
+ if (mydate.getDate() < 10) { isodate = isodate + "0"; }
+ isodate = isodate + mydate.getDate() + " ";
+ if (mydate.getHours() < 10) { isodate = isodate + "0"; }
+ isodate = isodate + mydate.getHours() + ":";
+ if (mydate.getMinutes() < 10) { isodate = isodate + "0"; }
+ isodate = isodate + mydate.getMinutes();
+ return encodeURI(isodate);
+}
+
+$(document).ready(function() {
+
+ mySelectTop = 0;
+ mySelectLeft = 0;
+ mySelectRight = 0;
+ mySelectBottom = 0;
+
+ myImgTop = 0;
+ myImgLeft = 0;
+ myImgRight = 0;
+ myImgBottom = 0;
+
+ RRDLeftDiff = 68; // difference between left border of RRD image and content
+ RRDRightDiff = 33; // difference between right border of RRD image and content
+ RRDImgWidth = 697; // Width of the Smokeping RRD Graphik
+ RRDImgUsable = 596; // 598 = 697 - 68 - 33;
+
+ mySelectTop = 0;
+ mySelectLeft = 0;
+ mySelectRight = 0;
+ mySelectBottom = 0;
+
+ StartDateString = 0;
+ EndDateString = 0;
+
+ $("div.zoom").mousedown(function() {
+
+ var rrdimg = $("div.zoom").children("img");
+ myImgTop = rrdimg.get(0).y;
+ myImgLeft = rrdimg.get(0).x;
+ myImgRight = myImgLeft + rrdimg.get(0).width;
+ myImgBottom = myImgTop + rrdimg.get(0).height;
+
+ });
+
+ $("div.zoom").Selectable({
+ accept : 'selectableitem',
+ opacity : 0.2,
+ selectedclass : 'selecteditem',
+ helperclass : 'selecthelper'
+ });
+
+});
+
+// will be started by modified iSelect (StopApply Function)
+function changeRRDImage(){
+
+ var oldimg = $("div.zoom").children("img");
+
+ myURLObj = new urlObj(document.URL);
+
+ // parse start and stop parameter from URL
+ var myURL = myURLObj.getUrlBase();
+ var myRawStartDate = (StartDateString != 0) ? StartDateString : myURLObj.getUrlParameterValue("start");
+ var myRawStopDate = (EndDateString != 0) ? EndDateString : myURLObj.getUrlParameterValue("end");
+ var myRawTarget = myURLObj.getUrlParameterValue("target");
+
+ var myParsedStartDate = ISODateToJS(myRawStartDate);
+ myParsedStartEpoch = Math.floor(myParsedStartDate.getTime()/1000.0);
+
+ var myParsedStopDate = ISODateToJS(myRawStopDate);
+ myParsedStopEpoch = Math.floor(myParsedStopDate.getTime()/1000.0);
+
+ myParsedDivEpoch = myParsedStopEpoch - myParsedStartEpoch;
+
+ var mySerialDate = new Date();
+ var mySerial = mySerialDate.getTime();
+
+ // Generate Selected Range in Unix Timestamps
+ var genStart = myParsedStartEpoch + (((mySelectLeft - RRDLeftDiff) / RRDImgUsable ) * myParsedDivEpoch);
+ var genStop = myParsedStartEpoch + (((mySelectRight - RRDLeftDiff) / RRDImgUsable ) * myParsedDivEpoch);
+
+ var floorGenStart = Math.floor(genStart);
+ var floorGenStop = Math.floor(genStop);
+
+ var StartDate = new Date(floorGenStart*1000);
+ var StopDate = new Date(floorGenStop*1000);
+
+ // floor to last full minute
+ var MinuteGenStart = ( Math.floor(floorGenStart / 60) * 60 );
+ var MinuteGenStop = ( Math.floor(floorGenStop / 60) * 60 );
+
+ // create new image based on old image and fetched data
+ var newimg = new Image();
+ newimg = oldimg;
+
+ StartDateString = JSToISODate(StartDate);
+ EndDateString = JSToISODate(StopDate);
+
+ // construct Image URL
+ myGraph = "img/__navcache/" + mySerial + "_" + MinuteGenStop + "_" + MinuteGenStart + ".png";
+
+ // Fetch image with ajax
+ var result = $.get(myURL + "?displaymode=a;start=" + StartDateString+ ";end=" + EndDateString + ";target=" + myRawTarget + ";serial=" + mySerial,
+ function(){
+ // replacement image with AJAX
+ newimg.attr("src", myGraph);
+ });
+};
+
diff --git a/lib/Smokeping.pm b/lib/Smokeping.pm
index 413a039..8315bee 100644
--- a/lib/Smokeping.pm
+++ b/lib/Smokeping.pm
@@ -758,6 +758,7 @@ sub get_detail ($$$$;$){
# b) 'n' navigator mode with one graph. below the graph one can specify the end time
# and the length of the graph.
# c) 'c' chart mode, one graph with a link to it's full page
+ # d) 'a' ajax mode, generate image based on given url
#
my $cfg = shift;
my $q = shift;
@@ -785,7 +786,7 @@ sub get_detail ($$$$;$){
my $page;
return "<div>ERROR: unknown displaymode $mode</div>"
- unless $mode =~ /^[snc]$/;
+ unless $mode =~ /^[snca]$/;
for (@dirs) {
$dir .= "/$_";
@@ -824,15 +825,22 @@ sub get_detail ($$$$;$){
}
close HG;
}
- } elsif ($mode eq 'n') {
+ }
+ elsif ($mode eq 'n' or $mode eq 'a') {
mkdir $cfg->{General}{imgcache}."/__navcache",0755 unless -d $cfg->{General}{imgcache}."/__navcache";
# remove old images after one hour
my $pattern = $cfg->{General}{imgcache}."/__navcache/*.png";
for (glob $pattern){
unlink $_ if time - (stat $_)[9] > 3600;
}
- $imgbase =$cfg->{General}{imgcache}."/__navcache/".time()."$$";
- $imghref =$cfg->{General}{imgurl}."/__navcache/".time()."$$";
+ if ($mode eq 'n') {
+ $imgbase =$cfg->{General}{imgcache}."/__navcache/".time()."$$";
+ $imghref =$cfg->{General}{imgurl}."/__navcache/".time()."$$";
+ } else {
+ my $serial = $q->param('serial');
+ $imgbase =$cfg->{General}{imgcache}."/__navcache/".$serial;
+ $imghref =$cfg->{General}{imgurl}."/__navcache/".$serial;
+ }
@tasks = (["Navigator Graph", parse_datetime($q->param('start')),parse_datetime($q->param('end'))]);
my ($graphret,$xs,$ys) = RRDs::graph
@@ -1068,11 +1076,12 @@ sub get_detail ($$$$;$){
my ($graphret,$xs,$ys) = RRDs::graph @task;
my $ERROR = RRDs::error();
- if ($mode eq 'n'){
- $page .= "<div>";
- $page .= ( $ERROR || qq|<IMG BORDER="0" WIDTH="$xs" HEIGHT="$ys" SRC="${imghref}_${end}_${start}.png">| );
- $page .= "</div>";
- $page .= $q->start_form(-method=>'GET')
+ if ($mode eq 'n' or $mode eq 'a'){
+ $page .= qq|<div class="zoom" style="cursor: crosshair;">|;
+ $page .= ( $ERROR || qq|<IMG style="cursor: crosshair;" BORDER="0" WIDTH="$xs" HEIGHT="$ys" SRC="${imghref}_${end}_${start}.png"> | );
+ $page .= "</div>";
+
+ $page .= $q->start_form(-method=>'GET')
. "<p>Time range: "
. $q->textfield(-name=>'start',-default=>$startstr)
. "&nbsp;&nbsp;to&nbsp;&nbsp;".$q->textfield(-name=>'end',-default=>$endstr)