function Class() { };

Class.prototype.construct = function() { };

Class.extend = function(def) {

    var classDef = function() {
        if (arguments[0] !== Class) {
            this.construct.apply(this, arguments);
        }
    };

    var proto = new this(Class);
    var superClass = this.prototype;

    for (var n in def) {
        var item = def[n];
        if (item instanceof Function) item.$ = superClass;
                else classDef[n] = item;
        proto[n] = item;
    }

    classDef.prototype = proto;
    classDef.extend = this.extend;

    return classDef;
};

function createMethodReference(object, methodName) {
    return function () {
        return object[methodName].apply(object, arguments);
    };
}

var ScrollingHandler = Class.extend({

    construct:
        function(elementId) {
            this._elementId = elementId;
            this.assignListener();
        },

    assignListener:
        function() {
            var scrollControlElem =
                        document.getElementById(this._elementId);
            if (scrollControlElem) {
                scrollControlElem.onscroll =
                    createMethodReference(this, "_onElementScroll");
            }
        },

    _onElementScroll:
        function(ev) {
            ev = ev || window.event;
            alert("please stop scrolling, I've already got an event: " + ev);
        }
});


function cloneObj(objToClone) {
    var clone = [];
    for (i in objToClone) {
        clone[i] = objToClone[i];
    }
    return clone;
}

function oc(a) {
    var o = {};
    for(var i=0;i<a.length;i++) {
        o[a[i]]='';
    }
    return o;
}

function Hash()
{
    this.length = 0;
    this.items = new Array();
    for (var i = 0; i < arguments.length; i++) {
        this.items[arguments[i][0]] = arguments[i][1];
    }
}

function getTime() {
    return new Date().getTime();
}

function getTimeDelta(timeBegin, timeEnd) {
    timeEnd = timeEnd || getTime();
    return timeEnd - timeBegin;
}

Number.prototype.NaN0=function() { return isNaN(this) ? 0 : this; }


var USER_DATA = {

    Browser: {
        KHTML: /Konqueror|KHTML/.test(navigator.userAgent) &&
                !/Apple/.test(navigator.userAgent),
        Safari: /KHTML/.test(navigator.userAgent) &&
                /Apple/.test(navigator.userAgent),
        Opera: !!window.opera,
        MSIE: !!(window.attachEvent && !window.opera),
        Gecko: /Gecko/.test(navigator.userAgent) &&
                !/Konqueror|KHTML/.test(navigator.userAgent)
    },

    OS: {
        Windows: navigator.platform.indexOf("Win") > -1,
        Mac: navigator.platform.indexOf("Mac") > -1,
        Linux: navigator.platform.indexOf("Linux") > -1
    }
}


var IS_IE = USER_DATA['Browser'].MSIE;

function getPosition(e){
    var left = 0;
    var top  = 0;

    while (e.offsetParent) {
        left += e.offsetLeft + (e.currentStyle ?
            (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
        top  += e.offsetTop  + (e.currentStyle ?
            (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
        e = e.offsetParent;
    }

    left += e.offsetLeft + (e.currentStyle ?
            (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
    top  += e.offsetTop  + (e.currentStyle ?
            (parseInt(e.currentStyle.borderTopWidth)).NaN0(): 0); 	

    return {x:left, y:top};
}

function getAlignedPosition(e) {
    var left = 0;
    var top  = 0;

    while (e.offsetParent) {
        left += e.offsetLeft + (e.currentStyle ?
            (parseInt(e.currentStyle.borderLeftWidth)).NaN0() : 0);
        top  += e.offsetTop  + (e.currentStyle ?
            (parseInt(e.currentStyle.borderTopWidth)).NaN0() : 0);
        e  = e.offsetParent;
        if (e.scrollLeft) {left -= e.scrollLeft; }
        if (e.scrollTop)  {top  -= e.scrollTop; }
    }

    var docBody = document.documentElement ?
        document.documentElement : document.body;

    left += e.offsetLeft +
        (e.currentStyle ?
                (parseInt(e.currentStyle.borderLeftWidth)).NaN0()
                : 0) +
        (IS_IE ? (parseInt(docBody.scrollLeft)).NaN0() : 0) -
        (parseInt(docBody.clientLeft)).NaN0();
    top  += e.offsetTop  +
        (e.currentStyle ?
                (parseInt(e.currentStyle.borderTopWidth)).NaN0()
                :  0) +
        (IS_IE ? (parseInt(docBody.scrollTop)).NaN0() : 0) -
        (parseInt(docBody.clientTop)).NaN0();

    return {x:left, y:top};
}

function mouseCoords(ev) {

    if (ev.pageX || ev.pageY) {
        return {x:ev.pageX, y:ev.pageY};
    }

    var docBody = document.documentElement
                        ? document.documentElement
                        : document.body;

    return {
        x: ev.clientX + docBody.scrollLeft - docBody.clientLeft,
        y: ev.clientY + docBody.scrollTop  - docBody.clientTop
    };
}

function getMouseOffset(target, ev, aligned) {
    ev = ev || window.event;
    if (aligned == null) aligned = false;

    var docPos    = aligned
        ? getAlignedPosition(target)
        : getPosition(target);
    var mousePos  = mouseCoords(ev);

    return {
        x: mousePos.x - docPos.x,
        y: mousePos.y - docPos.y
    };
}

function findOffsetHeight(e) {
    var res = 0;
    while ((res == 0) && e.parentNode) {
        e = e.parentNode;
        res = e.offsetHeight;
    }
    return res;
}

function getOffsetHeight(e) {
    return this.element.offsetHeight ||
            this.element.style.pixelHeight ||
            findOffsetHeight(e);
}

function walkTree(node, mapFunction, dataPackage) {
    if (node == null) return;
    mapFunction(node, dataPackage);
    for (var i = 0; i < node.childNodes.length; i++) {
        walkTree(node.childNodes[i], mapFunction, dataPackage);
    }
}

function searchTree(node, searchFunction, dataPackage) {
    if (node == null) return;
    var funcResult = searchFunction(node, dataPackage);
    if (funcResult) return funcResult;
    for (var i = 0; i < node.childNodes.length; i++) {
        var searchResult = searchTree(node.childNodes[i],
                            searchFunction, dataPackage);
        if (searchResult) return searchResult;
    }
}

function removeChildrenRecursively(node)
{
    if (!node) return;
    while (node.hasChildNodes()) {
        removeChildrenRecursively(node.firstChild);
        node.removeChild(node.firstChild);
    }
}

function removeElementById(nodeId) {
    document.getElementById(nodeId).parentNode.removeChild(
                            document.getElementById(nodeId));
}

var IS_SAFARI = USER_DATA['Browser'].Safari;

function getElmAttr(elm, attrName, ns) {
    // IE6 fails getAttribute when used on table element
    var elmValue = null;
    try {
        elmValue = (elm.getAttribute
                    ? elm.getAttribute((ns ? (ns + NS_SYMB) : '')
                    + attrName) : null);
    } catch (e) { return null; }
    if (!elmValue && IS_SAFARI) {
        elmValue = (elm.getAttributeNS
                    ? elm.getAttributeNS(ns, attrName)
                    : null);
    }
    return elmValue;
}

function setElmAttr(elm, attrName, value, ns) {
    if (!IS_SAFARI || !ns) {
        return (elm.setAttribute
                    ? elm.setAttribute((ns ? (ns + NS_SYMB) : '')
                    + attrName, value) : null);
    } else {
        return (elm.setAttributeNS
                    ? elm.setAttributeNS(ns, attrName, value)
                    : null);
    }
}

function remElmAttr(elm, attrName, ns) {
    if (!IS_SAFARI || !ns) {
        return (elm.removeAttribute
                    ? elm.removeAttribute((ns ? (ns + NS_SYMB) : '')
                    + attrName) : null);
    } else {
        return (elm.removeAttributeNS
                    ? elm.removeAttributeNS(ns, attrName)
                    : null);
    }
}

function makeRequest(url, parameters, onComplete, package) {

    var http_request = false;
    try {
        http_request = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e1) {
        try {
            http_request= new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e2) {
            http_request = new XMLHttpRequest();
        }
    }

    //if (http_request.overrideMimeType) { // optional
    //  http_request.overrideMimeType('text/xml');
    //}

    if (!http_request) {
      alert('Cannot create XMLHTTP instance');
      return false;
    }

    completeListener = function() {
        if (http_request.readyState == 4) {
            if (http_request.status == 200) {
                onComplete(http_request, package)
            }
        }
    };

    //var salt = hex_md5(new Date().toString());
    http_request.onreadystatechange = completeListener;
    http_request.open('GET', url + "?" + parameters, true);
    //http_request.open('GET', './proxy.php?' + parameters +
                    // "&salt=" + salt, true);
    http_request.send(null);
}

function LOG(informerName, text) {
    var logElement = document.getElementById('LOG_DIV');
    if (logElement) {
        logElement.appendChild(document.createTextNode(
                        informerName + ': ' + text));
        logElement.appendChild(document.createElement('br'));
        logElement.scrollTop += 50;
    }
}

var Console = Class.extend({
    // the stub class to allow using console when browser have it,
    // if not - just pass all calls
    construct: function() {},
    log: function() { },
    info: function() { },
    warn: function() { },
    error: function() { }
});

if (!window.console) {
    console = new Console();
}
