if (typeof Tools == 'undefined') {
    var Tools = new Object();
}


/**
 * Tools.getElementById()
 *
 * This method is a cross-browser wrapper for getElementById()
 *
 * @author Steffen Eckardt
 * @param  e       The element id
 * @param  d       The document (default is document)
 * @return Object
 */
Tools.getElementById = function(e, d) {
    d = (typeof d == 'object' && (d.getElementById || d.all) ? d : document);
    return (typeof e != 'string' && typeof e != 'number' ? null : (d.getElementById ? d.getElementById(e) : (d.all ? d.all[e] : null)));
};


/**
 * Tools.addOnLoadEvent()
 *
 * This method adds a window.onload() event to the existing ones.
 *
 * @author Steffen Eckardt
 * @param  oFunc  The function to add
 * @return void
 */
Tools.addOnLoadEvent = function(oFunc) {
    if (typeof oFunc != 'function') {
        return;
    }

    var oOnLoad = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = oFunc;
    } else {
        window.onload = function() {
            oOnLoad();
            oFunc();
        }
    }
}

/**
 * Tools.addOnUnloadEvent()
 *
 * This method adds a window.unonload() event to the existing ones.
 *
 * @author Steffen Eckardt
 * @param  oFunc  The function to add
 * @return void
 */
Tools.addOnUnloadEvent = function(oFunc) {
    if (typeof oFunc != 'function') {
        return;
    }

    var oOnUnload = window.unonload;
    if (typeof window.unonload != 'function') {
        window.onunload = oFunc;
    } else {
        window.onunload = function() {
            oOnUnload();
            oFunc();
        }
    }
}

/**
 * String.prototype.htmlEntities
 *
 * Replaces all characters in this string defined in the XHTML 1.0 Entity Sets
 * (Latin-1 Characters, Special Characters, and Symbols) with their Numeric
 * Entity References.
 *
 * @author  Stuart Wigley
 * @author  Randolph Fielding
 * @return  A modified string
 */
String.prototype.htmlEntities = function() {
    var s = '';
    var c;

    for (var i = 0; i < this.length; i++) {
        c = this.charCodeAt(i);
        if (c == 34 || c == 38 || c == 39 || c == 60 || c == 62 || (c >= 160 && c <= 255) || c == 338 || c == 339 || c == 352 || c == 353 || c == 376 || c == 402 || c == 710 || c == 732 || (c >= 913 && c <= 929) || (c >= 931 && c <= 937) || (c >= 945 && c <= 969) || c == 977 || c == 978 || c == 982 || c == 8194 || c == 8195 || c == 8201 || (c >= 8204 && c <= 8207) || c == 8211 || c == 8212 || (c >= 8216 && c <= 8218) || (c >= 8220 && c <= 8222) || (c >= 8224 && c <= 8226) || c == 8230 || c == 8240 || c == 8242 || c == 8243 || c == 8249 || c == 8250 || c == 8254 || c == 8260 || c == 8364 || c == 8465 || c == 8472 || c == 8476 || c == 8482 || c == 8501 || (c >= 8592 && c <= 8596) || c == 8629 || (c >= 8656 && c <= 8660) || c == 8704 || c == 8706 || c == 8707 || c == 8709 || (c >= 8711 && c <= 8713) || c == 8715 || c == 8719 || c == 8721 || c == 8722 || c == 8727 || c == 8730 || c == 8733 || c == 8734 || c == 8736 || (c >= 8743 && c <= 8747) || c == 8756 || c == 8764 || c == 8773 || c == 8776 || c == 8800 || c == 8801 || c == 8804 || c == 8805 || (c >= 8834 && c <= 8836) || c == 8838 || c == 8839 || c == 8853 || c == 8855 || c == 8869 || c == 8901 || (c >= 8968 && c <= 8971) || c == 9001 || c == 9002 || c == 9674 || c == 9824 || c == 9827 || c == 9829 || c == 9830) {
            s += '&#' + c + ';';
        } else {
            s += this.charAt(i);
        }
    }
    return s;
}

/**
 * Class Tools.Event
 *
 * This class creates and returns a cross-browser Event object.
 *
 * Mainly inspired by the great XLib (c) http://cross-browser.com
 *
 * @author  Steffen Eckardt
 * @since   2006-11-27
 * @version 1.0
 */
Tools.Event = function(evt) {
    this.e = evt || window.event;

    if (!this.e) {
        return;
    }
    if (this.e.type) {
        this.type = this.e.type;
    }
    if (this.e.target) {
        this.target = this.e.target;
    } else if (this.e.srcElement) {
        this.target = this.e.srcElement;
    }

    // Section B
    if (this.e.relatedTarget) {
        this.relatedTarget = this.e.relatedTarget;
    } else if (this.e.type == 'mouseover' && this.e.fromElement) {
        this.relatedTarget = this.e.fromElement;
    } else if (this.e.type == 'mouseout') {
        this.relatedTarget = this.e.toElement;
    }

    // End Section B
    if (typeof this.e.pageX != 'undefined' && typeof this.e.pageY != 'undefined') {
        this.pageX = this.e.pageX;
        this.pageY = this.e.pageY;
    } else if (typeof this.e.clientX != 'undefined' && typeof this.e.clientY != 'undefined') {
        this.pageX = this.e.clientX + Tools.Browser.getScrollLeft();
        this.pageY = this.e.clientY + Tools.Browser.getScrollTop();
    }

    // Section A
    if (typeof this.e.offsetX != 'undefined' && typeof this.e.offsetY != 'undefined') {
        this.offsetX = this.e.offsetX;
        this.offsetY = this.e.offsetY;
    } else if (typeof this.e.layerX != 'undefined' && typeof this.e.layerY != 'undefined') {
        this.offsetX = this.e.layerX;
        this.offsetY = this.e.layerY;
    } else {
        this.offsetX = this.pageX - this.getPageX(this.target);
        this.offsetY = this.pageY - this.getPageY(this.target);
    }

    // End Section A
    this.keyCode  = this.e.keyCode || this.e.which || 0;
    this.shiftKey = this.e.shiftKey;
    this.ctrlKey  = this.e.ctrlKey;
    this.altKey   = this.e.altKey;
};

Tools.Event.prototype = {
    preventDefault: function() {
        if (this.e && this.e.preventDefault) {
            this.e.preventDefault();
        } else if (window.event) {
            window.event.returnValue = false;
        }
    },

    stopPropagation: function() {
        if (this.e && this.e.stopPropagation) {
            this.e.stopPropagation();
        } else if (window.event) {
            window.event.cancelBubble = true;
        }
    },

    getPageX: function(e) {
        if (!e.id || !(e = Tools.getElementById(e.id))) {
            return 0;
        }
        var x = 0;
        while (e) {
            if (typeof e.offsetLeft != "undefined") {
                x += e.offsetLeft;
            }
            e = typeof e.offsetParent != "undefined" ? e.offsetParent : null;
        }
        return x;
    },

    getPageY: function(e) {
        if (!e.id || !(e = Tools.getElementById(e.id))) {
            return 0;
        }
        var y = 0;
        while (e) {
            if (typeof e.offsetTop != "undefined") {
                y += e.offsetTop;
            }
            e = typeof e.offsetParent != "undefined" ? e.offsetParent : null;
        }
        return y;
    }
};


/**
 * Class Tools.EventListener
 *
 * This class creates a cross-browser EventListener object.
 *
 * Mainly inspired by the great XLib (c) http://cross-browser.com
 * and the addEvent() method at http://www.quirksmode.org
 *
 * @author  Steffen Eckardt
 * @since   2006-11-27
 * @version 1.0
 */
Tools.EventListener = {
    __isProblematicDom: function(sEvt) {
        return false;
    },

    __isProblematicIe: function(sEvt) {
        return (sEvt == 'scroll');
    },

    addEventListener: function(e, eT, eL, cap) {
        if (!e) {
            return;
        }
        eT    = eT.toLowerCase();
        var b = true;

        if (e.addEventListener) {
            if (!Tools.EventListener.__isProblematicDom(eT)) {
                e.addEventListener(eT, eL, cap || false);
                b = false;
            }
        } else if (e.attachEvent) {
            try {
                if (!Tools.EventListener.__isProblematicIe(eT)) {
                    e['e' + eT + eL] = eL;
                    e[eT + eL] = function() {
                        e['e' + eT + eL](window.event);
                    }
                    e.attachEvent('on' + eT, e[eT + eL]);
                    b = false;
                }
            } catch (e) {
            }
        }
        if (b) {
            e['on' + eT] = eL;
        }
    },

    removeEventListener: function(e, eT, eL, cap) {
        if (!e) {
            return;
        }
        eT    = eT.toLowerCase();
        var b = true;

        if (e.removeEventListener) {
            if (!Tools.EventListener.__isProblematicDom(eT)) {
                e.removeEventListener(eT, eL, cap || false);
                b = false;
            }
        } else if (e.detachEvent) {
            try {
                if (!Tools.EventListener.__isProblematicIe(eT)) {
                    e.detachEvent('on' + eT, e[eT + eL]);
                    e['on' + eT]     = null;
                    e[eT + eL]       = null;
                    e['e' + eT + eL] = null;
                    b                = false;
                }
            } catch (e) {
            }
        }
        if (b) {
            e['on' + eT] = null;
        }
    }
};


/**
 * Class Tools.Browser
 *
 * This class contains static methods used to do some browser checks.
 *
 * @author  Steffen Eckardt
 * @since   2006-08-19
 * @version 1.1
 */
Tools.Browser = {
    init: function() {
        // Basic variables
        this.b              = null;
        this.v              = null;

        // Browser Identities
        this.IDCAMINO    = "Camino";
        this.IDCHIMERA   = "Chimera";
        this.IDEPIPHANY  = "Epiphany";
        this.IDFIREBIRD  = "Mozilla Firebird";
        this.IDFIREFOX   = "Mozilla Firefox";
        this.IDGALEON    = "Galeon";
        this.IDICAB      = "iCab";
        this.IDKMELEON   = "K-Meleon";
        this.IDKONQUEROR = "Konqueror";
        this.IDMOZILLA   = "Mozilla";
        this.IDMSIE      = "Internet Explorer";
        this.IDNETSCAPE  = "Netscape";
        this.IDOMNIWEB   = "OmniWeb";
        this.IDOPERA     = "Opera";
        this.IDPKVIEWER  = "Pknowledge Viewer";
        this.IDSAFARI    = "Safari";
        this.IDSEAMONKEY = "SeaMonkey";
        this.IDSHIIRA    = "Shiira";

        // Init browser
        this.isPknowledgeViewer();
        this.isFirefox();
        this.isFirebird();
        this.isOpera();
        this.isSeaMonkey();
        this.isKonqueror();
        this.isOmniWeb();
        this.isSafari();
        this.isCamino();
        this.isChimera();
        this.isKMeleon();
        this.isShiira();
        this.isICab();
        this.isEpiphany();
        this.isIE();
        this.isNetscape(); // Checks/invokes isMozilla()
    },

    getBrowser: function() {
        return this.b;
    },

    getPlatform: function() {
        return navigator.platform;
    },

    getUserAgent: function() {
        return navigator.userAgent;
    },

    getVendor: function() {
        return navigator.vendor;
    },

    getVersion: function() {
        return this.v;
    },

    getVersionMajor: function() {
        return parseInt(this.getVersion());
    },

    getAppCodeName: function() {
        return navigator.appCodeName;
    },

    getAppName: function() {
        return navigator.appName;
    },

    getAppMinorVersion: function() {
        return navigator.appMinorVersion;
    },

    getAppVersion: function() {
        return navigator.appVersion;
    },

    getCpuClass: function() {
        return navigator.cpuClass;
    },

    getLanguage: function() {
        return (navigator.browserLanguage ? navigator.browserLanguage : (navigator.language ? navigator.language : navigator.systemLanguage));
    },

    isBrowser: function(sIdentity, iVersion, bUp, sCheck1) {
        if (sCheck1 != null) {
            this.cb(sIdentity, sCheck1);
        }
        if (iVersion) {
            return (bUp ? (this.b == sIdentity && this.getVersionMajor() >= iVersion) : (this.b == sIdentity && this.getVersionMajor() == iVersion));
        } else {
            return (this.b == sIdentity);
        }
    },

    setBrowser: function(s, b, v) {
        if (b === true) {
            this.b = s;
            this.v = v;
        }
    },

    // cb() --> check browser via user agent
    cb: function(s1, s2) {
        if (!this.b || !this.v) {
            this.setBrowser(s1, this.csua(s2), this.cvua(s2));
        }
    },

    // cs() --> check substring
    cs: function(s1, s2) {
        return (typeof s1 != "undefined" && typeof s2 != "undefined" && s1.toString().toLowerCase().indexOf(s2.toString().toLowerCase()) != -1);
    },

    // csua() --> check substring inside the user agent
    csua: function(s) {
        return this.cs(this.getUserAgent(), s);
    },

    // csv() --> check substring inside navigator.appVersion
    csv: function(m, o) {
        return this.cs(this.getAppVersion(), m, o);
    },

    // cv() --> check version
    cv: function(s, m, o) {
        if (typeof s != "undefined" && typeof m != "undefined") {
            var i = s.toString().toLowerCase().indexOf(m.toString().toLowerCase());
            if (i != -1) {
                // Find exact version
                o = (typeof o == "number" ? o : m.length + 1);
                return s.substring(i + o).replace(/([a-z0-9\.,]+)(.*)/i, "$1");
            }
        }
    },

    // cvua() --> check version inside the user agent
    cvua: function(m, o) {
        return this.cv(this.getUserAgent(), m, o);
    },

    // cs() --> check property
    cp: function(m) {
        return m ? true : false;
    },

    isCamino: function(iVersion, bUp) {
        return this.isBrowser(this.IDCAMINO, iVersion, bUp, "camino");
    },

    isChimera: function(iVersion, bUp) {
        return this.isBrowser(this.IDCHIMERA, iVersion, bUp, "chimera");
    },

    isEpiphany: function(iVersion, bUp) {
        return this.isBrowser(this.IDEPIPHANY, iVersion, bUp, "epiphany");
    },

    isFirebird: function(iVersion, bUp) {
        return this.isBrowser(this.IDFIREBIRD, iVersion, bUp, "firebird");
    },

    isFirefox: function(iVersion, bUp) {
        this.cb(this.IDFIREFOX, "firefox");
        return this.isPknowledgeViewer() || this.isBrowser(this.IDFIREFOX, iVersion, bUp, "bonecho");
    },

    isGaleon: function(iVersion, bUp) {
        return this.isBrowser(this.IDGALEON, iVersion, bUp, "galeon");
    },

    isGecko: function() {
        return (!this.isKHTML() && ((navigator.product && navigator.product.toLowerCase() == "gecko") || (this.getUserAgent().toLowerCase().indexOf("gecko") != -1)));
    },

    isICab: function(iVersion, bUp) {
        return this.isBrowser(this.IDICAB, iVersion, bUp, "icab");
    },

    isIE: function(iVersion, bUp) {
        if (!this.b || !this.v) {
            this.setBrowser(this.IDMSIE, (this.csua("msie") && !this.csua("opera") && !this.csua("safari")), this.cvua("msie"));
        }
        return this.isBrowser(this.IDMSIE, iVersion, bUp);
    },

    isKHTML: function() {
        return (this.isSafari() || this.isKonqueror() || this.isOmniWeb() || this.isShiira() || this.getUserAgent().toLowerCase().indexOf("khtml") != -1);
    },

    isKMeleon: function(iVersion, bUp) {
        this.cb(this.IDKMELEON, "k-meleon");
        return this.isBrowser(this.IDKMELEON, iVersion, bUp);
    },

    isKonqueror: function(iVersion, bUp) {
        return this.isBrowser(this.IDKONQUEROR, iVersion, bUp, "konqueror");
    },

    isMozilla: function(iVersion, bUp) {
        if (!this.b || !this.v) {
            this.setBrowser(this.IDMOZILLA, this.csua("gecko"), this.cvua("rv"));
        }
        return this.isBrowser(this.IDMOZILLA, iVersion, bUp);
    },

    isNetscape: function(iVersion, bUp) {
        if (!this.b || !this.v) {
            var a = this.getUserAgent();
            // Newer Netscapes (>4)
            this.setBrowser(this.IDNETSCAPE, this.csua("netscape"), (this.cvua("netscape6") || this.cvua("netscape")));
            // Older Netscapes (<=4)
            if (!this.isMozilla()) {
                this.cb(this.IDNETSCAPE, "mozilla");
            }
        }
        return this.isBrowser(this.IDNETSCAPE, iVersion, bUp);
    },

    isOmniWeb: function(iVersion, bUp) {
        if (!this.b || !this.v) {
            this.setBrowser(this.IDOMNIWEB, (this.csua("omniweb/v") || this.csua("omniweb")), (this.cvua("omniweb/") || this.cvua("omniweb")));
        }
        return this.isBrowser(this.IDOMNIWEB, iVersion, bUp);
    },

    isOpera: function(iVersion, bUp) {
        if (!this.b || !this.v) {
            this.setBrowser(this.IDOPERA, (this.cp(window.opera) || this.csua("opera")), this.cvua("opera"));
        }
        return this.isBrowser(this.IDOPERA, iVersion, bUp);
    },

    isPknowledgeViewer: function(iVersion, bUp) {
        return this.isBrowser(this.IDPKVIEWER, iVersion, bUp, "pknowledge viewer");
    },

    isSafari: function(iVersion, bUp) {
        this.cb(this.IDSAFARI, "safari");
        if (!this.b || !this.v) {
            this.setBrowser(this.IDSAFARI, (this.csv("safari") || this.cs(this.getVendor(), "apple")), this.cvua("safari"));
        }
        return this.isBrowser(this.IDSAFARI, iVersion, bUp);
    },

    isSeaMonkey: function(iVersion, bUp) {
        return this.isBrowser(this.IDSEAMONKEY, iVersion, bUp, "seamonkey");
    },

    isShiira: function(iVersion, bUp) {
        return this.isBrowser(this.IDSHIIRA, iVersion, bUp, "shiira");
    },

    getFlashVersion: function(bReturnAll) {
        UFO.getFlashVersion();
        if (UFO.fv[0] == 0) {
            return null;
        } else if (bReturnAll === true) {
            return UFO.fv[0] + ".0." + UFO.fv[1];
        } else {
            return UFO.fv[0];
        }
    },

    hasFlash: function(iMajor, iMinor, iRev) {
        UFO.getFlashVersion();
        iMajor = typeof iMajor == "number" ? iMajor : 0;
        iMinor = typeof iMinor == "number" ? iMinor : 0;
        iRev   = typeof iRev == "number"   ? iRev   : 0;
        return UFO.hasFlashVersion(iMajor, iRev);
    },

    getClientWidth: function(oDoc) {
        var w = 0;
        oDoc  = typeof oDoc == 'object' ? oDoc : document;

        if (this.isOpera() && this.getVersion() < 6) {
            w = window.innerWidth;
        } else if (oDoc.compatMode == "CSS1Compat" && !window.opera && oDoc.documentElement && oDoc.documentElement.clientWidth) {
            w = oDoc.documentElement.clientWidth;
        } else if (oDoc.body && oDoc.body.clientWidth) {
            w = oDoc.body.clientWidth;
        } else if (typeof window.innerWidth != "undefined" && typeof window.innerHeight != "undefined" && typeof oDoc.height != "undefined") {
            w = window.innerWidth;
            if (oDoc.height > window.innerHeight) {
                w -= 16;
            }
        }
        return w;
    },

    getClientHeight: function(oDoc) {
        var h = 0;
        oDoc  = typeof oDoc == 'object' ? oDoc : document;

        if (this.isOpera() && this.getVersion() < 6) {
            h = window.innerHeight;
        } else if (oDoc.compatMode == "CSS1Compat" && !window.opera && oDoc.documentElement && oDoc.documentElement.clientHeight) {
            h = oDoc.documentElement.clientHeight;
        } else if (oDoc.body && oDoc.body.clientHeight) {
            h = oDoc.body.clientHeight;
        } else if (typeof window.innerWidth != "undefined" && typeof window.innerHeight != "undefined" && typeof oDoc.width != "undefined") {
            h = window.innerHeight;
            if (oDoc.width > window.innerWidth) {
                h -= 16;
            }
        }
        return h;
    },

    getScrollLeft: function(e, bWin) {
        var offset = 0;
        if (typeof e == "undefined" || bWin || e == document || (e.tagName && e.tagName.toLowerCase() == "html") || (e.tagName && e.tagName.toLowerCase() == "body")) {
            var w = window;
            if (bWin && e) {
                w = e;
            }
            if (w.document.documentElement && w.document.documentElement.scrollLeft) {
                offset = w.document.documentElement.scrollLeft;
            } else if (w.document.body && typeof w.document.body.scrollLeft != "undefined") {
                offset = w.document.body.scrollLeft;
            }
        } else {
            e = Tools.getElementById(e);
            if (e && !isNaN(e.scrollLeft) && typeof e.scrollLeft == "number") {
                offset = e.scrollLeft;
            }
        }
        return offset;
    },

    getScrollTop: function(e, bWin) {
        var offset = 0;
        if (typeof e == "undefined" || bWin || e == document || (e.tagName && e.tagName.toLowerCase() == "html") || (e.tagName && e.tagName.toLowerCase() == "body")) {
            var w = window;
            if (bWin && e) {
                w = e;
            }
            if (w.document.documentElement && w.document.documentElement.scrollTop) {
                offset = w.document.documentElement.scrollTop;
            } else if (w.document.body && typeof w.document.body.scrollTop != "undefined") {
                offset = w.document.body.scrollTop;
            }
        } else {
            e = Tools.getElementById(e);
            if (e && !isNaN(e.scrollTop) && typeof e.scrollTop == "number") {
                offset = e.scrollTop;
            }
        }
        return offset;
    }
};

Tools.Browser.init();


/**
 * Class Tools.OS
 *
 * This class contains static methods used to do some OS specific browser checks.
 *
 * @author  Steffen Eckardt
 * @since   2006-08-19
 * @version 1.0
 */
Tools.OS = {
    init: function() {
        // basic variables
        this.n           = null;

        // OS Identities
        this.IDAIX       = 'AIX';
        this.IDBSD       = 'BSD';
        this.IDDEC       = 'DEC';
        this.IDFREEBSD   = 'FreeBSD';
        this.IDHPUX      = 'HP-UX';
        this.IDIRIX      = 'Irix';
        this.IDLINUX     = 'Linux';
        this.IDMAC       = 'Mac';
        this.IDMACOSX    = 'Mac OS X';
        this.IDMPRAS     = 'MPras';
        this.IDOPENBSD   = 'OpenBSD';
        this.IDOS2       = 'OS/2';
        this.IDPALMOS    = 'PalmOS';
        this.IDRELIANT   = 'Reliant';
        this.IDSCO       = 'SCO';
        this.IDSINIX     = 'Sinix';
        this.IDSUNOS     = 'SunOS';
        this.IDSYMBIAN   = 'SymbianOS';
        this.IDWIN       = 'Windows';
        this.IDWIN95     = 'Windows 95';
        this.IDWIN98     = 'Windows 98';
        this.IDWINME     = 'Windows ME';
        this.IDWINNT     = 'Windows NT';
        this.IDWIN2K     = 'Windows 2000';
        this.IDWIN2KSP1  = 'Windows 2000, ServicePack 1 (SP1)';
        this.IDWIN2K3    = 'Windows Server 2003 / Windows XP x64 Edition';
        this.IDWIN2K3SP1 = 'Windows Server 2003, ServicePack 1 (SP1)';
        this.IDWINXP     = 'Windows XP';
        this.IDWINXPMCE  = 'Windows XP Media Center Edition';
        this.IDWINXPSP2  = 'Windows XP, ServicePack 2 (SP2)';
        this.IDWINVISTA  = 'Windows Vista';
        this.IDWINCE     = 'Windows CE';
        this.IDUNIX      = 'Unix';
        this.IDUNIXWARE  = 'UnixWare';
        this.IDVMS       = 'VMS';

        // Init OS
        this.isOS2();
        this.isWin();
        this.isUnix();
        this.isMac();
    },

    getName: function() {
        return this.n;
    },

    setOS: function(s, b) {
        if (b === true) {
            this.n = s;
        }
    },

    // co() --> Check OS via user agent
    co: function(s1, s2) {
        if (!this.n) {
            this.setOS(s1, this.csua(s2));
        }
    },

    // cop() --> Check OS via platform
    cop: function(s1, s2) {
        if (!this.n) {
            this.setOS(s1, this.csp(s2));
        }
    },

    // cov() --> Check OS via appVersion
    cov: function(s1, s2) {
        if (!this.n) {
            this.setOS(s1, this.csv(s2));
        }
    },

    // cs() --> check substring
    cs: function(s1, s2) {
        return (typeof s1 != 'undefined' && typeof s2 != 'undefined' && s1.toString().toLowerCase().indexOf(s2.toString().toLowerCase()) != -1);
    },

    // csua() --> check substring inside the user agent
    csua: function(s) {
        return this.cs(Tools.Browser.getUserAgent(), s);
    },

    // csp() --> check substring inside the platform
    csp: function(s) {
        return this.cs(Tools.Browser.getPlatform(), s);
    },

    // csv() --> check substring inside the navigator.appVersion
    csv: function(s) {
        return this.cs(Tools.Browser.getAppVersion(), s);
    },

    isOS: function(sIdentity, sCheck1, sCheck2) {
        if (sCheck1 != null) {
            this.co(sIdentity, sCheck1);
        }
        if (sCheck2 != null) {
            this.cop(sIdentity, sCheck2);
        }
        return (this.n == sIdentity);
    },

    isAix: function() {
        return this.isOS(this.IDAIX, 'aix');
    },

    isBSD: function() {
        return (this.isFreeBSD() || this.isOpenBSD() || this.isOS(this.IDBSD, 'bsd'));
    },

    isDec: function() {
        var s = this.IDDEC;
        this.co(s, 'osf1');
        this.co(s, 'dec_alpha');
        this.co(s, 'alphaserver');
        this.co(s, 'ultrix');
        this.co(s, 'alphastation');
        return this.isOS(s, 'dec');
    },

    isFreeBSD: function() {
        return this.isOS(this.IDFREEBSD, 'freebsd');
    },

    isHpux: function() {
        return this.isOS(this.IDHPUX, 'hp-ux');
    },

    isIrix: function() {
        return this.isOS(this.IDIRIX, 'irix');
    },

    isLinux: function() {
        this.cop(this.IDLINUX, 'linux');
        return this.isOS(this.IDLINUX, 'linux');
    },

    isMac: function() {
        return (this.isMacOSX() || this.isOS(this.IDMAC, null, 'mac'));
    },

    isMacOSX: function() {
        return this.isOS(this.IDMACOSX, 'mac os x');
    },

    isMobile: function() {
        return (this.isWinCE() || this.isPalm() || this.isSymbian());
    },

    isMpras: function() {
        return this.isOS(this.IDMPRAS, 'ncr');
    },

    isOpenBSD: function() {
        return this.isOS(this.IDOPENBSD, 'openbsd');
    },

    isOS2: function() {
        this.co(this.IDOS2, 'ibm-webexplorer');
        this.cov(this.IDOS2, 'os/2');
        return this.isOS(this.IDOS2, 'os/2');
    },

    isPalm: function() {
        return this.isOS(this.IDPALMOS, 'palmos');
    },

    isReliant: function() {
        return this.isOS(this.IDRELIANT, 'reliant');
    },

    isSCO: function() {
        this.co(this.IDSCO, 'sco');
        return this.isOS(this.IDSCO, 'unix_sv');
    },

    isSinix: function() {
        return this.isOS(this.IDSINIX, 'sinix');
    },

    isSunOS: function() {
        return this.isOS(this.IDSUNOS, 'sunos');
    },

    isSymbian: function() {
        return this.isOS(this.IDSYMBIAN, 'symbian');
    },

    isUnix: function() {
        return (Tools.Browser.getUserAgent().indexOf('x11') != -1 || this.isSunOS() || this.isIrix() || this.isHpux() || this.isSCO() || this.isUnixware() || this.isMpras() || this.isReliant() || this.isSinix() || this.isAix() || this.isDec() || this.isLinux() || this.isBSD());
    },

    isUnixware: function() {
        return this.isOS(this.IDUNIXWARE, 'unix_system_v');
    },

    isVMS: function() {
        this.co(this.IDVMS, 'openvms');
        return this.isOS(this.IDVMS, 'vax');
    },

    isWin: function() {
        return (this.isWin32() || this.isWin64() || this.isWinCE() || this.isOS(this.IDWIN, null, 'win'));
    },

    isWin32: function() {
        return (this.isWinXP() || this.isWin2000() || this.isWinNT() || this.isWinME() || this.isWin98() || this.isWin95());
    },

    isWin64: function() {
        return (this.isWinVista() || this.isWin2003());
    },

    isWinVista: function() {
        return this.isOS(this.IDWINVISTA, 'windows nt 6.0');
    },

    isWinXP: function() {
        var b = (this.isWinXPMCE() || this.isWinXPSP2());
        this.co(this.IDWINXP, 'windows nt 5.1');
        return (b || this.isOS(this.IDWINXP, 'msie 7.0b'));
    },

    isWinXPMCE: function() {
        if (!this.n) {
            this.setOS(this.IDWINXPMCE, (this.csua('windows nt 5.1') && this.csua('media center')));
        }
        return this.isOS(this.IDWINXPMCE);
    },

    isWinXPSP2: function() {
        if (!this.n) {
            this.setOS(this.IDWINXPSP2, (this.csua('windows nt 5.1') && this.csua('sv1')));
        }
        return this.isOS(this.IDWINXPSP2);
    },

    isWin2000: function() {
        return (this.isWin2000SP1() || this.isOS(this.IDWIN2K, 'windows nt 5.0'));
    },

    isWin2000SP1: function() {
        return this.isOS(this.IDWIN2KSP1, 'windows nt 5.01');
    },

    isWin2003: function() {
        return (this.isWin2003SP1() || this.isOS(this.IDWIN2K3, 'windows nt 5.2'));
    },

    isWin2003SP1: function() {
        if (!this.n) {
            this.setOS(this.IDWIN2K3SP1, (this.csua('windows nt 5.2') && this.csua('sv1')));
        }
        return this.isOS(this.IDWIN2K3SP1);
    },

    isWinNT: function() {
        this.co(this.IDWINNT, 'windows nt');
        return this.isOS(this.IDWINNT, 'winnt');
    },

    isWinME: function() {
        return this.isOS(this.IDWINME, 'win 9x 4.90');
    },

    isWin98: function() {
        this.co(this.IDWIN98, 'win98');
        return this.isOS(this.IDWIN98, 'windows 98');
    },

    isWin95: function() {
        this.co(this.IDWIN95, 'win95');
        return this.isOS(this.IDWIN95, 'windows 95');
    },

    isWinCE: function() {
        this.co(this.IDWINCE, 'windows ce');
        this.co(this.IDWINCE, 'mspie');
        return this.isOS(this.IDWINCE, 'pocket internet explorer');
    }
};

Tools.OS.init();


/**
 * Class Tools.Math
 *
 * This class contains static methods to do some special mathemetical tasks.
 *
 * @author  Steffen Eckardt
 * @since   2006-08-18
 * @version 1.0
 */
Tools.Math = {
    parseInt: function(mValue, iDefault) {
        var i = parseInt(mValue);
        return (isFinite(i) ? i : (typeof iDefault == 'number' ? iDefault : 0));
    }
};


/**
 * Class Tools.AppletIncluder
 *
 * This class handles the inclusion of applets via JavaScript to be able to get a
 * flexible workaround for the EOLAS patent and other issues...
 *
 * @author  Steffen Eckardt
 * @since   2006-08-17
 * @version 1.0
 * @param   sSource    The java class.
 * @param   sId        The name/id of the applet.
 * @param   iWidth     The applet's width.
 * @param   iHeight    The applet's height.
 * @param   sCodeBase  The codebase.
 * @param   sArchives  Needed JARs: Comma-separated values like "wbc.jar,sac.jar,jmf.jar".
 * @param   sAlign     The applet's alignment.
 * @param   sCssClass  The surrounding <object>, <embed> or <applet> tag's CSS class name.
 */
Tools.AppletIncluder = function(sSource, sId, iWidth, iHeight, sCodeBase, sArchives, sAlign, sCssClass) {
    // Funnily enough Safari and Konqueror need the ActiveX styled <object> tag like Internet Explorer...
    this.isIEFaker  = (Tools.Browser.isSafari() || Tools.Browser.isKonqueror());
    this.isIE       = ((Tools.Browser.isIE() && Tools.OS.isWin()) || this.isIEFaker);
    this.isNS       = (Tools.Browser.isNetscape(5, true) || Tools.Browser.isGecko());

    // Attributes and parameters
    this.attributes = new Array();
    this.params     = new Array();
    this.isPopup    = false;
    this.popupTitle = null;

    this.align      = (typeof sAlign == 'string' || typeof sAlign == 'number')       ? sAlign.toString() : null;
    this.archives   = (typeof sArchives == 'string' || typeof sArchives == 'number') ? sArchives.toString() : null;
    this.className  = (typeof sCssClass == 'string' || typeof sCssClass == 'number') ? sCssClass.toString() : null;
    this.code       = (typeof sSource == 'string' || typeof sSource == 'number')     ? sSource.toString() : null;
    this.codebase   = (typeof sCodeBase == 'string' || typeof sCodeBase == 'number') ? sCodeBase.toString() : null;
    this.id         = (typeof sId == 'string' || typeof sId == 'number')             ? sId.toString() : null;
    this.height     = typeof iHeight == 'number'                                     ? Tools.Math.parseInt(iHeight, 0) : 0;
    this.width      = typeof iWidth == 'number'                                      ? Tools.Math.parseInt(iWidth, 0) : 0;
};

Tools.AppletIncluder.prototype = {
    addParam: function(sName, mValue) {
        if (typeof sName == 'string') {
            if (mValue != null) {
                this.params[sName] = mValue.toString();
            } else {
                this.params[sName] = null;
            }
        }
    },

    /**
     * Because of an annoying bug inside the print() implementation of IE all
     * applets must have a minimum dimension of at least 4x4 px
     */
    getRealHeight: function() {
        return Tools.Browser.isIE() ? Math.max(this.height, 4) : this.height;
    },

    getRealWidth: function() {
        return Tools.Browser.isIE() ? Math.max(this.width, 4) : this.width;
    },

    getAttributes: function(aAttributes) {
        var out        = '';
        var attributes = typeof aAttributes == 'object' ? aAttributes : this.attributes;

        for (var attr in attributes) {
            if (attributes[attr] != null && typeof attributes[attr] != 'function') {
                out += ' ' + attr + '="' + attributes[attr] + '"';
            }
        }
        return out;
    },

    getAttributesCodeApplet: function() {
        var attributes          = this.attributes;
        attributes['id']        = this.id;
        attributes['name']      = this.id;
        attributes['code']      = this.code;
        attributes['codebase']  = this.codebase;
        attributes['archive']   = this.archives;
        attributes['width']     = this.getRealWidth();
        attributes['height']    = this.getRealHeight();
        attributes['align']     = this.align;
        attributes['mayscript'] = 'true';

        return this.getAttributes(attributes);
    },

    getAttributesCodeEmbed: function() {
        var attributes            = this.attributes;
        attributes['id']          = this.id;
        attributes['name']        = this.id;
        attributes['code']        = this.code;
        attributes['codebase']    = this.codebase;
        attributes['type']        = 'application/x-java-applet;jpi-version=1.4';
        attributes['width']       = this.getRealWidth();
        attributes['height']      = this.getRealHeight();
        attributes['align']       = this.align;
        attributes['pluginspage'] = 'http://java.sun.com/j2se/1.4/download.html';
        attributes['mayscript']   = 'true';

        return this.getAttributes(attributes);
    },

    getAttributesCodeObject: function() {
        var attributes          = this.attributes;
        attributes['id']        = this.id;
        attributes['name']      = this.id;
        attributes['codetype']  = 'application/java';
        attributes['width']     = this.getRealWidth();
        attributes['height']    = this.getRealHeight();
        attributes['align']     = this.align;

        if (this.isIE) {
            attributes['classid']       = 'clsid:8AD9C840-044E-11D1-B3E9-00805F499D93';
            attributes['codebase']      = 'http://java.sun.com/products/plugin/autodl/jinstall-1_4-windows-i586.cab#Version=1,4,0,0';
        } else {
            attributes['classid']  = 'java:' + this.code;
            attributes['archive']  = this.archives;
        }

        return this.getAttributes(attributes);
    },

    getInclusionCodeApplet: function() {
        var out = '<applet' + this.getAttributesCodeApplet() + '>' + this.getParamCodeApplet() + '\n</applet>';
        return out;
    },

    getInclusionCodeEmbed: function() {
        var out = '<embed' + this.getAttributesCodeEmbed() + '>' + this.getParamCodeEmbed() + '\n</embed>';
        return out;
    },

    getInclusionCodeObject: function() {
        var out = '<object' + this.getAttributesCodeObject() + '>' + this.getParamCodeObject() + '\n</object>';
        return out;
    },

    getParams: function(aParams) {
        var out    = '';
        var params = typeof aParams == 'object' ? aParams : this.params;

        for (var param in params) {
            if (params[param] != null && typeof params[param] != 'function') {
                out += '\n  <param name="' + param + '" value="' + params[param] + '" />';
            }
        }
        return out;
    },

    getParamCodeApplet: function() {
        var params             = this.params;
        params['popup_window'] = this.isPopup === true ? 'true' : 'false';
        return this.getParams(params);
    },

    getParamCodeEmbed: function() {
        var params             = this.params;
        params['popup_window'] = this.isPopup === true ? 'true' : 'false';
        return this.getParams(params);
    },

    getParamCodeObject: function() {
        var params             = this.params;
        params['name']         = this.id;
        params['code']         = this.code;
        params['codebase']     = this.codebase;
        params['popup_window'] = this.isPopup === true ? 'true' : 'false';
        params['mayscript']    = 'true';

        if (this.isIE) {
            params['type']       = 'application/x-java-applet;jpi-version=1.4';
            params['archive']    = this.archives;
            params['scriptable'] = 'true';
        }

        return this.getParams(params);
    },

    isPopup: function() {
        return this.isPopup;
    },

    setAttribute: function(sName, mValue) {
        if (typeof sName == 'string') {
            if (typeof mValue != null && (typeof mValue == 'string' || typeof mValue == 'number')) {
                this.attributes[sName] = mValue;
            } else {
                this.attributes[sName] = null;
            }
        }
    },

    setPopup: function(mTitle) {
        if (typeof mTitle == 'string' && mTitle.length > 0) {
            this.isPopup    = true;
            this.popupTitle = mTitle;
        } else if (typeof mTitle == 'boolean') {
            this.isPopup    = mTitle;
        }

        if (this.isPopup === true) {
            this.width  = 0;
            this.height = 0;
        }
    },

    getCode: function() {
        var s = this.getWrapperHead();
        if (Tools.Browser.isNetscape(4)) {
            s += this.getInclusionCodeEmbed();
        } else if ((this.isNS || (this.isIE && Tools.Browser.isIE(5, true)) || this.isIEFaker) && !Tools.Browser.isOpera()) {
            s += this.getInclusionCodeObject();
        } else {
            s += this.getInclusionCodeApplet();
        }
        s += this.getWrapperFoot();
        return s;
    },

    write: function() {
        document.writeln(this.getCode());
    },

    getWrapperHead: function() {
        if (this.isPopup === true && this.popupTitle != null) {
            var sTitle = this.popupTitle.toString().htmlEntities();
            return '<table border="0" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top"><a href="javascript:sac(\'' + this.id + '\', \'main\');" title="' + sTitle + '"><img border="0" src="../../images/symbols/btn_chk.gif" alt="" /></a></td><td><a href="javascript:sac(\'' + this.id + '\', \'main\');" title="' + sTitle + '">' + this.popupTitle + '</a></td><td>';
        } else if (Tools.Browser.isIE() && (this.width == 0 || this.height == 0)) {
            return '<div style="position: absolute; left: -' + (this.getRealWidth() + 1) + 'px; top: -' + (this.getRealHeight() + 1) + 'px;">';
        }
        return '';
    },

    getWrapperFoot: function() {
        if (this.isPopup === true && this.popupTitle != null) {
            return '</td></tr></tbody></table>';
        } else if (Tools.Browser.isIE() && (this.width == 0 || this.height == 0)) {
            return '</div>';
        }
        return '';
    }
};


/**
 * Class Tools.SwfIncluder
 *
 * This class handles the inclusion of Flash movies via JavaScript to be able to get a
 * flexible workaround for the EOLAS patent and other issues...It's mainly just a wrapper
 * around the great Unobtrusive Flash Objects (UFO) class (c) Bobby van der Sluis
 * http://www.bobbyvandersluis.com/ufo
 *
 * @author  Steffen Eckardt
 * @since   2006-08-21
 * @version 1.1
 * @param   sSource         The path to the SWF file.
 * @param   sId             The ID of the object or embed tag. The embed tag will also have
 *                          this value set as it's name attribute for files that take advantage
 *                          of swliveconnect.
 * @param   iWidth          The movie's width.
 * @param   iHeight         The movie's height.
 * @param   mVersion        The required player version for the Flash content. This can be a string
 *                          in the format of "6.0.65". Or it can just require the major version,
 *                          such as "6".
 * @param   aParams         The movie's parameters.
 */
Tools.SwfIncluder = function(sSource, sId, iWidth, iHeight, mVersion, aParams) {
    this.defMajor = 6;
    this.defMinor = 0;
    this.defBuild = 0;
    this.source   = (typeof sSource == 'string' || typeof sSource == 'number') ? sSource.toString() : null;
    this.id       = (typeof sId == 'string' || typeof sId == 'number') ? sId.toString() : 'C4KSwfMovieDiv_' + new Date().getMilliseconds() + '_' + Math.round(Math.random() * 1000000);
    this.width    = typeof iWidth == 'number' ? Tools.Math.parseInt(iWidth, 0) : 0;
    this.height   = typeof iHeight == 'number' ? Tools.Math.parseInt(iHeight, 0) : 0;
    this.version  = this.splitVersion(mVersion);
    this.params   = typeof aParams == 'object' ? aParams : new Array();
    this.initParams();
}

Tools.SwfIncluder.prototype = {
    __setParam: function(sParam, sType, mDefault) {
        sType = (typeof sType == 'string' ? sType : 'string');
        if (typeof this.__params[sParam] == 'undefined' || typeof this.__params[sParam] != sType) {
            this.params[sParam] = (mDefault != null ? mDefault : null);
        }
        return this.params[sParam];
    },

    initParams: function() {
        this.__params = this.params;
        this.params   = new Array();
        this.__setParam('allowscriptaccess', 'string', 'always');
        this.__setParam('bgcolor', 'number', 0xFFFFFF);
        this.__setParam('loop', 'boolean', false);
        this.__setParam('menu', 'boolean', false);
        this.__setParam('name', 'string', this.id);
        this.__setParam('quality', 'string', 'high');
        this.__setParam('swliveconnect', 'boolean', true);
        this.__setParam('wmode', 'string', 'transparent');
    },

    splitVersion: function(mV) {
        var v;
        if (typeof mV == 'number') {
            mV = parseInt(mV);
            mV = isNaN(mV) ? this.defMajor : mV;
            v  = new Array(mV, 0, 0);
        } else if (typeof mV == 'string') {
            var a  = mV.split('.', 3);
            var v1 = typeof a[0] != 'undefined' ? parseInt(a[0]) : this.defMajor;
            var v2 = typeof a[1] != 'undefined' ? parseInt(a[1]) : this.defMinor;
            var v3 = typeof a[2] != 'undefined' ? parseInt(a[2]) : this.defBuild;
            v1     = isNaN(v1) ? this.defMajor : v1;
            v2     = isNaN(v2) ? this.defMinor : v2;
            v3     = isNaN(v3) ? this.defBuild : v3;
            v  = new Array(v1, v2, v3);
        } else {
            v  = new Array(this.defMajor, this.defMinor, this.defBuild);
        }
        return v;
    },

    getDiv: function() {
        return '<div id="' + this.id + '">Adobe Flash&#153; content is loading. Require Adobe Flash&#153; Player ' + this.version[0] + '.' + this.version[1] + '.' + this.version[2] + '. <a href="http://www.adobe.com/go/getflashplayer" target="_blank">Click here to download.</a></div>';
    },

    getId: function() {
        return this.id;
    },

    write: function() {
        var ufo = {
            movie: this.source,
            width: this.width,
            height: this.height,
            majorversion: this.version[0],
            build: this.version[2]
        };
        for (var i in this.params) {
            if (this.params[i] != null && typeof this.params[i] != 'function') {
                ufo[i] = this.params[i];
            }
        }
        if (!Tools.getElementById(this.id)) {
            document.writeln(this.getDiv());
        }
        UFO.create(ufo, this.id);
    }
};

Tools.SwfIncluder.getVersion = function(bReturnAll) {
    UFO.getFlashVersion();
    if (bReturnAll) {
        return UFO.fv[0] + '.0.' + UFO.fv[1];
    } else {
        return UFO.fv[0];
    }
};


/**
 * Class Tools.SwfAudioIncluder
 *
 * This class handles the inclusion of a SWF audio player to play MP3 files.
 *
 * The SwfAudioIncluder is based on the great MP3Player (c) by Jeroen Wijering.
 * http://www.jeroenwijering.com
 *
 * @author  Steffen Eckardt
 * @since   2006-11-08
 * @version 1.0
 * @param   sSource  The url of the MP3 file to play.
 * @param   sId      The player object's name/id.
 * @param   iWidth   The player's width
 * @param   iHeight  The player's height
 * @param   aParams  Params used by the MP3Player.
 */
Tools.SwfAudioIncluder = function(sSource, sId, iWidth, iHeight, aParams) {
    this.playerPath = Config.getPathSwf() + 'mp3player.swf';
    this.source     = (typeof sSource == 'string' || typeof sSource == 'number') ? sSource.toString() : null;
    this.id         = (typeof sId == 'string' || typeof sId == 'number') ? sId.toString() : 'C4KSwfAudioPlayerDiv_' + new Date().getMilliseconds() + '_' + Math.round(Math.random() * 1000000);
    this.width      = typeof iWidth == 'number' ? Tools.Math.parseInt(iWidth, 320) : 320;
    this.height     = typeof iHeight == 'number' ? Tools.Math.parseInt(iHeight, 0) : 0;
    this.params     = typeof aParams == 'object' ? aParams : new Array();
    this.includer   = null;
    this.initParams();
};

Tools.SwfAudioIncluder.prototype = {
    __setParam: function(sParam, sType, mDefault) {
        sType = (typeof sType == 'string' ? sType : 'string');
        if (typeof this.__params[sParam] == 'undefined' || typeof this.__params[sParam] != sType) {
            this.params[sParam] = (mDefault != null ? mDefault : null);
        }
        return this.params[sParam];
    },

    initParams: function() {
        this.__params = this.params;
        this.params   = new Array();
        this.__setParam('autoscroll', 'boolean', false);
        this.__setParam('autostart', 'boolean', true);
        this.__setParam('backcolor', 'number', 0xFFFFFF);
        this.__setParam('bufferlength', 'number', 10);
        this.__setParam('callback', 'string');
        this.__setParam('displayheight', 'number', this.getHeight());
        this.__setParam('enablejs', 'boolean', true);
        this.__setParam('frontcolor', 'number', 0x000000);
        this.__setParam('lightcolor', 'number', 0x000000);
        this.__setParam('linkfromdisplay', 'boolean', false);
        this.__setParam('linktarget', 'string', '_blank');
        this.__setParam('overstretch', 'boolean', false);
        this.__setParam('repeat', 'boolean', false);
        this.__setParam('showdigits', 'boolean', true);
        this.__setParam('showeq', 'boolean', false);
        this.__setParam('showfsbutton', 'boolean', false);
        this.__setParam('shownavigation', 'boolean', true);
        this.__setParam('shuffle', 'boolean', true);
        this.__setParam('thumbsinplaylist', 'boolean', false);
        this.__setParam('volume', 'number', 100);
    },

    getHeight: function() {
        return (this.height < 0 ? 0 : this.height);
    },

    getHeightTotal: function() {
        return (this.getHeight() + 20);
    },

    getId: function() {
        return this.id;
    },

    getIncluder: function() {
        if (this.includer == null) {
            this.includer = new Tools.SwfIncluder(this.getPath(), this.id, this.getWidth(), this.getHeightTotal(), 8);
        }
        return this.includer;
    },

    getPath: function() {
        var a = new Array();
        a.push('file=' + this.getSource());
        a.push('width=' + this.getWidth());
        a.push('height=' + this.getHeightTotal());
        for (var i in this.params) {
            if (this.params[i] != null && typeof this.params[i] != 'function') {
                a.push(i + '=' + this.params[i]);
            }
        }
        return this.playerPath + '?' + a.join('&');
    },

    getSource: function() {
        var s = this.source ? this.source.toString() : '';
        return (s.indexOf('objects/') == 0 ? Config.getPathHtmlContent() + s : s);
    },

    getWidth: function() {
        return (this.width < 160 ? 160 : this.width);
    },

    write: function() {
        this.getIncluder().write();
        if (this.width == 0) {
            // Hide the player completely if width == 0
            var obj = Tools.getElementById(this.getId());
            if (obj) {
                obj.style.visibility = 'hidden';
            }
        }
    }
};


/**
 * Class Tools.SwfVideoIncluder
 *
 * This class handles the inclusion of a SWF video player to play FLV videos.
 *
 * The SwfVideoIncluder is based on the great FLVPlayer (c) by Jeroen Wijering.
 * http://www.jeroenwijering.com
 *
 * @author  Steffen Eckardt
 * @since   2006-11-07
 * @version 1.0
 * @param   sSource  The url of the FLV file to display.
 * @param   sId      The video object's name/id.
 * @param   iWidth   The video's width
 * @param   iHeight  The video's height
 * @param   aParams  Params used by the FLVPlayer.
 */
Tools.SwfVideoIncluder = function(sSource, sId, iWidth, iHeight, aParams) {
    this.playerPath = Config.getPathSwf() + 'flvplayer.swf';
    this.source     = (typeof sSource == 'string' || typeof sSource == 'number') ? sSource.toString() : null;
    this.id         = (typeof sId == 'string' || typeof sId == 'number') ? sId.toString() : 'C4KSwfVideoPlayerDiv_' + new Date().getMilliseconds() + '_' + Math.round(Math.random() * 1000000);
    this.width      = typeof iWidth == 'number' ? Tools.Math.parseInt(iWidth, 320) : 320;
    this.height     = typeof iHeight == 'number' ? Tools.Math.parseInt(iHeight, 240) : 240;
    this.params     = typeof aParams == 'object' ? aParams : new Array();
    this.includer   = null;
    this.initParams();
};

Tools.SwfVideoIncluder.prototype = {
    __setParam: function(sParam, sType, mDefault) {
        sType = (typeof sType == 'string' ? sType : 'string');
        if (typeof this.__params[sParam] == 'undefined' || typeof this.__params[sParam] != sType) {
            this.params[sParam] = (mDefault != null ? mDefault : null);
        }
        return this.params[sParam];
    },

    initParams: function() {
        this.__params = this.params;
        this.params   = new Array();
        this.__setParam('autoscroll', 'boolean', false);
        this.__setParam('autostart', 'boolean', true);
        this.__setParam('backcolor', 'number', 0xFFFFFF);
        this.__setParam('bufferlength', 'number', 10);
        this.__setParam('callback', 'string');
        this.__setParam('displayheight', 'number', this.getHeight());
        this.__setParam('enablejs', 'boolean', true);
        this.__setParam('frontcolor', 'number', 0x000000);
        this.__setParam('lightcolor', 'number', 0x000000);
        this.__setParam('linkfromdisplay', 'boolean', false);
        this.__setParam('linktarget', 'string', '_blank');
        this.__setParam('overstretch', 'boolean', false);
        this.__setParam('repeat', 'boolean', false);
        this.__setParam('showdigits', 'boolean', true);
        this.__setParam('showfsbutton', 'boolean', false);
        this.__setParam('showicons', 'boolean', false);
        this.__setParam('shownavigation', 'boolean', true);
        this.__setParam('shuffle', 'boolean', true);
        this.__setParam('thumbsinplaylist', 'boolean', false);
        this.__setParam('volume', 'number', 100);
    },

    getHeight: function() {
        return (this.height < 0 ? 0 : this.height);
    },

    getHeightTotal: function() {
        return (this.getHeight() + 20);
    },

    getId: function() {
        return this.id;
    },

    getIncluder: function() {
        if (this.includer == null) {
            this.includer = new Tools.SwfIncluder(this.getPath(), this.id, this.getWidth(), this.getHeightTotal(), 8);
        }
        return this.includer;
    },

    getPath: function() {
        var a = new Array();
        a.push('file=' + this.getSource());
        a.push('width=' + this.getWidth());
        a.push('height=' + this.getHeightTotal());
        for (var i in this.params) {
            if (this.params[i] != null && typeof this.params[i] != 'function') {
                a.push(i + '=' + this.params[i]);
            }
        }
        return this.playerPath + '?' + a.join('&');
    },

    getSource: function() {
        var s = this.source ? this.source.toString() : '';
        return (s.indexOf('objects/') == 0 ? Config.getPathHtmlContent() + s : s);
    },

    getWidth: function() {
        return (this.width < 160 ? 160 : this.width);
    },

    write: function() {
        this.getIncluder().write();
    }
};


/**
 * Class Tools.DataIncluder
 *
 * This class is the base class for handling the inclusions of data objects (f.i.
 * Videos or SVG graphics) via JavaScript to be able to get a flexible workaround
 * for the EOLAS patent and other issues...
 *
 * @author  Steffen Eckardt
 * @since   2006-08-23
 * @version 1.0
 * @param   sSource    The data source.
 * @param   sId        The object's name/id.
 * @param   sType      The object's MIME type.
 * @param   iWidth     The object's width.
 * @param   iHeight    The object's height.
 * @param   sAlign     The object's alignment.
 * @param   sCssClass  The object's CSS class name.
 */
Tools.DataIncluder = function(sSource, sId, sType, iWidth, iHeight, sAlign, sCssClass) {
    this.attributes = new Array();
    this.params     = new Array();
    this.isPopup    = false;
    this.popupTitle = null;
    this.popupTable = true;

    this.align      = (typeof sAlign == 'string' || typeof sAlign == 'number') ? sAlign.toString() : null;
    this.className  = (typeof sCssClass == 'string' || typeof sCssClass == 'number') ? sCssClass.toString() : null;
    this.data       = (typeof sSource == 'string' || typeof sSource == 'number')? sSource.toString() : null;
    this.id         = (typeof sId == 'string' || typeof sId == 'number') ? sId.toString() : null;
    this.height     = typeof iHeight == 'number' ? Tools.Math.parseInt(iHeight, 0) : 0;
    this.type       = (typeof sType == 'string' || typeof sType == 'number') ? sType.toLowerCase().toString() : null;
    this.typeReturn = false;
    this.width      = typeof iWidth == 'number' ? Tools.Math.parseInt(iWidth, 320) : 320;

    if (this.type != null) {
        if (Config.isMimeTypeSwfAudio(this.type)) {
            new Tools.SwfAudioIncluder(sSource, sId, iWidth, iHeight).write();
            this.typeReturn = true;
            return;
        } else if (Config.isMimeTypeSwfVideo(this.type)) {
            new Tools.SwfVideoIncluder(sSource, sId, iWidth, iHeight).write();
            this.typeReturn = true;
            return;
        }

        if (this.type.indexOf('audio/') == 0) {
            // Set a minimum height for audio player controls
            this.height = (this.width > 0 && this.height < 20 ? 20 : this.height);
        }
    }
};

Tools.DataIncluder.prototype = {
    addParam: function(sName, mValue) {
        if (typeof sName == 'string') {
            if (mValue != null && (typeof mValue == 'string' || typeof mValue == 'number')) {
                this.params[sName] = mValue;
            } else {
                this.params[sName] = null;
            }
        }
    },

    getAttributes: function(aAttributes) {
        var out        = '';
        var attributes = typeof aAttributes == 'object' ? aAttributes : this.attributes;

        for (var attr in attributes) {
            if (attributes[attr] != null && typeof attributes[attr] != 'function') {
                out += ' ' + attr + '="' + attributes[attr] + '"';
            }
        }
        return out;
    },

    getAttributesCodeEmbed: function() {
        var attributes       = this.attributes;
        attributes['id']     = this.id;
        attributes['name']   = this.id;
        attributes['src']    = this.data;
        attributes['type']   = this.type;
        attributes['width']  = this.width;
        attributes['height'] = this.height;
        attributes['align']  = this.align;
        attributes['class']  = this.className;
        return this.getAttributes(attributes);
    },

    getAttributesCodeObject: function() {
        var attributes       = this.attributes;
        attributes['id']     = this.id;
        attributes['name']   = this.id;
        attributes['data']   = this.data;
        attributes['type']   = this.type;
        attributes['width']  = this.width;
        attributes['height'] = this.height;
        attributes['align']  = this.align;
        attributes['class']  = this.className;
        return this.getAttributes(attributes);
    },

    getInclusionCodeEmbed: function() {
        return '<embed' + this.getAttributesCodeEmbed() + '>' + this.getParamCodeEmbed() + '\n</embed>';
    },

    getInclusionCodeObject: function() {
        return '<object' + this.getAttributesCodeObject() + '>' + this.getParamCodeObject() + '\n</object>';
    },

    getParams: function(aParams) {
        var out    = '';
        var params = typeof aParams == 'object' ? aParams : this.params;

        for (var param in params) {
            if (params[param] != null && typeof params[param] != 'function') {
                out += '\n  <param name="' + param + '" value="' + params[param] + '" />';
            }
        }
        return out;
    },

    getParamCodeEmbed: function() {
        return this.getParams(this.params);
    },

    getParamCodeObject: function() {
        var params     = this.params;
        params['name'] = this.id;
        params['src']  = this.data;
        return this.getParams(params);
    },

    isPopup: function() {
        return this.isPopup;
    },

    setAttribute: function(sName, mValue) {
        if (typeof sName == 'string') {
            if (mValue != null && (typeof mValue == 'string' || typeof mValue == 'number')) {
                this.attributes[sName] = mValue;
            } else {
                this.attributes[sName] = null;
            }
        }
    },

    setPopup: function(mTitle, bShowTable) {
        if (typeof mTitle == 'string' && mTitle.length > 0) {
            this.isPopup    = true;
            this.popupTitle = mTitle;
        } else if (typeof mTitle == 'boolean') {
            this.isPopup    = mTitle;
        }

        if (typeof bShowTable == 'boolean') {
            this.popupTable = bShowTable;
        }
    },

    write: function() {
        if (this.typeReturn !== false) {
            return;
        }
        if (this.isPopup === true && this.popupTitle != null) {
            this.getWrapperHead();
            this.getWrapperFoot();
        } else {
            if (Tools.Browser.isNetscape(4)) {
                document.writeln(this.getInclusionCodeEmbed());
            } else {
                document.writeln(this.getInclusionCodeObject());
            }
        }
    },

    getWrapperHead: function() {
        if (this.isPopup === true && this.popupTitle != null) {
            var sTitle  = this.popupTitle.toString().htmlEntities();
            var sLink   = typeof object == 'function' ? "javascript:object('" + this.data + "', " + this.width + ", " + this.height + ");" : this.data;
            var sTarget = typeof object == 'function' ? '_self' : '_blank';
            if (this.popupTable === true) {
                document.writeln('<table border="0" cellspacing="0" cellpadding="0"><tbody><tr valign="middle"><td><a href="' + sLink + '" title="' + sTitle + '" target="' + sTarget + '"><img border="0" src="../../images/symbols/btn_obj.gif" alt="" /></a></td><td><a href="' + sLink + '" title="' + sTitle + '" target="' + sTarget + '">' + this.popupTitle + '</a></td></tr></tbody></table>');
            } else {
                document.writeln('<a href="' + sLink + '" title="' + sTitle + '" target="' + sTarget + '">' + this.popupTitle + '</a>');
            }
        }
    },

    getWrapperFoot: function() {
    }
};


// MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006 Valerio Proietti, <http://mad4milk.net>, MIT Style License.
var Class = function(properties){
    var klass = function(){
        for (var p in this){
            if (this[p]) this[p]._proto_ = this;
        }
        if (arguments[0] != 'noinit' && this.initialize) return this.initialize.apply(this, arguments);
    };
    klass.extend = this.extend;
    klass.implement = this.implement;
    klass.prototype = properties;
    return klass;
};

Class.empty = function(){};

Class.create = function(properties){
    return new Class(properties);
};

Class.prototype = {

    extend: function(properties){
        var pr0t0typ3 = new this('noinit');
        for (var property in properties){
            var previous = pr0t0typ3[property];
            var current = properties[property];
            if (previous && previous != current) current = previous.parentize(current) || current;
            pr0t0typ3[property] = current;
        }
        return new Class(pr0t0typ3);
    },

    implement: function(properties){
        for (var property in properties) this.prototype[property] = properties[property];
    }

};

Object.extend = function(){
    var args = arguments;
    if (args[1]) args = [args[0], args[1]];
    else args = [this, args[0]];
    for (var property in args[1]) args[0][property] = args[1][property];
    return args[0];
};

Object.Native = function(){
    for (var i = 0; i < arguments.length; i++) arguments[i].extend = Class.prototype.implement;
};

new Object.Native(Function, Array, String, Number);

Function.extend({

    parentize: function(current){
        var previous = this;
        return function(){
            this.parent = previous;
            return current.apply(this, arguments);
        };
    }

});

Function.extend({

    pass: function(args, bind){
        var fn = this;
        if ($type(args) != 'array') args = [args];
        return function(){
            return fn.apply(bind || fn._proto_ || fn, args);
        };
    },

    bind: function(bind){
        var fn = this;
        return function(){
            return fn.apply(bind, arguments);
        };
    },

    bindAsEventListener: function(bind){
        var fn = this;
        return function(event){
            fn.call(bind, event || window.event);
            return false;
        };
    },

    delay: function(ms, bind){
        return setTimeout(this.bind(bind || this._proto_ || this), ms);
    },

    periodical: function(ms, bind){
        return setInterval(this.bind(bind || this._proto_ || this), ms);
    }

});

function $clear(timer){
    clearTimeout(timer);
    clearInterval(timer);
    return null;
};

function $type(obj){
    if (!obj) return false;
    var type = false;
    if (obj instanceof Function) type = 'function';
    else if (obj.nodeName){
        if (obj.nodeType == 3 && !/\S/.test(obj.nodeValue)) type = 'textnode';
        else if (obj.nodeType == 1) type = 'element';
    }
    else if (obj instanceof Array) type = 'array';
    else if (typeof obj == 'object') type = 'object';
    else if (typeof obj == 'string') type = 'string';
    else if (typeof obj == 'number' && isFinite(obj)) type = 'number';
    return type;
};

var Chain = new Class({

    chain: function(fn){
        this.chains = this.chains || [];
        this.chains.push(fn);
        return this;
    },

    callChain: function(){
        if (this.chains && this.chains.length) this.chains.splice(0, 1)[0].delay(10, this);
    },

    clearChain: function(){
        this.chains = [];
    }

});

if (!Array.prototype.forEach){

    Array.prototype.forEach = function(fn, bind){
        for(var i = 0; i < this.length ; i++) fn.call(bind, this[i], i);
    };
}

Array.extend({

    each: Array.prototype.forEach,

    copy: function(){
        var newArray = [];
        for (var i = 0; i < this.length; i++) newArray.push(this[i]);
        return newArray;
    },

    remove: function(item){
        for (var i = 0; i < this.length; i++){
            if (this[i] == item) this.splice(i, 1);
        }
        return this;
    },

    test: function(item){
        for (var i = 0; i < this.length; i++){
            if (this[i] == item) return true;
        };
        return false;
    },

    extend: function(newArray){
        for (var i = 0; i < newArray.length; i++) this.push(newArray[i]);
        return this;
    },

    associate: function(keys){
        var newArray = [];
        for (var i =0; i < this.length; i++) newArray[keys[i]] = this[i];
        return newArray;
    }

});

function $A(array){
    return Array.prototype.copy.call(array);
};

String.extend({

    test: function(regex, params){
        return this.match(new RegExp(regex, params));
    },
    toInt: function(){
        return parseInt(this);
    },

    camelCase: function(){
        return this.replace(/-\D/gi, function(match){
            return match.charAt(match.length - 1).toUpperCase();
        });
    },
    capitalize: function(){
        return this.toLowerCase().replace(/\b[a-z]/g, function(match){
            return match.toUpperCase();
        });
    },

    trim: function(){
        return this.replace(/^\s*|\s*$/g, '');
    },

    clean: function(){
        return this.replace(/\s\s/g, ' ').trim();
    },

    rgbToHex: function(array){
        var rgb = this.test('([\\d]{1,3})', 'g');
        if (rgb[3] == 0) return 'transparent';
        var hex = [];
        for (var i = 0; i < 3; i++){
            var bit = (rgb[i]-0).toString(16);
            hex.push(bit.length == 1 ? '0'+bit : bit);
        }
        var hexText = '#'+hex.join('');
        if (array) return hex;
        else return hexText;
    },

    hexToRgb: function(array){
        var hex = this.test('^[#]{0,1}([\\w]{1,2})([\\w]{1,2})([\\w]{1,2})$');
        var rgb = [];
        for (var i = 1; i < hex.length; i++){
            if (hex[i].length == 1) hex[i] += hex[i];
            rgb.push(parseInt(hex[i], 16));
        }
        var rgbText = 'rgb('+rgb.join(',')+')';
        if (array) return rgb;
        else return rgbText;
    }

});

Number.extend({

    toInt: function(){
        return this;
    }

});

var Element = new Class({

    initialize: function(el){
        if ($type(el) == 'string') el = document.createElement(el);
        return $(el);
    },

    inject: function(el, where){
        el = $(el) || new Element(el);
        switch(where){
            case "before": $(el.parentNode).insertBefore(this, el); break;
            case "after": {
                    if (!el.getNext()) $(el.parentNode).appendChild(this);
                    else $(el.parentNode).insertBefore(this, el.getNext());
            } break;
            case "inside": el.appendChild(this); break;
        }
        return this;
    },

    injectBefore: function(el){
        return this.inject(el, 'before');
    },

    injectAfter: function(el){
        return this.inject(el, 'after');
    },

    injectInside: function(el){
        return this.inject(el, 'inside');
    },

    adopt: function(el){
        this.appendChild($(el) || new Element(el));
        return this;
    },

    remove: function(){
        this.parentNode.removeChild(this);
    },

    clone: function(contents){
        return $(this.cloneNode(contents || true));
    },

    replaceWith: function(el){
        var el = $(el) || new Element(el);
        this.parentNode.replaceChild(el, this);
        return el;
    },

    appendText: function(text){
        if (this.getTag() == 'style' && window.ActiveXObject) this.styleSheet.cssText = text;
        else this.appendChild(document.createTextNode(text));
        return this;
    },

    hasClass: function(className){
        return !!this.className.test("\\b"+className+"\\b");
    },

    addClass: function(className){
        if (!this.hasClass(className)) this.className = (this.className+' '+className.trim()).clean();
        return this;
    },

    removeClass: function(className){
        if (this.hasClass(className)) this.className = this.className.replace(className.trim(), '').clean();
        return this;
    },

    toggleClass: function(className){
        if (this.hasClass(className)) return this.removeClass(className);
        else return this.addClass(className);
    },

    setStyle: function(property, value){
        if (property == 'opacity') this.setOpacity(parseFloat(value));
        else this.style[property.camelCase()] = value;
        return this;
    },

    setStyles: function(source){
        if ($type(source) == 'object') {
            for (var property in source) this.setStyle(property, source[property]);
        } else if ($type(source) == 'string') {
            if (window.ActiveXObject) this.cssText = source;
            else this.setAttribute('style', source);
        }
        return this;
    },

    setOpacity: function(opacity){
        if (opacity == 0){
            if(this.style.visibility != "hidden") this.style.visibility = "hidden";
        } else {
            if(this.style.visibility != "visible") this.style.visibility = "visible";
        }
        if (window.ActiveXObject) this.style.filter = "alpha(opacity=" + opacity*100 + ")";
        this.style.opacity = opacity;
        return this;
    },

    getStyle: function(property){
        var proPerty = property.camelCase();
        var style = this.style[proPerty] || false;
        if (!style) {
            if (document.defaultView) style = document.defaultView.getComputedStyle(this,null).getPropertyValue(property);
            else if (this.currentStyle) style = this.currentStyle[proPerty];
        }
        if (style && ['color', 'backgroundColor', 'borderColor'].test(proPerty) && style.test('rgb')) style = style.rgbToHex();
        return style;
    },

    addEvent: function(action, fn){
        this[action+fn] = fn.bind(this);
        if (this.addEventListener) this.addEventListener(action, fn, false);
        else this.attachEvent('on'+action, this[action+fn]);
        var el = this;
        if (this != window) Unload.functions.push(function(){
            el.removeEvent(action, fn);
            el[action+fn] = null;
        });
        return this;
    },

    removeEvent: function(action, fn){
        if (this.removeEventListener) this.removeEventListener(action, fn, false);
        else this.detachEvent('on'+action, this[action+fn]);
        return this;
    },

    getBrother: function(what){
        var el = this[what+'Sibling'];
        while ($type(el) == 'textnode') el = el[what+'Sibling'];
        return $(el);
    },

    getPrevious: function(){
        return this.getBrother('previous');
    },

    getNext: function(){
        return this.getBrother('next');
    },

    getFirst: function(){
        var el = this.firstChild;
        while ($type(el) == 'textnode') el = el.nextSibling;
        return $(el);
    },

    getLast: function(){
        var el = this.lastChild;
        while ($type(el) == 'textnode')
        el = el.previousSibling;
        return $(el);
    },

    setProperty: function(property, value){
        var el = false;
        switch(property){
            case 'class': this.className = value; break;
            case 'style': this.setStyles(value); break;
            case 'name': if (window.ActiveXObject && this.getTag() == 'input'){
                el = $(document.createElement('<input name="'+value+'" />'));
                $A(this.attributes).each(function(attribute){
                    if (attribute.name != 'name') el.setProperty(attribute.name, attribute.value);

                });
                if (this.parentNode) this.replaceWith(el);
            };
            default: this.setAttribute(property, value);
        }
        return el || this;
    },

    setProperties: function(source){
        for (var property in source) this.setProperty(property, source[property]);
        return this;
    },

    setHTML: function(html){
        this.innerHTML = html;
        return this;
    },

    getProperty: function(property){
        return this.getAttribute(property);
    },

    getTag: function(){
        return this.tagName.toLowerCase();
    },

    getOffset: function(what){
        what = what.capitalize();
        var el = this;
        var offset = 0;
        do {
            offset += el['offset'+what] || 0;
            el = el.offsetParent;
        } while (el);
        return offset;
    },

    getTop: function(){
        return this.getOffset('top');
    },

    getLeft: function(){
        return this.getOffset('left');
    },

    getValue: function(){
        var value = false;
        switch(this.getTag()){
            case 'select': value = this.getElementsByTagName('option')[this.selectedIndex].value; break;
            case 'input': if ( (this.checked && ['checkbox', 'radio'].test(this.type)) || (['hidden', 'text', 'password'].test(this.type)) )
                value = this.value; break;
            case 'textarea': value = this.value;
        }
        return value;
    }

});

new Object.Native(Element);

Element.extend({
    hasClassName: Element.prototype.hasClass,
    addClassName: Element.prototype.addClass,
    removeClassName: Element.prototype.removeClass,
    toggleClassName: Element.prototype.toggleClass
});

function $Element(el, method, args){
    if ($type(args) != 'array') args = [args];
    return Element.prototype[method].apply(el, args);
};

function $(el){
    if ($type(el) == 'string') el = document.getElementById(el);
    if ($type(el) == 'element'){
        if (!el.extend){
            Unload.elements.push(el);
            el.extend = Object.extend;
            el.extend(Element.prototype);
        }
        return el;
    } else return false;
};

window.addEvent = document.addEvent = Element.prototype.addEvent;
window.removeEvent = document.removeEvent = Element.prototype.removeEvent;

var Unload = {

    elements: [], functions: [], vars: [],

    unload: function(){
        Unload.functions.each(function(fn){
            fn();
        });

        window.removeEvent('unload', window.removeFunction);

        Unload.elements.each(function(el){
            for(var p in Element.prototype){
                window[p] = null;
                document[p] = null;
                el[p] = null;
            }
            el.extend = null;
        });
    }

};

window.removeFunction = Unload.unload;
window.addEvent('unload', window.removeFunction);
var Drag = {};

Drag.Base = new Class({

    setOptions: function(options){
        this.options = Object.extend({
            handle: false,
            unit: 'px',
            onStart: Class.empty,
            onComplete: Class.empty,
            onDrag: Class.empty,
            xMax: false,
            xMin: false,
            yMax: false,
            yMin: false
        }, options || {});
    },

    initialize: function(el, xModifier, yModifier, options){
        this.setOptions(options);
        this.element = $(el);
        this.handle = $(this.options.handle) || this.element;
        if (xModifier) this.xp = xModifier.camelCase();
        if (yModifier) this.yp = yModifier.camelCase();
        this.handle.onmousedown = this.start.bind(this);
    },

    start: function(evt){
        evt = evt || window.event;
        this.startX = evt.clientX;
        this.startY = evt.clientY;

        this.handleX = this.startX - this.handle.getLeft();
        this.handleY = this.startY - this.handle.getTop();

        this.set(evt);
        this.options.onStart.pass(this.element, this).delay(10);
        document.onmousemove = this.drag.bind(this);
        document.onmouseup = this.end.bind(this);
        return false;
    },

    addStyles: function(x, y){
        if (this.xp){
            var stylex = this.element.getStyle(this.xp).toInt();

            var movex = function(val){
                this.element.setStyle(this.xp, val+this.options.unit);
            }.bind(this);

            if (this.options.xMax && stylex >= this.options.xMax){
                if (this.clientX <= this.handleX+this.handle.getLeft()) movex(stylex+x);
                if (stylex > this.options.xMax) movex(this.options.xMax);
            } else if(this.options.xMin && stylex <= this.options.xMin){
                if (this.clientX >= this.handleX+this.handle.getLeft()) movex(stylex+x);
                if (stylex < this.options.xMin) movex(this.options.xMin);
            } else movex(stylex+x);
        }
        if (this.yp){
            var styley = this.element.getStyle(this.yp).toInt();

            var movey = function(val){
                this.element.setStyle(this.yp, val+this.options.unit);
            }.bind(this);

            if (this.options.yMax && styley >= this.options.yMax){
                if (this.clientY <= this.handleY+this.handle.getTop()) movey(styley+y);
                if (styley > this.options.yMax) movey(this.options.yMax);
            } else if(this.options.yMin && styley <= this.options.yMin){
                if (this.clientY >= this.handleY+this.handle.getTop()) movey(styley+y);
                if (styley < this.options.yMin) movey(this.options.yMin);
            } else movey(styley+y);
        }
    },

    drag: function(evt){
        evt = evt || window.event;
        this.clientX = evt.clientX;
        this.clientY = evt.clientY;
        this.options.onDrag.pass(this.element, this).delay(5);
        this.addStyles((this.clientX-this.lastMouseX), (this.clientY-this.lastMouseY));
        this.set(evt);
        return false;
    },

    set: function(evt){
        this.lastMouseX = evt.clientX;
        this.lastMouseY = evt.clientY;
        return false;
    },

    end: function(){
        document.onmousemove = null;
        document.onmouseup = null;
        this.options.onComplete.pass(this.element, this).delay(10);
    }

});

Drag.Move = Drag.Base.extend({

    extendOptions: function(options){
        this.options = Object.extend(this.options || {}, Object.extend({
            onSnap: Class.empty,
            droppables: [],
            snapDistance: 8,
            snap: true,
            xModifier: 'left',
            yModifier: 'top',
            container: false
        }, options || {}));
    },

    initialize: function(el, options){
        this.extendOptions(options);
        this.container = $(this.options.container);
        this.parent(el, this.options.xModifier, this.options.yModifier, this.options);
    },

    start: function(evt){
        if (this.options.container) {
            var cont = $(this.options.container).getPosition();
            Object.extend(this.options, {
                xMax: cont.right-this.element.offsetWidth,
                xMin: cont.left,
                yMax: cont.bottom-this.element.offsetHeight,
                yMin: cont.top
            });
        }
        this.parent(evt);
        if (this.options.snap) document.onmousemove = this.checkAndDrag.bind(this);
        return false;
    },

    drag: function(evt){
        this.parent(evt);
        this.options.droppables.each(function(drop){
            if (this.checkAgainst(drop)){
                if (drop.onOver && !drop.dropping) drop.onOver.pass([this.element, this], drop).delay(10);
                drop.dropping = true;
            } else {
                if (drop.onLeave && drop.dropping) drop.onLeave.pass([this.element, this], drop).delay(10);
                drop.dropping = false;
            }
        }, this);
        return false;
    },

    checkAndDrag: function(evt){
        evt = evt || window.event;
        var distance = Math.round(Math.sqrt(Math.pow(evt.clientX - this.startX, 2)+Math.pow(evt.clientY - this.startY, 2)));
        if (distance > this.options.snapDistance){
            this.set(evt);
            this.options.onSnap.pass(this.element, this).delay(10);
            document.onmousemove = this.drag.bind(this);
            this.addStyles(-(this.startX-evt.clientX), -(this.startY-evt.clientY));
        }
        return false;
    },

    checkAgainst: function(el){
        x = this.clientX+Window.getScrollLeft();
        y = this.clientY+Window.getScrollTop();
        var el = $(el).getPosition();
        return (x > el.left && x < el.right && y < el.bottom && y > el.top);
    },

    end: function(){
        this.parent();
        this.options.droppables.each(function(drop){
            if (drop.onDrop && this.checkAgainst(drop)) drop.onDrop.pass([this.element, this], drop).delay(10);
        }, this);
    }

});

Element.extend({

    makeDraggable: function(options){
        return new Drag.Move(this, options);
    },

    makeResizable: function(options){
        return new Drag.Base(this, 'width', 'height', options);
    },

    getPosition: function(){
        var obj = {};
        obj.width = this.offsetWidth;
        obj.height = this.offsetHeight;
        obj.left = this.getLeft();
        obj.top = this.getTop();
        obj.right = obj.left + obj.width;
        obj.bottom = obj.top + obj.height;
        return obj;
    }

});

var Window = {

    disableImageCache: function(){
        if (window.ActiveXObject) document.execCommand("BackgroundImageCache", false, true);
    },

    extend: Object.extend,

    getWidth: function(){
        return window.innerWidth || document.documentElement.clientWidth || 0;
    },

    getHeight: function(){
        return window.innerHeight || document.documentElement.clientHeight || 0;
    },

    getScrollHeight: function(){
        return document.documentElement.scrollHeight;
    },

    getScrollWidth: function(){
        return document.documentElement.scrollWidth;
    },

    getScrollTop: function(){
        return document.documentElement.scrollTop || window.pageYOffset || 0;
    },

    getScrollLeft: function(){
        return document.documentElement.scrollLeft || window.pageXOffset || 0;
    },

    onDomReady: function(init){
        var state = document.readyState;
        if (state && document.childNodes && !document.all && !navigator.taintEnabled){ //khtml
            if (state.test(/loaded|complete/)) return init();
            else return Window.onDomReady.pass(init).delay(100);
        } else if (state && window.ActiveXObject){ //ie
            var script = $('_ie_ready_');
            if (!script) document.write("<script id='_ie_ready_' defer='true' src='://'></script>");
            $('_ie_ready_').addEvent('readystatechange', function(){
                if (this.readyState == 'complete') init();
            });
            return;
        } else { //others
            var myInit = function() {
                if (arguments.callee.done) return;
                arguments.callee.done = true;
                init();
            };
            window.addEvent("load", myInit);
            document.addEvent("DOMContentLoaded", myInit);
        }
    }

};


/* Unobtrusive Flash Objects (UFO) v3.21 <http://www.bobbyvandersluis.com/ufo/>
   Copyright 2005, 2006 Bobby van der Sluis
   This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
*/

var UFO = {
    req: ["movie", "width", "height", "majorversion", "build"],
    opt: ["play", "loop", "menu", "quality", "scale", "salign", "wmode", "bgcolor", "base", "flashvars", "devicefont", "allowscriptaccess", "seamlesstabbing", "allowfullscreen"],
    optAtt: ["id", "name", "align"],
    optExc: ["swliveconnect"],
    ximovie: "ufo.swf",
    xiwidth: "215",
    xiheight: "138",
    ua: navigator.userAgent.toLowerCase(),
    pluginType: "",
    fv: [0,0],
    foList: [],

    create: function(FO, id) {
        if (!UFO.uaHas("w3cdom") || UFO.uaHas("ieMac")) return;
        UFO.getFlashVersion();
        UFO.foList[id] = UFO.updateFO(FO);
        UFO.createCSS("#" + id, "visibility:hidden;");
        UFO.domLoad(id);
    },

    updateFO: function(FO) {
        if (typeof FO.xi != "undefined" && FO.xi == "true") {
            if (typeof FO.ximovie == "undefined") FO.ximovie = UFO.ximovie;
            if (typeof FO.xiwidth == "undefined") FO.xiwidth = UFO.xiwidth;
            if (typeof FO.xiheight == "undefined") FO.xiheight = UFO.xiheight;
        }
        FO.mainCalled = false;
        return FO;
    },

    domLoad: function(id) {
        var _t = setInterval(function() {
            if ((document.getElementsByTagName("body")[0] != null || document.body != null) && document.getElementById(id) != null) {
                UFO.main(id);
                clearInterval(_t);
            }
        }, 250);
        if (typeof document.addEventListener != "undefined") {
            document.addEventListener("DOMContentLoaded", function() { UFO.main(id); clearInterval(_t); } , null); // Gecko, Opera 9+
        }
    },

    main: function(id) {
        var _fo = UFO.foList[id];
        if (_fo.mainCalled) return;
        UFO.foList[id].mainCalled = true;
        document.getElementById(id).style.visibility = "hidden";
        if (UFO.hasRequired(id)) {
            if (UFO.hasFlashVersion(parseInt(_fo.majorversion, 10), parseInt(_fo.build, 10))) {
                if (typeof _fo.setcontainercss != "undefined" && _fo.setcontainercss == "true") UFO.setContainerCSS(id);
                UFO.writeSWF(id);
            }
            else if (_fo.xi == "true" && UFO.hasFlashVersion(6, 65)) {
                UFO.createDialog(id);
            }
        }
        document.getElementById(id).style.visibility = "visible";
    },

    createCSS: function(selector, declaration) {
        var _h = document.getElementsByTagName("head")[0];
        var _s = UFO.createElement("style");
        if (!UFO.uaHas("ieWin")) _s.appendChild(document.createTextNode(selector + " {" + declaration + "}")); // bugs in IE/Win
        _s.setAttribute("type", "text/css");
        _s.setAttribute("media", "screen");
        _h.appendChild(_s);
        if (UFO.uaHas("ieWin") && document.styleSheets && document.styleSheets.length > 0) {
            var _ls = document.styleSheets[document.styleSheets.length - 1];
            if (typeof _ls.addRule == "object") _ls.addRule(selector, declaration);
        }
    },

    setContainerCSS: function(id) {
        var _fo = UFO.foList[id];
        var _w = /%/.test(_fo.width) ? "" : "px";
        var _h = /%/.test(_fo.height) ? "" : "px";
        UFO.createCSS("#" + id, "width:" + _fo.width + _w +"; height:" + _fo.height + _h +";");
        if (_fo.width == "100%") {
            UFO.createCSS("body", "margin-left:0; margin-right:0; padding-left:0; padding-right:0;");
        }
        if (_fo.height == "100%") {
            UFO.createCSS("html", "height:100%; overflow:hidden;");
            UFO.createCSS("body", "margin-top:0; margin-bottom:0; padding-top:0; padding-bottom:0; height:100%;");
        }
    },

    createElement: function(el) {
        return (UFO.uaHas("xml") && typeof document.createElementNS != "undefined") ?  document.createElementNS("http://www.w3.org/1999/xhtml", el) : document.createElement(el);
    },

    createObjParam: function(el, aName, aValue) {
        var _p = UFO.createElement("param");
        _p.setAttribute("name", aName);
        _p.setAttribute("value", aValue);
        el.appendChild(_p);
    },

    uaHas: function(ft) {
        var _u = UFO.ua;
        switch(ft) {
            case "w3cdom":
                return (typeof document.getElementById != "undefined" && typeof document.getElementsByTagName != "undefined" && (typeof document.createElement != "undefined" || typeof document.createElementNS != "undefined"));
            case "xml":
                var _m = document.getElementsByTagName("meta");
                var _l = _m.length;
                for (var i = 0; i < _l; i++) {
                    if (/content-type/i.test(_m[i].getAttribute("http-equiv")) && /xml/i.test(_m[i].getAttribute("content"))) return true;
                }
                return false;
            case "ieMac":
                return /msie/.test(_u) && !/opera/.test(_u) && /mac/.test(_u);
            case "ieWin":
                return /msie/.test(_u) && !/opera/.test(_u) && /win/.test(_u);
            case "gecko":
                return /gecko/.test(_u) && !/applewebkit/.test(_u);
            case "opera":
                return /opera/.test(_u);
            case "safari":
                return /applewebkit/.test(_u);
            default:
                return false;
        }
    },

    getFlashVersion: function() {
        if (UFO.fv[0] != 0) return;
        if (navigator.plugins && typeof navigator.plugins["Shockwave Flash"] == "object") {
            UFO.pluginType = "npapi";
            var _d = navigator.plugins["Shockwave Flash"].description;
            if (typeof _d != "undefined") {
                _d = _d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
                var _m = parseInt(_d.replace(/^(.*)\..*$/, "$1"), 10);
                var _r = /r/.test(_d) ? parseInt(_d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
                UFO.fv = [_m, _r];
            }
        }
        else if (window.ActiveXObject) {
            UFO.pluginType = "ax";
            try { // avoid fp 6 crashes
                var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
            }
            catch(e) {
                try {
                    var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
                    UFO.fv = [6, 0];
                    _a.AllowScriptAccess = "always"; // throws if fp < 6.47
                }
                catch(e) {
                    if (UFO.fv[0] == 6) return;
                }
                try {
                    var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
                }
                catch(e) {}
            }
            if (typeof _a == "object") {
                var _d = _a.GetVariable("$version"); // bugs in fp 6.21/6.23
                if (typeof _d != "undefined") {
                    _d = _d.replace(/^\S+\s+(.*)$/, "$1").split(",");
                    UFO.fv = [parseInt(_d[0], 10), parseInt(_d[2], 10)];
                }
            }
        }
    },

    hasRequired: function(id) {
        var _l = UFO.req.length;
        for (var i = 0; i < _l; i++) {
            if (typeof UFO.foList[id][UFO.req[i]] == "undefined") return false;
        }
        return true;
    },

    hasFlashVersion: function(major, release) {
        return (UFO.fv[0] > major || (UFO.fv[0] == major && UFO.fv[1] >= release)) ? true : false;
    },

    writeSWF: function(id) {
        var _fo = UFO.foList[id];
        var _e = document.getElementById(id);
        if (UFO.pluginType == "npapi") {
            if (UFO.uaHas("gecko") || UFO.uaHas("xml")) {
                while(_e.hasChildNodes()) {
                    _e.removeChild(_e.firstChild);
                }
                var _obj = UFO.createElement("object");
                _obj.setAttribute("type", "application/x-shockwave-flash");
                _obj.setAttribute("data", _fo.movie);
                _obj.setAttribute("width", _fo.width);
                _obj.setAttribute("height", _fo.height);
                var _l = UFO.optAtt.length;
                for (var i = 0; i < _l; i++) {
                    if (typeof _fo[UFO.optAtt[i]] != "undefined") _obj.setAttribute(UFO.optAtt[i], _fo[UFO.optAtt[i]]);
                }
                var _o = UFO.opt.concat(UFO.optExc);
                var _l = _o.length;
                for (var i = 0; i < _l; i++) {
                    if (typeof _fo[_o[i]] != "undefined") UFO.createObjParam(_obj, _o[i], _fo[_o[i]]);
                }
                _e.appendChild(_obj);
            }
            else {
                var _emb = "";
                var _o = UFO.opt.concat(UFO.optAtt).concat(UFO.optExc);
                var _l = _o.length;
                for (var i = 0; i < _l; i++) {
                    if (typeof _fo[_o[i]] != "undefined") _emb += ' ' + _o[i] + '="' + _fo[_o[i]] + '"';
                }
                _e.innerHTML = '<embed type="application/x-shockwave-flash" src="' + _fo.movie + '" width="' + _fo.width + '" height="' + _fo.height + '" pluginspage="http://www.macromedia.com/go/getflashplayer"' + _emb + '></embed>';
            }
        }
        else if (UFO.pluginType == "ax") {
            var _objAtt = "";
            var _l = UFO.optAtt.length;
            for (var i = 0; i < _l; i++) {
                if (typeof _fo[UFO.optAtt[i]] != "undefined") _objAtt += ' ' + UFO.optAtt[i] + '="' + _fo[UFO.optAtt[i]] + '"';
            }
            var _objPar = "";
            var _l = UFO.opt.length;
            for (var i = 0; i < _l; i++) {
                if (typeof _fo[UFO.opt[i]] != "undefined") _objPar += '<param name="' + UFO.opt[i] + '" value="' + _fo[UFO.opt[i]] + '" />';
            }
            var _p = window.location.protocol == "https:" ? "https:" : "http:";
            _e.innerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + _objAtt + ' width="' + _fo.width + '" height="' + _fo.height + '" codebase="' + _p + '//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=' + _fo.majorversion + ',0,' + _fo.build + ',0"><param name="movie" value="' + _fo.movie + '" />' + _objPar + '</object>';
        }
    },

    createDialog: function(id) {
        var _fo = UFO.foList[id];
        UFO.createCSS("html", "height:100%; overflow:hidden;");
        UFO.createCSS("body", "height:100%; overflow:hidden;");
        UFO.createCSS("#xi-con", "position:absolute; left:0; top:0; z-index:1000; width:100%; height:100%; background-color:#fff; filter:alpha(opacity:75); opacity:0.75;");
        UFO.createCSS("#xi-dia", "position:absolute; left:50%; top:50%; margin-left: -" + Math.round(parseInt(_fo.xiwidth, 10) / 2) + "px; margin-top: -" + Math.round(parseInt(_fo.xiheight, 10) / 2) + "px; width:" + _fo.xiwidth + "px; height:" + _fo.xiheight + "px;");
        var _b = document.getElementsByTagName("body")[0];
        var _c = UFO.createElement("div");
        _c.setAttribute("id", "xi-con");
        var _d = UFO.createElement("div");
        _d.setAttribute("id", "xi-dia");
        _c.appendChild(_d);
        _b.appendChild(_c);
        var _mmu = window.location;
        if (UFO.uaHas("xml") && UFO.uaHas("safari")) {
            var _mmd = document.getElementsByTagName("title")[0].firstChild.nodeValue = document.getElementsByTagName("title")[0].firstChild.nodeValue.slice(0, 47) + " - Flash Player Installation";
        }
        else {
            var _mmd = document.title = document.title.slice(0, 47) + " - Flash Player Installation";
        }
        var _mmp = UFO.pluginType == "ax" ? "ActiveX" : "PlugIn";
        var _uc = typeof _fo.xiurlcancel != "undefined" ? "&xiUrlCancel=" + _fo.xiurlcancel : "";
        var _uf = typeof _fo.xiurlfailed != "undefined" ? "&xiUrlFailed=" + _fo.xiurlfailed : "";
        UFO.foList["xi-dia"] = { movie:_fo.ximovie, width:_fo.xiwidth, height:_fo.xiheight, majorversion:"6", build:"65", flashvars:"MMredirectURL=" + _mmu + "&MMplayerType=" + _mmp + "&MMdoctitle=" + _mmd + _uc + _uf };
        UFO.writeSWF("xi-dia");
    },

    expressInstallCallback: function() {
        var _b = document.getElementsByTagName("body")[0];
        var _c = document.getElementById("xi-con");
        _b.removeChild(_c);
        UFO.createCSS("body", "height:auto; overflow:auto;");
        UFO.createCSS("html", "height:auto; overflow:auto;");
    },

    cleanupIELeaks: function() {
        var _o = document.getElementsByTagName("object");
        var _l = _o.length
        for (var i = 0; i < _l; i++) {
            _o[i].style.display = "none";
            for (var x in _o[i]) {
                if (typeof _o[i][x] == "function") {
                    _o[i][x] = null;
                }
            }
        }
    }
};

if (typeof window.attachEvent != "undefined" && UFO.uaHas("ieWin")) {
    window.attachEvent("onunload", UFO.cleanupIELeaks);
}
