/**
 * Interface Elements for jQuery
 * Easing formulas
 *
 * http://interface.eyecon.ro
 *
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 */
 
/**
 * Starting with jQuery 1.1  the fx function accepts easing formulas that can be used with .animation() and most of FX plugins from Interface. The object can be extended to accept new easing formulas
 */
 
 jQuery.extend({    
    /**
     *
     * @param Integer p period step in animation
     * @param Integer n current time
     * @param Mixed firstNum begin value
     * @param Mixed delta change in
     * @param Integer duration duration
     */
    easing :  {
        linear: function(p, n, firstNum, delta, duration) {
            return ((-Math.cos(p*Math.PI)/2) + 0.5) * delta + firstNum;
        },
        
        easein: function(p, n, firstNum, delta, duration) {
            return delta*(n/=duration)*n*n + firstNum;
        },
        
        easeout: function(p, n, firstNum, delta, duration) {
            return -delta * ((n=n/duration-1)*n*n*n - 1) + firstNum;
        },
        
        easeboth: function(p, n, firstNum, delta, duration) {
            if ((n/=duration/2) < 1)
                return delta/2*n*n*n*n + firstNum;
                return -delta/2 * ((n-=2)*n*n*n - 2) + firstNum;
        },
        
        bounceout: function(p, n, firstNum, delta, duration) {
            if ((n/=duration) < (1/2.75)) {
                return delta*(7.5625*n*n) + firstNum;
            } else if (n < (2/2.75)) {
                return delta*(7.5625*(n-=(1.5/2.75))*n + .75) + firstNum;
            } else if (n < (2.5/2.75)) {
                return delta*(7.5625*(n-=(2.25/2.75))*n + .9375) + firstNum;
            } else {
                return delta*(7.5625*(n-=(2.625/2.75))*n + .984375) + firstNum;
            }
        },
        
        bouncein: function(p, n, firstNum, delta, duration) {
            if (jQuery.easing.bounceout)
                return delta - jQuery.easing.bounceout (p, duration - n, 0, delta, duration) + firstNum;
            return firstNum + delta;
        },
        
        bounceboth: function(p, n, firstNum, delta, duration) {
            if (jQuery.easing.bouncein && jQuery.easing.bounceout)
                if (n < duration/2)
                    return jQuery.easing.bouncein(p, n*2, 0, delta, duration) * .5 + firstNum;
                return jQuery.easing.bounceout(p, n*2-duration, 0, delta, duration) * .5 + delta*.5 + firstNum; 
            return firstNum + delta;
        },
        
        elasticin: function(p, n, firstNum, delta, duration) {
            var a, s;
               if (n == 0)
                   return firstNum;
               if ((n/=duration)==1)
                   return firstNum+delta;
               a = delta * 0.3;
               p=duration*.3;
            if (a < Math.abs(delta)) {
                a=delta;
                s=p/4;
            } else { 
                s = p/(2*Math.PI) * Math.asin (delta/a);
            }
            return -(a*Math.pow(2,10*(n-=1)) * Math.sin( (n*duration-s)*(2*Math.PI)/p )) + firstNum; 
        },
        
        elasticout:function(p, n, firstNum, delta, duration) {
            var a, s;
            if (n==0)
                return firstNum;
            if ((n/=duration/2)==2)
                return firstNum + delta;
               a = delta * 0.3;
               p=duration*.3;
            if (a < Math.abs(delta)){
                a = delta;
                s=p/4;
            } else { 
                s = p/(2*Math.PI) * Math.asin (delta/a);
            }
            return a*Math.pow(2,-10*n) * Math.sin( (n*duration-s)*(2*Math.PI)/p ) + delta + firstNum;
        },
        
        elasticboth: function(p, n, firstNum, delta, duration) {
            var a, s;
            if (n==0)
                return firstNum;
            if ((n/=duration/2)==2)
                return firstNum + delta;
               a = delta * 0.3;
               p=duration*.3;
            if (a < Math.abs(delta)){
                a = delta;
                s=p/4;
            } else { 
                s = p/(2*Math.PI) * Math.asin (delta/a);
            }
            if (n < 1) {
                return -.5*(a*Math.pow(2,10*(n-=1)) * Math.sin( (n*duration-s)*(2*Math.PI)/p )) + firstNum;
            }
            return a*Math.pow(2,-10*(n-=1)) * Math.sin( (n*duration-s)*(2*Math.PI)/p )*.5 + delta + firstNum; 
        }
    }
});/**
 * 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
    }
);/**
 * Interface Elements for jQuery
 * Droppables
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * With the Draggables plugin, Droppable allows you to create drop zones for draggable elements.
 *
 * @name Droppable
 * @cat Plugins/Interface
 * @param Hash options A hash of options
 * @option String accept The class name for draggables to get accepted by the droppable (mandatory)
 * @option String activeclass When an acceptable draggable is moved, the droppable gets this class
 * @option String hoverclass When an acceptable draggable is inside the droppable, the droppable gets
 *                           this class
 * @option String tolerance  Choose from 'pointer', 'intersect', or 'fit'. The pointer options means
 *                           that the pointer must be inside the droppable in order for the draggable
 *                           to be dropped. The intersect option means that the draggable must intersect
 *                           the droppable. The fit option means that the entire draggable must be
 *                           inside the droppable.
 * @option Function onDrop   When an acceptable draggable is dropped on a droppable, this callback is
 *                           called. It passes the draggable DOMElement as a parameter.
 * @option Function onHover  When an acceptable draggable is hovered over a droppable, this callback
 *                           is called. It passes the draggable DOMElement as a parameter.
 * @option Function onOut    When an acceptable draggable leaves a droppable, this callback is called.
 *                           It passes the draggable DOMElement as a parameter.
 * @example                  $('#dropzone1').Droppable(
 *                             {
 *                               accept : 'dropaccept', 
 *                               activeclass: 'dropzoneactive', 
 *                               hoverclass:    'dropzonehover',
 *                               ondrop:    function (drag) {
 *                                              alert(this); //the droppable
 *                                              alert(drag); //the draggable
 *                                        },
 *                               fit: true
 *                             }
 *                           )
 */

jQuery.iDrop = {
    fit : function (zonex, zoney, zonew, zoneh)
    {
        return     zonex <= jQuery.iDrag.dragged.dragCfg.nx && 
                (zonex + zonew) >= (jQuery.iDrag.dragged.dragCfg.nx + jQuery.iDrag.dragged.dragCfg.oC.w) &&
                zoney <= jQuery.iDrag.dragged.dragCfg.ny && 
                (zoney + zoneh) >= (jQuery.iDrag.dragged.dragCfg.ny + jQuery.iDrag.dragged.dragCfg.oC.h) ? true :false;
    },
    intersect : function (zonex, zoney, zonew, zoneh)
    {
        return     ! ( zonex > (jQuery.iDrag.dragged.dragCfg.nx + jQuery.iDrag.dragged.dragCfg.oC.w)
                || (zonex + zonew) < jQuery.iDrag.dragged.dragCfg.nx 
                || zoney > (jQuery.iDrag.dragged.dragCfg.ny + jQuery.iDrag.dragged.dragCfg.oC.h) 
                || (zoney + zoneh) < jQuery.iDrag.dragged.dragCfg.ny
                ) ? true :false;
    },
    pointer : function (zonex, zoney, zonew, zoneh)
    {
        return    zonex < jQuery.iDrag.dragged.dragCfg.currentPointer.x
                && (zonex + zonew) > jQuery.iDrag.dragged.dragCfg.currentPointer.x 
                && zoney < jQuery.iDrag.dragged.dragCfg.currentPointer.y 
                && (zoney + zoneh) > jQuery.iDrag.dragged.dragCfg.currentPointer.y
                ? true :false;
    },
    overzone : false,
    highlighted : {},
    count : 0,
    zones : {},
    
    highlight : function (elm)
    {
        if (jQuery.iDrag.dragged == null) {
            return;
        }
        var i;
        jQuery.iDrop.highlighted = {};
        var oneIsSortable = false;
        for (i in jQuery.iDrop.zones) {
            if (jQuery.iDrop.zones[i] != null) {
                var iEL = jQuery.iDrop.zones[i].get(0);
                if (jQuery(jQuery.iDrag.dragged).is('.' + iEL.dropCfg.a)) {
                    if (iEL.dropCfg.m == false) {
                        iEL.dropCfg.p = jQuery.extend(
                            jQuery.iUtil.getPositionLite(iEL),
                            jQuery.iUtil.getSizeLite(iEL)
                        );//jQuery.iUtil.getPos(iEL);
                        iEL.dropCfg.m = true;
                    }
                    if (iEL.dropCfg.ac) {
                        jQuery.iDrop.zones[i].addClass(iEL.dropCfg.ac);
                    }
                    jQuery.iDrop.highlighted[i] = jQuery.iDrop.zones[i];
                    //if (jQuery.iSort && jQuery.iDrag.dragged.dragCfg.so) {
                    if (jQuery.iSort && iEL.dropCfg.s && jQuery.iDrag.dragged.dragCfg.so) {
                        iEL.dropCfg.el = jQuery('.' + iEL.dropCfg.a, iEL);
                        elm.style.display = 'none';
                        jQuery.iSort.measure(iEL);
                        iEL.dropCfg.os = jQuery.iSort.serialize(jQuery.attr(iEL, 'id')).hash;
                        elm.style.display = elm.dragCfg.oD;
                        oneIsSortable = true;
                    }
                    if (iEL.dropCfg.onActivate) {
                        iEL.dropCfg.onActivate.apply(jQuery.iDrop.zones[i].get(0), [jQuery.iDrag.dragged]);
                    }
                }
            }
        }
        //if (jQuery.iSort && jQuery.iDrag.dragged.dragCfg.so) {
        if (oneIsSortable) {
            jQuery.iSort.start();
        }
    },
    /**
     * remeasure the droppable
     * 
     * useful when the positions/dimensions for droppables 
     * are changed while dragging a element
     * 
     * this works for sortables too but with a greate processor 
     * penality because remeasures each sort items too
     */
    remeasure : function()
    {
        jQuery.iDrop.highlighted = {};
        for (i in jQuery.iDrop.zones) {
            if (jQuery.iDrop.zones[i] != null) {
                var iEL = jQuery.iDrop.zones[i].get(0);
                if (jQuery(jQuery.iDrag.dragged).is('.' + iEL.dropCfg.a)) {
                    iEL.dropCfg.p = jQuery.extend(
                        jQuery.iUtil.getPositionLite(iEL),
                        jQuery.iUtil.getSizeLite(iEL)
                    );
                    if (iEL.dropCfg.ac) {
                        jQuery.iDrop.zones[i].addClass(iEL.dropCfg.ac);
                    }
                    jQuery.iDrop.highlighted[i] = jQuery.iDrop.zones[i];
                    
                    if (jQuery.iSort && iEL.dropCfg.s && jQuery.iDrag.dragged.dragCfg.so) {
                        iEL.dropCfg.el = jQuery('.' + iEL.dropCfg.a, iEL);
                        elm.style.display = 'none';
                        jQuery.iSort.measure(iEL);
                        elm.style.display = elm.dragCfg.oD;
                    }
                }
            }
        }
    },
    
    checkhover : function (e)
    {
        if (jQuery.iDrag.dragged == null) {
            return;
        }
        jQuery.iDrop.overzone = false;
        var i;
        var applyOnHover = false;
        var hlt = 0;
        for (i in jQuery.iDrop.highlighted)
        {
            var iEL = jQuery.iDrop.highlighted[i].get(0);
            if ( 
                    jQuery.iDrop.overzone == false
                     && 
                    jQuery.iDrop[iEL.dropCfg.t](
                         iEL.dropCfg.p.x, 
                        iEL.dropCfg.p.y, 
                        iEL.dropCfg.p.wb, 
                        iEL.dropCfg.p.hb
                    )
                     
            ) {
                if (iEL.dropCfg.hc && iEL.dropCfg.h == false) {
                    jQuery.iDrop.highlighted[i].addClass(iEL.dropCfg.hc);
                }
                //chec if onHover function has to be called
                if (iEL.dropCfg.h == false &&iEL.dropCfg.onHover) {
                    applyOnHover = true;
                }
                iEL.dropCfg.h = true;
                jQuery.iDrop.overzone = iEL;
                //if(jQuery.iSort && jQuery.iDrag.dragged.dragCfg.so) {
                if(jQuery.iSort && iEL.dropCfg.s && jQuery.iDrag.dragged.dragCfg.so) {
                    jQuery.iSort.helper.get(0).className = iEL.dropCfg.shc;
                    jQuery.iSort.checkhover(iEL);
                }
                hlt ++;
            } else if(iEL.dropCfg.h == true) {
                //onOut function
                if (iEL.dropCfg.onOut) {
                    iEL.dropCfg.onOut.apply(iEL, [e, jQuery.iDrag.helper.get(0).firstChild, iEL.dropCfg.fx]);
                }
                if (iEL.dropCfg.hc) {
                    jQuery.iDrop.highlighted[i].removeClass(iEL.dropCfg.hc);
                }
                iEL.dropCfg.h = false;
            }
        }
        if (jQuery.iSort && !jQuery.iDrop.overzone && jQuery.iDrag.dragged.so) {
            jQuery.iSort.helper.get(0).style.display = 'none';
            //jQuery('body').append(jQuery.iSort.helper.get(0));
        }
        //call onhover
        if(applyOnHover) {
            jQuery.iDrop.overzone.dropCfg.onHover.apply(jQuery.iDrop.overzone, [e, jQuery.iDrag.helper.get(0).firstChild]);
        }
    },
    checkdrop : function (e)
    {
        var i;
        for (i in jQuery.iDrop.highlighted) {
            var iEL = jQuery.iDrop.highlighted[i].get(0);
            if (iEL.dropCfg.ac) {
                jQuery.iDrop.highlighted[i].removeClass(iEL.dropCfg.ac);
            }
            if (iEL.dropCfg.hc) {
                jQuery.iDrop.highlighted[i].removeClass(iEL.dropCfg.hc);
            }
            if(iEL.dropCfg.s) {
                jQuery.iSort.changed[jQuery.iSort.changed.length] = i;
            }
            if (iEL.dropCfg.onDrop && iEL.dropCfg.h == true) {
                iEL.dropCfg.h = false;
                iEL.dropCfg.onDrop.apply(iEL, [e, iEL.dropCfg.fx]);
            }
            iEL.dropCfg.m = false;
            iEL.dropCfg.h  = false;
        }
        jQuery.iDrop.highlighted = {};
    },
    destroy : function()
    {
        return this.each(
            function()
            {
                if (this.isDroppable) {
                    if (this.dropCfg.s) {
                        id = jQuery.attr(this,'id');
                        jQuery.iSort.collected[id] = null;
                        jQuery('.' + this.dropCfg.a, this).DraggableDestroy();
                    }
                    jQuery.iDrop.zones['d' + this.idsa] = null;
                    this.isDroppable = false;
                    this.f = null;
                }
            }
        );
    },
    build : function (o)
    {
        return this.each(
            function()
            {
                if (this.isDroppable == true || !o.accept || !jQuery.iUtil || !jQuery.iDrag){
                    return;
                }
                this.dropCfg = {
                    a : o.accept,
                    ac: o.activeclass||false, 
                    hc:    o.hoverclass||false,
                    shc: o.helperclass||false,
                    onDrop:    o.ondrop||o.onDrop||false,
                    onHover: o.onHover||o.onhover||false,
                    onOut: o.onOut||o.onout||false,
                    onActivate: o.onActivate||false,
                    t: o.tolerance && ( o.tolerance == 'fit' || o.tolerance == 'intersect') ? o.tolerance : 'pointer',
                    fx: o.fx ? o.fx : false,
                    m: false,
                    h: false
                };
                if (o.sortable == true && jQuery.iSort) {
                    id = jQuery.attr(this,'id');
                    jQuery.iSort.collected[id] = this.dropCfg.a;
                    this.dropCfg.s = true;
                    if(o.onChange) {
                        this.dropCfg.onChange = o.onChange;
                        this.dropCfg.os = jQuery.iSort.serialize(id).hash;
                    }
                }
                this.isDroppable = true;
                this.idsa = parseInt(Math.random() * 10000);
                jQuery.iDrop.zones['d' + this.idsa] = jQuery(this);
                jQuery.iDrop.count ++;
            }
        );
    }
};

/**
 * Destroy an existing droppable on a collection of elements
 * 
 * @name DroppableDestroy
 * @descr Destroy a droppable
 * @type jQuery
 * @cat Plugins/Interface
 * @example $('#drag2').DroppableDestroy();
 */

jQuery.fn.extend(
    {
        DroppableDestroy : jQuery.iDrop.destroy,
        Droppable : jQuery.iDrop.build
    }
);

 
/**
 * Recalculate all Droppables
 *
 * @name $.recallDroppables
 * @type jQuery
 * @cat Plugins/Interface
 * @example $.recallDroppable();
 */

jQuery.recallDroppables = jQuery.iDrop.remeasure;/**
 * Interface Elements for jQuery
 * FX - blind
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
 
/**
 * Applies a blinding animation to element
 */
jQuery.fn.extend(
    {
        /**
         * @name BlindUp
         * @description blinds the element up
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        BlindUp : function (speed, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.BlindDirection(this, speed, callback, 'up', easing);
            });
        },
        
        /**
         * @name BlindDown
         * @description blinds the element down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        BlindDown : function (speed, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.BlindDirection(this, speed, callback, 'down', easing);
            });
        },
        
        /**
         * @name BlindToggleVertically
         * @description blinds the element up or down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        BlindToggleVertically : function (speed, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.BlindDirection(this, speed, callback, 'togglever', easing);
            });
        },
        
        /**
         * @name BlindLeft
         * @description blinds the element left
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        BlindLeft : function (speed, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.BlindDirection(this, speed, callback, 'left', easing);
            });
        },
        
        /**
         * @name BlindRight
         * @description blinds the element right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        BlindRight : function (speed, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.BlindDirection(this, speed, callback, 'right', easing);
            });
        },
        
        /**
         * @name BlindToggleHorizontally
         * @description blinds the element left and right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        BlindToggleHorizontally : function (speed, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.BlindDirection(this, speed, callback, 'togglehor', easing);
            });
        }
    }
);

jQuery.fx.BlindDirection = function (e, speed, callback, direction, easing)
{
    if (!jQuery.fxCheckTag(e)) {
        jQuery.dequeue(e, 'interfaceFX');
        return false;
    }
    var z = this;
    z.el = jQuery(e);
    z.size = jQuery.iUtil.getSize(e);
    z.easing = typeof callback == 'string' ? callback : easing||null;
    if (!e.ifxFirstDisplay)
        e.ifxFirstDisplay = z.el.css('display');
    if ( direction == 'togglever') {
        direction = z.el.css('display') == 'none' ? 'down' : 'up';
    } else if (direction == 'togglehor') {
        direction = z.el.css('display') == 'none' ? 'right' : 'left';
    }
    z.el.show();
    z.speed = speed;
    z.callback = typeof callback == 'function' ? callback : null;
    z.fx = jQuery.fx.buildWrapper(e);
    z.direction = direction;
    z.complete = function()
    {
        if (z.callback && z.callback.constructor == Function) {
            z.callback.apply(z.el.get(0));
        }
        if(z.direction == 'down' || z.direction == 'right'){
            z.el.css('display', z.el.get(0).ifxFirstDisplay == 'none' ? 'block' : z.el.get(0).ifxFirstDisplay);
        } else {
            z.el.hide();
        }
        jQuery.fx.destroyWrapper(z.fx.wrapper.get(0), z.fx.oldStyle);
        jQuery.dequeue(z.el.get(0), 'interfaceFX');
    };
    switch (z.direction) {
        case 'up':
            fxh = new jQuery.fx(
                z.fx.wrapper.get(0),
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'height'
            );
            fxh.custom(z.fx.oldStyle.sizes.hb, 0);
        break;
        case 'down':
            z.fx.wrapper.css('height', '1px');
            z.el.show();
            fxh = new jQuery.fx(
                z.fx.wrapper.get(0),
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'height'
            );
            fxh.custom(0, z.fx.oldStyle.sizes.hb);
        break;
        case 'left':
            fxh = new jQuery.fx(
                z.fx.wrapper.get(0),
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'width'
            );
            fxh.custom(z.fx.oldStyle.sizes.wb, 0);
        break;
        case 'right':
            z.fx.wrapper.css('width', '1px');
            z.el.show();
            fxh = new jQuery.fx(
                z.fx.wrapper.get(0),
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'width'
            );
            fxh.custom(0, z.fx.oldStyle.sizes.wb);
        break;
    }
};/**
 * Interface Elements for jQuery
 * FX - bounce
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * @name Bounce
 * @description makes the element to bounce
 * @param Integer hight the hight in pxels for element to jumps to
 * @param Function callback (optional) A function to be executed whenever the animation completes.
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */
jQuery.fn.Bounce = function (hight, callback) {
    return this.queue('interfaceFX', function(){
        if (!jQuery.fxCheckTag(this)) {
            jQuery.dequeue(this, 'interfaceFX');
            return false;
        }
        var e = new jQuery.fx.iBounce(this, hight, callback);
        e.bounce();
    });
};
jQuery.fx.iBounce = function (e, hight, callback)
{
    var z = this;
    z.el = jQuery(e);
    z.el.show();
    z.callback = callback;
    z.hight = parseInt(hight)||40;
    z.oldStyle = {};
    z.oldStyle.position = z.el.css('position');
    z.oldStyle.top = parseInt(z.el.css('top'))||0;
    z.oldStyle.left = parseInt(z.el.css('left'))||0;
    
    if (z.oldStyle.position != 'relative' && z.oldStyle.position != 'absolute') {
        z.el.css('position', 'relative');
    }
    
    z.times = 5;
    z.cnt = 1;
    
    z.bounce = function ()
    {
        z.cnt ++;
        z.e = new jQuery.fx(
            z.el.get(0), 
            {
             duration: 120,
             complete : function ()
             {
                z.e = new jQuery.fx(
                    z.el.get(0), 
                    {
                        duration: 80,
                        complete : function ()
                        {
                            z.hight = parseInt(z.hight/2);
                            if (z.cnt <= z.times)
                                z.bounce();
                            else {
                                z.el.css('position', z.oldStyle.position).css('top', z.oldStyle.top + 'px').css('left', z.oldStyle.left + 'px');
                                jQuery.dequeue(z.el.get(0), 'interfaceFX');
                                if (z.callback && z.callback.constructor == Function) {
                                    z.callback.apply(z.el.get(0));
                                }
                            }
                        }
                    },
                    'top'
                );
                z.e.custom (z.oldStyle.top-z.hight, z.oldStyle.top);
             }
            }, 
            'top'
        );
        z.e.custom (z.oldStyle.top, z.oldStyle.top-z.hight);
    };
        
};/**
 * Interface Elements for jQuery
 * FX - drop
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Applies a dropping effect to element
 */
jQuery.fn.extend(
    {
        /**
         * @name DropOutDown
         * @description drops the element out down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropOutDown : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this, speed, callback, 'down', 'out', easing);
            });
        },
        
        /**
         * @name DropInDown
         * @description drops the element in down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropInDown : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'down', 'in', easing);
            });
        },
        
        /**
         * @name DropToggleDown
         * @description drops the element in/out down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropToggleDown : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'down', 'toggle', easing);
            });
        },
        
        /**
         * @name DropOutUp
         * @description drops the element out up
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropOutUp : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this, speed, callback, 'up', 'out', easing);
            });
        },
        
        /**
         * @name DropInUp
         * @description drops the element in up
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropInUp : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'up', 'in', easing);
            });
        },
        
        /**
         * @name DropToggleUp
         * @description drops the element in/out up
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropToggleUp : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'up', 'toggle', easing);
            });
        },
        
        /**
         * @name DropOutLeft
         * @description drops the element out left
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropOutLeft : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this, speed, callback, 'left', 'out', easing);
            });
        },
        
        /**
         * @name DropInLeft
         * @description drops the element in left
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropInLeft : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'left', 'in', easing);
            });
        },
        
        /**
         * @name DropToggleLeft
         * @description drops the element in/out left
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropToggleLeft : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'left', 'toggle', easing);
            });
        },
        
        /**
         * @name DropOutRight
         * @description drops the element out right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropOutRight : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this, speed, callback, 'right', 'out', easing);
            });
        },
        
        /**
         * @name DropInRight
         * @description drops the element in right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropInRight : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'right', 'in', easing);
            });
        },
        
        /**
         * @name DropToggleRight
         * @description drops the element in/out right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        DropToggleRight : function (speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DropOutDirectiont(this,  speed, callback, 'right', 'toggle', easing);
            });
        }
    }
);

jQuery.fx.DropOutDirectiont = function (e, speed, callback, direction, type, easing)
{
    if (!jQuery.fxCheckTag(e)) {
        jQuery.dequeue(e, 'interfaceFX');
        return false;
    }
    var z = this;
    z.el = jQuery(e);
    z.easing = typeof callback == 'string' ? callback : easing||null;
    z.oldStyle = {};
    z.oldStyle.position = z.el.css('position');
    z.oldStyle.top = z.el.css('top');
    z.oldStyle.left = z.el.css('left');
    if (!e.ifxFirstDisplay)
        e.ifxFirstDisplay = z.el.css('display');
    if ( type == 'toggle') {
        type = z.el.css('display') == 'none' ? 'in' : 'out';
    }
    z.el.show();
    
    if (z.oldStyle.position != 'relative' && z.oldStyle.position != 'absolute') {
        z.el.css('position', 'relative');
    }
    z.type = type;
    callback = typeof callback == 'function' ? callback : null;
    /*sizes = ['em','px','pt','%'];
    for(i in sizes) {
        if (z.oldStyle.top.indexOf(sizes[i])>0) {
            z.topUnit = sizes[1];
            z.topSize = parseFloat(z.oldStyle.top)||0;
        }
        if (z.oldStyle.left.indexOf(sizes[i])>0) {
            z.leftUnit = sizes[1];
            z.leftSize = parseFloat(z.oldStyle.left)||0;
        }
    }*/
    
    directionIncrement = 1;
    switch (direction){
        case 'up':
            z.e = new jQuery.fx(z.el.get(0), jQuery.speed(speed - 15, z.easing,callback), 'top');
            z.point = parseFloat(z.oldStyle.top)||0;
            z.unit = z.topUnit;
            directionIncrement = -1;
        break;
        case 'down':
            z.e = new jQuery.fx(z.el.get(0), jQuery.speed(speed - 15, z.easing,callback), 'top');
            z.point = parseFloat(z.oldStyle.top)||0;
            z.unit = z.topUnit;
        break;
        case 'right':
            z.e = new jQuery.fx(z.el.get(0), jQuery.speed(speed - 15, z.easing,callback), 'left');
            z.point = parseFloat(z.oldStyle.left)||0;
            z.unit = z.leftUnit;
        break;
        case 'left':
            z.e = new jQuery.fx(z.el.get(0), jQuery.speed(speed - 15, z.easing,callback), 'left');
            z.point = parseFloat(z.oldStyle.left)||0;
            z.unit = z.leftUnit;
            directionIncrement = -1;
        break;
    }
    z.e2 = new jQuery.fx(
        z.el.get(0),
        jQuery.speed
        (
             speed, z.easing,
            function()
            {
                z.el.css(z.oldStyle);
                if (z.type == 'out') {
                    z.el.css('display', 'none');
                } else 
                    z.el.css('display', z.el.get(0).ifxFirstDisplay == 'none' ? 'block' : z.el.get(0).ifxFirstDisplay);
                
                jQuery.dequeue(z.el.get(0), 'interfaceFX');
            }
         ),
        'opacity'
    );
    if (type == 'in') {
        z.e.custom(z.point+ 100*directionIncrement, z.point);
        z.e2.custom(0,1);
    } else {
        z.e.custom(z.point, z.point + 100*directionIncrement);
        z.e2.custom(1,0);
    }
};/**
 * Interface Elements for jQuery
 * FX - fold
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Applies a folding animation to element
 */
jQuery.fn.extend(
    {
        /**
         * @name Fold
         * @description folds the element
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Integer height the height in pixels to fold element to
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        Fold : function (speed, height, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DoFold(this, speed, height, callback, 'fold', easing);
            });
        },
        
        /**
         * @name UnFold
         * @description unfolds the element
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Integer height the height in pixels to unfold element to
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        UnFold : function (speed, height, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DoFold(this, speed, height, callback, 'unfold', easing);
            });
        },
        
        /**
         * @name FoldToggle
         * @description folds/unfolds the element
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Integer height the height in pixels to folds/unfolds element to
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        FoldToggle : function (speed, height, callback, easing)
        {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.DoFold(this, speed, height, callback, 'toggle', easing);
            });
        }
    }
);

jQuery.fx.DoFold = function (e, speed, height, callback, type, easing)
{
    if (!jQuery.fxCheckTag(e)) {
        jQuery.dequeue(e, 'interfaceFX');
        return false;
    }
    var z = this;
    z.el = jQuery(e);
    z.easing = typeof callback == 'string' ? callback : easing||null;
    z.callback = typeof callback == 'function' ? callback : null;
    if ( type == 'toggle') {
        type = z.el.css('display') == 'none' ? 'unfold' : 'fold';
    }
    //z.el.show();
    z.speed = speed;
    z.height = height && height.constructor == Number ? height : 20;
    z.fx = jQuery.fx.buildWrapper(e);
    z.type = type;
    z.complete = function()
    {
        if (z.callback && z.callback.constructor == Function) {
            z.callback.apply(z.el.get(0));
        }
        if(z.type == 'unfold'){
            z.el.show();
        } else {
            z.el.hide();
        }
        jQuery.fx.destroyWrapper(z.fx.wrapper.get(0), z.fx.oldStyle);
        jQuery.dequeue(z.el.get(0), 'interfaceFX');
    };
    if ( z.type == 'unfold') {
        z.el.show();
        z.fx.wrapper.css('height', z.height + 'px').css('width', '1px');
        
        z.ef = new jQuery.fx(
                z.fx.wrapper.get(0),
                jQuery.speed (
                    z.speed,
                    z.easing,
                    function()
                    {
                        z.ef = new jQuery.fx(
                            z.fx.wrapper.get(0),
                            jQuery.speed(
                                z.speed,
                                z.easing, 
                                z.complete
                            ),
                            'height'
                        );
                        z.ef.custom(z.height, z.fx.oldStyle.sizes.hb);
                    }
                ), 
                'width'
            );
        z.ef.custom(0, z.fx.oldStyle.sizes.wb);
    } else {
        z.ef = new jQuery.fx(
                z.fx.wrapper.get(0),
                jQuery.speed(
                    z.speed,
                    z.easing,
                    function()
                    {
                        z.ef = new jQuery.fx(
                            z.fx.wrapper.get(0),
                            jQuery.speed(
                                z.speed,
                                z.easing,
                                z.complete
                            ),
                            'width'
                        );
                        z.ef.custom(z.fx.oldStyle.sizes.wb, 0);
                    }
                ), 
                'height'
            );
        z.ef.custom(z.fx.oldStyle.sizes.hb, z.height);
    }
};

/**
 * Interface Elements for jQuery
 * FX - Highlight
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */


/**
 * @name Highlight
 * @description Animates the backgroudn color to create a highlight animation
 * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
 * @param String color color to highlight from
 * @param Function callback (optional) A function to be executed whenever the animation completes.
 * @param String easing (optional) The name of the easing effect that you want to use.
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */
jQuery.fn.Highlight = function(speed, color, callback, easing) {
    return this.queue(
        'interfaceColorFX',
        function()
        {
            this.oldStyleAttr = jQuery(this).attr("style") || '';
            easing = typeof callback == 'string' ? callback : easing||null;
            callback = typeof callback == 'function' ? callback : null;
            var oldColor = jQuery(this).css('backgroundColor');
            var parentEl = this.parentNode;
            while(oldColor == 'transparent' && parentEl) {
                oldColor = jQuery(parentEl).css('backgroundColor');
                parentEl = parentEl.parentNode;
            }
            jQuery(this).css('backgroundColor', color);
            
            
            /* In IE, style is a object.. */
            if(typeof this.oldStyleAttr == 'object') this.oldStyleAttr = this.oldStyleAttr["cssText"];
            
            jQuery(this).animate(
                {'backgroundColor':oldColor},
                speed,
                easing,
                function() {
                    jQuery.dequeue(this, 'interfaceColorFX');
                    if(typeof jQuery(this).attr("style") == 'object') {
                        jQuery(this).attr("style")["cssText"] = "";
                        jQuery(this).attr("style")["cssText"] = this.oldStyleAttr;
                    } else {
                        jQuery(this).attr("style", this.oldStyleAttr);    
                    }
                    if (callback)
                        callback.apply(this);
                }
              );
        }
    );
};/**
 * Interface Elements for jQuery
 * FX
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Validates elements that can be animated
 */
jQuery.fxCheckTag = function(e)
{
    if (/^tr$|^td$|^tbody$|^caption$|^thead$|^tfoot$|^col$|^colgroup$|^th$|^body$|^header$|^script$|^frame$|^frameset$|^option$|^optgroup$|^meta$/i.test(e.nodeName) )
        return false;
    else 
        return true;
};

/**
 * Destroy the wrapper used for some animations
 */
jQuery.fx.destroyWrapper = function(e, old)
{
    var c = e.firstChild;
    var cs = c.style;
    cs.position = old.position;
    cs.marginTop = old.margins.t;
    cs.marginLeft = old.margins.l;
    cs.marginBottom = old.margins.b;
    cs.marginRight = old.margins.r;
    cs.top = old.top + 'px';
    cs.left = old.left + 'px';
    e.parentNode.insertBefore(c, e);
    e.parentNode.removeChild(e);
};

/**
 * Builds a wrapper used for some animations
 */
jQuery.fx.buildWrapper = function(e)
{
    if (!jQuery.fxCheckTag(e))
        return false;
    var t = jQuery(e);
    var es = e.style;
    var restoreStyle = false;
    
    if (t.css('display') == 'none') {
        oldVisibility = t.css('visibility');
        t.css('visibility', 'hidden').show();
        restoreStyle = true;
    }
    var oldStyle = {};
    oldStyle.position = t.css('position');
    oldStyle.sizes = jQuery.iUtil.getSize(e);
    oldStyle.margins = jQuery.iUtil.getMargins(e);
    
    var oldFloat = e.currentStyle ? e.currentStyle.styleFloat : t.css('float');
    oldStyle.top = parseInt(t.css('top'))||0;
    oldStyle.left = parseInt(t.css('left'))||0;
    var wid = 'w_' + parseInt(Math.random() * 10000);
    var wr = document.createElement(/^img$|^br$|^input$|^hr$|^select$|^textarea$|^object$|^iframe$|^button$|^form$|^table$|^ul$|^dl$|^ol$/i.test(e.nodeName) ? 'div' : e.nodeName);
    jQuery.attr(wr,'id', wid);
    var wrapEl = jQuery(wr).addClass('fxWrapper');
    var wrs = wr.style;
    var top = 0;
    var left = 0;
    // JMB Software Edit
    // Handle fixed positioning
    if (oldStyle.position == 'relative' || oldStyle.position == 'absolute' || oldStyle.position == 'fixed'){
        top = oldStyle.top;
        left = oldStyle.left;
    }
    
    wrs.top = top + 'px';
    wrs.left = left + 'px';
    // JMB Software Edit
    // Handle fixed positioning
    wrs.position = oldStyle.position != 'relative' && oldStyle.position != 'absolute' && oldStyle.position != 'fixed' ? 'relative' : oldStyle.position;
    wrs.height = oldStyle.sizes.hb + 'px';
    wrs.width = oldStyle.sizes.wb + 'px';
    wrs.marginTop = oldStyle.margins.t;
    wrs.marginRight = oldStyle.margins.r;
    wrs.marginBottom = oldStyle.margins.b;
    wrs.marginLeft = oldStyle.margins.l;
    wrs.overflow = 'hidden';
    if (jQuery.browser.msie) {
        wrs.styleFloat = oldFloat;
    } else {
        wrs.cssFloat = oldFloat;
    }
    if (jQuery.browser == "msie") {
        es.filter = "alpha(opacity=" + 0.999*100 + ")";
    }
    es.opacity = 0.999;
    //t.wrap(wr);
    e.parentNode.insertBefore(wr, e);
    wr.appendChild(e);
    es.marginTop = '0px';
    es.marginRight = '0px';
    es.marginBottom = '0px';
    es.marginLeft = '0px';
    es.position = 'absolute';
    es.listStyle = 'none';
    es.top = '0px';
    es.left = '0px';
    if (restoreStyle) {
        t.hide();
        es.visibility = oldVisibility;
    }
    return {oldStyle:oldStyle, wrapper:jQuery(wr)};
};

/**
 * named colors
 */
jQuery.fx.namedColors = {
    aqua:[0,255,255],
    azure:[240,255,255],
    beige:[245,245,220],
    black:[0,0,0],
    blue:[0,0,255],
    brown:[165,42,42],
    cyan:[0,255,255],
    darkblue:[0,0,139],
    darkcyan:[0,139,139],
    darkgrey:[169,169,169],
    darkgreen:[0,100,0],
    darkkhaki:[189,183,107],
    darkmagenta:[139,0,139],
    darkolivegreen:[85,107,47],
    darkorange:[255,140,0],
    darkorchid:[153,50,204],
    darkred:[139,0,0],
    darksalmon:[233,150,122],
    darkviolet:[148,0,211],
    fuchsia:[255,0,255],
    gold:[255,215,0],
    green:[0,128,0],
    indigo:[75,0,130],
    khaki:[240,230,140],
    lightblue:[173,216,230],
    lightcyan:[224,255,255],
    lightgreen:[144,238,144],
    lightgrey:[211,211,211],
    lightpink:[255,182,193],
    lightyellow:[255,255,224],
    lime:[0,255,0],
    magenta:[255,0,255],
    maroon:[128,0,0],
    navy:[0,0,128],
    olive:[128,128,0],
    orange:[255,165,0],
    pink:[255,192,203],
    purple:[128,0,128],
    red:[255,0,0],
    silver:[192,192,192],
    white:[255,255,255],
    yellow:[255,255,0]
};

/**
 * parses a color to an object for reg, green and blue
 */
jQuery.fx.parseColor = function(color, notColor)
{
    if (jQuery.fx.namedColors[color]) 
        return {
            r: jQuery.fx.namedColors[color][0],
            g: jQuery.fx.namedColors[color][1],
            b: jQuery.fx.namedColors[color][2]
        };
    else if (result = /^rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)$/.exec(color))
        return {
            r: parseInt(result[1]),
            g: parseInt(result[2]),
            b: parseInt(result[3])
        };
    else if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)$/.exec(color)) 
        return {
            r: parseFloat(result[1])*2.55,
            g: parseFloat(result[2])*2.55,
            b: parseFloat(result[3])*2.55
        };
    else if (result = /^#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color))
        return {
            r: parseInt("0x"+ result[1] + result[1]),
            g: parseInt("0x" + result[2] + result[2]),
            b: parseInt("0x" + result[3] + result[3])
        };
    else if (result = /^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color))
        return {
            r: parseInt("0x" + result[1]),
            g: parseInt("0x" + result[2]),
            b: parseInt("0x" + result[3])
        };
    else
        return notColor == true ? false : {r: 255, g: 255, b: 255};
};
/**
 * CSS rules that can be animated
 */
jQuery.fx.cssProps = {
    borderBottomWidth:1,
    borderLeftWidth:1,
    borderRightWidth:1,
    borderTopWidth:1,
    bottom:1,
    fontSize:1,
    height:1,
    left:1,
    letterSpacing:1,
    lineHeight:1,
    marginBottom:1,
    marginLeft:1,
    marginRight:1,
    marginTop:1,
    maxHeight:1,
    maxWidth:1,
    minHeight:1,
    minWidth:1,
    opacity:1,
    outlineOffset:1,
    outlineWidth:1,
    paddingBottom:1,
    paddingLeft:1,
    paddingRight:1,
    paddingTop:1,
    right:1,
    textIndent:1,
    top:1,
    width:1,
    zIndex:1
};
/**
 * CSS color rules that can be animated
 */
jQuery.fx.colorCssProps = {
    backgroundColor:1,
    borderBottomColor:1,
    borderLeftColor:1,
    borderRightColor:1,
    borderTopColor:1,
    color:1,
    outlineColor:1
};

jQuery.fx.cssSides = ['Top', 'Right', 'Bottom', 'Left'];
jQuery.fx.cssSidesEnd = {
    'borderWidth': ['border', 'Width'],
    'borderColor': ['border', 'Color'],
    'margin': ['margin', ''],
    'padding': ['padding', '']
};

/**
 * Overwrite animation to use new FX function
 */
jQuery.fn.extend({
    
    animate: function( prop, speed, easing, callback ) {
        return this.queue(function(){
            var opt = jQuery.speed(speed, easing, callback);
            var e = new jQuery.fxe( this, opt, prop );
            
        });
    },
    pause: function(speed, callback) {
        return this.queue(function(){
            var opt = jQuery.speed(speed, callback);
            var e = new jQuery.pause( this, opt );
        });
    },
    stop : function(step) {
        return this.each(function(){
            if (this.animationHandler)
                jQuery.stopAnim(this, step);
            
        });
    },
    stopAll : function(step) {
        return this.each(function(){
            if (this.animationHandler)
                jQuery.stopAnim(this, step);
            if ( this.queue && this.queue['fx'] )
                this.queue.fx = [];
        });
    }
});
/**
 * Improved FXC function that aniamtes collection of properties per timer. Accepts inline styles and class names to animate
 */
jQuery.extend({
    pause: function(elem, options)
    {
        var z = this, values;
        z.step = function()
        {
            if ( jQuery.isFunction( options.complete ) )
                options.complete.apply( elem );
        };
        z.timer=setInterval(function(){z.step();},options.duration);
        elem.animationHandler = z;
    },
    easing :  {
        linear: function(p, n, firstNum, delta, duration) {
            return ((-Math.cos(p*Math.PI)/2) + 0.5) * delta + firstNum;
        }
    },
    fxe: function( elem, options, prop ){
        var z = this, values;

        // The styles
        var y = elem.style;
        var oldOverflow = jQuery.css(elem, "overflow");
        var oldDisplay= jQuery.css(elem, "display");
        var props = {};
        z.startTime = (new Date()).getTime();
        options.easing = options.easing && jQuery.easing[options.easing] ? options.easing : 'linear';
        
        z.getValues = function(tp, vp)
        {
            if (jQuery.fx.cssProps[tp]) {
                if (vp == 'show' || vp == 'hide' || vp == 'toggle') {
                    if ( !elem.orig ) elem.orig = {};
                    var r = parseFloat( jQuery.curCSS(elem, tp) );
                    elem.orig[tp] = r && r > -10000 ? r : (parseFloat( jQuery.css(elem,tp) )||0);
                    vp = vp == 'toggle' ? ( oldDisplay == 'none' ? 'show' : 'hide') : vp;
                    options[vp] = true;
                    props[tp] = vp == 'show' ? [0, elem.orig[tp]] : [elem.orig[tp], 0];
                    if (tp != 'opacity')
                        y[tp] = props[tp][0] + (tp != 'zIndex' && tp != 'fontWeight' ? 'px':'');
                    else
                        jQuery.attr(y, "opacity", props[tp][0]);
                } else {
                    props[tp] = [parseFloat( jQuery.curCSS(elem, tp) ), parseFloat(vp)||0];
                }
            } else if (jQuery.fx.colorCssProps[tp])
                props[tp] = [jQuery.fx.parseColor(jQuery.curCSS(elem, tp)), jQuery.fx.parseColor(vp)];
            else if(/^margin$|padding$|border$|borderColor$|borderWidth$/i.test(tp)) {
                var m = vp.replace(/\s+/g, ' ').replace(/rgb\s*\(\s*/g,'rgb(').replace(/\s*,\s*/g,',').replace(/\s*\)/g,')').match(/([^\s]+)/g);
                switch(tp){
                    case 'margin':
                    case 'padding':
                    case 'borderWidth':
                    case 'borderColor':
                        m[3] = m[3]||m[1]||m[0];
                        m[2] = m[2]||m[0];
                        m[1] = m[1]||m[0];
                        for(var i = 0; i < jQuery.fx.cssSides.length; i++) {
                            var nmp = jQuery.fx.cssSidesEnd[tp][0] + jQuery.fx.cssSides[i] + jQuery.fx.cssSidesEnd[tp][1];
                            props[nmp] = tp == 'borderColor' ?
                                [jQuery.fx.parseColor(jQuery.curCSS(elem, nmp)), jQuery.fx.parseColor(m[i])]
                                : [parseFloat( jQuery.curCSS(elem, nmp) ), parseFloat(m[i])];
                        }
                        break;
                    case 'border':
                        for(var i = 0; i< m.length; i++) {
                            var floatVal = parseFloat(m[i]);
                            var sideEnd = !isNaN(floatVal) ? 'Width' : (!/transparent|none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset/i.test(m[i]) ? 'Color' : false);
                            if (sideEnd) {
                                for(var j = 0; j < jQuery.fx.cssSides.length; j++) {
                                    nmp = 'border' + jQuery.fx.cssSides[j] + sideEnd;
                                    props[nmp] = sideEnd == 'Color' ?
                                [jQuery.fx.parseColor(jQuery.curCSS(elem, nmp)), jQuery.fx.parseColor(m[i])]
                                : [parseFloat( jQuery.curCSS(elem, nmp) ), floatVal];
                                }
                            } else {
                                y['borderStyle'] = m[i];
                            }
                        }
                        break;
                }
            } else {
                y[tp] = vp;
            }
            return false;
        };
        
        for(p in prop) {
            if (p == 'style') {
                var newStyles = jQuery.parseStyle(prop[p]);
                for (np in newStyles) {
                    this.getValues(np, newStyles[np]);
                }
            } else if (p == 'className') {
                if (document.styleSheets)
                    for (var i=0; i<document.styleSheets.length; i++){
                        var cssRules = document.styleSheets[i].cssRules||document.styleSheets[i].rules||null;
                        if (cssRules) {
                            for (var j=0; j<cssRules.length; j++) {
                                if(cssRules[j].selectorText == '.' + prop[p]) {
                                    var rule = new RegExp('\.' + prop[p] + ' {');
                                    var styles = cssRules[j].style.cssText;
                                    var newStyles = jQuery.parseStyle(styles.replace(rule, '').replace(/}/g, ''));
                                    for (np in newStyles) {
                                        this.getValues(np, newStyles[np]);
                                    }
                                }
                            }
                        }
                    }
            } else {
                this.getValues(p, prop[p]);
            }
        }
        y.display = oldDisplay == 'none' ? 'block' : oldDisplay;
        y.overflow = 'hidden';
        
        /*if (options.show)
            y.display = "";*/
        
        z.step = function(){
            var t = (new Date()).getTime();
            if (t > options.duration + z.startTime) {
                clearInterval(z.timer);
                z.timer = null;
                for (p in props) {
                    if ( p == "opacity" )
                        jQuery.attr(y, "opacity", props[p][1]);
                    else if (typeof props[p][1] == 'object')
                        y[p] = 'rgb(' + props[p][1].r +',' + props[p][1].g +',' + props[p][1].b +')';
                    else 
                        y[p] = props[p][1] + (p != 'zIndex' && p != 'fontWeight' ? 'px':'');
                }
                if ( options.hide || options.show )
                    for ( var p in elem.orig )
                        if (p == "opacity")
                            jQuery.attr(y, p, elem.orig[p]);
                        else
                            y[p] = "";
                y.display = options.hide ? 'none' : (oldDisplay !='none' ? oldDisplay : 'block');
                y.overflow = oldOverflow;
                elem.animationHandler = null;
                if ( jQuery.isFunction( options.complete ) )
                    options.complete.apply( elem );
            } else {
                var n = t - this.startTime;
                var pr = n / options.duration;
                for (p in props) {
                    if (typeof props[p][1] == 'object') {
                        y[p] = 'rgb('
                        + parseInt(jQuery.easing[options.easing](pr, n,  props[p][0].r, (props[p][1].r-props[p][0].r), options.duration))
                        + ','
                        + parseInt(jQuery.easing[options.easing](pr, n,  props[p][0].g, (props[p][1].g-props[p][0].g), options.duration))
                        + ','
                        + parseInt(jQuery.easing[options.easing](pr, n,  props[p][0].b, (props[p][1].b-props[p][0].b), options.duration))
                        +')';
                    } else {
                        var pValue = jQuery.easing[options.easing](pr, n,  props[p][0], (props[p][1]-props[p][0]), options.duration);
                        if ( p == "opacity" )
                            jQuery.attr(y, "opacity", pValue);
                        else 
                            y[p] = pValue + (p != 'zIndex' && p != 'fontWeight' ? 'px':'');
                    }
                }

            }
        };
    z.timer=setInterval(function(){z.step();},13);
    elem.animationHandler = z;
    },
    stopAnim: function(elem, step)
    {
        if (step)
            elem.animationHandler.startTime -= 100000000;
        else {
            window.clearInterval(elem.animationHandler.timer);
            elem.animationHandler = null;
            jQuery.dequeue(elem, "fx");
        }
    }
}
);

jQuery.parseStyle = function(styles) {
    var newStyles = {};
    if (typeof styles == 'string') {
        styles = styles.toLowerCase().split(';');
        for(var i=0; i< styles.length; i++){
            rule = styles[i].split(':');
            if (rule.length == 2) {
                newStyles[jQuery.trim(rule[0].replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}))] = jQuery.trim(rule[1]);
            }
        }
    }
    return newStyles;
};

jQuery.iAccordion = {
    build : function(options)
    {
        return this.each(
            function()
            {
                if (!options.headerSelector || !options.panelSelector)
                    return;
                var el = this;
                el.accordionCfg = {
                    panelHeight            : options.panelHeight||300,
                    headerSelector        : options.headerSelector,
                    panelSelector        : options.panelSelector,
                    activeClass            : options.activeClass||'fakeAccordionClass',
                    hoverClass            : options.hoverClass||'fakeAccordionClass',
                    onShow                : options.onShow && typeof options.onShow == 'function' ? options.onShow : false,
                    onHide                : options.onShow && typeof options.onHide == 'function' ? options.onHide : false,
                    onClick                : options.onClick && typeof options.onClick == 'function' ? options.onClick : false,
                    headers                : jQuery(options.headerSelector, this),
                    panels                : jQuery(options.panelSelector, this),
                    speed                : options.speed||400,
                    currentPanel        : options.currentPanel||0
                };
                el.accordionCfg.panels
                    .hide()
                    .css('height', '1px')
                    .eq(0)
                    .css(
                        {
                            height: el.accordionCfg.panelHeight + 'px',
                            display: 'block'
                        }
                    )
                    .end();
                    
                el.accordionCfg.headers
                .each(
                    function(nr)
                    {
                        this.accordionPos = nr;
                    }
                )
                .hover(
                    function()
                    {
                        //jQuery(this).addClass(el.accordionCfg.hoverClass);
                    },
                    function()
                    {
                        //jQuery(this).removeClass(el.accordionCfg.hoverClass);
                    }
                )
                .bind(
                    'click',
                    function(e)
                    {
                        if (el.accordionCfg.currentPanel == this.accordionPos)
                            return;
                        /*el.accordionCfg.headers
                            .eq(el.accordionCfg.currentPanel)
                            //.removeClass(el.accordionCfg.activeClass)
                            .end()
                            .eq(this.accordionPos)
                            //.addClass(el.accordionCfg.activeClass)
                            .end();*/
                        el.accordionCfg.panels
                        .eq(el.accordionCfg.currentPanel)
                            .animate(
                                {height:0},
                                el.accordionCfg.speed,
                                function()
                                {
                                    this.style.display = 'none';
                                    if (el.accordionCfg.onHide) {
                                        el.accordionCfg.onHide.apply(el, [this]);
                                    }
                                }
                            )
                        .end()
                        .eq(this.accordionPos)
                            .show()
                            .animate (
                                {height:el.accordionCfg.panelHeight},
                                el.accordionCfg.speed,
                                function()
                                {
                                    this.style.display = 'block';
                                    if (el.accordionCfg.onShow) {
                                        el.accordionCfg.onShow.apply(el, [this]);
                                    }
                                }
                            )
                        .end();
                        
                        if (el.accordionCfg.onClick) {
                            el.accordionCfg.onClick.apply(
                                el, 
                                [
                                    this, 
                                    el.accordionCfg.panels.get(this.accordionPos),
                                    el.accordionCfg.headers.get(el.accordionCfg.currentPanel),
                                    el.accordionCfg.panels.get(el.accordionCfg.currentPanel)
                                ]
                            );
                        }
                        el.accordionCfg.currentPanel = this.accordionPos;
                    }
                )
                .eq(0)
                /*.addClass(el.accordionCfg.activeClass)*/
                .end();
                jQuery(this)
                    .css('height', jQuery(this).css('height'));
                    /*.css('overflow', 'hidden');*/
            }
        );
    }
};

jQuery.fn.Accordion = jQuery.iAccordion.build;


/**
 * Interface Elements for jQuery
 * FX - open/close/switch
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Applies an open/close animation to element
 */
jQuery.fn.extend(
    {
        /**
         * @name CloseVertically
         * @description closes the element vertically
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        CloseVertically : function (speed, callback, easing) {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.OpenClose(this, speed, callback, 'vertically', 'close', easing);
            });
        },
        
        /**
         * @name CloseHorizontally
         * @description closes the element horizontally
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        CloseHorizontally : function (speed, callback, easing) {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.OpenClose(this, speed, callback, 'horizontally', 'close', easing);
            });
        },
        
        /**
         * @name SwitchHorizontally
         * @description opens/closes the element horizontally
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SwitchHorizontally : function (speed, callback, easing) 
        {
            return this.queue('interfaceFX', function(){
                if (jQuery.css(this, 'display') == 'none') {
                    new jQuery.fx.OpenClose(this, speed, callback, 'horizontally', 'open', easing);
                } else {
                    new jQuery.fx.OpenClose(this, speed, callback, 'horizontally', 'close', easing);
                }
            });
        },
        
        /**
         * @name SwitchVertically
         * @description opens/closes the element vertically
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SwitchVertically : function (speed, callback, easing) 
        {
            return this.queue('interfaceFX', function(){
                if (jQuery.css(this, 'display') == 'none') {
                    new jQuery.fx.OpenClose(this, speed, callback, 'vertically', 'open', easing);
                } else {
                    new jQuery.fx.OpenClose(this, speed, callback, 'vertically', 'close', easing);
                }
            });
        },
        
        /**
         * @name OpenVertically
         * @description opens the element vertically
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        OpenVertically : function (speed, callback, easing) {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.OpenClose(this, speed, callback, 'vertically', 'open', easing);
            });
        },
        
        /**
         * @name OpenHorizontally
         * @description opens the element horizontally
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        OpenHorizontally : function (speed, callback, easing) {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.OpenClose(this, speed, callback, 'horizontally', 'open', easing);
            });
        }
    }
);

jQuery.fx.OpenClose = function (e, speed, callback, direction, type, easing)
{
    if (!jQuery.fxCheckTag(e)) {
        jQuery.dequeue(e, 'interfaceFX');
        return false;
    }
    var z = this;
    var restoreStyle = false;
    z.el = jQuery(e);
    z.easing = typeof callback == 'string' ? callback : easing||null;
    z.callback = typeof callback == 'function' ? callback : null;
    z.type = type;
    z.speed = speed;
    z.oldP = jQuery.iUtil.getSize(e);
    z.oldStyle = {};
    z.oldStyle.position = z.el.css('position');
    z.oldStyle.display = z.el.css('display');
    if (z.oldStyle.display == 'none') {
        oldVisibility = z.el.css('visibility');
        z.el.show();
        restoreStyle = true;
    }
    z.oldStyle.top = z.el.css('top');
    z.oldStyle.left = z.el.css('left');
    if (restoreStyle) {
        z.el.hide();
        z.el.css('visibility', oldVisibility);
    }
    z.oldStyle.width = z.oldP.w + 'px';
    z.oldStyle.height = z.oldP.h + 'px';
    z.oldStyle.overflow = z.el.css('overflow');
    z.oldP.top = parseInt(z.oldStyle.top)||0;
    z.oldP.left = parseInt(z.oldStyle.left)||0;
    //z.el.show();
    
    if (z.oldStyle.position != 'relative' && z.oldStyle.position != 'absolute') {
        z.el.css('position', 'relative');
    }
    z.el.css('overflow', 'hidden')
        .css('height', type == 'open' && direction == 'vertically' ? 1 : z.oldP.h + 'px')
        .css('width', type == 'open' && direction == 'horizontally' ? 1 : z.oldP.w + 'px');
    
    z.complete = function()
    {
        z.el.css(z.oldStyle);
        if (z.type == 'close')
            z.el.hide();
        else 
            z.el.show();
        jQuery.dequeue(z.el.get(0), 'interfaceFX');
    };
    
    switch (direction) {
        case 'vertically':
            z.eh = new jQuery.fx(
                z.el.get(0),
                jQuery.speed(speed-15, z.easing, callback),
                'height'
            );
            z.et = new jQuery.fx(
                z.el.get(0),
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'top'
            );
            if (z.type == 'close') {
                z.eh.custom(z.oldP.h,0);
                z.et.custom(z.oldP.top, z.oldP.top + z.oldP.h/2);
            } else {
                z.eh.custom(0, z.oldP.h);
                z.et.custom(z.oldP.top + z.oldP.h/2, z.oldP.top);
            }
        break;
        case 'horizontally':
            z.eh = new jQuery.fx(
                z.el.get(0),
                jQuery.speed(speed-15, z.easing, callback),
                'width'
            );
            z.et = new jQuery.fx(
                z.el.get(0),
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'left'
            );
            if (z.type == 'close') {
                z.eh.custom(z.oldP.w,0);
                z.et.custom(z.oldP.left, z.oldP.left + z.oldP.w/2);
            } else {
                z.eh.custom(0, z.oldP.w);
                z.et.custom(z.oldP.left + z.oldP.w/2, z.oldP.left);
            }
        break;
    }
};/**
 * Interface Elements for jQuery
 * FX - pulsate
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
 
/**
 * @name Bounce
 * @description makes the element to pulsate
 * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
 * @param Integer times how many times to pulsate
 * @param Function callback (optional) A function to be executed whenever the animation completes.
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */
jQuery.fn.Pulsate = function(speed, times, callback) {
    return this.queue('interfaceFX',function(){
        if (!jQuery.fxCheckTag(this)) {
            jQuery.dequeue(this, 'interfaceFX');
            return false;
        }
        var fx = new jQuery.fx.Pulsate(this, speed, times, callback);
        fx.pulse();
    });
};

jQuery.fx.Pulsate = function (el, speed, times, callback)
{    
    var z = this;
    z.times = times;
    z.cnt = 1;
    z.el = el;
    z.speed = speed;
    z.callback = callback;
    jQuery(z.el).show();
    z.pulse = function()
    {
        z.cnt ++;
        z.e = new jQuery.fx(
            z.el, 
            jQuery.speed(
                z.speed, 
                function(){
                    z.ef = new jQuery.fx(
                        z.el, 
                        jQuery.speed(
                            z.speed,
                            function()
                            {
                                if (z.cnt <= z.times)
                                    z.pulse();
                                else {
                                    jQuery.dequeue(z.el, 'interfaceFX');
                                    if (z.callback && z.callback.constructor == Function) {
                                        z.callback.apply(z.el);
                                    }
                                }
                            }
                        ), 
                        'opacity'
                    );
                    z.ef.custom(0,1);
                }
            ), 
            'opacity'
        );
        z.e.custom(1,0);
    };
};
/**
 * Interface Elements for jQuery
 * FX - scale/grow/shrink/puff
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
/**
 * Applies a scallign animation to element
 */
jQuery.fn.extend(
    {
        /**
         * @name Grow
         * @description scales the element from 0 to intitial size
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        Grow : function(speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.Scale(this, speed, 1, 100, true, callback, 'grow', easing);
            });
        },
        
        /**
         * @name Shrink
         * @description scales the element from intitial size to 0
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        Shrink : function(speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.Scale(this, speed, 100, 1, true, callback, 'shrink', easing);
            });
        },
        
        /**
         * @name Puff
         * @description makes element to dispear by scalling to 150% and fading it out
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        Puff : function(speed, callback, easing) {
            return this.queue('interfaceFX',function(){
                var easing = easing || 'easeout';
                new jQuery.fx.Scale(this, speed, 100, 150, true, callback, 'puff', easing);
            });
        },
        
        /**
         * @name Scale
         * @description scales the element
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Integer from initial scalling procentage
         * @param Integer to final scalling procentage
         * @param Boolean reastore whatever to restore the initital scalling procentage when animation ends
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        Scale : function(speed, from, to, restore, callback, easing) {
            return this.queue('interfaceFX',function(){
                new jQuery.fx.Scale(this, speed, from, to, restore, callback, 'Scale', easing);
            });
        }
    }
);

jQuery.fx.Scale = function (e, speed, from, to, restore, callback, type, easing)
{
    if (!jQuery.fxCheckTag(e)) {
        jQuery.dequeue(e, 'interfaceFX');
        return false;
    }
    var z = this;
    z.el = jQuery(e);
    z.from = parseInt(from) || 100;
    z.to = parseInt(to) || 100;
    z.easing = typeof callback == 'string' ? callback : easing||null;
    z.callback = typeof callback == 'function' ? callback : null;
    z.duration = jQuery.speed(speed).duration;
    z.restore = restore|| null;
    z.oldP = jQuery.iUtil.getSize(e);
    z.oldStyle = {
        width: z.el.css('width'),
        height: z.el.css('height'),
        fontSize: z.el.css('fontSize')||'100%',
        position : z.el.css('position'),
        display : z.el.css('display'),
        top : z.el.css('top'),
        left : z.el.css('left'),
        overflow : z.el.css('overflow'),
        borderTopWidth : z.el.css('borderTopWidth'),
        borderRightWidth : z.el.css('borderRightWidth'),
        borderBottomWidth : z.el.css('borderBottomWidth'),
        borderLeftWidth : z.el.css('borderLeftWidth'),
        paddingTop : z.el.css('paddingTop'),
        paddingRight : z.el.css('paddingRight'),
        paddingBottom : z.el.css('paddingBottom'),
        paddingLeft : z.el.css('paddingLeft')
    };
    z.width = parseInt(z.oldStyle.width)||e.offsetWidth||0;
    z.height = parseInt(z.oldStyle.height)||e.offsetHeight||0;
    z.top = parseInt(z.oldStyle.top)||0;
    z.left = parseInt(z.oldStyle.left)||0;
    sizes = ['em','px','pt','%'];
    for(i in sizes) {
        if (z.oldStyle.fontSize.indexOf(sizes[i])>0) {
            z.fontUnit = sizes[i];
            z.fontSize = parseFloat(z.oldStyle.fontSize);
        }
        if (z.oldStyle.borderTopWidth.indexOf(sizes[i])>0) {
            z.borderTopUnit = sizes[i];
            z.borderTopSize = parseFloat(z.oldStyle.borderTopWidth)||0;
        }
        if (z.oldStyle.borderRightWidth.indexOf(sizes[i])>0) {
            z.borderRightUnit = sizes[i];
            z.borderRightSize = parseFloat(z.oldStyle.borderRightWidth)||0;
        }
        if (z.oldStyle.borderBottomWidth.indexOf(sizes[i])>0) {
            z.borderBottomUnit = sizes[i];
            z.borderBottomSize = parseFloat(z.oldStyle.borderBottomWidth)||0;
        }
        if (z.oldStyle.borderLeftWidth.indexOf(sizes[i])>0) {
            z.borderLeftUnit = sizes[i];
            z.borderLeftSize = parseFloat(z.oldStyle.borderLeftWidth)||0;
        }
        if (z.oldStyle.paddingTop.indexOf(sizes[i])>0) {
            z.paddingTopUnit = sizes[i];
            z.paddingTopSize = parseFloat(z.oldStyle.paddingTop)||0;
        }
        if (z.oldStyle.paddingRight.indexOf(sizes[i])>0) {
            z.paddingRightUnit = sizes[i];
            z.paddingRightSize = parseFloat(z.oldStyle.paddingRight)||0;
        }
        if (z.oldStyle.paddingBottom.indexOf(sizes[i])>0) {
            z.paddingBottomUnit = sizes[i];
            z.paddingBottomSize = parseFloat(z.oldStyle.paddingBottom)||0;
        }
        if (z.oldStyle.paddingLeft.indexOf(sizes[i])>0) {
            z.paddingLeftUnit = sizes[i];
            z.paddingLeftSize = parseFloat(z.oldStyle.paddingLeft)||0;
        }
    }
    
    
    if (z.oldStyle.position != 'relative' && z.oldStyle.position != 'absolute') {
        z.el.css('position', 'relative');
    }
    z.el.css('overflow', 'hidden');
    z.type = type;
    switch(z.type)
    {
        case 'grow':
            z.startTop = z.top + z.oldP.h/2;
            z.endTop = z.top;
            z.startLeft = z.left + z.oldP.w/2;
            z.endLeft = z.left;
            break;
        case 'shrink':
            z.endTop = z.top + z.oldP.h/2;
            z.startTop = z.top;
            z.endLeft = z.left + z.oldP.w/2;
            z.startLeft = z.left;
            break;
        case 'puff':
            z.endTop = z.top - z.oldP.h/4;
            z.startTop = z.top;
            z.endLeft = z.left - z.oldP.w/4;
            z.startLeft = z.left;
            break;
    }
    z.firstStep = false;
    z.t=(new Date).getTime();
    z.clear = function(){clearInterval(z.timer);z.timer=null;};
    z.step = function(){
        if (z.firstStep == false) {
            z.el.show();
            z.firstStep = true;
        }
        var t = (new Date).getTime();
        var n = t - z.t;
        var p = n / z.duration;
        if (t >= z.duration+z.t) {
            setTimeout(
                function(){
                        o = 1;    
                    if (z.type) {
                        t = z.endTop;
                        l = z.endLeft;
                        if (z.type == 'puff')
                            o = 0;
                    }
                    z.zoom(z.to, l, t, true, o);
                },
                13
            );
            z.clear();
        } else {
            o = 1;
            if (!jQuery.easing || !jQuery.easing[z.easing]) {
                s = ((-Math.cos(p*Math.PI)/2) + 0.5) * (z.to-z.from) + z.from;
            } else {
                s = jQuery.easing[z.easing](p, n, z.from, (z.to-z.from), z.duration);
            }
            if (z.type) {
                if (!jQuery.easing || !jQuery.easing[z.easing]) {
                    t = ((-Math.cos(p*Math.PI)/2) + 0.5) * (z.endTop-z.startTop) + z.startTop;
                    l = ((-Math.cos(p*Math.PI)/2) + 0.5) * (z.endLeft-z.startLeft) + z.startLeft;
                    if (z.type == 'puff')
                        o = ((-Math.cos(p*Math.PI)/2) + 0.5) * (-0.9999) + 0.9999;
                } else {
                    t = jQuery.easing[z.easing](p, n, z.startTop, (z.endTop-z.startTop), z.duration);
                    l = jQuery.easing[z.easing](p, n, z.startLeft, (z.endLeft-z.startLeft), z.duration);
                    if (z.type == 'puff')
                        o = jQuery.easing[z.easing](p, n, 0.9999, -0.9999, z.duration);
                }
            }
            z.zoom(s, l, t, false, o);
        }
    };
    z.timer=setInterval(function(){z.step();},13);
    z.zoom = function(percent, left, top, finish, opacity)
    {
        z.el
            .css('height', z.height * percent/100 + 'px')
            .css('width', z.width * percent/100 + 'px')
            .css('left', left + 'px')
            .css('top', top + 'px')
            .css('fontSize', z.fontSize * percent /100 + z.fontUnit);
        if (z.borderTopSize)
            z.el.css('borderTopWidth', z.borderTopSize * percent /100 + z.borderTopUnit);
        if (z.borderRightSize)
            z.el.css('borderRightWidth', z.borderRightSize * percent /100 + z.borderRightUnit);
        if (z.borderBottomSize)
            z.el.css('borderBottomWidth', z.borderBottomSize * percent /100 + z.borderBottomUnit);
        if (z.borderLeftSize)
            z.el.css('borderLeftWidth', z.borderLeftSize * percent /100 + z.borderLeftUnit);
        if (z.paddingTopSize)
            z.el.css('paddingTop', z.paddingTopSize * percent /100 + z.paddingTopUnit);
        if (z.paddingRightSize)
            z.el.css('paddingRight', z.paddingRightSize * percent /100 + z.paddingRightUnit);
        if (z.paddingBottomSize)
            z.el.css('paddingBottom', z.paddingBottomSize * percent /100 + z.paddingBottomUnit);
        if (z.paddingLeftSize)
            z.el.css('paddingLeft', z.paddingLeftSize * percent /100 + z.paddingLeftUnit);
        if (z.type == 'puff') {
            if (window.ActiveXObject)
                z.el.get(0).style.filter = "alpha(opacity=" + opacity*100 + ")";
            z.el.get(0).style.opacity = opacity;
        }
        if (finish){
            if (z.restore){
                z.el.css(z.oldStyle);
            }
            if (z.type == 'shrink' || z.type == 'puff'){
                z.el.css('display', 'none');
                if (z.type == 'puff') {
                    if (window.ActiveXObject)
                        z.el.get(0).style.filter = "alpha(opacity=" + 100 + ")";
                    z.el.get(0).style.opacity = 1;
                }
            }else 
                z.el.css('display', 'block');
            if (z.callback)
                z.callback.apply(z.el.get(0));
            
            jQuery.dequeue(z.el.get(0), 'interfaceFX');
        }
    };
};/**
 * Interface Elements for jQuery
 * FX - scroll to
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */
/**
 * Applies a scrolling effect to document until the element gets into viewport
 */
jQuery.fn.extend (
    {
        /**
         * @name ScrollTo
         * @description scrolls the document until the lement gets into viewport
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param String axis (optional) whatever to scroll on vertical, horizontal or both axis ['vertical'|'horizontal'|null]
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        ScrollTo : function(speed, axis, easing) {
            o = jQuery.speed(speed);
            return this.queue('interfaceFX',function(){
                new jQuery.fx.ScrollTo(this, o, axis, easing);
            });
        },
        /**
         * @name ScrollToAnchors
         * @description all links to '#elementId' will animate scroll
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param String axis (optional) whatever to scroll on vertical, horizontal or both axis ['vertical'|'horizontal'|null]
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        /*inspired by David Maciejewski www.macx.de*/
        ScrollToAnchors : function(speed, axis, easing) {
            return this.each(
                function()
                {
                    jQuery('a[@href*="#"]', this).click(
                        function(e)
                        {
                            parts = this.href.split('#');
                            jQuery('#' + parts[1]).ScrollTo(speed, axis, easing);
                            return false;
                        }
                    );
                }
            )
        }
    }
);

jQuery.fx.ScrollTo = function (e, o, axis, easing)
{
    var z = this;
    z.o = o;
    z.e = e;
    z.axis = /vertical|horizontal/.test(axis) ? axis : false;
    z.easing = easing;
    p = jQuery.iUtil.getPosition(e);
    s = jQuery.iUtil.getScroll();
    z.clear = function(){clearInterval(z.timer);z.timer=null;jQuery.dequeue(z.e, 'interfaceFX');};
    z.t=(new Date).getTime();
    s.h = s.h > s.ih ? (s.h - s.ih) : s.h;
    s.w = s.w > s.iw ? (s.w - s.iw) : s.w;
    z.endTop = p.y > s.h ? s.h : p.y;
    z.endLeft = p.x > s.w ? s.w : p.x;
    z.startTop = s.t;
    z.startLeft = s.l;
    z.step = function(){
        var t = (new Date).getTime();
        var n = t - z.t;
        var p = n / z.o.duration;
        if (t >= z.o.duration+z.t) {
            z.clear();
            setTimeout(function(){z.scroll(z.endTop, z.endLeft)},13);
        } else {
            if (!z.axis || z.axis == 'vertical') {
                if (!jQuery.easing || !jQuery.easing[z.easing]) {
                    st = ((-Math.cos(p*Math.PI)/2) + 0.5) * (z.endTop-z.startTop) + z.startTop;
                } else {
                    st = jQuery.easing[z.easing](p, n, z.startTop, (z.endTop - z.startTop), z.o.duration);
                }
            } else {
                st = z.startTop;
            }
            if (!z.axis || z.axis == 'horizontal') {
                if (!jQuery.easing || !jQuery.easing[z.easing]) {
                    sl = ((-Math.cos(p*Math.PI)/2) + 0.5) * (z.endLeft-z.startLeft) + z.startLeft;
                } else {
                    sl = jQuery.easing[z.easing](p, n, z.startLeft, (z.endLeft - z.startLeft), z.o.duration);
                }
            } else {
                sl = z.startLeft;
            }
            z.scroll(st, sl);
        }
    };
    z.scroll = function (t, l){window.scrollTo(l, t);};
    z.timer=setInterval(function(){z.step();},13);
};/**
 * Interface Elements for jQuery
 * FX - shake
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * @name Shake
 * @description makes the element to shake
 * @param Integer times how many tomes to shake the element
 * @param Function callback (optional) A function to be executed whenever the animation completes.
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */
jQuery.fn.Shake = function (times, callback) {
    return this.queue('interfaceFX',function(){
        if (!jQuery.fxCheckTag(this)) {
            jQuery.dequeue(this, 'interfaceFX');
            return false;
        }
        var e = new jQuery.fx.Shake(this, times, callback);
        e.shake();
    });
};
jQuery.fx.Shake = function (e, times, callback)
{
    var z = this;
    z.el = jQuery(e);
    z.el.show();
    z.times = parseInt(times)||3;
    z.callback = callback;
    z.cnt = 1;
    z.oldStyle = {};
    z.oldStyle.position = z.el.css('position');
    z.oldStyle.top = parseInt(z.el.css('top'))||0;
    z.oldStyle.left = parseInt(z.el.css('left'))||0;
    
    if (z.oldStyle.position != 'relative' && z.oldStyle.position != 'absolute') {
        z.el.css('position', 'relative');
    }
    
    z.shake = function ()
    {
        z.cnt ++;
        
        z.e = new jQuery.fx(
            z.el.get(0), 
            {
                duration: 60,
                complete : function ()
                {
                    z.e = new jQuery.fx(
                        z.el.get(0), 
                         {
                             duration: 60,
                             complete : function ()
                             {
                                z.e = new jQuery.fx(
                                    e,
                                    {
                                        duration: 60, 
                                        complete: function(){
                                            if (z.cnt <= z.times)
                                                z.shake();
                                            else {
                                                z.el.css('position', z.oldStyle.position).css('top', z.oldStyle.top + 'px').css('left', z.oldStyle.left + 'px');
                                                jQuery.dequeue(z.el.get(0), 'interfaceFX');
                                                if (z.callback && z.callback.constructor == Function) {
                                                    z.callback.apply(z.el.get(0));
                                                }
                                            }
                                        }
                                    },
                                    'left'
                                );
                                z.e.custom (z.oldStyle.left-20, z.oldStyle.left);
                             }
                        },
                        'left'
                    );
                    z.e.custom (z.oldStyle.left+20, z.oldStyle.left-20);
                }
            },
            'left'
        );
        z.e.custom (z.oldStyle.left, z.oldStyle.left+20);
    };
        
};/**
 * Interface Elements for jQuery
 * FX - slide
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Slides the element
 */
jQuery.fn.extend(
    {
        /**
         * @name SlideInUp
         * @description slides the element in up
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideInUp : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'up', 'in', easing);
            });
        },
        
        /**
         * @name SlideOutUp
         * @description slides the element out up
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideOutUp : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'up', 'out', easing);
            });
        },
        
        /**
         * @name SlideToggleUp
         * @description slides the element in/out up
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideToggleUp : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'up', 'toggle', easing);
            });
        },
        
        /**
         * @name SlideInDown
         * @description slides the element in down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideInDown : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'down', 'in', easing);
            });
        },
        
        /**
         * @name SlideOutDown
         * @description slides the element out down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideOutDown : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'down', 'out', easing);
            });
        },
        
        /**
         * @name SlideToggleDown
         * @description slides the element in/out down
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideToggleDown : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'down', 'toggle', easing);
            });
        },
        
        /**
         * @name SlideInLeft
         * @description slides the element in left
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideInLeft : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'left', 'in', easing);
            });
        },
        
        /**
         * @name SlideOutLeft
         * @description slides the element out left
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideOutLeft :  function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'left', 'out', easing);
            });
        },
        
        /**
         * @name SlideToggleLeft
         * @description slides the element in/out left
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideToggleLeft : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'left', 'toggle', easing);
            });
        },
        
        /**
         * @name SlideInRight
         * @description slides the element in right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideInRight : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'right', 'in', easing);
            });
        },
        
        /**
         * @name SlideOutRight
         * @description slides the element out right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideOutRight : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'right', 'out', easing);
            });
        },
        
        /**
         * @name SlideToggleRight
         * @description slides the element in/out right
         * @param Mixed speed animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
         * @param Function callback (optional) A function to be executed whenever the animation completes.
         * @param String easing (optional) The name of the easing effect that you want to use.
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SlideToggleRight : function (speed,callback, easing)
        {
            return this.queue('interfaceFX', function(){
                new jQuery.fx.slide(this, speed, callback, 'right', 'toggle', easing);
            });
        }
    }
);

jQuery.fx.slide = function(e, speed, callback, direction, type, easing)
{
    if (!jQuery.fxCheckTag(e)) {
        jQuery.dequeue(e, 'interfaceFX');
        return false;
    }
    var z = this;
    z.el = jQuery(e);
    z.easing = typeof callback == 'string' ? callback : easing||null;
    z.callback = typeof callback == 'function' ? callback : null;
    if ( type == 'toggle') {
        type = z.el.css('display') == 'none' ? 'in' : 'out';
    }
    if (!e.ifxFirstDisplay)
        e.ifxFirstDisplay = z.el.css('display');
    z.el.show();
    
    z.speed = speed;
    z.fx = jQuery.fx.buildWrapper(e);
    
    z.type = type;
    z.direction = direction;
    z.complete = function()
    {
        if(z.type == 'out')
            z.el.css('visibility', 'hidden');
        jQuery.fx.destroyWrapper(z.fx.wrapper.get(0), z.fx.oldStyle);
        if(z.type == 'in'){
            z.el.css('display', z.el.get(0).ifxFirstDisplay == 'none' ? 'block' : z.el.get(0).ifxFirstDisplay);
        } else {
            z.el.css('display', 'none');
            z.el.css('visibility', 'visible');
        }
        if (z.callback && z.callback.constructor == Function) {
            z.callback.apply(z.el.get(0));
        }
        jQuery.dequeue(z.el.get(0), 'interfaceFX');
    };
    switch (z.direction) {
        case 'up':
            z.ef = new jQuery.fx(
                z.el.get(0), 
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'top'
            );
            z.efx = new jQuery.fx(
                z.fx.wrapper.get(0), 
                jQuery.speed(
                    z.speed,
                    z.easing
                ),
                'height'
            );
            if (z.type == 'in') {
                z.ef.custom (-z.fx.oldStyle.sizes.hb, 0);
                z.efx.custom(0, z.fx.oldStyle.sizes.hb);
            } else {
                z.ef.custom (0, -z.fx.oldStyle.sizes.hb);
                z.efx.custom (z.fx.oldStyle.sizes.hb, 0);
            }
        break;
        case 'down':
            z.ef = new jQuery.fx(
                z.el.get(0), 
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'top'
            );
            if (z.type == 'in') {
                z.ef.custom (z.fx.oldStyle.sizes.hb, 0);
            } else {
                z.ef.custom (0, z.fx.oldStyle.sizes.hb);
            }
        break;
        case 'left':
            z.ef = new jQuery.fx(
                z.el.get(0), 
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'left'
            );
            z.efx = new jQuery.fx(
                z.fx.wrapper.get(0), 
                jQuery.speed(
                    z.speed,
                    z.easing
                ),
                'width'
            );
            if (z.type == 'in') {
                z.ef.custom (-z.fx.oldStyle.sizes.wb, 0);
                z.efx.custom (0, z.fx.oldStyle.sizes.wb);
            } else {
                z.ef.custom (0, -z.fx.oldStyle.sizes.wb);
                z.efx.custom (z.fx.oldStyle.sizes.wb, 0);
            }
        break;
        case 'right':
            z.ef = new jQuery.fx(
                z.el.get(0), 
                jQuery.speed(
                    z.speed,
                    z.easing,
                    z.complete
                ),
                'left'
            );
            if (z.type == 'in') {
                z.ef.custom (z.fx.oldStyle.sizes.wb, 0);
            } else {
                z.ef.custom (0, z.fx.oldStyle.sizes.wb);
            }
        break;
    }
};
/**
 * Interface Elements for jQuery
 * FX - transfer
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

jQuery.transferHelper = null;
/**
 * 
 * @name TransferTo
 * @description Animates an new build element to simulate a transfer action from one element to other
 * @param Hash hash A hash of parameters
 * @option Mixed to DOMElement or element ID to transfer to
 * @option String className CSS class to apply to transfer element
 * @option String duration animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast']
 * @option Function callback (optional) A function to be executed whenever the animation completes.
 *
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */
jQuery.fn.TransferTo = function(o)
{
    return this.queue('interfaceFX', function(){
        new jQuery.fx.itransferTo(this, o);
    });
};
jQuery.fx.itransferTo = function(e, o)
{
    
    if(jQuery.transferHelper == null)
    {
        jQuery('body', document).append('<div id="transferHelper"></div>');
        jQuery.transferHelper = jQuery('#transferHelper');
    }
    jQuery.transferHelper.css('display', 'block').css('position', 'absolute');
    
    var z = this;
    z.el = jQuery(e);
    if(!o || !o.to) {
        return;
    }
    
    if (o.to.constructor == String && document.getElementById(o.to)) {
        o.to = document.getElementById(o.to);
    } else if ( !o.to.childNodes ) {
        return;
    }
    
    if (!o.duration) {
        o.duration = 500;
    }
    z.duration = o.duration;
    z.to = o.to;
    z.classname = o.className;
    z.complete = o.complete;
    if (z.classname) {
        jQuery.transferHelper.addClass(z.classname);
    }
    z.diffWidth = 0;
    z.diffHeight = 0;
    
    if(jQuery.boxModel) {
        z.diffWidth = (parseInt(jQuery.transferHelper.css('borderLeftWidth')) || 0 )
                    + (parseInt(jQuery.transferHelper.css('borderRightWidth')) || 0)
                    + (parseInt(jQuery.transferHelper.css('paddingLeft')) || 0)
                    + (parseInt(jQuery.transferHelper.css('paddingRight')) || 0);
        z.diffHeight = (parseInt(jQuery.transferHelper.css('borderTopWidth')) || 0 )
                    + (parseInt(jQuery.transferHelper.css('borderBottomWidth')) || 0)
                    + (parseInt(jQuery.transferHelper.css('paddingTop')) || 0)
                    + (parseInt(jQuery.transferHelper.css('paddingBottom')) || 0);
    }
    z.start = jQuery.extend(
        jQuery.iUtil.getPosition(z.el.get(0)),
        jQuery.iUtil.getSize(z.el.get(0))
    );
    z.end = jQuery.extend(
        jQuery.iUtil.getPosition(z.to),
        jQuery.iUtil.getSize(z.to)
    );
    z.start.wb -= z.diffWidth;
    z.start.hb -= z.diffHeight;
    z.end.wb -= z.diffWidth;
    z.end.hb -= z.diffHeight;
    z.callback = o.complete;

    // Execute the transfer
    jQuery.transferHelper
        .css('width', z.start.wb + 'px')
        .css('height', z.start.hb + 'px')
        .css('top', z.start.y + 'px')
        .css('left', z.start.x + 'px')
        .animate(
            {
                top: z.end.y,
                left: z.end.x,
                width: z.end.wb,
                height: z.end.hb
            },
            z.duration,
            function()
            {
                // Set correct classname
                if(z.classname)
                    jQuery.transferHelper.removeClass(z.classname);
                jQuery.transferHelper.css('display', 'none');
    
                // Callback
                if (z.complete && z.complete.constructor == Function) {
                    z.complete.apply(z.el.get(0), [z.to]);
                }
                // Done
                jQuery.dequeue(z.el.get(0), 'interfaceFX');
            }
        );
};/**
 * Interface Elements for jQuery
 * Resizable
 *
 * http://interface.eyecon.ro
 *
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 *
 */

jQuery.iResize = {
    resizeElement: null,
    resizeDirection: null,
    dragged: null,
    pointer: null,
    sizes: null,
    position: null,
    /**
     * internal: Start function
     */
    startDrag: function(e) {
        jQuery.iResize.dragged = (this.dragEl) ? this.dragEl: this;
        jQuery.iResize.pointer = jQuery.iUtil.getPointer(e);

        // Save original size
        jQuery.iResize.sizes = {
            width: parseInt(jQuery(jQuery.iResize.dragged).css('width')) || 0,
            height: parseInt(jQuery(jQuery.iResize.dragged).css('height')) || 0
        };

        // Save original position
        jQuery.iResize.position = {
            top: parseInt(jQuery(jQuery.iResize.dragged).css('top')) || 0,
            left: parseInt(jQuery(jQuery.iResize.dragged).css('left')) || 0
        };

        // Assign event handlers
        jQuery(document)
            .bind('mousemove', jQuery.iResize.moveDrag)
            .bind('mouseup', jQuery.iResize.stopDrag);

        // Callback?
        if (typeof jQuery.iResize.dragged.resizeOptions.onDragStart === 'function') {
            jQuery.iResize.dragged.resizeOptions.onDragStart.apply(jQuery.iResize.dragged);
        }

        return false;
    },
    /**
     * internal: Stop function
     */
    stopDrag: function(e) {
        // Unbind event handlers
        jQuery(document)
            .unbind('mousemove', jQuery.iResize.moveDrag)
            .unbind('mouseup', jQuery.iResize.stopDrag);

        // Callback?
        if (typeof jQuery.iResize.dragged.resizeOptions.onDragStop === 'function') {
            jQuery.iResize.dragged.resizeOptions.onDragStop.apply(jQuery.iResize.dragged);
        }

        // Remove dragged element
        jQuery.iResize.dragged = null;
    },
    /**
     * internal: Move function
     */
    moveDrag: function(e) {
        if (!jQuery.iResize.dragged) {
            return;
        }

        pointer = jQuery.iUtil.getPointer(e);

        // Calculate new positions
        newTop = jQuery.iResize.position.top - jQuery.iResize.pointer.y + pointer.y;
        newLeft = jQuery.iResize.position.left - jQuery.iResize.pointer.x + pointer.x;
        newTop = Math.max(
                        Math.min(newTop, jQuery.iResize.dragged.resizeOptions.maxBottom - jQuery.iResize.sizes.height),
                        jQuery.iResize.dragged.resizeOptions.minTop
                    );
        newLeft = Math.max(
                        Math.min(newLeft, jQuery.iResize.dragged.resizeOptions.maxRight- jQuery.iResize.sizes.width),
                        jQuery.iResize.dragged.resizeOptions.minLeft
                    );

        // Callback
        if (typeof jQuery.iResize.dragged.resizeOptions.onDrag === 'function') {
            var newPos = jQuery.iResize.dragged.resizeOptions.onDrag.apply(jQuery.iResize.dragged, [newLeft, newTop]);
            if (typeof newPos == 'array' && newPos.length == 2) {
                newLeft = newPos[0];
                newTop = newPos[1];
            }
        }

        // Update the element
        jQuery.iResize.dragged.style.top = newTop + 'px';
        jQuery.iResize.dragged.style.left = newLeft + 'px';

        return false;
    },
    start: function(e) {
        // Bind event handlers
        jQuery(document)
            .bind('mousemove', jQuery.iResize.move)
            .bind('mouseup', jQuery.iResize.stop);

        // Initialize resizable
        jQuery.iResize.resizeElement = this.resizeElement;
        jQuery.iResize.resizeDirection = this.resizeDirection;
        jQuery.iResize.pointer = jQuery.iUtil.getPointer(e);
        jQuery.iResize.sizes = {
                width: parseInt(jQuery(this.resizeElement).css('width'))||0,
                height: parseInt(jQuery(this.resizeElement).css('height'))||0
            };
        jQuery.iResize.position = {
                top: parseInt(jQuery(this.resizeElement).css('top'))||0,
                left: parseInt(jQuery(this.resizeElement).css('left'))||0
            };

        // Callback function
        if (jQuery.iResize.resizeElement.resizeOptions.onStart) {
            jQuery.iResize.resizeElement.resizeOptions.onStart.apply(jQuery.iResize.resizeElement, [this]);
        }

        return false;
    },
    stop: function() {
        // Unbind event handlers
        jQuery(document)
            .unbind('mousemove', jQuery.iResize.move)
            .unbind('mouseup', jQuery.iResize.stop);

        // Callback function
        if (jQuery.iResize.resizeElement.resizeOptions.onStop) {
            jQuery.iResize.resizeElement.resizeOptions.onStop.apply(jQuery.iResize.resizeElement, [jQuery.iResize.resizeDirection]);
        }

        // Unbind
        jQuery.iResize.resizeElement = null;
        jQuery.iResize.resizeDirection = null;
    },
    getWidth: function(dx, side) {
        return Math.min(
                        Math.max(jQuery.iResize.sizes.width + dx * side, jQuery.iResize.resizeElement.resizeOptions.minWidth),
                        jQuery.iResize.resizeElement.resizeOptions.maxWidth
                    );
    },
    getHeight: function(dy, side) {
        return Math.min(
                        Math.max(jQuery.iResize.sizes.height + dy * side, jQuery.iResize.resizeElement.resizeOptions.minHeight),
                        jQuery.iResize.resizeElement.resizeOptions.maxHeight
                    );
    },
    getHeightMinMax: function(height) {
        return Math.min(
                        Math.max(height, jQuery.iResize.resizeElement.resizeOptions.minHeight),
                        jQuery.iResize.resizeElement.resizeOptions.maxHeight
                    );
    },
    move: function(e) {
        if (jQuery.iResize.resizeElement == null) {
            return;
        }

        pointer = jQuery.iUtil.getPointer(e);
        dx = pointer.x - jQuery.iResize.pointer.x;
        dy = pointer.y - jQuery.iResize.pointer.y;

        newSizes = {
                width: jQuery.iResize.sizes.width,
                height: jQuery.iResize.sizes.height
            };
        newPosition = {
                top: jQuery.iResize.position.top,
                left: jQuery.iResize.position.left
            };

        switch (jQuery.iResize.resizeDirection){
            case 'e':
                newSizes.width = jQuery.iResize.getWidth(dx,1);
                break;
            case 'se':
                newSizes.width = jQuery.iResize.getWidth(dx,1);
                newSizes.height = jQuery.iResize.getHeight(dy,1);
                break;
            case 'w':
                newSizes.width = jQuery.iResize.getWidth(dx,-1);
                newPosition.left = jQuery.iResize.position.left - newSizes.width + jQuery.iResize.sizes.width;
                break;
            case 'sw':
                newSizes.width = jQuery.iResize.getWidth(dx,-1);
                newPosition.left = jQuery.iResize.position.left - newSizes.width + jQuery.iResize.sizes.width;
                newSizes.height = jQuery.iResize.getHeight(dy,1);
                break;
            case 'nw':
                newSizes.height = jQuery.iResize.getHeight(dy,-1);
                newPosition.top = jQuery.iResize.position.top - newSizes.height + jQuery.iResize.sizes.height;
                newSizes.width = jQuery.iResize.getWidth(dx,-1);
                newPosition.left = jQuery.iResize.position.left - newSizes.width + jQuery.iResize.sizes.width;
                break;
            case 'n':
                newSizes.height = jQuery.iResize.getHeight(dy,-1);
                newPosition.top = jQuery.iResize.position.top - newSizes.height + jQuery.iResize.sizes.height;
                break;
            case 'ne':
                newSizes.height = jQuery.iResize.getHeight(dy,-1);
                newPosition.top = jQuery.iResize.position.top - newSizes.height + jQuery.iResize.sizes.height;
                newSizes.width = jQuery.iResize.getWidth(dx,1);
                break;
            case 's':
                newSizes.height = jQuery.iResize.getHeight(dy,1);
                break;
        }

        if (jQuery.iResize.resizeElement.resizeOptions.ratio) {
            if (jQuery.iResize.resizeDirection == 'n' || jQuery.iResize.resizeDirection == 's')
                nWidth = newSizes.height * jQuery.iResize.resizeElement.resizeOptions.ratio;
            else
                nWidth = newSizes.width;
            nHeight = jQuery.iResize.getHeightMinMax(nWidth * jQuery.iResize.resizeElement.resizeOptions.ratio);
            nWidth = nHeight / jQuery.iResize.resizeElement.resizeOptions.ratio;

            switch (jQuery.iResize.resizeDirection){
                case 'n':
                case 'nw':
                case 'ne':
                    newPosition.top += newSizes.height - nHeight;
                break;
            }

            switch (jQuery.iResize.resizeDirection){
                case 'nw':
                case 'w':
                case 'sw':
                    newPosition.left += newSizes.width - nWidth;
                break;
            }

            newSizes.height = nHeight;
            newSizes.width = nWidth;
        }

        if (newPosition.top < jQuery.iResize.resizeElement.resizeOptions.minTop) {
            nHeight = newSizes.height + newPosition.top - jQuery.iResize.resizeElement.resizeOptions.minTop;
            newPosition.top = jQuery.iResize.resizeElement.resizeOptions.minTop;

            if (jQuery.iResize.resizeElement.resizeOptions.ratio) {
                nWidth = nHeight / jQuery.iResize.resizeElement.resizeOptions.ratio;
                switch (jQuery.iResize.resizeDirection){
                    case 'nw':
                    case 'w':
                    case 'sw':
                        newPosition.left += newSizes.width - nWidth;
                    break;
                }
                newSizes.width = nWidth;
            }
            newSizes.height = nHeight;
        }

        if (newPosition.left < jQuery.iResize.resizeElement.resizeOptions.minLeft ) {
            nWidth = newSizes.width + newPosition.left - jQuery.iResize.resizeElement.resizeOptions.minLeft;
            newPosition.left = jQuery.iResize.resizeElement.resizeOptions.minLeft;

            if (jQuery.iResize.resizeElement.resizeOptions.ratio) {
                nHeight = nWidth * jQuery.iResize.resizeElement.resizeOptions.ratio;
                switch (jQuery.iResize.resizeDirection){
                    case 'n':
                    case 'nw':
                    case 'ne':
                        newPosition.top += newSizes.height - nHeight;
                    break;
                }
                newSizes.height = nHeight;
            }
            newSizes.width = nWidth;
        }

        if (newPosition.top + newSizes.height > jQuery.iResize.resizeElement.resizeOptions.maxBottom) {
            newSizes.height = jQuery.iResize.resizeElement.resizeOptions.maxBottom - newPosition.top;
            if (jQuery.iResize.resizeElement.resizeOptions.ratio) {
                newSizes.width = newSizes.height / jQuery.iResize.resizeElement.resizeOptions.ratio;
            }

        }

        if (newPosition.left + newSizes.width > jQuery.iResize.resizeElement.resizeOptions.maxRight) {
            newSizes.width = jQuery.iResize.resizeElement.resizeOptions.maxRight - newPosition.left;
            if (jQuery.iResize.resizeElement.resizeOptions.ratio) {
                newSizes.height = newSizes.width * jQuery.iResize.resizeElement.resizeOptions.ratio;
            }

        }

        var newDimensions = false;
        if (jQuery.iResize.resizeElement.resizeOptions.onResize) {
            newDimensions = jQuery.iResize.resizeElement.resizeOptions.onResize.apply( jQuery.iResize.resizeElement, [ newSizes, newPosition ] );
            if (newDimensions) {
                if (newDimensions.sizes) {
                    jQuery.extend(newSizes, newDimensions.sizes);
                }

                if (newDimensions.position) {
                    jQuery.extend(newPosition, newDimensions.position);
                }
            }
        }
            elS = jQuery.iResize.resizeElement.style;
            elS.left = newPosition.left + 'px';
            elS.top = newPosition.top + 'px';
            elS.width = newSizes.width + 'px';
            elS.height = newSizes.height + 'px';

        return false;
    },
    /**
     * Builds the resizable
     */
    build: function(options) {
        if (!options || !options.handlers || options.handlers.constructor != Object) {
            return;
        }

        return this.each(
            function() {
                var el = this;
                el.resizeOptions = options;
                el.resizeOptions.minWidth = options.minWidth || 10;
                el.resizeOptions.minHeight = options.minHeight || 10;
                el.resizeOptions.maxWidth = options.maxWidth || 3000;
                el.resizeOptions.maxHeight = options.maxHeight || 3000;
                el.resizeOptions.minTop = options.minTop || -1000;
                el.resizeOptions.minLeft = options.minLeft || -1000;
                el.resizeOptions.maxRight = options.maxRight || 3000;
                el.resizeOptions.maxBottom = options.maxBottom || 3000;
                elPosition = jQuery(el).css('position');
                if (!(elPosition == 'relative' || elPosition == 'absolute')) {
                    el.style.position = 'relative';
                }

                directions = /n|ne|e|se|s|sw|w|nw/g;
                for (i in el.resizeOptions.handlers) {
                    if (i.toLowerCase().match(directions) != null) {
                        if (el.resizeOptions.handlers[i].constructor == String) {
                            handle = jQuery(el.resizeOptions.handlers[i]);
                            if (handle.size() > 0) {
                                el.resizeOptions.handlers[i] = handle.get(0);
                            }
                        }

                        if (el.resizeOptions.handlers[i].tagName) {
                            el.resizeOptions.handlers[i].resizeElement = el;
                            el.resizeOptions.handlers[i].resizeDirection = i;
                            jQuery(el.resizeOptions.handlers[i]).bind('mousedown', jQuery.iResize.start);
                        }
                    }
                }

                if (el.resizeOptions.dragHandle) {
                    if (typeof el.resizeOptions.dragHandle === 'string') {
                        handleEl = jQuery(el.resizeOptions.dragHandle);
                        if (handleEl.size() > 0) {
                            handleEl.each(function() {
                                    this.dragEl = el;
                                });
                            handleEl.bind('mousedown', jQuery.iResize.startDrag);
                        }
                    } else if (el.resizeOptions.dragHandle == true) {
                        jQuery(this).bind('mousedown', jQuery.iResize.startDrag);
                    }
                }
            }
        );
    },
    /**
     * Destroys the resizable
     */
    destroy: function() {
        return this.each(
            function() {
                var el = this;

                // Unbind the handlers
                for (i in el.resizeOptions.handlers) {
                    el.resizeOptions.handlers[i].resizeElement = null;
                    el.resizeOptions.handlers[i].resizeDirection = null;
                    jQuery(el.resizeOptions.handlers[i]).unbind('mousedown', jQuery.iResize.start);
                }

                // Remove the draghandle
                if (el.resizeOptions.dragHandle) {
                    if (typeof el.resizeOptions.dragHandle === 'string') {
                        handle = jQuery(el.resizeOptions.dragHandle);
                        if (handle.size() > 0) {
                            handle.unbind('mousedown', jQuery.iResize.startDrag);
                        }
                    } else if (el.resizeOptions.dragHandle == true) {
                        jQuery(this).unbind('mousedown', jQuery.iResize.startDrag);
                    }
                }

                // Reset the options
                el.resizeOptions = null;
            }
        );
    }
};


jQuery.fn.extend ({
        /**
         * Create a resizable element with a number of advanced options including callback, dragging
         * 
         * @name Resizable
         * @description Create a resizable element with a number of advanced options including callback, dragging
         * @param Hash hash A hash of parameters. All parameters are optional.
         * @option Hash handlers hash with keys for each resize direction (e, es, s, sw, w, nw, n) and value string selection
         * @option Integer minWidth (optional) the minimum width that element can be resized to
         * @option Integer maxWidth (optional) the maximum width that element can be resized to
         * @option Integer minHeight (optional) the minimum height that element can be resized to
         * @option Integer maxHeight (optional) the maximum height that element can be resized to
         * @option Integer minTop (optional) the minmum top position to wich element can be moved to
         * @option Integer minLeft (optional) the minmum left position to wich element can be moved to
         * @option Integer maxRight (optional) the maximum right position to wich element can be moved to
         * @option Integer maxBottom (optional) the maximum bottom position to wich element can be moved to
         * @option Float ratio (optional) the ratio between width and height to constrain elements sizes to that ratio
         * @option Mixed dragHandle (optional) true to make the element draggable, string selection for drag handle
         * @option Function onDragStart (optional) A function to be executed whenever the dragging starts
         * @option Function onDragStop (optional) A function to be executed whenever the dragging stops
         * @option Function onDrag (optional) A function to be executed whenever the element is dragged
         * @option Function onStart (optional) A function to be executed whenever the element starts to be resized
         * @option Function onStop (optional) A function to be executed whenever the element stops to be resized
         * @option Function onResize (optional) A function to be executed whenever the element is resized
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        Resizable: jQuery.iResize.build,
        /**
         * Destroy a resizable
         * 
         * @name ResizableDestroy
         * @description Destroy a resizable
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        ResizableDestroy: jQuery.iResize.destroy
    });/**
 * 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.
 *
 *
 */

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));
    //
    // 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');
        }
    );
};/**
 * Interface Elements for jQuery
 * Slider
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

jQuery.iSlider = {
    tabindex : 1,
    set : function (values)
    {
        var values = values;
        return this.each(
            function()
            {
                this.slideCfg.sliders.each(
                    function (key) 
                    { 
                        jQuery.iSlider.dragmoveBy(this,values[key]);
                    }
                );
            }
        );
    },
    
    get : function()
    {
        var values = [];
        this.each(
            function(slider)
            {
                if (this.isSlider) {
                    values[slider] = [];
                    var elm = this;
                    var sizes = jQuery.iUtil.getSize(this);
                    this.slideCfg.sliders.each(
                        function (key) 
                        {
                            var x = this.offsetLeft;
                            var y = this.offsetTop;
                            xproc = parseInt(x * 100 / (sizes.w - this.offsetWidth));
                            yproc = parseInt(y * 100 / (sizes.h - this.offsetHeight));
                            values[slider][key] = [xproc||0, yproc||0, x||0, y||0];
                        }
                    );
                }
            }
        );
        return values;
    },
    
    modifyContainer : function (elm)
    {
        elm.dragCfg.containerMaxx = elm.dragCfg.cont.w - elm.dragCfg.oC.wb;
        elm.dragCfg.containerMaxy = elm.dragCfg.cont.h - elm.dragCfg.oC.hb;
        if (elm.SliderContainer.slideCfg.restricted ) {
            next = elm.SliderContainer.slideCfg.sliders.get(elm.SliderIteration+1);
            if (next) {
                elm.dragCfg.cont.w = (parseInt(jQuery(next).css('left'))||0) + elm.dragCfg.oC.wb;
                elm.dragCfg.cont.h = (parseInt(jQuery(next).css('top'))||0) + elm.dragCfg.oC.hb;
            }
            prev = elm.SliderContainer.slideCfg.sliders.get(elm.SliderIteration-1);
            if (prev) {
                var prevLeft = parseInt(jQuery(prev).css('left'))||0;
                var prevTop = parseInt(jQuery(prev).css('left'))||0;
                elm.dragCfg.cont.x += prevLeft;
                elm.dragCfg.cont.y += prevTop;
                elm.dragCfg.cont.w -= prevLeft;
                elm.dragCfg.cont.h -= prevTop;
            }
        }
        elm.dragCfg.maxx = elm.dragCfg.cont.w - elm.dragCfg.oC.wb;
        elm.dragCfg.maxy = elm.dragCfg.cont.h - elm.dragCfg.oC.hb;
        if(elm.dragCfg.fractions) {
            elm.dragCfg.gx = ((elm.dragCfg.cont.w - elm.dragCfg.oC.wb)/elm.dragCfg.fractions) || 1;
            elm.dragCfg.gy = ((elm.dragCfg.cont.h - elm.dragCfg.oC.hb)/elm.dragCfg.fractions) || 1;
            elm.dragCfg.fracW = elm.dragCfg.maxx / elm.dragCfg.fractions;
            elm.dragCfg.fracH = elm.dragCfg.maxy / elm.dragCfg.fractions;
        }
        
        elm.dragCfg.cont.dx = elm.dragCfg.cont.x - elm.dragCfg.oR.x;
        elm.dragCfg.cont.dy = elm.dragCfg.cont.y - elm.dragCfg.oR.y;
        
        jQuery.iDrag.helper.css('cursor', 'default');
    },
    
    onSlide : function(elm, x, y)
    {
        if (elm.dragCfg.fractions) {
                xfrac = parseInt(x/elm.dragCfg.fracW);
                xproc = xfrac * 100 / elm.dragCfg.fractions;
                yfrac = parseInt(y/elm.dragCfg.fracH);
                yproc = yfrac * 100 / elm.dragCfg.fractions;
        } else {
            xproc = parseInt(x * 100 / elm.dragCfg.containerMaxx);
            yproc = parseInt(y * 100 / elm.dragCfg.containerMaxy);
        }
        elm.dragCfg.lastSi = [xproc||0, yproc||0, x||0, y||0];
        if (elm.dragCfg.onSlide)
            elm.dragCfg.onSlide.apply(elm, elm.dragCfg.lastSi);
    },
    
    dragmoveByKey : function (event)
    {
        pressedKey = event.charCode || event.keyCode || -1;
        
        switch (pressedKey)
        {
            //end
            case 35:
                jQuery.iSlider.dragmoveBy(this.dragElem, [2000, 2000] );
            break;
            //home
            case 36:
                jQuery.iSlider.dragmoveBy(this.dragElem, [-2000, -2000] );
            break;
            //left
            case 37:
                jQuery.iSlider.dragmoveBy(this.dragElem, [-this.dragElem.dragCfg.gx||-1, 0] );
            break;
            //up
            case 38:
                jQuery.iSlider.dragmoveBy(this.dragElem, [0, -this.dragElem.dragCfg.gy||-1] );
            break;
            //right
            case 39:
                jQuery.iSlider.dragmoveBy(this.dragElem, [this.dragElem.dragCfg.gx||1, 0] );
            break;
            //down;
            case 40:
                jQuery.iDrag.dragmoveBy(this.dragElem, [0, this.dragElem.dragCfg.gy||1] );
            break;
        }
    },
    
    dragmoveBy : function (elm, position) 
    {
        if (!elm.dragCfg) {
            return;
        }
        
        elm.dragCfg.oC = jQuery.extend(
            jQuery.iUtil.getPosition(elm),
            jQuery.iUtil.getSize(elm)
        );
        
        elm.dragCfg.oR = {
            x : parseInt(jQuery.css(elm, 'left'))||0,
            y : parseInt(jQuery.css(elm, 'top'))||0
        };
        
        elm.dragCfg.oP = jQuery.css(elm, 'position');
        if (elm.dragCfg.oP != 'relative' && elm.dragCfg.oP != 'absolute') {
            elm.style.position = 'relative';
        }
        
        jQuery.iDrag.getContainment(elm);
        jQuery.iSlider.modifyContainer(elm);        
        
        dx = parseInt(position[0]) || 0;
        dy = parseInt(position[1]) || 0;
        
        nx = elm.dragCfg.oR.x + dx;
        ny = elm.dragCfg.oR.y + dy;
        if(elm.dragCfg.fractions) {
            newCoords = jQuery.iDrag.snapToGrid.apply(elm, [nx, ny, dx, dy]);
            if (newCoords.constructor == Object) {
                dx = newCoords.dx;
                dy = newCoords.dy;
            }
            nx = elm.dragCfg.oR.x + dx;
            ny = elm.dragCfg.oR.y + dy;
        }
        
        newCoords = jQuery.iDrag.fitToContainer.apply(elm, [nx, ny, dx, dy]);
        if (newCoords && newCoords.constructor == Object) {
            dx = newCoords.dx;
            dy = newCoords.dy;
        }
        
        nx = elm.dragCfg.oR.x + dx;
        ny = elm.dragCfg.oR.y + dy;
        
        if (elm.dragCfg.si && (elm.dragCfg.onSlide || elm.dragCfg.onChange)) {
            jQuery.iSlider.onSlide(elm, nx, ny);
        }
        nx = !elm.dragCfg.axis || elm.dragCfg.axis == 'horizontally' ? nx : elm.dragCfg.oR.x||0;
        ny = !elm.dragCfg.axis || elm.dragCfg.axis == 'vertically' ? ny : elm.dragCfg.oR.y||0;
        elm.style.left = nx + 'px';
        elm.style.top = ny + 'px';
    },
    
    build : function(o) {
        return this.each(
            function()
            {
                if (this.isSlider == true || !o.accept || !jQuery.iUtil || !jQuery.iDrag || !jQuery.iDrop){
                    return;
                }
                toDrag = jQuery(o.accept, this);
                if (toDrag.size() == 0) {
                    return;
                }
                var params = {
                    containment: 'parent',
                    si : true,
                    onSlide : o.onSlide && o.onSlide.constructor == Function ? o.onSlide : null,
                    onChange : o.onChange && o.onChange.constructor == Function ? o.onChange : null,
                    handle: this,
                    opacity: o.opacity||false
                };
                if (o.fractions && parseInt(o.fractions)) {
                    params.fractions = parseInt(o.fractions)||1;
                    params.fractions = params.fractions > 0 ? params.fractions : 1;
                }
                if (toDrag.size() == 1)
                    toDrag.Draggable(params);
                else {
                    jQuery(toDrag.get(0)).Draggable(params);
                    params.handle = null;
                    toDrag.Draggable(params);
                }
                toDrag.keydown(jQuery.iSlider.dragmoveByKey);
                toDrag.attr('tabindex',jQuery.iSlider.tabindex++);    
                
                this.isSlider = true;
                this.slideCfg = {};
                this.slideCfg.onslide = params.onslide;
                this.slideCfg.fractions = params.fractions;
                this.slideCfg.sliders = toDrag;
                this.slideCfg.restricted = o.restricted ? true : false;
                sliderEl = this;
                sliderEl.slideCfg.sliders.each(
                    function(nr)
                    {
                        this.SliderIteration = nr;
                        this.SliderContainer = sliderEl;
                    }
                );
                if (o.values && o.values.constructor == Array) {
                    for (i = o.values.length -1; i>=0;i--) {
                        if (o.values[i].constructor == Array && o.values[i].length == 2) {
                            el = this.slideCfg.sliders.get(i);
                            if (el.tagName) {
                                jQuery.iSlider.dragmoveBy(el, o.values[i]);
                            }
                        }
                    }
                }
            }
        );
    }
};
jQuery.fn.extend(
    {
        /**
         * Create a slider width options
         * 
         * @name Slider
         * @description Create a slider width options
         * @param Hash hash A hash of parameters. All parameters are optional.
         * @option Mixed accepts string to select slider indicators or DOMElement slider indicator
         * @option Integer factions (optional) number of sgments to divide and snap slider
         * @option Function onSlide (optional) A function to be executed whenever slider indicator it is moved
         * @option Function onChanged (optional) A function to be executed whenever slider indicator was moved
         * @option Array values (optional) Initial values for slider indicators
         * @option Boolean restricted (optional) if true the slider indicator can not be moved beyond adjacent indicators
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        Slider : jQuery.iSlider.build,
        /**
         * Set value/position for slider indicators
         * 
         * @name SliderSetValues
         * @description Set value/position for slider indicators
         * @param Array values array width values for each indicator
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SliderSetValues : jQuery.iSlider.set,
        /**
         * Get value/position for slider indicators
         * 
         * @name SliderSetValues
         * @description Get value/position for slider indicators
         * @type jQuery
         * @cat Plugins/Interface
         * @author Stefan Petre
         */
        SliderGetValues : jQuery.iSlider.get
    }
);/**
 * Interface Elements for jQuery
 * Sortables
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Allows you to resort elements within a container by dragging and dropping. Requires
 * the Draggables and Droppables plugins. The container and each item inside the container
 * must have an ID. Sortables are especially useful for lists.
 * 
 * @see Plugins/Interface/Draggable
 * @see Plugins/Interface/Droppable
 * @author Stefan Petre
 * @name Sortable
 * @cat Plugins/Interface
 * @param Hash options        A hash of options
 * @option String accept      The class name for items inside the container (mandatory)
 * @option String activeclass The class for the container when one of its items has started to move
 * @option String hoverclass  The class for the container when an acceptable item is inside it
 * @option String helperclass The helper is used to point to the place where the item will be 
 *                            moved. This is the class for the helper.
 * @option Float opacity      Opacity (between 0 and 1) of the item while being dragged
 * @option Boolean ghosting   When true, the sortable is ghosted when dragged
 * @option String tolerance   Either 'pointer', 'intersect', or 'fit'. See Droppable for more details
 * @option Boolean fit        When true, sortable must be inside the container in order to drop
 * @option Integer fx         Duration for the effect applied to the sortable
 * @option Function onchange  Callback that gets called when the sortable list changed. It takes
 *                            an array of serialized elements
 * @option Boolean floats     True if the sorted elements are floated
 * @option String containment Use 'parent' to constrain the drag to the container
 * @option String axis        Use 'horizontally' or 'vertically' to constrain dragging to an axis
 * @option String handle      The jQuery selector that indicates the draggable handle
 * @option DOMElement handle  The node that indicates the draggable handle
 * @option Function onHover   Callback that is called when an acceptable item is dragged over the
 *                            container. Gets the hovering DOMElement as a parameter
 * @option Function onOut     Callback that is called when an acceptable item leaves the container.
 *                            Gets the leaving DOMElement as a parameter
 * @option Object cursorAt    The mouse cursor will be moved to the offset on the dragged item
 *                            indicated by the object, which takes "top", "bottom", "left", and
 *                            "right" keys
 * @option Function onStart   Callback function triggered when the dragging starts
 * @option Function onStop    Callback function triggered when the dragging stops
 * @example                   $('ul').Sortable(
 *                                {
 *                                    accept : 'sortableitem',
 *                                    activeclass : 'sortableactive',
 *                                     hoverclass : 'sortablehover',
 *                                     helperclass : 'sorthelper',
 *                                     opacity:     0.5,
 *                                     fit :    false
 *                                 }
 *                             )
 */

jQuery.iSort = {
    changed : [],
    collected : {},
    helper : false,
    inFrontOf: null,
    
    start : function ()
    {
        if (jQuery.iDrag.dragged == null) {
            return;
        }
        var shs, margins,c, cs;
        
        jQuery.iSort.helper.get(0).className = jQuery.iDrag.dragged.dragCfg.hpc;
        shs = jQuery.iSort.helper.get(0).style;
        shs.display = 'block';
        jQuery.iSort.helper.oC = jQuery.extend(
            jQuery.iUtil.getPosition(jQuery.iSort.helper.get(0)),
            jQuery.iUtil.getSize(jQuery.iSort.helper.get(0))
        );
        
        shs.width = jQuery.iDrag.dragged.dragCfg.oC.wb + 'px';
        shs.height = jQuery.iDrag.dragged.dragCfg.oC.hb + 'px';
        //shs.cssFloat = jQuery.iDrag.dragged.dragCfg.oF;
        margins = jQuery.iUtil.getMargins(jQuery.iDrag.dragged);
        shs.marginTop = margins.t;
        shs.marginRight = margins.r;
        shs.marginBottom = margins.b;
        shs.marginLeft = margins.l;
        if (jQuery.iDrag.dragged.dragCfg.ghosting == true) {
            c = jQuery.iDrag.dragged.cloneNode(true);
            cs = c.style;
            cs.marginTop = '0px';
            cs.marginRight = '0px';
            cs.marginBottom = '0px';
            cs.marginLeft = '0px';
            cs.display = 'block';
            jQuery.iSort.helper.empty().append(c);
        }
        jQuery(jQuery.iDrag.dragged).after(jQuery.iSort.helper.get(0));
        jQuery.iDrag.dragged.style.display = 'none';
    },
    
    check : function (e)
    {
        if (!e.dragCfg.so && jQuery.iDrop.overzone.sortable) {
            if (e.dragCfg.onStop)
                e.dragCfg.onStop.apply(dragged);
            jQuery(e).css('position', e.dragCfg.initialPosition || e.dragCfg.oP);
            jQuery(e).DraggableDestroy();
            jQuery(jQuery.iDrop.overzone).SortableAddItem(e);
        }
        jQuery.iSort.helper.removeClass(e.dragCfg.hpc).html('&nbsp;');
        jQuery.iSort.inFrontOf = null;
        var shs = jQuery.iSort.helper.get(0).style;
        shs.display = 'none';
        jQuery.iSort.helper.after(e);
        if (e.dragCfg.fx > 0) {
            jQuery(e).fadeIn(e.dragCfg.fx);
        }
        jQuery('body').append(jQuery.iSort.helper.get(0));
        var ts = [];
        var fnc = false;
        for(var i=0; i<jQuery.iSort.changed.length; i++){
            var iEL = jQuery.iDrop.zones[jQuery.iSort.changed[i]].get(0);
            var id = jQuery.attr(iEL, 'id');
            var ser = jQuery.iSort.serialize(id);
            if (iEL.dropCfg.os != ser.hash) {
                iEL.dropCfg.os = ser.hash;
                if (fnc == false && iEL.dropCfg.onChange) {
                    fnc = iEL.dropCfg.onChange;
                }
                ser.id = id;
                ts[ts.length] = ser;
            }
        }
        jQuery.iSort.changed = [];
        if (fnc != false && ts.length > 0) {
            fnc(ts);
        }
    },
    
    checkhover : function(e,o)
    {
        if (!jQuery.iDrag.dragged)
            return;
        var cur = false;
        var i = 0;
        if ( e.dropCfg.el.size() > 0) {
            for (i = e.dropCfg.el.size(); i >0; i--) {
                if (e.dropCfg.el.get(i-1) != jQuery.iDrag.dragged) {
                    if (!e.sortCfg.floats) {
                        if ( 
                        (e.dropCfg.el.get(i-1).pos.y + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny  
                        ) {
                            cur = e.dropCfg.el.get(i-1);
                        } else {
                            break;
                        }
                    } else {
                        if (
                        (e.dropCfg.el.get(i-1).pos.x + e.dropCfg.el.get(i-1).pos.wb/2) > jQuery.iDrag.dragged.dragCfg.nx && 
                        (e.dropCfg.el.get(i-1).pos.y + e.dropCfg.el.get(i-1).pos.hb/2) > jQuery.iDrag.dragged.dragCfg.ny  
                        ) {
                            cur = e.dropCfg.el.get(i-1);
                        }
                    }
                }
            }
        }
        //helpos = jQuery.iUtil.getPos(jQuery.iSort.helper.get(0));
        if (cur && jQuery.iSort.inFrontOf != cur) {
            jQuery.iSort.inFrontOf = cur;
            jQuery(cur).before(jQuery.iSort.helper.get(0));
        } else if(!cur && (jQuery.iSort.inFrontOf != null || jQuery.iSort.helper.get(0).parentNode != e) ) {
            jQuery.iSort.inFrontOf = null;
            jQuery(e).append(jQuery.iSort.helper.get(0));
        }
        jQuery.iSort.helper.get(0).style.display = 'block';
    },
    
    measure : function (e)
    {
        if (jQuery.iDrag.dragged == null) {
            return;
        }
        e.dropCfg.el.each (
            function ()
            {
                this.pos = jQuery.extend(
                    jQuery.iUtil.getSizeLite(this),
                    jQuery.iUtil.getPositionLite(this)
                );
            }
        );
    },
    
    serialize : function(s)
    {
        var i;
        var h = '';
        var o = {};
        if (s) {
            if (jQuery.iSort.collected[s] ) {
                o[s] = [];
                jQuery('#' + s + ' .' + jQuery.iSort.collected[s]).each(
                    function ()
                    {
                        if (h.length > 0) {
                            h += '&';
                        }
                        h += s + '[]=' + jQuery.attr(this,'id');
                        o[s][o[s].length] = jQuery.attr(this,'id');
                    }
                );
            } else {
                for ( a in s) {
                    if (jQuery.iSort.collected[s[a]] ) {
                        o[s[a]] = [];            
                        jQuery('#' + s[a] + ' .' + jQuery.iSort.collected[s[a]]).each(
                            function ()
                            {
                                if (h.length > 0) {
                                    h += '&';
                                }
                                h += s[a] + '[]=' + jQuery.attr(this,'id');
                                o[s[a]][o[s[a]].length] = jQuery.attr(this,'id');
                            }
                        );
                    }
                }
            }
        } else {
            for ( i in jQuery.iSort.collected){
                o[i] = [];
                jQuery('#' + i + ' .' + jQuery.iSort.collected[i]).each(
                    function ()
                    {
                        if (h.length > 0) {
                            h += '&';
                        }
                        h += i + '[]=' + jQuery.attr(this,'id');
                        o[i][o[i].length] = jQuery.attr(this,'id');
                    }
                );
            }
        }
        return {hash:h, o:o};
    },
    
    addItem : function (e)
    {
        if ( !e.childNodes ) {
            return;
        }
        return this.each(
            function ()
            {
                if(!this.sortCfg || !jQuery(e).is('.' +  this.sortCfg.accept))
                    jQuery(e).addClass(this.sortCfg.accept);
                jQuery(e).Draggable(this.sortCfg.dragCfg);
            }
        );
    },
    
    destroy: function()
    {
        return this.each(
            function()
            {
                jQuery('.' + this.sortCfg.accept).DraggableDestroy();
                jQuery(this).DroppableDestroy();
                this.sortCfg = null;
                this.isSortable = null;
            }
        );
    },
    
    build : function (o)
    {
        if (o.accept && jQuery.iUtil && jQuery.iDrag && jQuery.iDrop) {
            if (!jQuery.iSort.helper) {
                jQuery('body',document).append('<div id="sortHelper">&nbsp;</div>');
                jQuery.iSort.helper = jQuery('#sortHelper');
                jQuery.iSort.helper.get(0).style.display = 'none';
            }
            this.Droppable(
                {
                    accept :  o.accept,
                    activeclass : o.activeclass ? o.activeclass : false,
                    hoverclass : o.hoverclass ? o.hoverclass : false,
                    helperclass : o.helperclass ? o.helperclass : false,
                    /*onDrop: function (drag, fx) 
                            {
                                jQuery.iSort.helper.after(drag);
                                if (fx > 0) {
                                    jQuery(drag).fadeIn(fx);
                                }
                            },*/
                    onHover: o.onHover||o.onhover,
                    onOut: o.onOut||o.onout,
                    sortable : true,
                    onChange :     o.onChange||o.onchange,
                    fx : o.fx ? o.fx : false,
                    ghosting : o.ghosting ? true : false,
                    tolerance: o.tolerance ? o.tolerance : 'intersect'
                }
            );
            
            return this.each(
                function()
                {
                    var dragCfg = {
                        revert : o.revert? true : false,
                        zindex : 3000,
                        opacity : o.opacity ? parseFloat(o.opacity) : false,
                        hpc : o.helperclass ? o.helperclass : false,
                        fx : o.fx ? o.fx : false,
                        so : true,
                        ghosting : o.ghosting ? true : false,
                        handle: o.handle ? o.handle : null,
                        containment: o.containment ? o.containment : null,
                        onStart : o.onStart && o.onStart.constructor == Function ? o.onStart : false,
                        onDrag : o.onDrag && o.onDrag.constructor == Function ? o.onDrag : false,
                        onStop : o.onStop && o.onStop.constructor == Function ? o.onStop : false,
                        axis : /vertically|horizontally/.test(o.axis) ? o.axis : false,
                        snapDistance : o.snapDistance ? parseInt(o.snapDistance)||0 : false,
                        cursorAt: o.cursorAt ? o.cursorAt : false
                    };
                    jQuery('.' + o.accept, this).Draggable(dragCfg);
                    this.isSortable = true;
                    this.sortCfg = {
                        accept :  o.accept,
                        revert : o.revert? true : false,
                        zindex : 3000,
                        opacity : o.opacity ? parseFloat(o.opacity) : false,
                        hpc : o.helperclass ? o.helperclass : false,
                        fx : o.fx ? o.fx : false,
                        so : true,
                        ghosting : o.ghosting ? true : false,
                        handle: o.handle ? o.handle : null,
                        containment: o.containment ? o.containment : null,
                        floats: o.floats ? true : false,
                        dragCfg : dragCfg
                    }
                }
            );
        }
    }
};

jQuery.fn.extend(
    {
        Sortable : jQuery.iSort.build,
        /**
         * A new item can be added to a sortable by adding it to the DOM and then adding it via
         * SortableAddItem. 
         *
         * @name SortableAddItem
         * @param DOMElement elem A DOM Element to add to the sortable list
         * @example $('#sortable1').append('<li id="newitem">new item</li>')
         *                         .SortableAddItem($("#new_item")[0])
         * @type jQuery
         * @cat Plugins/Interface
         */
        SortableAddItem : jQuery.iSort.addItem,
        /**
         * Destroy a sortable
         *
         * @name SortableDestroy
         * @example $('#sortable1').SortableDestroy();
         * @type jQuery
         * @cat Plugins/Interface
         */
        SortableDestroy: jQuery.iSort.destroy
    }
);

/**
 * This function returns the hash and an object (can be used as arguments for $.post) for every 
 * sortable in the page or specific sortables. The hash is based on the 'id' attributes of 
 * container and items.
 *
 * @params String sortable The id of the sortable to serialize
 * @name $.SortSerialize
 * @type String
 * @cat Plugins/Interface
 */

jQuery.SortSerialize = jQuery.iSort.serialize;

/**
 * Interface Elements for jQuery
 * Tooltip
 * 
 * http://interface.eyecon.ro
 * 
 * Copyright (c) 2006 Stefan Petre
 * Dual licensed under the MIT (MIT-LICENSE.txt) 
 * and GPL (GPL-LICENSE.txt) licenses.
 *   
 *
 */

/**
 * Creates tooltips using title attribute
 *
 * 
 * 
 * @name ToolTip
 * @description Creates tooltips using title attribute
 * @param Hash hash A hash of parameters
 * @option String position tooltip's position ['top'|'left'|'right'|'bottom'|'mouse']
 * @options Function onShow (optional) A function to be executed whenever the tooltip is displayed
 * @options Function onHide (optional) A function to be executed whenever the tooltip is hidden
 *
 * @type jQuery
 * @cat Plugins/Interface
 * @author Stefan Petre
 */
jQuery.iTooltip = {
    current : null,
    focused : false,
    oldTitle : null,
    focus : function(e)
    {
        jQuery.iTooltip.focused = true;
        jQuery.iTooltip.show(e, this, true);
    },
    hidefocused : function(e)
    {
        if (jQuery.iTooltip.current != this)
            return ;
        jQuery.iTooltip.focused = false;
        jQuery.iTooltip.hide(e, this);
    },
    show : function(e, el, focused)
    {
        if (jQuery.iTooltip.current != null)
            return ;
        if (!el) {
            el = this;
        }
        
        jQuery.iTooltip.current = el;
        pos = jQuery.extend(
            jQuery.iUtil.getPosition(el),
            jQuery.iUtil.getSize(el)
        );
        jEl = jQuery(el);
        title = jEl.attr('title');
        href = jEl.attr('href');
        if (title) {
            jQuery.iTooltip.oldTitle = title;
            jEl.attr('title','');
            // JMB Software
            // Added call to escapeHTML
            jQuery('#tooltipTitle').html(escapeHTML(title));
            if (href)
                jQuery('#tooltipURL').html(href.replace('http://', ''));
            else 
                jQuery('#tooltipURL').html('');
            helper = jQuery('#tooltipHelper');
            if(el.tooltipCFG.className){
                helper.get(0).className = el.tooltipCFG.className;
            } else {
                helper.get(0).className = '';
            }
            helperSize = jQuery.iUtil.getSize(helper.get(0));
            filteredPosition = focused && el.tooltipCFG.position == 'mouse' ? 'bottom' : el.tooltipCFG.position;
            
            switch (filteredPosition) {
                case 'top':
                    ny = pos.y - helperSize.hb;
                    nx = pos.x;
                break;
                case 'left' :
                    ny = pos.y;
                    nx = pos.x - helperSize.wb;
                break;
                case 'right' :
                    ny = pos.y;
                    nx = pos.x + pos.wb;
                break;
                case 'mouse' :
                    jQuery('body').bind('mousemove', jQuery.iTooltip.mousemove);
                    pointer = jQuery.iUtil.getPointer(e);
                    ny = pointer.y + 15;
                    nx = pointer.x + 15;
                break;
                default :
                    ny = pos.y + pos.hb;
                    nx = pos.x;
                break;
            }
            helper.css(
                {
                    top     : ny + 'px',
                    left    : nx + 'px'
                }
            );
            if (el.tooltipCFG.delay == false) {
                helper.show();
            } else {
                helper.fadeIn(el.tooltipCFG.delay);
            }
            if (el.tooltipCFG.onShow) 
                el.tooltipCFG.onShow.apply(el);
            jEl.bind('mouseout',jQuery.iTooltip.hide)
               .bind('blur',jQuery.iTooltip.hidefocused);
        }
    },
    mousemove : function(e)
    {
        if (jQuery.iTooltip.current == null) {
            jQuery('body').unbind('mousemove', jQuery.iTooltip.mousemove);
            return;    
        }
        pointer = jQuery.iUtil.getPointer(e);
        jQuery('#tooltipHelper').css(
            {
                top     : pointer.y + 15 + 'px',
                left    : pointer.x + 15 + 'px'
            }
        );
    },
    hide : function(e, el)
    {
        if (!el) {
            el = this;
        }
        if (jQuery.iTooltip.focused != true && jQuery.iTooltip.current == el) {
            jQuery.iTooltip.current = null;
            jQuery('#tooltipHelper').fadeOut(1);
            jQuery(el)
                .attr('title',jQuery.iTooltip.oldTitle)
                .unbind('mouseout', jQuery.iTooltip.hide)
                .unbind('blur', jQuery.iTooltip.hidefocused);
            if (el.tooltipCFG.onHide) 
                el.tooltipCFG.onHide.apply(el);
            jQuery.iTooltip.oldTitle = null;
        }
    },
    build : function(options)
    {
        if (!jQuery.iTooltip.helper)
        {
            jQuery('body').append('<div id="tooltipHelper"><div id="tooltipTitle"></div><div id="tooltipURL"></div></div>');
            jQuery('#tooltipHelper').css(
                {
                    position:    'absolute',
                    zIndex:        3000,
                    display:     'none'
                }
            );
            jQuery.iTooltip.helper = true;
        }
        return this.each(
            function(){
                if(jQuery.attr(this,'title')) {
                    this.tooltipCFG = {
                        position    : /top|bottom|left|right|mouse/.test(options.position) ? options.position : 'bottom',
                        className    : options.className ? options.className : false,
                        delay        : options.delay ? options.delay : false,
                        onShow        : options.onShow && options.onShow.constructor == Function ? options.onShow : false,
                        onHide        : options.onHide && options.onHide.constructor == Function ? options.onHide : false
                    };
                    var el = jQuery(this);
                    el.bind('mouseover',jQuery.iTooltip.show);
                    el.bind('focus',jQuery.iTooltip.focus);
                }
            }
        );
    }
};

jQuery.fn.ToolTip = jQuery.iTooltip.build;/**
 * 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.
 *
 *
 */

jQuery.iUtil = {
    getPosition : function(e)
    {
        var x = 0;
        var y = 0;
        var es = e.style;
        var restoreStyles = false;
        if (jQuery(e).css('display') == 'none') {
            var oldVisibility = es.visibility;
            var oldPosition = es.position;
            restoreStyles = true;
            es.visibility = 'hidden';
            es.display = 'block';
            es.position = 'absolute';
        }
        var el = e;
        while (el){
            x += el.offsetLeft + (el.currentStyle && !jQuery.browser.opera ?parseInt(el.currentStyle.borderLeftWidth)||0:0);
            y += el.offsetTop + (el.currentStyle && !jQuery.browser.opera ?parseInt(el.currentStyle.borderTopWidth)||0:0);
            el = el.offsetParent;
        }
        el = e;
        while (el && el.tagName  && el.tagName.toLowerCase() != 'body')
        {
            x -= el.scrollLeft||0;
            y -= el.scrollTop||0;
            el = el.parentNode;
        }
        if (restoreStyles == true) {
            es.display = 'none';
            es.position = oldPosition;
            es.visibility = oldVisibility;
        }
        return {x:x, y:y};
    },
    getPositionLite : function(el)
    {
        var x = 0, y = 0;
        while(el) {
            x += el.offsetLeft || 0;
            y += el.offsetTop || 0;
            el = el.offsetParent;
        }
        return {x:x, y:y};
    },
    getSize : function(e)
    {
        var w = jQuery.css(e,'width');
        var h = jQuery.css(e,'height');
        var wb = 0;
        var hb = 0;
        var es = e.style;
        if (jQuery(e).css('display') != 'none') {
            wb = e.offsetWidth;
            hb = e.offsetHeight;
        } else {
            var oldVisibility = es.visibility;
            var oldPosition = es.position;
            es.visibility = 'hidden';
            es.display = 'block';
            es.position = 'absolute';
            wb = e.offsetWidth;
            hb = e.offsetHeight;
            es.display = 'none';
            es.position = oldPosition;
            es.visibility = oldVisibility;
        }
        return {w:w, h:h, wb:wb, hb:hb};
    },
    getSizeLite : function(el)
    {
        return {
            wb:el.offsetWidth||0,
            hb:el.offsetHeight||0
        };
    },
    getClient : function(e)
    {
        var h, w, de;
        if (e) {
            w = e.clientWidth;
            h = e.clientHeight;
        } else {
            de = document.documentElement;
            w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
            h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
        }
        return {w:w,h:h};
    },
    getScroll : function (e)
    {
        var t=0, l=0, w=0, h=0, iw=0, ih=0;
        if (e && e.nodeName.toLowerCase() != 'body') {
            t = e.scrollTop;
            l = e.scrollLeft;
            w = e.scrollWidth;
            h = e.scrollHeight;
            iw = 0;
            ih = 0;
        } else  {
            // JMB Software edit:
            // Added != undefined to allow dimensions to be gathered when scrollTop is defined but 0
            if (document.documentElement && document.documentElement.scrollTop != undefined) {
                t = document.documentElement.scrollTop;
                l = document.documentElement.scrollLeft;
                w = document.documentElement.scrollWidth;
                h = document.documentElement.scrollHeight;
            }
            else if (document.body) {
                t = document.body.scrollTop;
                l = document.body.scrollLeft;
                w = document.body.scrollWidth;
                h = document.body.scrollHeight;
            }
            iw = self.innerWidth||document.documentElement.clientWidth||document.body.clientWidth||0;
            ih = self.innerHeight||document.documentElement.clientHeight||document.body.clientHeight||0;
        }
        return { t: t, l: l, w: w, h: h, iw: iw, ih: ih };
    },
    getMargins : function(e, toInteger)
    {
        var el = jQuery(e);
        var t = el.css('marginTop') || '';
        var r = el.css('marginRight') || '';
        var b = el.css('marginBottom') || '';
        var l = el.css('marginLeft') || '';
        if (toInteger)
            return {
                t: parseInt(t)||0,
                r: parseInt(r)||0,
                b: parseInt(b)||0,
                l: parseInt(l)
            };
        else
            return {t: t, r: r,    b: b, l: l};
    },
    getPadding : function(e, toInteger)
    {
        var el = jQuery(e);
        var t = el.css('paddingTop') || '';
        var r = el.css('paddingRight') || '';
        var b = el.css('paddingBottom') || '';
        var l = el.css('paddingLeft') || '';
        if (toInteger)
            return {
                t: parseInt(t)||0,
                r: parseInt(r)||0,
                b: parseInt(b)||0,
                l: parseInt(l)
            };
        else
            return {t: t, r: r,    b: b, l: l};
    },
    getBorder : function(e, toInteger)
    {
        var el = jQuery(e);
        var t = el.css('borderTopWidth') || '';
        var r = el.css('borderRightWidth') || '';
        var b = el.css('borderBottomWidth') || '';
        var l = el.css('borderLeftWidth') || '';
        if (toInteger)
            return {
                t: parseInt(t)||0,
                r: parseInt(r)||0,
                b: parseInt(b)||0,
                l: parseInt(l)||0
            };
        else
            return {t: t, r: r,    b: b, l: l};
    },
    getPointer : function(event)
    {
        var x = event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft)) || 0;
        var y = event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) || 0;
        return {x:x, y:y};
    },
    traverseDOM : function(nodeEl, func)
    {
        func(nodeEl);
        nodeEl = nodeEl.firstChild;
        while(nodeEl){
            jQuery.iUtil.traverseDOM(nodeEl, func);
            nodeEl = nodeEl.nextSibling;
        }
    },
    purgeEvents : function(nodeEl)
    {
        jQuery.iUtil.traverseDOM(
            nodeEl,
            function(el)
            {
                for(var attr in el){
                    if(typeof el[attr] === 'function') {
                        el[attr] = null;
                    }
                }
            }
        );
    },
    // JMB Software edit:
    // Corrected to properly center elements vertically within the visible region of the page
    centerEl : function(el, axis)
    {
        var clientScroll = $.iUtil.getScroll();
        var windowSize = $.iUtil.getSize(el);
        var left = (parseInt(clientScroll.l) + (parseInt(clientScroll.iw) - parseInt(windowSize.w))/2)+"px";
        var top = (parseInt(clientScroll.t) + (parseInt(clientScroll.ih) - parseInt(windowSize.h))/2)+"px";

        if (!axis || axis == 'vertically')
            $(el).css({top: top});

        if (!axis || axis == 'horizontally')
            $(el).css({left: left});
    },
    fixPNG : function (el, emptyGIF) {
        var images = jQuery('img[@src*="png"]', el||document), png;
        images.each( function() {
            png = this.src;                
            this.src = emptyGIF;
            this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + png + "')";
        });
    }
};

// Helper function to support older browsers!
[].indexOf || (Array.prototype.indexOf = function(v, n){
    n = (n == null) ? 0 : n;
    var m = this.length;
    for (var i=n; i<m; i++)
        if (this[i] == v)
            return i;
    return -1;
});


// JMB Software
// added function
function escapeHTML(str) {
    var div = document.createElement('div');
    var text = document.createTextNode(str);
    div.appendChild(text);
    return div.innerHTML;
}


(function($) {
    
    // the tooltip element
    var helper,
        // the current tooltipped element
        current,
        // the title of the current element, used for restoring
        title,
        // position tooltip by tracking mouse
        track = true;
        
    $.fn.extend({
        Tooltip: function(settings) {
            createHelper();
            return this.each(function() {
                    this.tSettings = settings;
                })
                .bind('mouseover', save)
                .bind('mouseover', handle);
        },
        getAndSetAttr: function(name, value) {
            var result = this.attr(name);
            this.attr(name, value);
            return result;
        },
        hideWhenEmpty: function() {
            return this.each(function() {
                $(this)[ $(this).html() ? "show" : "hide" ]();
            });
        },
        url: function() {
            return this.attr('href') || this.attr('src');
        }
    });
    
    function createHelper() {
        // there can be only one tooltip helper
        if( helper )
            return;

        helper = $('<div id="tooltip"></div>').hide().appendTo('body');
    }
    
    // main event handler to start showing tooltips
    function handle(event) {        
        show();

        // if selected, update the helper position when the mouse moves
        $('body').bind('mousemove', update);
            
        // update at least once
        update(event);
        
        // hide the helper when the mouse moves out of the element
        $(this).bind('mouseout', hide);
    }
    
    // save elements title before the tooltip is displayed
    function save() {
        // if this is the current source, or it has no title (occurs with click event), stop
        if ( this == current )
            return;

        // save current
        current = this;
        title = $(this).getAndSetAttr('title', '');
        
        helper.html(escapeHTML(title));//.show();
    }
    
    // delete timeout and show helper
    function show() {
        helper.show();
        update(null);
        
    }
    
    /**
     * callback for mousemove
     * updates the helper position
     * removes itself when no current element
     */
    function update(event)    {
          
        // stop updating when tracking is disabled and the tooltip is visible
        if ( !track && helper.is(":visible")) {
            $('body').unbind('mousemove', update)
        }
        
        // if no current element is available, remove this listener
        if( current == null ) {
            $('body').unbind('mousemove', update);
            return;    
        }
  
        var left = helper[0].offsetLeft;
        var top = helper[0].offsetTop;
        if(event) {
            // position the helper 15 pixel to bottom right, starting from mouse position
            left = event.pageX + 12;
            top = event.pageY + 8;
            helper.css({
                left: left + 'px',
                top: top + 'px'
            });
        }
        
        var v = viewport();
        var h = helper[0];
        
        // check horizontal position
        if(v.x + v.cx < h.offsetLeft + h.offsetWidth) {
            left -= h.offsetWidth + 20;
            helper.css({left: left + 'px'});
        }
        
        // check vertical position
        if(v.y + v.cy < h.offsetTop + h.offsetHeight) {
            top -= h.offsetHeight + 20;
            helper.css({top: top + 'px'});
        }        
    }
    
    function viewport() {
        var e = document.documentElement || {},
            b = document.body || {},
            w = window;
        function min() {
            var v = Infinity;
            for( var i = 0;  i < arguments.length;  i++ ) {
                var n = arguments[i];
                if( n && n < v ) v = n;
            }
            return v;
        }
        return {
            x: w.pageXOffset || e.scrollLeft || b.scrollLeft || 0,
            y: w.pageYOffset || e.scrollTop || b.scrollTop || 0,
            cx: min( e.clientWidth, b.clientWidth, w.innerWidth ),
            cy: min( e.clientHeight, b.clientHeight, w.innerHeight )
        };
    }
    
    // hide helper and restore added classes and the title
    function hide(event) {
        // no more current element
        current = null;
        
        helper.hide();
        
        $(this).unbind('mouseout', hide).attr('title', title);
    }
    
    $.Tooltip = {};

})(jQuery);