/**
 * jex.js
 *
 * jex (Photo-Online Javascript Framework)
 *
 * @copyright iLibris
 * @author    Alan Schatteman
 * @license   license
 * @version   1.0
 * @package   photo-online
 */

var jexBasePath;

/**
 * PROTOTYPES
 ************/
if (!Array.indexOf) { // IE fix
    Array.prototype.indexOf = function(obj) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == obj) {
                return i;
            }
        }
        return -1;
    }
}
if (!String.right) { // right substring
    String.prototype.right = function(i) {
        // ABCDE - 2 => DE
        return this.substr(this.length-i);
    }
}
if (!String.left) { // left substring
    String.prototype.left = function(i) {
        // ABCDE - 2 => AB
        return this.substr(0,i);
    }
}

/**
 * jex initialization
 */
if (typeof jex == "undefined") { var jex = {

    /**
     * properties
     */
    baseScriptUri:    "",
    _layout:          "serenity",
    _modIncluded:     new Array(),
    _extIncluded:     new Array(),
    _styleIncluded:   new Array(),
    ajaxPath:         './',
    _texts:           {},
    _index:           -1,

    /**
     * methods
     */
    getXMLHttpObj: function() {
        if (typeof(XMLHttpRequest) != 'undefined') {
            return new XMLHttpRequest();
        }
        var axO = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.4.0',
                   'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP',
                   'Microsoft.XMLHTTP'], i;
        for (i = 0; i < axO.length; i++) {
            try {
                return new ActiveXObject(axO[i]);
            }
            catch(e) {
            }
        }
        return null;
    },

    /**
     * moduleLoaded
     */
    moduleLoaded: function(module)
    {
        for (var i = 0, max = this._modIncluded.length; i < max; i++) {
            if (this._modIncluded[i] == module) {
                return true;
            }
        }
        return false;
    },

    /**
     * externalLoaded
     */
    externalLoaded: function(sSrc)
    {
        for(var i=0,iM=jex._extIncluded.length;i<iM;i++){
            if(this._extIncluded[i]==eSrc){
                return true;
            }
        }
        return false;
    },

    /**
     * setLayout
     */
    setLayout: function(sLayout)
    {
        if (jex._layout != sLayout) {
            jex._layout = sLayout;

            // reload previous styles
            for (var i = 0, iMax = this._styleIncluded.length; i < iMax; i++) {
                jex.loadStyle(this._styleIncluded[i], true);
            }
        }
    },

    /**
     * setAjaxPath
     */
    setAjaxPath: function(sPath)
    {
        jex.ajaxPath = sPath;
    },

    /**
     *
     */
    layoutPath: function()
    {
        return jex.baseScriptUri+"src/themes/"+jex._layout;
    },
    imagePath: function()
    {
        return this.layoutPath()+"/img";
    },

    /**
     * styleLoaded
     */
    styleLoaded: function(style)
    {
        for (var i = 0, iMax = this._styleIncluded.length; i < iMax; i++) {
            if (this._styleIncluded[i] == style) {
                return true;
            }
        }
        return false;
    },

    /**
     * loadStyle
     */
    loadStyle: function(style, bOverride)
    {
        if (bOverride || !jex.styleLoaded(style)) {
            this._styleIncluded[this._styleIncluded.length] = style;

            var suffix = jex.browser.isMsie ? "ie" : "gecko";
            jex.html.insertCssFile(jex.baseScriptUri+"src/themes/"+jex._layout+"/css/"+style+"_"+suffix+".css?"+jex.date.secondsSince1970);
        }
    },

    /**
     * _includePath
     */
    _includePath: function(sPath)
    {
        var oXML = jex.getXMLHttpObj();

        // use xmlhttprequest + eval to load the page
        //if (oXML != false) { // Doesn't work in IE?
        if (oXML && (typeof oXML == "object")) {

            oXML.open('GET', sPath, false);
            oXML.send(null);

            // eval the page
            if(window.execScript){
              //alert(oXML.responseText);//UNCOMMENT THIS TO DEBUG THE IE EVAL BUG
              window.execScript(oXML.responseText);//eval in global scope for IE
            }
            else{
              eval(oXML.responseText);
            }

            // pull out every line
            var strarray = oXML.responseText.split(/\n/);

            // a regexp that matches function lines
            var oRegExp = /^\s*function\s*([a-z_0-9]+)/i;

            // find all matches
            for (var i = 0; i < strarray.length; i++) {
                var matches = oRegExp.exec(strarray[i]);
                if (matches != null) {
                    window[matches[1]] = eval(matches[1]);
                }
            }
        }
        else if (document.head != null) {
            // IE, use ye old <script> method
            document.head.insertAdjacentHTML('beforeEnd', '<script></script>');
        }
        else {
            // everything else, use <script> method.
            var h = document.getElementsByTagName('head');
            h[0].insertAdjacentHTML('beforeEnd', '<script></script>');
        }
    },

    /**
     * require
     */
    require: function(sModule)
    {
        if (!jex.moduleLoaded(sModule)) {
            jex._modIncluded[this._modIncluded.length]=sModule;
            var sPath=jex.baseScriptUri+"src/"+sModule.replace(".", "/")+".js?"+jex.date.secondsSince1970;
            jex._includePath(sPath);
        }
    },

    /**
     * requireExternal
     */
    requireExternal: function(sPath)
    {
        if(!jex.externalLoaded(sPath)){
            jex._extIncluded[this._extIncluded.length]=sPath;
            /*var sPath=sPath+"?"+jex.date.secondsSince1970;*/
            jex._includePath(sPath);
        }
    },

    /**
     * byId
     */
    byId: function(sId, eParent)
    {
        if (!eParent) {
            return document.getElementById(sId);
        }
        else {
            var eElem = null;
            if ($(eParent).attr("jextype")=="tabcontainer") {
                return eParent.byId(sId);
            }
            else if (eParent.childNodes) {
                for (var i = 0; i < eParent.childNodes.length && eElem == null; i++) {
                    if (eParent.childNodes[i].id == sId) {
                        eElem = eParent.childNodes[i];
                    }
                    else {
                        eElem = jex.byId(sId, eParent.childNodes[i]);
                    }
                }
            }
            return eElem;
        }
    },

    /**
     * byIdRecursive
     */
    byIdRecursive: function(sId, eParent)
    {
        if (eParent && eParent.childNodes && eParent.childNodes.length) {
            for (var i = 0, iMax = eParent.childNodes.length; i < iMax; i++) {
                var eElem = eParent.childNodes[i];
                if (jex.isElement(eElem) && eElem.id != sId) {
                    eElem = jex.byIdRecursive(sId, eElem);
                }
                if (jex.isElement(eElem) && eElem.id == sId) {
                    return eElem;
                }
            }
        }

        return null;
    },

    /**
     * widgetById
     */
    widgetById: function(sId, eParent)
    {
        var eChild = jex.byId(sId, eParent);
        if (!eChild || !jex.isElement(eChild)) {
            return null;
        }
        var eWidget=$(eChild).data("parentWidget");
        return jex.isElement(eWidget) ? eWidget : eChild;
    },

    /**
     * isElement
     */
    isElement: function(e)
    {
        return (e && jex.typeOf(e) == "object" && e.tagName) ? true : false;
    },

    /**
     * isFragment
     */
    isFragment: function(e)
    {
        return (e && jex.typeOf(e) == "object" && (e.nodeName == "#documentfragment") || (e.nodeName == "#document fragment") || (e.nodeName == "#document-fragment"));
    },

    /**
     * isText
     */
    isText: function(e)
    {
        return (e && jex.typeOf(e) == "object" && e.nodeName == "#text");
    },

    /**
     * isInput
     */
    isInput: function(e)
    {
        return (jex.isElement(e) && ((e.tagName=="INPUT"&&e.type!="button"&&e.type!="submit"&&e.type!="reset")||e.tagName=="SELECT"||e.tagName=="TEXTAREA"));
    },

    /**
     * setText
     */
    setText: function(sName, sText)
    {
        jex._texts[sName] = sText;
    },

    /**
     * getText
     */
    getText: function(sName)
    {
        return (jex._texts[sName] ? ""+jex._texts[sName]+"" : ""+sName+"");
    },

    /**
     * hasChildren
     */
    hasChildren: function(e)
    {
        return (this.isElement(e) && e.childNodes && e.childNodes.length);
    },

    /**
     * getElementsByType
     *
     * ... not recusive, why not???
     */
    getElementsByType: function(e, sType)
    {
        var a = new Array();

        if (!e || !e.childNodes || !e.childNodes.length) {
            return a;
        }

        for (var i = 0; i < e.childNodes.length; i++) {
            if (jex.typeOf(e.childNodes[i]) == "object" && e.childNodes[i].tagName) {
                a.push(e.childNodes[i]);
            }
        }

        return a;
    },

    /**
     * getElementsByAttribute
     */
    getElementsByAttribute: function(sAtt, sAttValue, eParent, sTagName)
    {
        var a = new Array();

        var e = jex.isElement(eParent) ? eParent : document.body;

        var aChild = e.getElementsByTagName((sTagName || '*'));

        for (var i = 0; i < aChild.length; i++) {
            if ((!sTagName||aChild[i].tagName==sTagName)&&(typeof aChild[i].getAttribute=="function"&&aChild[i].getAttribute(sAtt)==sAttValue)) {
                a.push(aChild[i]);
            }
        }

        return a;
    },

    /**
     * byChildren
     */
    byChildren: function(e)
    {
        if (!e || !e.childNodes || !e.childNodes.length) {
            return null;
        }

        if (arguments && arguments.length) {
            for (var c = 1; c < arguments.length; c++) {
                var aNodes = jex.getElementsByType(e, "object");
                if (!aNodes[arguments[c]]) {
                    return null;
                }
                e = aNodes[arguments[c]];
            }
        }

        return e;
    },

    /**
     * typeOf
     */
    typeOf: function(oValue)
    {
        var s = typeof oValue;
        if (s === 'object') {
            if (oValue) {
                if (oValue instanceof Array) {
                    s = 'array';
                }
            }
            else {
                s = 'null';
            }
        }
        return s.toLowerCase();
    },

    /**
     * clone
     */
    clone: function(oData)
    {
        var oNew = null;

        var sType = jex.typeOf(oData);
        switch (sType) {

            case "object":
                oNew = oData.cloneNode();
                break;

            case "array":
                oNew = new Array();
                for (var i = 0; i < oData.length; i++) {
                    oNew.push(jex.clone(oData[i]));
                }
                break;

            default:
                oNew = oData;
        }

        return oNew;
    },

    /**
     * newIndex
     */
    newIndex: function()
    {
        return ++jex._index;
    },

    /**
     * newUUID
     */
    newUUID: function()
    {
        var d = new Date();
        return jex.md5.hex_md5(""+d.getTime()+(++jex._index)+"");
    },

    /**
     * enableFocus
     */
    enableFocus: function(e, bChildren)
    {
        if (!e) {
            return;
        }

        e.onfocus = null;

        if (bChildren) {
            for (var i = 0; i < e.childNodes.length; i++) {
                jex.enableFocus(e.childNodes[i], bChildren);
            }
        }
    },

    /**
     * disableFocus
     */
    disableFocus: function(e, bChildren)
    {
        if (!e) {
            return;
        }

        e.onfocus = function(e){this.blur();}

        if (bChildren) {
            for (var i = 0; i < e.childNodes.length; i++) {
                jex.disableFocus(e.childNodes[i], bChildren);
            }
        }
    },

    /**
     * enableSelection
     */
    enableSelection: function(e, bChildren)
    {
        if (!e) {
            return;
        }

        e.unselectable = "off";
        e.onselectstart = function() { return true; };
        if (e.style) { e.style.MozUserSelect = ""; }

        if (bChildren) {
            for (var i = 0; i < e.childNodes.length; i++) {
                jex.enableSelection(e.childNodes[i], bChildren);
            }
        }
    },

    /**
     * disableSelection
     */
    disableSelection: function(e, bChildren)
    {
        if (!jex.isElement(e)) {
            return;
        }

        e.unselectable = "on";
        e.onselectstart = function() { return false; };
        if (e.style) {
            e.style.MozUserSelect = "none";
        }

        if (bChildren) {
            for (var i = 0; i < e.childNodes.length; i++) {
                jex.disableSelection(e.childNodes[i], bChildren);
            }
        }
    },

    /**
     * collectionToArray
     */
    collectionToArray: function(oCollection)
    {
        a = new Array();
        for (i = 0; i < oCollection.length; i++)
            a[a.length] = oCollection[i];
        return a;
    },

    /**
     * styleById
     */
    styleById: function(elemId)
    {
        return  obj = document.layers ? document.layers[elemId]
                                      : document.getElementById ? document.getElementById(elemId).style
                                                                : document.all[elemId].style;
    },

    /**
     * readRequest
     */
    readRequest: function()
    {
        var oReq={};
        var sReq=window.location.search.substring(1);
        var aReq=sReq.split("&");
        for (var i=0;i<aReq.length;i++) {
            var aIt=aReq[i].split("=");
            oReq[aIt[0]]=aIt[1];
        }
        return oReq;
    }

};}

/**
 * date initialization
 */
if (typeof jex.date == "undefined") { jex.date = {

    /**
     * variables
     */
    secondsSince1970: null

};

var oDate = new Date();
jex.date.secondsSince1970 = oDate.getTime();

}

/**
 * constant initialization
 */
if (typeof jex.constant == "undefined") { jex.constant = {

    TEXT               :  1,
    TEXT_SMALL         :  2,
    TEXT_MEDIUM        :  3,
    TEXT_LARGE         :  4,
    TEXTAREA           :  5,
    TEXTAREA_SMALL     :  6,
    TEXTAREA_MEDIUM    :  7,
    TEXTAREA_LARGE     :  8,
    CHECKBOX           :  9,
    CHECKBOX_TEXT      : 10,
    RADIO              : 11,
    SELECT             : 12,
    RICHTEXTBOX        : 13,
    RICHTEXTBOX_SMALL  : 14,
    RICHTEXTBOX_MEDIUM : 15,
    RICHTEXTBOX_LARGE  : 16,

    LINK_URL    : 1,
    LINK_ACTION : 2,

    EVENT_ONCLICK     :  1,
    EVENT_ONDBLCLICK  :  2,
    EVENT_ONMOUSEOVER :  3,
    EVENT_ONMOUSEOUT  :  4,

    POS_DEFAULT     : 0,
    POS_TOPLEFT     : 1,
    POS_TOP         : 2,
    POS_TOPRIGHT    : 3,
    POS_LEFT        : 4,
    POS_MIDDLE      : 5,
    POS_RIGHT       : 6,
    POS_BOTTOMLEFT  : 7,
    POS_BOTTOM      : 8,
    POS_BOTTOMRIGHT : 9,

    PASSWORD_BAD:    0,
    PASSWORD_WEAK:   1,
    PASSWORD_MEDIUM: 2,
    PASSWORD_STRONG: 3,

    AURIGMA_CAB_VERSION: "4,7,16,0",
    AURIGMA_JAR_VERSION: "2.7.16.0",

    HTML_FILLUP: '<span style="font-size:1px;">&nbsp;</span>',

    POST : 1,
    GET  : 2,

    LEFT  : -1,
    RIGHT :  1,

    OR_HORIZONTAL : 1,
    OR_VERTICAL   : 2,

    STATUS_OK    : 1,
    STATUS_ERROR : 2,

    INCH : 25.4,
    PPI  : 72,

    GECKO_BOGUS : '<br type="_moz">'

};}

/**
 * get basepath
 */
if (jexBasePath) {
    jex.baseScriptUri = jexBasePath;
}

/**
 * get base uri path
 */
(function(){
    if (jexBasePath != null) {
        jex.baseScriptUri = jexBasePath;
    }
    else if ((jex.baseScriptUri == "") && document && document.getElementsByTagName) {
        var scripts = document.getElementsByTagName("script");
        var rePkg = /(jex)\.js([\?\.]|$)/i;
        for (var i = 0; i < scripts.length; i++) {
            var src = scripts[i].getAttribute("src");
            if (!src) {
                continue;
            }
            var m = src.match(rePkg);
            if (m) {
                var root = src.substring(0, m.index);
                if (jex.baseScriptUri == "") {
                    jex.baseScriptUri = root;
                }
                break;
            }
        }
    }
})();

/**
 * browser initialization
 */
if (typeof jex.browser == "undefined") { jex.browser = {

    /**
     * properties
     */
    browser:       null,
    identifier:    null,
    version:       null,
    engine:        null,
    engineVersion: null,

    isGecko:       false,
    isMsie:        false,
    isKhtml:       false,
    isOmniweb:     false,
    isOpera:       false,
    isRobot:       false,
    isIcab:        false,
    isNetfront:    false,
    isMozold:      false,
    isElinks:      false,
    isW3m:         false,
    isLinks:       false,
    isJava:        false,
    isLibwwwFm:    false,
    isDillo:       false,

    os:            null,
    osVersion:     null,

    isWindows:     false,
    isLinux:       false,
    isMac:         false,
    isUnix:        false,

    numFrames:     0,

    /**
     * getBrowser
     */
    getBrowser: function(obj)
    {
        var b = new Array("unknown", "unknown", "unknown", "unknown");

        var brs=jex.browser.isEmpty(obj)?navigator.userAgent.toLowerCase():obj;
        jex.browser.browser=brs;

        if (brs.search(/omniweb[\/\s]v?(\d+([\.-]\d)*)/) != -1) {
        // Omniweb
            b[0]="omniweb";
            b[1]=brs.match(/omniweb[\/\s]v?(\d+([\.-]\d)*)/)[1];
            (b[1] > 4.5 ? b[2]="khtml" : b[2]="omniweb");
            (brs.search(/omniweb[\/\s]((\d+([\.-]\d)*)-)?v(\d+([\.-]\d)*)/) == -1 ?       b[3]=brs.match(/omniweb[\/\s](\d+([\.-]\d)*)/)[1] :        b[3]=brs.match(/omniweb[\/\s]((\d+([\.-]\d)*)-)?v(\d+([\.-]\d)*)/)[4]);
        } else if (brs.search(/opera[\/\s](\d+(\.?\d)*)/) != -1) {
        // Opera
            b[0]="opera";
            b[1]=brs.match(/opera[\/\s](\d+(\.?\d)*)/)[1];
            b[2]="opera";
            b[3]=b[1];
        } else if (brs.search(/crazy\s?browser\s(\d+(\.?\d)*)/) != -1) {
        // Crazy Browser
            b[0]="crazy";
            b[1]=brs.match(/crazy\s?browser\s(\d+(\.?\d)*)/)[1];
            b[2]="msie";
            b[3]=jex.browser.getMSIEVersion();
        } else if (brs.search(/myie2/) != -1) {
        // MyIE2
            b[0]="myie2";
            b[2]="msie";
            b[3]=brs.match(/msie\s(\d+(\.?\d)*)/)[1];
        } else if (brs.search(/netcaptor/) != -1) {
        // NetCaptor
            b[0]="netcaptor";
            b[1]=brs.match(/netcaptor\s(\d+(\.?\d)*)/)[1];
            b[2]="msie";
            b[3]=jex.browser.getMSIEVersion();
        } else if (brs.search(/avant\sbrowser/) != -1) {
        // Avant Browser
            b[0]="avantbrowser";
            b[2]="msie";
            b[3]=jex.browser.getMSIEVersion();
        } else if (brs.search(/msn\s(\d+(\.?\d)*)/) != -1) {
        // MSN Explorer
            b[0]="msn";
            b[1]=brs.match(/msn\s(\d+(\.?\d)*)/)[1];
            b[2]="msie";
            b[3]=jex.browser.getMSIEVersion();
        } else if (brs.search(/msie\s(\d+(\.?\d)*)/) != -1) {
        // MS Internet Explorer
            b[0]="msie";
            b[1]=jex.browser.getMSIEVersion();
            b[2]="msie";
            b[3]=b[1];
        } else if (brs.search(/powermarks\/(\d+(\.?\d)*)/) != -1) {
        // PowerMarks
            b[0]="powermarks";
            b[1]=brs.match(/powermarks\/(\d+(\.?\d)*)/)[1];
            b[2]="msie";
            try {
                b[3]=jex.browser.getMSIEVersion();
            } catch (e) { }
        } else if (brs.search(/konqueror[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Konqueror
            b[0]="konqueror";
            b[1]=brs.match(/konqueror[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="khtml";
        } else if (brs.search(/safari\/(\d)*/) != -1) {
        // Safari
            b[0]="safari";
            b[1]=brs.match(/safari\/(\d+(\.?\d*)*)/)[1];
            b[2]="khtml";
            b[3]=brs.match(/applewebkit\/(\d+(\.?\d*)*)/)[1];
        } else if(brs.search(/zyborg/) != -1) {
        // Zyborg (SSD)
            b[0]="zyborg";
            b[1]=brs.match(/zyborg\/(\d+(\.?\d)*)/)[1];
            b[2]="robot";
            b[3]="-1"
        } else if (brs.search(/netscape6[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Netscape 6.x
            b[0]="netscape";
            b[1]=brs.match(/netscape6[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/netscape\/(7\.\d*)/) != -1) {
        // Netscape 7.x
            b[0]="netscape";
            b[1]=brs.match(/netscape\/(7\.\d*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/galeon[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Galeon
            b[0]="galeon";
            b[1]=brs.match(/galeon[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/nautilus[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Nautilus
            b[0]="nautilus";
            b[1]=brs.match(/nautilus[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/firefox[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Firefox
            b[0]="firefox";
            b[1]=brs.match(/firefox[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/k-meleon[\/\s](\d+([\.-]\d)*)/) != -1) {
        // K-Meleon
            b[0]="kmeleon";
            b[1]=brs.match(/k-meleon[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/firebird[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Firebird
            b[0]="firebird";
            b[1]=brs.match(/firebird[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/phoenix[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Phoenix
            b[0]="phoenix";
            b[1]=brs.match(/phoenix[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/camino[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Camino
            b[0]="camino";
            b[1]=brs.match(/camino[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/epiphany[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Epiphany
            b[0]="epiphany";
            b[1]=brs.match(/epiphany[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/chimera[\/\s](\d+([\.-]\d)*)/) != -1) {
        // Chimera
            b[0]="chimera";
            b[1]=brs.match(/chimera[\/\s](\d+([\.-]\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/icab[\s\/]?(\d+(\.?\d)*)/) !=-1) {
        // iCab
            b[0]="icab";
            b[1]=brs.match(/icab[\s\/]?(\d+(\.?\d)*)/)[1];
            b[2]="icab";
            b[3]=b[1];
        } else if (brs.search(/netfront\/(\d+([\._]\d)*)/) != -1) {
        // NetFront
            b[0]="netfront";
            b[1]=brs.match(/netfront\/(\d+([\._]\d)*)/)[1];
            b[2]="netfront";
            b[3]=b[1];
        } else if (brs.search(/netscape4\/(\d+([\.-]\d)*)/) != -1) {
        // Netscape 4.x
            b[0]="netscape";
            b[1]=brs.match(/netscape4\/(\d+([\.-]\d)*)/)[1];
            b[2]="mozold";
            b[3]=b[1];
        } else if ( (brs.search(/mozilla\/(4.\d*)/) != -1) && (brs.search(/msie\s(\d+(\.?\d)*)/) == -1) ) {
            b[0]="netscape";
            b[1]=brs.match(/mozilla\/(4.\d*)/)[1];
            b[2]="mozold";
            b[3]=b[1];
        } else if ((brs.search(/mozilla\/5.0/) != -1) && (brs.search(/gecko\//) != -1)) {
        // Mozilla Seamonkey
            b[0]="mozsea";
            b[1]=brs.match(/rv\x3a(\d+(\.?\d)*)/)[1];
            b[2]="gecko";
            b[3]=jex.browser.getGeckoVersion();
        } else if (brs.search(/elinks/) != -1) {
        // ELinks
            b[0]="elinks";
            (brs.search(/elinks\/(\d+(\.?\d)*)/) == -1 ?
                b[1]=brs.match(/elinks\s\x28(\d+(\.?\d)*)/)[1] :
                b[1]=brs.match(/elinks\/(\d+(\.?\d)*)/)[1]);
            b[2]="elinks";
            b[3]=b[1];
        } else if (brs.search(/w3m\/(\d+(\.?\d)*)/) != -1) {
        // w3m
            b[0]="w3m"
            b[1]=brs.match(/(^w3m|\sw3m)\/(\d+(\.?\d)*)/)[2];
            b[2]="w3m";
            b[3]=b[1];
        } else if (brs.search(/links/) != -1) {
        // Links
            b[0]="links";
            (brs.search(/links\/(\d+(\.?\d)*)/) == -1 ? b[1]=brs.match(/links\s\x28(\d+(\.?\d)*)/)[1] : b[1]=brs.match(/links\/(\d+(\.?\d)*)/)[1]);
            b[2]="links";
            b[3]=b[1];
        } else if (brs.search(/java[\/\s]?(\d+([\._]\d)*)/) != -1) {
        // Java (as web-browser)
            b[0]="java";
            b[1]=brs.match(/java[\/\s]?(\d+([\._]\d)*)/)[1];
            b[2]="java";
            b[3]=b[1];
        } else if(brs.search(/lynx/) != -1) {
        // Lynx (SSD)
            b[0]="lynx";
            b[1]=brs.match(/lynx\/(\d+(\.?\d)*)/)[1];
            b[2]="libwww-fm";
            b[3]=brs.match(/libwww-fm\/(\d+(\.?\d)*)/)[1];
        } else if(brs.search(/dillo/) != -1) {
        // Dillo (SSD)
            b[0]="dillo";
            b[1]=brs.match(/dillo\s*\/*(\d+(\.?\d)*)/)[1];/**/
            b[2]="dillo";
            b[3]=b[1];
        } else if(brs.search(/wget/) != -1) {
        // wget (SSD)
            b[0]="wget";
            b[1]=brs.match(/wget\/(\d+(\.?\d)*)/)[1];
            b[2]="robot";
            b[3]="-1"
        } else if(brs.search(/googlebot\-image/) != -1) {
        // GoogleBot-Image (SSD)
            b[0]="googlebotimg";
            b[1]=brs.match(/googlebot\-image\/(\d+(\.?\d)*)/)[1];
            b[2]="robot";
            b[3]="-1"
        } else if(brs.search(/googlebot/) != -1) {
        // GoogleBot (SSD)
            b[0]="googlebot";
            b[1]=brs.match(/googlebot\/(\d+(\.?\d)*)/)[1];
            b[2]="robot";
            b[3]="-1"
        } else if(brs.search(/msnbot/) != -1) {
        // MSNBot (SSD)
            b[0]="msnbot";
            b[1]=brs.match(/msnbot\/(\d+(\.?\d)*)/)[1];
            b[2]="robot";
            b[3]="-1"
        } else if(brs.search(/turnitinbot/) != -1) {
        // Turnitin (SSD)
            b[0]="turnitinbot";
            b[1]=brs.match(/turnitinbot\/(\d+(\.?\d)*)/)[1];
            b[2]="robot";
            b[3]="-1"
        } else {
            b[0]="unknown";
        }

        jex.browser.identifier    = b[0];
        jex.browser.version       = b[1];
        jex.browser.engine        = b[2];
        jex.browser.engineVersion = b[3];

        jex.browser.isGecko       = (jex.browser.engine=="gecko");
        jex.browser.isMsie        = (jex.browser.engine=="msie");
        jex.browser.isKhtml       = (jex.browser.engine=="khtml");
        jex.browser.isOmniweb     = (jex.browser.engine=="omniweb");
        jex.browser.isOpera       = (jex.browser.engine=="opera");
        jex.browser.isRobot       = (jex.browser.engine=="robot");
        jex.browser.isIcab        = (jex.browser.engine=="icab");
        jex.browser.isNetfront    = (jex.browser.engine=="netfront");
        jex.browser.isMozold      = (jex.browser.engine=="mozold");
        jex.browser.isElinks      = (jex.browser.engine=="elinks");
        jex.browser.isW3m         = (jex.browser.engine=="w3m");
        jex.browser.isLinks       = (jex.browser.engine=="links");
        jex.browser.isJava        = (jex.browser.engine=="java");
        jex.browser.isLibwwwFm    = (jex.browser.engine=="libwww-fm");
        jex.browser.isDillo       = (jex.browser.engine=="dillo");

        return b;
    },

    /**
     * getMajorVersion
     *
     * Return browser's (actual) major version or -1 if bad version entered
     */
    getMajorVersion: function(v)
    {
        return (isEmpty(v) ? -1 : (hasDot(v) ? v : v.match(/(\d*)(\.\d*)*/)[1]))
    },

    /**
     * getMinorVersion
     *
     * Return browser's (actual) minor version or -1 if bad version entered
     */
    getMinorVersion: function(v)
    {
        return (!jex.browser.isEmpty(v) ? (!hasDot(v) ? v.match(/\.(\d*([-\.]\d*)*)/)[1] : 0) : -1);
    },

    /**
     * getOS
     *
     * Return operating system we are running on top of
     */
    getOS: function(obj) {

        var os = new Array("unknown", "unknown");

        var brs=jex.browser.isEmpty(obj)?navigator.userAgent.toLowerCase():obj;

        if (brs.search(/windows\sce/) != -1) {
            os[0]="wince";
            try {
                os[1]=brs.match(/windows\sce\/(\d+(\.?\d)*)/)[1];
            } catch (e) { }
        } else if ((brs.search(/windows/) !=-1) || ((brs.search(/win9\d{1}/) != -1))) {
            os[0]="win";
            if (brs.search(/nt\s5\.1/) != -1) {
                os[1]="xp";
            } else if (brs.search(/nt\s5\.0/) != -1) {
                os[1]="2000";
            } else if ((brs.search(/win98/) != -1) || (brs.search(/windows\s98/) != -1)) {
                os[1]="98";
            } else if (brs.search(/windows\sme/) != -1) {
                os[1]="me";
            } else if (brs.search(/nt\s5\.2/) != -1) {
                os[1]="win2k3";
            } else if ((brs.search(/windows\s95/) != -1) || (brs.search(/win95/) != -1)) {
                os[1]="95";
            } else if ((brs.search(/nt\s4\.0/) != -1) || (brs.search(/nt4\.0/)) !=  -1) {
                os[1]="nt4";
            } else if ((brs.search(/nt\s6\.0/) != -1) || (brs.search(/nt6\.0/)) !=  -1) {
                os[1]="vista";
            }
        } else if (brs.search(/linux/) !=-1) {
            os[0]="linux";
            try {
                os[1] = brs.match(/linux\s?(\d+(\.?\d)*)/)[1];
            } catch (e) { }
        } else if (brs.search(/mac\sos\sx/) !=-1) {
            os[0]="macosx";
        } else if (brs.search(/freebsd/) !=-1) {
            os[0]="freebsd";
            try {
                os[1] = brs.match(/freebsd\s(\d(\.\d)*)*/)[1];
            } catch (e) { }
        } else if (brs.search(/sunos/) !=-1) {
            os[0]="sunos";
            try {
                os[1]=brs.match(/sunos\s(\d(\.\d)*)*/)[1];
            } catch (e) { }
        } else if (brs.search(/irix/) !=-1) {
            os[0]="irix";
            try {
                os[1]=brs.match(/irix\s(\d(\.\d)*)*/)[1];
            } catch (e) { }
        } else if (brs.search(/openbsd/) !=-1) {
            os[0]="openbsd";
            try {
                os[1] = brs.match(/openbsd\s(\d(\.\d)*)*/)[1];
            } catch (e) { }
        } else if ( (brs.search(/macintosh/) !=-1) || (brs.search(/mac\x5fpowerpc/) != -1) ) {
            os[0]="macclassic";
        } else if (brs.search(/os\/2/) !=-1) {
            os[0]="os2";
            try {
                os[1]=brs.match(/warp\s((\d(\.\d)*)*)/)[1];
            } catch (e) { }
        } else if (brs.search(/openvms/) !=-1) {
            os[0]="openvms";
            try {
                os[1]=brs.match(/openvms\sv((\d(\.\d)*)*)/)[1];
            } catch (e)  { }
        } else if ( (brs.search(/amigaos/) !=-1) || (brs.search(/amiga/) != -1) ) {
            os[0]="amigaos";
            try {
                os[1]=brs.match(/amigaos\s?(\d(\.\d)*)*/)[1];
            } catch (e) { }
        } else if (brs.search(/hurd/) !=-1) {
            os[0]="hurd";
        } else if (brs.search(/hp\-ux/) != -1) {
            os[0]="hpux";
            try {
                os[1]=brs.match(/hp\-ux\sb\.[\/\s]?(\d+([\._]\d)*)/)[1];
            } catch (e) { }
        } else if ( (brs.search(/unix/) !=-1) || (brs.search(/x11/) != -1 ) ) {
            os[0]="unix";
        } else if (brs.search(/cygwin/) !=-1) {
            os[0]="cygwin";
        } else if (brs.search(/java[\/\s]?(\d+([\._]\d)*)/) != -1) {
            os[0]="java";
            try {
                os[1]=brs.match(/java[\/\s]?(\d+([\._]\d)*)/)[1];
            } catch (e) { }
        } else if (brs.search(/palmos/) != -1) {
            os[0]="palmos";
        } else if (brs.search(/symbian\s?os\/(\d+([\._]\d)*)/) != -1) {
            os[0]="symbian";
            try {
                os[1]=brs.match(/symbian\s?os\/(\d+([\._]\d)*)/)[1];
            } catch (e) { }
        } else {
            os[0]="unknown";
        }

        jex.browser.os        = os[0];
        jex.browser.osVersion = os[1];

        jex.browser.isWindows  = (jex.browser.os=="win"||jex.browser.os=="wince");
        jex.browser.isLinux    = (jex.browser.os=="linux");
        jex.browser.isMac      = (jex.browser.os=="macosx"||jex.browser.os=="macclassic");
        jex.browser.isUnix     = (jex.browser.os=="unix");

        return os;
    },

    /**
     * getFrames
     *
     * Returns whether the document is loaded in frames or not
     */
    getFrames: function() {
        jex.browser.numFrames = (parent.frames) ? ((parent.frames.length) ? parent.frames.length : 0) : 0;
        return jex.browser.numFrames;
    },

    /**
     * getGeckoVersion
     *
     * Return Gecko version
     */
    getGeckoVersion: function() {
        return jex.browser.browser.match(/gecko\/([0-9]+)/)[1];
    },

    /**
     * getMSIEVersion
     *
     * Return MSIE version
     */
    getMSIEVersion: function() {
        return jex.browser.browser.match(/msie\s(\d+(\.?\d)*)/)[1];
    },

    /**
     * getFullUAString
     *
     * Return full browser UA string
     */
    getFullUAString: function(obj) {
        (jex.browser.isEmpty(obj) ? brs = navigator.userAgent.toLowerCase() : brs = obj);
        return brs;
    },

    /**
     * hasFlashPlugin
     *
     * Is Flash plug-in installed?
     */
    hasFlashPlugin: function(obj) {

        (jex.browser.isEmpty(obj) ? brs = navigator.userAgent.toLowerCase() : brs = obj);

        var f = new Array("0", "0");
        var brwEng = jex.browser.getBrowser(obj)[2];
        var opSys = jex.browser.getOS(obj)[0];

        //if (jex.browser.getBrowser(obj)[2]!="msie") {
        if ((brwEng=="gecko") || (brwEng=="opera") || (brwEng=="khtml") || (brwEng=="mozold") || (opSys=="macosx") || (opSys=="macclassic")) {
            // Non-IE Flash plug-in detection

            if (navigator.plugins && navigator.plugins.length) {
                x = navigator.plugins["Shockwave Flash"];
                if (x) {
                    f[0] = 2;
                    if (x.description) {
                        y = x.description;
                        f[1] = y.charAt(y.indexOf('.')-1);
                    }
                } else {
                    f[0] = 1;
                }
                if (navigator.plugins["Shockwave Flash 2.0"]) {
                    f[0] = 2;
                    f[0] = 2;
                }
            } else if (navigator.mimeTypes && navigator.mimeTypes.length) {
                x = navigator.mimeTypes['application/x-shockwave-flash'];
                if (x && x.enabledPlugin) {
                    f[0] = 2;
                } else {
                    f[0] = 1;
                }
            }

       return f;

      } else if (brwEng=="msie") {
          // IE flash detection.
           for(var i=15; i>0; i--) {
               try {
                   var flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + i);
                   f[1] = i;
                   break;
                   //return;
               } catch(e) { }
           }

           if (f[1]>0) {
               f[0]=2
           } else {
               f[0]=1
           }
       return f;
       } else {
           f[0]=0;
           f[1]=0;
           return f;
       }
    },

    /**
     * isEmpty
     *
     * FOR INTERNAL USE ONLY. THIS FUNCTIONS ARE SUBJECT TO CHANGE, DON'T TRUST THEM
     * Is input empty?
     */
    isEmpty: function(input) {
        return (input==null || input =="")
    },

    /**
     * hasDot
     *
     * Does this string contain a dot?
     */
    hasDot: function(input) {
        return (input.search(/\./) == -1)
    },

    /**
     * info
     */
    info: function()
    {
        return "browser: "+jex.browser.browser+"\n"
             + "identifier: "+jex.browser.identifier+"\n"
             + "version: "+jex.browser.version+"\n"
             + "engine: "+jex.browser.engine+"\n"
             + "engineVersion: "+jex.browser.engineVersion+"\n"
             + "os: "+jex.browser.os+"\n"
             + "osVersion: "+jex.browser.osVersion+"\n"
             + "numFrames: "+jex.browser.numFrames;
    }

};}

/**
 * get browser
 */
jex.browser.getBrowser();
jex.browser.getOS();
jex.browser.getFrames();

/**
 * html initialization
 */
if (typeof jex.html == "undefined") { jex.html = {

    /**
     * insertCssFile
     */
    insertCssFile: function(url)
    {
        if (!url) {
            return;
        }

        var oXML = jex.getXMLHttpObj();
        if (oXML && (typeof oXML == "object")) {
            oXML.open('GET', url, false);
            oXML.send(null);

            var cssContents = oXML.responseText;
            jex.html.insertCssText(cssContents);
        }
    },

    /**
     * insertCssText
     */
    insertCssText: function(cssStr)
    {
        if (!cssStr) {
            return; //  HTMLStyleElement
        }
        cssStr = jex.html.fixPathsInCssText(cssStr);

        var style = document.createElement("style");
        style.setAttribute("type", "text/css");
        // IE is b0rken enough to require that we add the element to the doc
        // before changing it's properties
        var head = document.getElementsByTagName("head")[0];
        if (!head) { // must have a head tag
            return; //  HTMLStyleElement
        }
        else {
            head.appendChild(style);
        }
        if (style.styleSheet) { // IE
            var setFunc = function() {
                try {
                    style.styleSheet.cssText = cssStr;
                }
                catch(e) { }
            };
            if (style.styleSheet.disabled) {
                setTimeout(setFunc, 10);
            }
            else {
                setFunc();
            }
        }
        else { // w3c
            var cssText = document.createTextNode(cssStr);
            style.appendChild(cssText);
        }
        return style;   //  HTMLStyleElement
    },

    /**
     * fixPathsInCssText
     */
    fixPathsInCssText: function(cssStr) {
        if (!cssStr) {
            return;
        }
        var match, str = "", url = "", urlChrs = "[\\t\\s\\w\\(\\)\\/\\.\\\\'\"-:#=&?~]+";
        var regex = new RegExp('url\\(\\s*('+urlChrs+')\\s*\\)');
        var regexProtocol = /(file|https?|ftps?):\/\//;
        var regexTrim=new RegExp("^[\\s]*(['\"]?)("+urlChrs+")\\1[\\s]*?$");

        while (match = regex.exec(cssStr)){
            url = jex.baseScriptUri + "src/" + match[1].replace(regexTrim, "$2");
            str += cssStr.substring(0, match.index) + "url(" + url + ")";
            cssStr = cssStr.substr(match.index + match[0].length);
        }
        return str + cssStr;    //  string
    }

};}

/**
 * math initialization
 */
if (typeof jex.math == "undefined") { jex.math = {

    /**
     * isEven
     */
    isEven: function(iNum)
    {
        return ((iNum % 2) ? false : true);
    },

    /**
     * rad2Deg
     */
    rad2Deg: function(dRad)
    {
        return ((dRad * 180) / Math.PI);
    },

    /**
     * deg2Rad
     */
    deg2Rad: function(dDeg)
    {
        return ((dDeg * Math.PI) / 180);
    },

    /**
     * absDegrees
     */
    absDegrees: function(dDeg)
    {
        // -360 < x < 360
        dDeg = dDeg % 360;

        // make positive
        if (dDeg < 0) {
            dDeg = 360 + dDeg;
        }

        return dDeg;
    },

    /**
     * rotatedRectangleDim
     */
    rotatedRectangleDim: function(dWidth, dHeight, dDegrees, bRound)
    {
        dDegrees = Math.abs(dDegrees) % 180;
        if (dDegrees > 90) {
            dDegrees = 180 - dDegrees;
        }

        var oDim;
        if (dDegrees == 0) {
            oDim = {width: dWidth, height: dHeight};
        }
        else if (dDegrees == 90) {
            oDim = {width: dHeight, height: dWidth};
        }
        else {
            dRads = jex.math.deg2Rad(dDegrees);
            dAW = Math.cos(dRads) * dWidth;
            dAH = Math.sin(dRads) * dWidth;
            dBW = Math.sin(dRads) * dHeight;
            dBH = Math.cos(dRads) * dHeight;
            oDim = {width: dAW + dBW, height: dAH + dBH};
        }

        if (bRound) {
            oDim.width = Math.round(oDim.width);
            oDim.height = Math.round(oDim.height);
        }

        return oDim;
    },

    /**
     * ptToPxl
     */
    ptToPxl: function(pt, dpi)
    {
        return Math.round((pt * dpi) / jex.constant.PPI);
    },

    /**
     * mmToPxl
     */
    mmToPxl: function(mm, dpi)
    {
        return Math.round((mm * dpi) / jex.constant.INCH);
    },

    /**
     * pxlToMm
     */
    pxlToMm: function(pxl, dpi)
    {
        return (pxl * jex.constant.INCH) / dpi;
    },

    /**
     * crop
     */
    crop: function(iPhotoW, iPhotoH, iCropW, iCropH)
    {
        var oDim = {"width":0,"height":0};

        var dP = iPhotoW / iPhotoH;
        var dC = iCropW / iCropH;
        if (dC > dP) {
            oDim.width  = iCropW;
            oDim.height = Math.round((iPhotoH * iCropW) / iPhotoW);
        }
        else {
            oDim.width  = Math.round((iPhotoW * iCropH) / iPhotoH);
            oDim.height = iCropH;
        }

        return oDim;
    },

    /**
     * fit
     */
    fit: function(iOrigW, iOrigH, iFitW, iFitH, bOuter)
    {
        var oDim = {"width":0,"height":0};

        var bS =  iFitW / iFitH > iOrigW / iOrigH;
        if ((bS && !bOuter) || (!bS && bOuter)) {
            oDim.width  = Math.round((iOrigW * iFitH) / iOrigH);
            oDim.height = iFitH;
        }
        else {
            oDim.width  = iFitW;
            oDim.height = Math.round((iOrigH * iFitW) / iOrigW);
        }

        return oDim;
    },

    /**
     * min
     */
    min: function(aList)
    {
        var oMin = null;

        if (jex.typeOf(aList) == "array") {
            var iMax = aList.length;
            if (iMax) {
                oMin = aList[0];
                for (var i = 1; i < iMax; i++) {
                    if (oMin > aList[i]) {
                        oMin = aList[i];
                    }
                }
            }
        }

        return oMin;
    },

    /**
     * max
     */
    max: function(aList)
    {
        var oMax = null;

        if (jex.typeOf(aList) == "array") {
            var iMax = aList.length;
            if (iMax) {
                oMax = aList[0];
                for (var i = 1; i < iMax; i++) {
                    if (oMax < aList[i]) {
                        oMax = aList[i];
                    }
                }
            }
        }

        return oMax;
    }

};}

/**
 * basic initialization
 */
if (typeof jex.basic == "undefined") { jex.basic = {

    /**
     * properties
     */
    marked_row: new Array(),     //This array is used to remember mark status of rows in browse mode
    _iScrLck:   {x: 0, y: 0},

    /**
     * poLog
     */
    poLog: function(object)
    {
        xajax_performXajaxFunction('poLog', object);
    },

    /**
     *areYouSure
     */
    areYouSure: function()
    {
        if (typeof webtext != "undefined") {
            return confirm(webtext['are_you_sure']);
        }
        else {
            return confirm('Are you sure?');
        }
    },

    /**
     * objectExists
     */
    objectExists: function(objName)
    {
        var obj = document.getElementById(objName);
        return (obj != null);

    },

    /**
     * isAlien
     */
    isAlien: function(a) {
       return jex.basic.isObject(a) && typeof a.constructor != 'function';
    },

    /**
     * isArray
     */
    isArray: function(a) {
        return jex.typeOf(a) == "array" && a.constructor == Array;
    },

    /**
     * isBoolean
     */
    isBoolean: function(a) {
        return typeof a == 'boolean';
    },

    /**
     * isEmpty
     */
    isEmpty: function(o)
    {
        return ((o == null) || (o.length == 0));
    },

    /**
     * isDigit
     */
    isDigit: function(c)
    {
        return ((c >= "0") && (c <= "9"));
    },

    /**
     * isInteger
     */
    isInteger: function(sParam)
    {
        var i;

        if (jex.basic.isEmpty(sParam)) {
            if (jex.basic.isInteger.arguments.length == 1) {
                return 0;
            }
            else {
                return (jex.basic.isInteger.arguments[1] == true);
            }
        }

        for (i = 0; i < sParam.length; i++) {
            var c = sParam.charAt(i);

            if (!jex.basic.isDigit(c)) return false;
        }

        return true;
    },

    /**
     * isFunction
     */
    isFunction: function(a) {
        return typeof a == 'function';
    },

    /**
     * isNull
     */
    isNull: function(a) {
        return a === null;
    },

    /**
     * isNumber
     */
    isNumber: function(a) {
        return typeof a == 'number' && isFinite(a);
    },

    /**
     * isObject
     */
    isObject: function(a) {
        return jex.typeOf(a) == 'object' || jex.basic.isFunction(a);
    },

    /**
     * isString
     */
    isString: function(a) {
        return typeof a == 'string';
    },

    /**
     * isUndefined
     */
    isUndefined: function(a) {
        return typeof a == 'undefined';
    },

    /**
     * passwordLevel
     */
    passwordLevel: function(sPassword)
    {
        var oStrongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
        var oMediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g");
        var oEnoughRegex = new RegExp("(?=.{6,}).*", "g");

        if (!sPassword || sPassword.length == 0 || false == oEnoughRegex.test(sPassword)) {
            return jex.constant.PASSWORD_BAD;
        } else if (oStrongRegex.test(sPassword)) {
            return jex.constant.PASSWORD_STRONG;
        } else if (oMediumRegex.test(sPassword)) {
            return jex.constant.PASSWORD_MEDIUM;
        }
        return jex.constant.PASSWORD_WEAK;
    },

    /**
     * passwordLevelMessage
     */
    passwordLevelMessage: function(iLevel)
    {
        if (iLevel == jex.constant.PASSWORD_STRONG) {
            return jex.getText("strong password");
        }
        else if (iLevel == jex.constant.PASSWORD_MEDIUM) {
            return jex.getText("medium password");
        }
        else if (iLevel == jex.constant.PASSWORD_WEAK) {
            return jex.getText("weak password");
        }
        else if (iLevel == jex.constant.PASSWORD_BAD) {
            return jex.getText("bad password");
        }
        return "";
    },

    /**
     * eventAction
     */
    eventAction: function(oEvent) {
        if (!oEvent) {
            return null;
        }
        else if (typeof oEvent == "function") {
            return oEvent;
        }
        else if (typeof oEvent == "string") {
            return function(){eval(oEvent);};
        }
        return null;
    },

    /**
     * invertCheckbox
     */
    invertCheckbox: function(cbxName)
    {
        var cbx = document.getElementById(cbxName);
        cbx.checked = !cbx.checked;
    },

    /**
     * inArray
     */
    inArray: function(oItem, aArray)
    {
        if (!oItem || !aArray) {
            return false;
        }

        if (!aArray.length) {
            return false;
        }

        for (var i = 0; i < aArray.length; i++) {
            if (aArray[i] == oItem) {
                return true;
            }
        }

        return false;
    },

    /**
     * indexOf
     */
    indexOf: function(aList, oItem)
    {
        for (var i = 0; i < aList.length; i++) {
            if (aList[i] == oItem) {
                return i;
            }
        }
        return -1;
    },

    /**
     * arrayMerge
     */
    arrayMerge: function(arr1, arr2)
    {
        var arr = new Array();

        if (arr1 && arr1.length) {
            for (var i = 0; i < arr1.length; i++) {
                arr.push(arr1[i]);
            }
        }
        if (arr2 && arr2.length) {
            for (var i = 0; i < arr2.length; i++) {
                arr.push(arr2[i]);
            }
        }

        return arr;
    },

    /**
     * objToArr
     */
    objToArr: function(obj)
    {
        var arr=new Array();
        if(jex.basic.isObject(obj)){
            for(s in obj){
                arr.push([s,obj[s]]);
            }
        }
        return arr;
    },

    /**
     * arrToObj
     */
    arrToObj: function(arr)
    {
        var obj={};
        if(jex.basic.isArray(arr)){
            for(var i=0,iMax=arr.length;i<iMax;i++){
                if(jex.basic.isArray(arr[i])&&(arr[i].length==2)){
                    obj[arr[i][0]]=arr[i][1];
                }
            }
        }
        return obj;
    },

    /**
     * objectInfo
     */
    objectInfo: function(oItem, sPrefix)
    {
        if (!oItem || typeof oItem != "object") {
            return;
        }

        var sText = '';
        var sPrefix = (sPrefix ? ""+sPrefix+"" : "");
        for (s in oItem) {
            var sType = typeof oItem[s];
            switch (sType) {

                case 'string':
                case 'boolean':
                case 'integer':
                    sText += sPrefix+s+" ("+sType+"): "+oItem[s]+"\n";
                    break;

                case 'function':
                    sText += sPrefix+s+" ("+sType+")"+"\n";
                    break;

                case 'object':
                    sText += sPrefix+s+" ("+sType+"):\n";
                    sText += sPrefix+jex.basic.objectInfo(oItem[s], '- ');
                    break;
            }
        }

        return sText;
    },

    /**
     * getInputValue
     *
     * Return the current value (or selected value) of the
     * input field... The field can be of type radio, select,
     * input or textarea. Return null if value is not found.
     */
    getInputValue: function(oInput)
    {
        var eInput = jex.isElement(oInput) ? oInput : jex.byId(""+oInput+"");

        // invalid input element
        if (!eInput) {
            return null;
        }

        // selectbox single select
        else if (eInput.type == "select-one") {
            return (eInput.selectedIndex >= 0 && eInput.options.length) ? eInput.options[eInput.selectedIndex].value : null;
        }
        // selectbox multiple select
        else if (eInput.type == "select-multiple") {
            var aRes = new Array();
            for (var i = 0; i < eInput.options.length; i++) {
                if (eInput.options[i].selected) {
                    aRes.push(eInput.options[i].value);
                }
            }
            return aRes;
        }
        // radio buttons
        else if (eInput.length) {
            return jex.basic.getRadioValue(eInput);
        }
        // checkbox
        else if (eInput.type == "checkbox") {
            return (eInput.checked ? 1 : 0);
        }
        // all others
        else {
            return eInput.value;
        }
    },

    /**
     * getRadioValue
     *
     * Return the selected value from a group of radio
     * buttons. 'radioObj' should be a radio button object.
     */
    getRadioValue: function(radioObj)
    {
        for (var i = 0; i < radioObj.length; i++) {
            if (radioObj[i].checked) {
                return radioObj[i].value;
            }
        }
        return null;
    },

    /**
     * getRadioValueById
     *
     * Return the selected value from a group of radio
     * buttons. 'radioObj' should be a radio button object.
     */
    getRadioValueById: function(sId, iOffset)
    {
        for (var i = iOffset, eRadio = jex.byId(sId+"_"+i); eRadio; i++, eRadio = jex.byId(sId+"_"+i)) {
            if (eRadio.checked) {
                return eRadio.value;
            }
        }
        return null;
    },

    /**
     * getLastRow
     */
    getLastRow: function(oTable)
    {
        if (!oTable) {
            return;
        }

        var iRows = oTable.rows.length;
        if (iRows > 0) {
            return oTable.rows[iRows-1];
        }
        else {
            var aRows = oTable.getElementsByTagName("tr");
            iRows = aRows.length;
            if (iRows > 0) {
                return aRows[iRows-1];
            }
            else {
                return null;
            }
        }
    },

    /**
     * getTotalRows
     */
    getTotalRows: function(oTable)
    {
        if (!oTable) {
            return;
        }

        var iRows = oTable.rows.length;
        if (iRows > 0) {
            return iRows;
        }
        else {
            var aRows = oTable.getElementsByTagName("tr");
            return aRows.length;
        }
    },

    /**
     * toggleBox
     */
    toggleBox: function(szDivID, iState) // 1 visible, 0 hidden
    { // design & code by 3SIGN  http://www.3sign.be
       var obj = document.layers ? document.layers[szDivID] :
       document.getElementById ?  document.getElementById(szDivID).style :
       document.all[szDivID].style;
       obj.visibility = document.layers ? (iState ? "show" : "hide") :
       (iState ? "visible" : "hidden");
    },

    /**
     * Popup
     */
    Popup: function(url, w, h)
    {
        var sDim='';
        if (w&&h){
            x=((screen.availWidth/2)-(w/2));
            y=((screen.availHeight/2)-(h/2));
            sDim=",width="+w+",height="+h+",top="+y+",left="+x;
        }
        var myWin=null;
        uploadPopup=window.open('','myPopup','menubar=no,scrollbars=yes,resizable=no,status=no,screenX=0,screenY=0'+sDim);
        uploadPopup.focus();
        if (uploadPopup!=null){
            if (uploadPopup.opener==null){
                uploadPopup.opener=self;
            }
            uploadPopup.location.href=url;
        }
    },

    /**
     * stripExtension
     */
    stripExtension: function(sFile)
    {
        var iPos = sFile.lastIndexOf(".");
        if (iPos != -1) {
            return sFile.substring(0, iPos);
        }

        return sFile;
    },

    /**
     * sprintf
     */
    sprintf: function()
    {
        if (!arguments || !arguments.length) {
            return '';
        }

        var sStr = ""+arguments[0]+"";

        var sNew = "";
        var c = 1;
        for (var i = 0; i < sStr.length; i++) {
            if (i < sStr.length - 1 && sStr.charAt(i) == "%") {
                // integer
                //
                if (sStr.charAt(i+1) == "d" || sStr.charAt(i+1) == "f" || sStr.charAt(i+1) == "c") {
                    sNew += ""+(arguments[c]?arguments[c++]:"")+"";
                }
                // char
                else if (sStr.charAt(i+1) == "c") {
                    sNew += ""+(arguments[c]?String.fromCharCode(arguments[c++]):"")+"";
                }
                else if (sStr.charAt(i+1) == "%") {
                    sNew += "%";
                }
                i++;
            }
            else {
                sNew += sStr.charAt(i);
            }
        }

        return sNew;
    },

    /**
     * getExtension
     */
    getExtension: function(sFile)
    {
        var iPos = sFile.lastIndexOf(".");
        if (iPos != -1) {
            return sFile.substring(iPos + 1, sFile.length);
        }

        return "";
    },

    /**
     * randomChar
     */
    randomChar: function(sContainer)
    {
        if (!sContainer || !sContainer.length) {
            sContainer = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        }
        var iNum = Math.round(Math.random() * (sContainer.length - 1));
        return sContainer.charAt(iNum);
    },

    /**
     * randomString
     */
    randomString: function(iMin, iMax, sContainer)
    {
        iMin = !iMin ? 8 : 1 * iMin;
        iMax = !iMax ? 8 : 1 * iMax;

        var sStr = "";
        var iTotal = Math.round(Math.random() * (iMax - iMin)) + iMin;
        for (var i = 0; i < iTotal; i++) {
            sStr += jex.basic.randomChar(sContainer);
        }

        return sStr;
    },

    /**
     * checkMail
     */
    checkMail: function(email)
    {
        var x = email;
        var filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
        if (filter.test(x)) {
            return true;
        } else {
            return false;
        };
    },

    /**
     * setVisibility
     */
    setVisibility: function(oElem, iState)
    {
        var eElem = jex.isElement(oElem) ? oElem : jex.byId(""+oElem+"");
        if (!eElem) {
            return false;
        }
        var oldState = (eElem.style.visibility == "" )
                       ? -1
                       : ( document.layers
                           ? ((eElem.style.visibility == "show")    ? 1 : 0)
                           : ((eElem.style.visibility == "visible") ? 1 : 0) );
        if (oldState == iState) {
            return false;
        }
        eElem.style.visibility = (iState == -1) ? ""
                              : ( document.layers ? (iState ? "show"    : "hide")
                                                  : (iState ? "visible" : "hidden") );
        var sDefault = (eElem.tagName == "THEAD" ||
                        eElem.tagName == "TBODY" ||
                        eElem.tagName == "TFOOT"  ) ? (!jex.browser.isMsie ? "table-row-group" : "")
            : ( (eElem.tagName == "TR") ? (!jex.browser.isMsie ? "table-row" : "")
            : "block" );
        eElem.style.display = (iState == -1) ? ""
                            : (iState ? sDefault : "none");
        return true;
    },

    /**
     * setObjVisibility
     */
    setObjVisibility: function(eObj, iState)
    {
        if (eObj != null) {
            eObj.style.visibility = document.layers ? (iState ? "show"    : "hide")
                                                    : (iState ? "visible" : "hidden");
            if (iState == -1) {
                eObj.style.display="";
            }
            else if (iState) {
                if (eObj.tagName=="TD") {
                    eObj.style.display="table-cell";
                }
                else {
                    eObj.style.display="block";
                }
            }
            else {
                eObj.style.display = "none";
            }
        }
    },

    /**
     * setChildrenVisibility
     */
    setChildrenVisibility: function(oObj, iState)
    {
        var eObj = (typeof oObj == "object") ? oObj : jex.byId(oObj);
        if (eObj != null) {
            for (var i = 0, iMaxI = eObj.childNodes.length; i < iMaxI; i++) {
                if (eObj.childNodes[i].tagName) {
                    jex.basic.setObjVisibility(eObj.childNodes[i], iState);
                }
            }
        }
    },

    /**
     * setOpacity
     */
    setOpacity: function (sId, iOpacity)
    {
        var oStyle = document.getElementById(sId).style;
        oStyle.opacity = (iOpacity / 100);
        oStyle.MozOpacity = (iOpacity / 100);
        oStyle.KhtmlOpacity = (iOpacity / 100);
        oStyle.filter = "alpha(opacity=" + iOpacity + ")";
    },

    /**
     * setObjOpacity
     */
    setObjOpacity: function (eObj, iOpacity)
    {
        eObj.style.opacity = (iOpacity / 100);
        eObj.style.MozOpacity = (iOpacity / 100);
        eObj.style.KhtmlOpacity = (iOpacity / 100);
        eObj.style.filter = "alpha(opacity=" + iOpacity + ")";
    },

    /**
     * toggleObjStyleVisibility
     */
    toggleObjStyleVisibility: function(eStyle)
    {
        var bVisible = ((eStyle.visibility == 'show') || (eStyle.visibility == 'visible'));
        eStyle.visibility = document.layers ? (!bVisible ? "show"    : "hide")
                                            : (!bVisible ? "visible" : "hidden");
        eStyle.display = (!bVisible ? "block" : "none");
    },

    /**
     * toggleVisibility
     */
    toggleVisibility: function(szDivID)
    {
        var eStyle = document.layers ? document.layers[szDivID]
                                     : document.getElementById ? document.getElementById(szDivID).style
                                                               : document.all[szDivID].style;
        this.toggleObjStyleVisibility(eStyle);
    },

    /**
     * setText
     *
     * sets the text of an object
     */
    setText: function(szDivID, text)
    {
        var obj = document.layers ? document.layers[szDivID]
                                  : document.getElementById ? document.getElementById(szDivID)
                                                         : document.all[szDivID];
        obj.innerHTML = text;
    },

    /**
     * toHex
     */
    toHex: function(i)
    {
        hex=i.toString(16);
        if(hex.length==1)hex="0"+hex;
        return hex.toUpperCase();
    },

    /**
     * colorPalette
     */
    colorPalette: function(sActive)
    {
        var aColor={"palette":new Array(),"active":0};
        var i=0;
        for(var g=0;g<256;g+=51){
          for(var b=0;b<256;b+=51){
            for(var r=0;r<256;r+=51,i++){
              var sColor='#'+jex.basic.toHex(r)+jex.basic.toHex(g)+jex.basic.toHex(b);
              if(sColor==sActive){aColor.active=i;}
              aColor.palette.push(sColor);
            }
          }
        }
        var ii=13;
        for(var c=255-ii;c>=ii;c-=ii,i++){
          var sColor='#'+jex.basic.toHex(c)+jex.basic.toHex(c)+jex.basic.toHex(c);
          if(sColor==sActive){aColor.active=i;}
          aColor.palette.push(sColor);
        }
        return aColor;
    },

    /**
     * setScrollPosition
     */
    setScrollPosition: function(x, y)
    {
        window.scrollTo(x, y);
    },

    /**
     * Viewport
     */
    Viewport: function()
    {
        this.windowX = (window.innerWidth ? window.innerWidth : (document.body && document.body.clientWidth ? document.body.clientWidth : 0));
        this.windowY = (window.innerHeight ? window.innerHeight : (document.body && document.body.clientHeight ? document.body.clientHeight : 0));
        this.scrollX = (document.documentElement && document.documentElement.scrollLeft) || window.pageXOffset || self.pageXOffset || document.body.scrollLeft;
        this.scrollY = (document.documentElement && document.documentElement.scrollTop) || window.pageYOffset || self.pageYOffset || document.body.scrollTop;
        this.pageX = (document.documentElement && document.documentElement.scrollWidth) ? document.documentElement.scrollWidth : (document.body.scrollWidth > document.body.offsetWidth) ? document.body.scrollWidth : document.body.offsetWidth;
        this.pageY = (document.documentElement && document.documentElement.scrollHeight) ? document.documentElement.scrollHeight : (document.body.scrollHeight > document.body.offsetHeight) ? document.body.scrollHeight : document.body.offsetHeight;
    },

    /**
     * screenLock
     */
    screenLock: function(bLock)
    {
        // get current screen positions
        if (bLock) {
            var oViewport = new jex.basic.Viewport();
            this._iScrLck.x = oViewport.scrollX;
            this._iScrLck.y = oViewport.scrollY;
        }

        // hide body scrollbars
        document.body.style.overflow = (bLock) ? "hidden" : "auto";

        // restore scroll position
        if (!bLock) {
            jex.basic.setScrollPosition(this._iScrLck.x, this._iScrLck.y);
        }
    },

    /**
     * setPointer
     *
     * Sets/unsets the pointer and marker in browse mode
     *
     * @param   object    the table row
     * @param   integer  the row number
     * @param   string    the action calling this script (over, out or click)
     * @param   string    the default background color
     * @param   string    the color to use for mouseover
     * @param   string    the color to use for marking a row
     *
     * @return  boolean  whether pointer is set or not
     */
    setPointer: function(theRow, theRowNum, theAction, theDefaultColor, thePointerColor, theMarkColor)
    {
        var theCells = null;

        // 1. Pointer and mark feature are disabled or the browser can't get the
        //    row -> exits
        if ((thePointerColor == '' && theMarkColor == '')
            || typeof(theRow.style) == 'undefined') {
            return false;
        }

        // 2. Gets the current row and exits if the browser can't get it
        if (typeof(document.getElementsByTagName) != 'undefined') {
            theCells = theRow.getElementsByTagName('td');
        }
        else if (typeof(theRow.cells) != 'undefined') {
            theCells = theRow.cells;
        }
        else {
            return false;
        }

        // 3. Gets the current color...
        var rowCellsCnt  = theCells.length;
        var domDetect    = null;
        var currentColor = null;
        var newColor     = null;

        // 3.1 ... with DOM compatible browsers except Opera that does not return
        //         valid values with "getAttribute"
        if (typeof(window.opera) == 'undefined'
            && typeof(theCells[0].getAttribute) != 'undefined') {
            currentColor = theCells[0].getAttribute('bgcolor');
            domDetect    = true;
        }
        // 3.2 ... with other browsers
        else {
            currentColor = theCells[0].style.backgroundColor;
            domDetect    = false;
        } // end 3

        // 3.3 ... Opera changes colors set via HTML to rgb(r,g,b) format so fix it
        if (currentColor.indexOf("rgb") >= 0)
        {
            var rgbStr = currentColor.slice(currentColor.indexOf('(') + 1,
                                         currentColor.indexOf(')'));
            var rgbValues = rgbStr.split(",");
            currentColor = "#";
            var hexChars = "0123456789ABCDEF";
            for (var i = 0; i < 3; i++)
            {
                var v = rgbValues[i].valueOf();
                currentColor += hexChars.charAt(v/16) + hexChars.charAt(v%16);
            }
        }

        // 4. Defines the new color
        // 4.1 Current color is the default one
        if (currentColor == ''
            || currentColor.toLowerCase() == theDefaultColor.toLowerCase()) {
            if (theAction == 'over' && thePointerColor != '') {
                newColor              = thePointerColor;
            }
            else if (theAction == 'click' && theMarkColor != '') {
                newColor              = theMarkColor;
                this.marked_row[theRowNum] = true;
                // Garvin: deactivated onclick marking of the checkbox because it's also executed
                // when an action (like edit/delete) on a single item is performed. Then the checkbox
                // would get deactived, even though we need it activated. Maybe there is a way
                // to detect if the row was clicked, and not an item therein...
                // document.getElementById('id_rows_to_delete' + theRowNum).checked = true;
            }
        }
        // 4.1.2 Current color is the pointer one
        else if (currentColor.toLowerCase() == thePointerColor.toLowerCase()
                 && (typeof(this.marked_row[theRowNum]) == 'undefined' || !this.marked_row[theRowNum])) {
            if (theAction == 'out') {
                newColor              = theDefaultColor;
            }
            else if (theAction == 'click' && theMarkColor != '') {
                newColor              = theMarkColor;
                this.marked_row[theRowNum] = true;
                // document.getElementById('id_rows_to_delete' + theRowNum).checked = true;
            }
        }
        // 4.1.3 Current color is the marker one
        else if (currentColor.toLowerCase() == theMarkColor.toLowerCase()) {
            if (theAction == 'click') {
                newColor              = (thePointerColor != '')
                                      ? thePointerColor
                                      : theDefaultColor;
                this.marked_row[theRowNum] = (typeof(this.marked_row[theRowNum]) == 'undefined' || !this.marked_row[theRowNum])
                                      ? true
                                      : null;
                // document.getElementById('id_rows_to_delete' + theRowNum).checked = false;
            }
        } // end 4

        // 5. Sets the new color...
        if (newColor) {
            var c = null;
            // 5.1 ... with DOM compatible browsers except Opera
            if (domDetect) {
                for (c = 0; c < rowCellsCnt; c++) {
                    theCells[c].setAttribute('bgcolor', newColor, 0);
                } // end for
            }
            // 5.2 ... with other browsers
            else {
                for (c = 0; c < rowCellsCnt; c++) {
                    theCells[c].style.backgroundColor = newColor;
                }
            }
        } // end 5

        return true;
    } // end of the 'setPointer()' function

};

jex.loadStyle("basic");

}

/**
 * md5
 *
 * A port of Paul Johnstone's MD5 implementation
 * http://pajhome.org.uk/crypt/md5/index.html
 *
 * Copyright (C) Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 *
 * JEx port by Alan Schatteman
 *
 * @copyright iLibris
 * @author    Alan Schatteman
 * @license   license
 * @version   1.0
 * @package   photo-online
 */

/**
 * md5 Initialization
 */
if (typeof jex.md5 == "undefined") { jex.md5 = {

    /*
     * Configurable variables. You may need to tweak these to be compatible with
     * the server-side, but the defaults work in most cases.
     */
    hexcase: 0,  /* hex output format. 0 - lowercase; 1 - uppercase        */
    b64pad: "", /* base-64 pad character. "=" for strict RFC compliance   */
    chrsz: 8,  /* bits per input character. 8 - ASCII; 16 - Unicode      */
    md5Empty: null,

    /*
     * These are the functions you'll usually want to call
     * They take string arguments and return either hex or base-64 encoded strings
     */
    hex_md5: function(s) {
        return jex.md5.binl2hex(jex.md5.core_md5(jex.md5.str2binl(s), s.length * jex.md5.chrsz));
    },
    b64_md5: function(s) {
        return jex.md5.binl2b64(jex.md5.core_md5(jex.md5.str2binl(s), s.length * jex.md5.chrsz));
    },
    str_md5: function(s) {
        return jex.md5.binl2str(jex.md5.core_md5(jex.md5.str2binl(s), s.length * jex.md5.chrsz));
    },
    hex_hmac_md5: function(key, data) {
        return jex.md5.binl2hex(jex.md5.core_hmac_md5(key, data));
    },
    b64_hmac_md5: function(key, data) {
        return jex.md5.binl2b64(jex.md5.core_hmac_md5(key, data));
    },
    str_hmac_md5: function(key, data) {
        return jex.md5.binl2str(jex.md5.core_hmac_md5(key, data));
    },
    // the default
    hash: function(s) {
        return jex.md5.hex_md5(s);
    },

    /*
     * Perform a simple self-test to see if the VM is working
     */
    md5_vm_test: function()
    {
      return jex.md5.hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
    },

    /*
     * Calculate the MD5 of an array of little-endian words, and a bit length
     */
    core_md5: function(x, len)
    {
      /* append padding */
      x[len >> 5] |= 0x80 << ((len) % 32);
      x[(((len + 64) >>> 9) << 4) + 14] = len;

      var a =  1732584193;
      var b = -271733879;
      var c = -1732584194;
      var d =  271733878;

      for(var i = 0; i < x.length; i += 16)
      {
        var olda = a;
        var oldb = b;
        var oldc = c;
        var oldd = d;

        a = jex.md5.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
        d = jex.md5.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
        c = jex.md5.md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
        b = jex.md5.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
        a = jex.md5.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
        d = jex.md5.md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
        c = jex.md5.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
        b = jex.md5.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
        a = jex.md5.md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
        d = jex.md5.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
        c = jex.md5.md5_ff(c, d, a, b, x[i+10], 17, -42063);
        b = jex.md5.md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
        a = jex.md5.md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
        d = jex.md5.md5_ff(d, a, b, c, x[i+13], 12, -40341101);
        c = jex.md5.md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
        b = jex.md5.md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

        a = jex.md5.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
        d = jex.md5.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
        c = jex.md5.md5_gg(c, d, a, b, x[i+11], 14,  643717713);
        b = jex.md5.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
        a = jex.md5.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
        d = jex.md5.md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
        c = jex.md5.md5_gg(c, d, a, b, x[i+15], 14, -660478335);
        b = jex.md5.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
        a = jex.md5.md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
        d = jex.md5.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
        c = jex.md5.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
        b = jex.md5.md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
        a = jex.md5.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
        d = jex.md5.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
        c = jex.md5.md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
        b = jex.md5.md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

        a = jex.md5.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
        d = jex.md5.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
        c = jex.md5.md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
        b = jex.md5.md5_hh(b, c, d, a, x[i+14], 23, -35309556);
        a = jex.md5.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
        d = jex.md5.md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
        c = jex.md5.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
        b = jex.md5.md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
        a = jex.md5.md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
        d = jex.md5.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
        c = jex.md5.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
        b = jex.md5.md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
        a = jex.md5.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
        d = jex.md5.md5_hh(d, a, b, c, x[i+12], 11, -421815835);
        c = jex.md5.md5_hh(c, d, a, b, x[i+15], 16,  530742520);
        b = jex.md5.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

        a = jex.md5.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
        d = jex.md5.md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
        c = jex.md5.md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
        b = jex.md5.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
        a = jex.md5.md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
        d = jex.md5.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
        c = jex.md5.md5_ii(c, d, a, b, x[i+10], 15, -1051523);
        b = jex.md5.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
        a = jex.md5.md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
        d = jex.md5.md5_ii(d, a, b, c, x[i+15], 10, -30611744);
        c = jex.md5.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
        b = jex.md5.md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
        a = jex.md5.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
        d = jex.md5.md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
        c = jex.md5.md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
        b = jex.md5.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

        a = jex.md5.safe_add(a, olda);
        b = jex.md5.safe_add(b, oldb);
        c = jex.md5.safe_add(c, oldc);
        d = jex.md5.safe_add(d, oldd);
      }
      return Array(a, b, c, d);
    },

    /*
     * These functions implement the four basic operations the algorithm uses.
     */
    md5_cmn: function(q, a, b, x, s, t)
    {
      return jex.md5.safe_add(jex.md5.bit_rol(jex.md5.safe_add(jex.md5.safe_add(a, q), jex.md5.safe_add(x, t)), s),b);
    },
    md5_ff: function(a, b, c, d, x, s, t)
    {
      return jex.md5.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
    },
    md5_gg: function(a, b, c, d, x, s, t)
    {
      return jex.md5.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
    },
    md5_hh: function(a, b, c, d, x, s, t)
    {
      return jex.md5.md5_cmn(b ^ c ^ d, a, b, x, s, t);
    },
    md5_ii: function(a, b, c, d, x, s, t)
    {
      return jex.md5.md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
    },

    /*
     * Calculate the HMAC-MD5, of a key and some data
     */
    core_hmac_md5: function(key, data)
    {
      var bkey = jex.md5.str2binl(key);
      if (bkey.length > 16) {
          bkey = jex.md5.core_md5(bkey, key.length * jex.md5.chrsz);
      }

      var ipad = Array(16), opad = Array(16);
      for(var i = 0; i < 16; i++)
      {
        ipad[i] = bkey[i] ^ 0x36363636;
        opad[i] = bkey[i] ^ 0x5C5C5C5C;
      }

      var hash = jex.md5.core_md5(ipad.concat(jex.md5.str2binl(data)), 512 + data.length * jex.md5.chrsz);
      return jex.md5.core_md5(opad.concat(hash), 512 + 128);
    },

    /*
     * Add integers, wrapping at 2^32. This uses 16-bit operations internally
     * to work around bugs in some JS interpreters.
     */
    safe_add: function(x, y)
    {
      var lsw = (x & 0xFFFF) + (y & 0xFFFF);
      var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
      return (msw << 16) | (lsw & 0xFFFF);
    },

    /*
     * Bitwise rotate a 32-bit number to the left.
     */
    bit_rol: function(num, cnt)
    {
      return (num << cnt) | (num >>> (32 - cnt));
    },

    /*
     * Convert a string to an array of little-endian words
     * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
     */
    str2binl: function(str)
    {
      var bin = Array();
      var mask = (1 << jex.md5.chrsz) - 1;
      for(var i = 0; i < str.length * jex.md5.chrsz; i += jex.md5.chrsz)
        bin[i>>5] |= (str.charCodeAt(i / jex.md5.chrsz) & mask) << (i%32);
      return bin;
    },

    /*
     * Convert an array of little-endian words to a string
     */
    binl2str: function(bin)
    {
      var str = "";
      var mask = (1 << jex.md5.chrsz) - 1;
      for(var i = 0; i < bin.length * 32; i += jex.md5.chrsz)
        str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
      return str;
    },

    /*
     * Convert an array of little-endian words to a hex string.
     */
    binl2hex: function(binarray)
    {
      var hex_tab = jex.md5.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
      var str = "";
      for(var i = 0; i < binarray.length * 4; i++)
      {
        str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
               hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
      }
      return str;
    },

    /*
     * Convert an array of little-endian words to a base-64 string
     */
    binl2b64: function(binarray)
    {
      var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
      var str = "";
      for(var i = 0; i < binarray.length * 4; i += 3)
      {
        var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                    | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                    |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
        for(var j = 0; j < 4; j++)
        {
          if(i * 8 + j * 6 > binarray.length * 32) str += jex.md5.b64pad;
          else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
        }
      }
      return str;
    },

    /**
     * isMd5
     */
    isMd5: function(sMd5)
    {
        var oRegExp = /^[0-9a-f]{32,32}$/;
        return oRegExp.exec(""+sMd5+"") ? true : false;
    }

};

jex.md5.md5Empty = jex.md5.hex_md5("");

}

/**
 * helper
 *
 * helper tooltips
 */
/**
 *  Initialization
 */
if (typeof jex.helper == "undefined") { jex.helper = {

    /**
     * constants
     */
    MESSAGEBOX: "messagebox",
    ADD:        "add",
    EDIT:       "edit",

    /**
     * attach
     */
    _attach: function(eWidget, eRoot)
    {
        if(!eWidget)return false;
        if(!eRoot){
          $(eWidget).data("activated",true).attr("id",$(eWidget).data("id"));
          return false;
        }
        jex.elem.insertBefore(eWidget,eRoot);
        jex.elem.removeElement(eRoot);
        $(eWidget).attr("id",$(eWidget).data("id"));
        return true;
    },

    /**
     * create
     *
     * Examples:
     *
     * oData types:
     * 1. default
     * oData = {
     *     text: "the text"
     * }
     *
     * 2. get help with Ajax call
     * oData = {
     *     text:       "temporary loading text...",
     *     controller: "helper",
     *     action:     "get_help",
     *     args:       ["arg1", "arg2"]
     * }
     *
     * 3. add/type with form-post (get)
     * oData = {
     *     type:   jex.helper.ADD,
     *     action: "external.php",
     *     data:   [
     *         ["initialController",BackOffice.controller],
     *         ["initialAction",BackOffice.action],
     *         ["inp_help_type",ContextHelp::TYPE_MODEL],
     *         ["inp_help_model","Brand"],
     *         ["inp_help_property","brandCode"]
     *     ],
     *     method: jex.constant.GET
     * }
     */
    create: function(sId, oRoot, oData)
    {
        var eRoot = jex.isElement(oRoot) ? oRoot : jex.byId(""+oRoot+"");

        var sClass = "JEX_helper"+(oData&&oData.type?" JEX_helper_"+oData.type:"");

        var eWidget = jex.create.div(null,sClass);

        // style stuff
        $(eWidget).css("width","12px").css("height","12px").css("cursor","pointer").append($(jex.create.pixel(12,12)));

        // set events
        /*
        eWidget.onclick = function()
        {
            this.blur();
        };
        jex.elem.addEvent(eWidget,"mouseover",function(){this.className=$(this).data("class")+" JEX_helper_over";});
        jex.elem.addEvent(eWidget,"mouseout",function(){this.className=$(this).data("class");});
        */
        $(eWidget)
          .mouseover(function(){
            $(this).removeClass("JEX_helper_over").addClass("JEX_helper_over");
            if(!$(this).data("loaded")&&$(this).data("bAJAX")){
              xajax_xajaxPerform($(this).data("controller"),$(this).data("action"),this.id,$(this).data("args"));
            }
          })
          .mouseout(function(){
            $(this).removeClass("JEX_helper_over");
          })
          .click(function(){
            if($(this).data("type")==jex.helper.ADD||$(this).data("type")==jex.helper.EDIT){
              if(oData&&oData.action&&oData.data){
                jex.elem.postForm(oData.action,oData.data,(oData.method?oData.method:jex.constant.POST));
              }
              else{
                $(this).remove();
              }
            }
          })
          .attr("jextype","helper")
          .data("id",(sId?sId:(eRoot?eRoot.id:"JEX_helper_"+jex.newIndex())))
          .data("type",oData&&oData.type?oData.type:jex.helper.MESSAGEBOX)
          .data("class",sClass)
          .data("contents",oData&&oData.text?oData.text:(eRoot?eRoot.innerHTML:""))
          .data("bAJAX",(oData&&oData.controller&&oData.action&&oData.args)?true:false)
          .data("loaded",false);
        if ($(eWidget).data("bAJAX")) {
            $(eWidget)
              .data("controller",oData.controller)
              .data("action",oData.action)
              .data("args",oData.args);
        }

        if ($(eWidget).data("type")==jex.helper.MESSAGEBOX){
          $(eWidget).data("tooltip",jex.tooltip.create($(eWidget).data("contents"),eWidget,true));
        }

        jex.helper._attach(eWidget, eRoot);

        return eWidget;
    },

    /**
     * attach
     */
    attach: function(oRoot)
    {
        return jex.helper.create(null,oRoot,null,false);
    },

    /**
     * attachNew
     */
    attachNew: function(oRoot)
    {
        return jex.helper.create(null,oRoot,null,true);
    },

    /**
     * doLoad
     */
    doLoad: function(sId, oData)
    {
        var eWidget = jex.widgetById(sId);
        if (!sId) {
            return;
        }
        var sContents = "";
        if (jex.typeOf(oData=="object")) {
            // set title
            if (oData.title) {
                sContents+="<div class=\"JEX_helper_title\">"+oData.title+"</div>";
            }
            // set contents
            if (oData.info) {
                sContents+="<div class=\"JEX_helper_contents\">"+oData.info+"</div>";
            }
            // set url
            if (oData.url) {
                var sA=$.gettext("more information");
                sContents+="<div class=\"JEX_helper_url\">";
                if (!oData.params || !oData.params.length) {
                    sContents+="<a href=\""+oData.url+"\" target=\"_blank\">"+sA+"</a>";
                }
                else {
                    var sForm="JEX_helper_form_"+jex.newIndex();
                    sContents+=jex.create.formInnerHTML(sForm,sForm,null,oData.url,jex.constant.POST,oData.params,"_blank",
                        '<a href="##" onclick="this.parentNode.submit();">'+sA+'</a>');
                }
                sContents+="</div>";
            }
        }
        if (!sContents.length) {
            sContents = jex.getText("no help available at this time");
        }
        $(eWidget)
          .data("loaded",true)
          .data("tooltip")
          .setContents(sContents);
    }

};

jex.require("elem");
jex.require("tooltip");

jex.loadStyle("widget");

}
