////////////////////////////////////////////////////////////////////////////////////////////////////
//
//	All scripts copyright (c) 2003-2010 by Comartis AG
//  All rights reserved

var dateinputformat = 'mmddyyyy';
var datesep='/';
var disabledElementBorder='888888';
var disabledElementForeground='888888';
var usingCuteEditor=true;
var usingLMS=true;
var adminURL='http://kdmcuniversity.kdmc.net/admin';
var LMSURL='http://kdmcuniversity.kdmc.net/lms';
var playerURL='http://kdmcuniversity.kdmc.net/player2';
var appURL='http://kdmcuniversity.kdmc.net/lms/';
var appImageURL='http://kdmcuniversity.kdmc.net/lms/images/';
var appImageURLPlusPrefix='http://kdmcuniversity.kdmc.net/lms/images/kdmc_';
var usingOldFormulaEditor = false;
var str_userisvalid=DHFUnescape('This%20username%20is%20still%20free.');
var str_usernotvalid=DHFUnescape('This%20username%20is%20already%20taken%2c%20please%20choose%20another.');
var str_cert_type_id=new DHFString(DHFUnescape('%5bCertificate%20type%20ID%20%24%241%5d'));
// Firebug helper functions
// debug.log	- Display a string or object ... if object then also show a hyperlink to the object
// debug.dir	- Display a tree view of an object
// debug.assert	- Assert that a particular value is true or throw an exception
// debug.trace	- Display a stack trace of JavaScript execution (functions with parameters passed) at the point where debug.trace is called
var debug = {}
debug.log = function(){};
debug.dir = function(){};
debug.assert = function(){};
debug.trace = function(){};
var flashMedia = {	'flv': {		'volume':'75',		'ShowMuteButton':'true',		'ShowPlayButton':'true',		'ShowTimeline':'true',		'ShowTimePlayed':'true',		'ShowVolume':'true',		'autoplay':'false',		'SpaceTogglesPlayPause':'true',		'width':'336',		'height':'270',		'filename':'mediaplayer.swf'	},
	'mp3': {		'volume':'75',		'ShowMuteButton':'true',		'ShowPlayButton':'true',		'ShowTimeline':'true',		'ShowTimePlayed':'true',		'ShowVolume':'true',		'autoplay':'false',		'SpaceTogglesPlayPause':'true',		'width':'309',		'height':'20',		'filename':'MediaPlayer.swf'	}
}
var CreditsDecimalDigits=2;
var minPasswordChars=-1;
var cuteEditorLanguageObj={0: 'en-EN'};
var str_ProcessingRequest=DHFUnescape('Processing%20request...');
var str_cancel='Cancel';
var kSecsPerHour = 3600;
var kSecsPerDay = 86400;
var kSecsPerWeek = 604800;
var DHF = {}; // DHF root namespace

DHF.indexOf = function(el, arr) {
    var len, from;
    
    if (Array.prototype.indexOf) {
        return arr.indexOf(el);
    }

    len = arr.length >>> 0;
    from = Number(arguments[2]) || 0;

    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
    if (from < 0) {
        from += len;
    }

    for (; from < len; from++) {
        if (from in arr && arr[from] === el) {
            return from;
        }
    }
    return -1;
};

DHF.HTMLUtils = {        
    DHFHideAllElements: function() {
        var i, elts;

        document.body.scrollTop = 0;
        
        elts = document.getElementsByTagName('TABLE');
        if(elts && elts.length > 0) {
            for (i = 0; i < elts.length; i++) {
                elts[i].style.display = 'none';
            }
        }
        
        elts = document.getElementsByTagName('DIV');
        if(elts && elts.length > 0) {
            for (i = 0; i < elts.length; i++) {
                elts[i].style.display = 'none';
            }
        }
    }
};

DHF.formUtils = {
    SubmittalForm: function(object, prefix, id, action, method, htmlmsg) {
        var s = '<form id="' + id + '" action="' + action + '" method="' + method + '">';

        s += DHFGenObjStringSub(object, '', prefix);
        
        return {
            add: function(name, value) {
                s += '<input type="hidden" name="' + name + '" value="' + value + '">';
            },

            addObject: function(obj,objname,objpath) {
                s += DHFGenObjStringSub(obj, objname, objpath);
            },

            submit: function() {
                var formContainer, el;

                s += '</form>';
                setAlertIfExists("DoSubmit "+s);

                formContainer = document.createElement('DIV');
                formContainer.innerHTML = s;
                document.body.appendChild(formContainer);
                
                el = document.getElementById(id);
                
                if (el) {
                    el.submit();
                }
            }
        };
    },
    
    GenProcessing: function(htmlmsg) {
        var msgContainer;

        DHF.HTMLUtils.DHFHideAllElements();
        
        msgContainer = document.createElement('DIV');
        msgContainer.style.position = 'absolute';
        msgContainer.style.top = '1px';
        msgContainer.style.left = '1px';
        msgContainer.innerHTML = DHFGenProcessingMsg();
        
        document.body.appendChild(msgContainer);
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
var swfobject = function() {
    var UNDEF = "undefined",
        OBJECT = "object",
        SHOCKWAVE_FLASH = "Shockwave Flash",
        SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
        FLASH_MIME_TYPE = "application/x-shockwave-flash",
        EXPRESS_INSTALL_ID = "SWFObjectExprInst",
        ON_READY_STATE_CHANGE = "onreadystatechange",
        
        win = window,
        doc = document,
        nav = navigator,
        
        plugin = false,
        domLoadFnArr = [main],
        regObjArr = [],
        objIdArr = [],
        listenersArr = [],
        storedAltContent,
        storedAltContentId,
        storedCallbackFn,
        storedCallbackObj,
        isDomLoaded = false,
        isExpressInstallActive = false,
        dynamicStylesheet,
        dynamicStylesheetMedia,
        autoHideShow = true,
    
    /* Centralized function for browser feature detection
        - User agent string detection is only used when no good alternative is possible
        - Is executed directly for optimal performance
    */    
    ua = function() {
        var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
            u = nav.userAgent.toLowerCase(),
            p = nav.platform.toLowerCase(),
            windows = p ? /win/.test(p) : /win/.test(u),
            mac = p ? /mac/.test(p) : /mac/.test(u),
            webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
            ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
            playerVersion = [0,0,0],
            d = null;
        if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
            d = nav.plugins[SHOCKWAVE_FLASH].description;
            if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
                plugin = true;
                ie = false; // cascaded feature detection for Internet Explorer
                d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
                playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
                playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
                playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
            }
        }
        else if (typeof win.ActiveXObject != UNDEF) {
            try {
                var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
                if (a) { // a will return null when ActiveX is disabled
                    d = a.GetVariable("$version");
                    if (d) {
                        ie = true; // cascaded feature detection for Internet Explorer
                        d = d.split(" ")[1].split(",");
                        playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
                    }
                }
            }
            catch(e) {}
        }
        return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
    }(),
    
    /* Cross-browser onDomLoad
        - Will fire an event as soon as the DOM of a web page is loaded
        - Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
        - Regular onload serves as fallback
    */ 
    onDomLoad = function() {
        if (!ua.w3) { return undefined; }
        if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically 
            callDomLoadFunctions();
        }
        if (!isDomLoaded) {
            if (typeof doc.addEventListener != UNDEF) {
                doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
            }        
            if (ua.ie && ua.win) {
                doc.attachEvent(ON_READY_STATE_CHANGE, function() {
                    if (doc.readyState == "complete") {
                        doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee);
                        callDomLoadFunctions();
                    }
                });
                if (win == top) { // if not inside an iframe
                    (function(){
                        if (isDomLoaded) { return undefined; }
                        try {
                            doc.documentElement.doScroll("left");
                        }
                        catch(e) {
                            setTimeout(arguments.callee, 0);
                            return undefined;
                        }
                        callDomLoadFunctions();
                    })();
                }
            }
            if (ua.wk) {
                (function(){
                    if (isDomLoaded) { return undefined; }
                    if (!/loaded|complete/.test(doc.readyState)) {
                        setTimeout(arguments.callee, 0);
                        return undefined;
                    }
                    callDomLoadFunctions();
                })();
            }
            addLoadEvent(callDomLoadFunctions);
        }
    }();
    
    function callDomLoadFunctions(){
        if (isDomLoaded) {
            return undefined;
        }
        try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
            var el = doc.getElementsByTagName("body")[0];
            if (el) {
                var t = el.appendChild(createElement("span"));
                t.parentNode.removeChild(t);
            } else {
                return undefined;
            }
        } catch (e) {
            return undefined;
        }
        isDomLoaded = true;
        var dl = domLoadFnArr.length;
        for (var i = 0; i < dl; i++) {
            domLoadFnArr[i]();
        }
    }
    
    function addDomLoadEvent(fn) {
        if (isDomLoaded) {
            fn();
        }
        else { 
            domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
        }
    }
    
    /* Cross-browser onload
        - Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
        - Will fire an event as soon as a web page including all of its assets are loaded 
     */
    function addLoadEvent(fn) {
        if (typeof win.addEventListener != UNDEF) {
            win.addEventListener("load", fn, false);
        }
        else if (typeof doc.addEventListener != UNDEF) {
            doc.addEventListener("load", fn, false);
        }
        else if (typeof win.attachEvent != UNDEF) {
            addListener(win, "onload", fn);
        }
        else if (typeof win.onload == "function") {
            var fnOld = win.onload;
            win.onload = function() {
                fnOld();
                fn();
            };
        }
        else {
            win.onload = fn;
        }
    }
    
    /* Main function
        - Will preferably execute onDomLoad, otherwise onload (as a fallback)
    */
    function main() { 
        if (plugin) {
            testPlayerVersion();
        }
        else {
            matchVersions();
        }
    }
    
    /* Detect the Flash Player version for non-Internet Explorer browsers
        - Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
          a. Both release and build numbers can be detected
          b. Avoid wrong descriptions by corrupt installers provided by Adobe
          c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
        - Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
    */
    function testPlayerVersion() {
        var b = doc.body;
        var obj = createElement(OBJECT);
        obj.setAttribute("type", FLASH_MIME_TYPE);
        var t = b.appendChild(obj);
        if (t) {
            var counter = 0;
            (function(){
                if (typeof t.GetVariable != UNDEF) {
                    var d = t.GetVariable("$version");
                    if (d) {
                        d = d.split(" ")[1].split(",");
                        ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
                    }
                }
                else if (counter < 10) {
                    counter++;
                    setTimeout(arguments.callee, 10);
                    return undefined;
                }
                b.removeChild(obj);
                t = null;
                matchVersions();
            })();
        }
        else {
            matchVersions();
        }
    }
    
    /* Perform Flash Player and SWF version matching; static publishing only
    */
    function matchVersions() {
        var rl = regObjArr.length;
        if (rl > 0) {
            for (var i = 0; i < rl; i++) { // for each registered object element
                var id = regObjArr[i].id;
                var cb = regObjArr[i].callbackFn;
                var cbObj = {success:false, id:id};
                if (ua.pv[0] > 0) {
                    var obj = getElementById(id);
                    if (obj) {
                        if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
                            setVisibility(id, true);
                            if (cb) {
                                cbObj.success = true;
                                cbObj.ref = getObjectById(id);
                                cb(cbObj);
                            }
                        }
                        else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
                            var att = {};
                            att.data = regObjArr[i].expressInstall;
                            att.width = obj.getAttribute("width") || "0";
                            att.height = obj.getAttribute("height") || "0";
                            if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
                            if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
                            // parse HTML object param element's name-value pairs
                            var par = {};
                            var p = obj.getElementsByTagName("param");
                            var pl = p.length;
                            for (var j = 0; j < pl; j++) {
                                if (p[j].getAttribute("name").toLowerCase() != "movie") {
                                    par[p[j].getAttribute("name")] = p[j].getAttribute("value");
                                }
                            }
                            showExpressInstall(att, par, id, cb);
                        }
                        else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF
                            displayAltContent(obj);
                            if (cb) { cb(cbObj); }
                        }
                    }
                }
                else {    // if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content)
                    setVisibility(id, true);
                    if (cb) {
                        var o = getObjectById(id); // test whether there is an HTML object element or not
                        if (o && typeof o.SetVariable != UNDEF) { 
                            cbObj.success = true;
                            cbObj.ref = o;
                        }
                        cb(cbObj);
                    }
                }
            }
        }
    }
    
    function getObjectById(objectIdStr) {
        var r = null;
        var o = getElementById(objectIdStr);
        if (o && o.nodeName == "OBJECT") {
            if (typeof o.SetVariable != UNDEF) {
                r = o;
            }
            else {
                var n = o.getElementsByTagName(OBJECT)[0];
                if (n) {
                    r = n;
                }
            }
        }
        return r;
    }
    
    /* Requirements for Adobe Express Install
        - only one instance can be active at a time
        - fp 6.0.65 or higher
        - Win/Mac OS only
        - no Webkit engines older than version 312
    */
    function canExpressInstall() {
        return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
    }
    
    /* Show the Adobe Express Install dialog
        - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
    */
    function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
        isExpressInstallActive = true;
        storedCallbackFn = callbackFn || null;
        storedCallbackObj = {success:false, id:replaceElemIdStr};
        var obj = getElementById(replaceElemIdStr);
        if (obj) {
            if (obj.nodeName == "OBJECT") { // static publishing
                storedAltContent = abstractAltContent(obj);
                storedAltContentId = null;
            }
            else { // dynamic publishing
                storedAltContent = obj;
                storedAltContentId = replaceElemIdStr;
            }
            att.id = EXPRESS_INSTALL_ID;
            if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; }
            if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; }
            doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
            var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
                fv = "MMredirectURL=" + win.location.toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
            if (typeof par.flashvars != UNDEF) {
                par.flashvars += "&" + fv;
            }
            else {
                par.flashvars = fv;
            }
            // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
            // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
            if (ua.ie && ua.win && obj.readyState != 4) {
                var newObj = createElement("div");
                replaceElemIdStr += "SWFObjectNew";
                newObj.setAttribute("id", replaceElemIdStr);
                obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
                obj.style.display = "none";
                (function(){
                    if (obj.readyState == 4) {
                        obj.parentNode.removeChild(obj);
                    }
                    else {
                        setTimeout(arguments.callee, 10);
                    }
                })();
            }
            createSWF(att, par, replaceElemIdStr);
        }
    }
    
    /* Functions to abstract and display alternative content
    */
    function displayAltContent(obj) {
        if (ua.ie && ua.win && obj.readyState != 4) {
            // IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
            // because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
            var el = createElement("div");
            obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
            el.parentNode.replaceChild(abstractAltContent(obj), el);
            obj.style.display = "none";
            (function(){
                if (obj.readyState == 4) {
                    obj.parentNode.removeChild(obj);
                }
                else {
                    setTimeout(arguments.callee, 10);
                }
            })();
        }
        else {
            obj.parentNode.replaceChild(abstractAltContent(obj), obj);
        }
    } 

    function abstractAltContent(obj) {
        var ac = createElement("div");
        if (ua.win && ua.ie) {
            ac.innerHTML = obj.innerHTML;
        }
        else {
            var nestedObj = obj.getElementsByTagName(OBJECT)[0];
            if (nestedObj) {
                var c = nestedObj.childNodes;
                if (c) {
                    var cl = c.length;
                    for (var i = 0; i < cl; i++) {
                        if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
                            ac.appendChild(c[i].cloneNode(true));
                        }
                    }
                }
            }
        }
        return ac;
    }
    
    /* Cross-browser dynamic SWF creation
    */
    function createSWF(attObj, parObj, id) {
        var r, el = getElementById(id);
        if (ua.wk && ua.wk < 312) { return r; }
        if (el) {
            if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
                attObj.id = id;
            }
            if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
                var att = "";
                for (var i in attObj) {
                    if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
                        if (i.toLowerCase() == "data") {
                            parObj.movie = attObj[i];
                        }
                        else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
                            att += ' class="' + attObj[i] + '"';
                        }
                        else if (i.toLowerCase() != "classid") {
                            att += ' ' + i + '="' + attObj[i] + '"';
                        }
                    }
                }
                var par = "";
                for (var j in parObj) {
                    if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
                        par += '<param name="' + j + '" value="' + parObj[j] + '" />';
                    }
                }
                el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
                objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
                r = getElementById(attObj.id);    
            }
            else { // well-behaving browsers
                var o = createElement(OBJECT);
                o.setAttribute("type", FLASH_MIME_TYPE);
                for (var m in attObj) {
                    if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
                        if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
                            o.setAttribute("class", attObj[m]);
                        }
                        else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
                            o.setAttribute(m, attObj[m]);
                        }
                    }
                }
                for (var n in parObj) {
                    if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
                        createObjParam(o, n, parObj[n]);
                    }
                }
                el.parentNode.replaceChild(o, el);
                r = o;
            }
        }
        return r;
    }
    
    function createObjParam(el, pName, pValue) {
        var p = createElement("param");
        p.setAttribute("name", pName);    
        p.setAttribute("value", pValue);
        el.appendChild(p);
    }
    
    /* Cross-browser SWF removal
        - Especially needed to safely and completely remove a SWF in Internet Explorer
    */
    function removeSWF(id) {
        var obj = getElementById(id);
        if (obj && obj.nodeName == "OBJECT") {
            if (ua.ie && ua.win) {
                obj.style.display = "none";
                (function(){
                    if (obj.readyState == 4) {
                        removeObjectInIE(id);
                    }
                    else {
                        setTimeout(arguments.callee, 10);
                    }
                })();
            }
            else {
                obj.parentNode.removeChild(obj);
            }
        }
    }
    
    function removeObjectInIE(id) {
        var obj = getElementById(id);
        if (obj) {
            for (var i in obj) {
                if (typeof obj[i] == "function") {
                    obj[i] = null;
                }
            }
            obj.parentNode.removeChild(obj);
        }
    }
    
    /* Functions to optimize JavaScript compression
    */
    function getElementById(id) {
        var el = null;
        try {
            el = doc.getElementById(id);
        }
        catch (e) {}
        return el;
    }
    
    function createElement(el) {
        return doc.createElement(el);
    }
    
    /* Updated attachEvent function for Internet Explorer
        - Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
    */    
    function addListener(target, eventType, fn) {
        target.attachEvent(eventType, fn);
        listenersArr[listenersArr.length] = [target, eventType, fn];
    }
    
    /* Flash Player and SWF content version matching
    */
    function hasPlayerVersion(rv) {
        var pv = ua.pv, v = rv.split(".");
        v[0] = parseInt(v[0], 10);
        v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
        v[2] = parseInt(v[2], 10) || 0;
        return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
    }
    
    /* Cross-browser dynamic CSS creation
        - Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
    */    
    function createCSS(sel, decl, media, newStyle) {
        if (ua.ie && ua.mac) { return undefined; }
        var h = doc.getElementsByTagName("head")[0];
        if (!h) { return undefined; } // to also support badly authored HTML pages that lack a head element
        var m = (media && typeof media == "string") ? media : "screen";
        if (newStyle) {
            dynamicStylesheet = null;
            dynamicStylesheetMedia = null;
        }
        if (!dynamicStylesheet || dynamicStylesheetMedia != m) { 
            // create dynamic stylesheet + get a global reference to it
            var s = createElement("style");
            s.setAttribute("type", "text/css");
            s.setAttribute("media", m);
            dynamicStylesheet = h.appendChild(s);
            if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
                dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
            }
            dynamicStylesheetMedia = m;
        }
        // add style rule
        if (ua.ie && ua.win) {
            if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
                dynamicStylesheet.addRule(sel, decl);
            }
        }
        else {
            if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
                dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
            }
        }
    }
    
    function setVisibility(id, isVisible) {
        if (!autoHideShow) { return undefined; }
        var v = isVisible ? "visible" : "hidden";
        if (isDomLoaded && getElementById(id)) {
            getElementById(id).style.visibility = v;
        }
        else {
            createCSS("#" + id, "visibility:" + v);
        }
    }

    /* Filter to avoid XSS attacks
    */
    function urlEncodeIfNecessary(s) {
        var regex = /[\\\"<>\.;]/;
        var hasBadChars = regex.exec(s) !== null;
        return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
    }
    
    /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
    */
    var cleanup = function() {
        if (ua.ie && ua.win) {
            window.attachEvent("onunload", function() {
                // remove listeners to avoid memory leaks
                var ll = listenersArr.length;
                for (var i = 0; i < ll; i++) {
                    listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
                }
                // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
                var il = objIdArr.length;
                for (var j = 0; j < il; j++) {
                    removeSWF(objIdArr[j]);
                }
                // cleanup library's main closures to avoid memory leaks
                for (var k in ua) {
                    ua[k] = null;
                }
                ua = null;
                for (var l in swfobject) {
                    swfobject[l] = null;
                }
                swfobject = null;
            });
        }
    }();
    
    return {
        /* Public API
            - Reference: http://code.google.com/p/swfobject/wiki/documentation
        */ 
        registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
            if (ua.w3 && objectIdStr && swfVersionStr) {
                var regObj = {};
                regObj.id = objectIdStr;
                regObj.swfVersion = swfVersionStr;
                regObj.expressInstall = xiSwfUrlStr;
                regObj.callbackFn = callbackFn;
                regObjArr[regObjArr.length] = regObj;
                setVisibility(objectIdStr, false);
            }
            else if (callbackFn) {
                callbackFn({success:false, id:objectIdStr});
            }
        },
        
        getObjectById: function(objectIdStr) {
            if (ua.w3) {
                return getObjectById(objectIdStr);
            }
        },
        
        embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
            var callbackObj = {success:false, id:replaceElemIdStr};
            if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
                setVisibility(replaceElemIdStr, false);
                addDomLoadEvent(function() {
                    widthStr += ""; // auto-convert to string
                    heightStr += "";
                    var att = {};
                    if (attObj && typeof attObj === OBJECT) {
                        for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
                            att[i] = attObj[i];
                        }
                    }
                    att.data = swfUrlStr;
                    att.width = widthStr;
                    att.height = heightStr;
                    var par = {}; 
                    if (parObj && typeof parObj === OBJECT) {
                        for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
                            par[j] = parObj[j];
                        }
                    }
                    if (flashvarsObj && typeof flashvarsObj === OBJECT) {
                        for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
                            if (typeof par.flashvars != UNDEF) {
                                par.flashvars += "&" + k + "=" + flashvarsObj[k];
                            }
                            else {
                                par.flashvars = k + "=" + flashvarsObj[k];
                            }
                        }
                    }
                    if (hasPlayerVersion(swfVersionStr)) { // create SWF
                        var obj = createSWF(att, par, replaceElemIdStr);
                        if (att.id == replaceElemIdStr) {
                            setVisibility(replaceElemIdStr, true);
                        }
                        callbackObj.success = true;
                        callbackObj.ref = obj;
                    }
                    else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
                        att.data = xiSwfUrlStr;
                        showExpressInstall(att, par, replaceElemIdStr, callbackFn);
                        return undefined;
                    }
                    else { // show alternative content
                        setVisibility(replaceElemIdStr, true);
                    }
                    if (callbackFn) { callbackFn(callbackObj); }
                });
            }
            else if (callbackFn) { callbackFn(callbackObj);    }
        },
        
        switchOffAutoHideShow: function() {
            autoHideShow = false;
        },
        
        ua: ua,
        
        getFlashPlayerVersion: function() {
            return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
        },
        
        hasFlashPlayerVersion: hasPlayerVersion,
        
        createSWF: function(attObj, parObj, replaceElemIdStr) {
            if (ua.w3) {
                return createSWF(attObj, parObj, replaceElemIdStr);
            }
            else {
                return undefined;
            }
        },
        
        showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
            if (ua.w3 && canExpressInstall()) {
                showExpressInstall(att, par, replaceElemIdStr, callbackFn);
            }
        },
        
        removeSWF: function(objElemIdStr) {
            if (ua.w3) {
                removeSWF(objElemIdStr);
            }
        },
        
        createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
            if (ua.w3) {
                createCSS(selStr, declStr, mediaStr, newStyleBoolean);
            }
        },
        
        addDomLoadEvent: addDomLoadEvent,
        
        addLoadEvent: addLoadEvent,
        
        getQueryParamValue: function(param) {
            var q = doc.location.search || doc.location.hash;
            if (q) {
                if (/\?/.test(q)) {
                    q = q.split("?")[1]; // strip question mark
                } 
                if (param == null) {
                    return urlEncodeIfNecessary(q);
                }
                var pairs = q.split("&");
                for (var i = 0; i < pairs.length; i++) {
                    if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
                        return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
                    }
                }
            }
            return "";
        },
        
        // For internal usage only
        expressInstallCallback: function() {
            if (isExpressInstallActive) {
                var obj = getElementById(EXPRESS_INSTALL_ID);
                if (obj && storedAltContent) {
                    obj.parentNode.replaceChild(storedAltContent, obj);
                    if (storedAltContentId) {
                        setVisibility(storedAltContentId, true);
                        if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
                    }
                    if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
                }
                isExpressInstallActive = false;
            } 
        }
    };
}();

function setAlertIfExists(str) {
    if (window.setAlert) {
        window.setAlert(str);
    }
}

function DHFGetTimeZoneOffsetInMinutes() {
    var d = new Date();

    return 0 - d.getTimezoneOffset();
}

function DHFIsDocumentLoaded() {
    if (document.readyState === undefined) {
        //Non-IE Browser
        return true;
    }
    
    if (document.readyState != "complete") {
        return false;
    } else {
        return true;
    }
}

function DHFShowElement(elementid, state) {
    var el = document.getElementById(elementid);
    
    if (el) {
        el.style.display = state ? '' : 'none';
        el.tabIndex = state ? 0 : -1;
        return true;
    } else {
        setAlertIfExists('DHFShowElement failed for element ' + elementid + ' state ' + state);
        return false;
    }
}

function DHFBlockElement(elementid, state) {
    var el = document.getElementById(elementid);
    
    if (el) {
        el.style.display = state ? 'block' : 'none';
    }
}

function DHFIsElementShown(elementid) {
    var el = document.getElementById(elementid);
    
    if (el) {
        return el.style.display != 'none';
    } else {
        setAlertIfExists('DHFIsElementShown failed for element ' + elementid);
    }
    return undefined;
}

function DHFShowElements(elementids, state) {
    var i, a = elementids.split(',');
    
    for (i = 0; i < a.length; i++) {
        DHFShowElement(a[i], state);
    }
}

function DHFSetElementVisibility(elementid, state) {
    var el = document.getElementById(elementid);

    if (el) {
        el.style.visibility = state ? 'inherit' : 'hidden';
    }
}

function DHFSetMultipleElementVisibility(elementids, state) {
    var i, a = elementids.split(',');

    for (i = 0; i < a.length; i++) {
        DHFSetElementVisibility(a[i], state);
    }
}
       
function DHFSetOpacity(elementID, opacity) {
    var el = document.getElementById(elementID);
    
    if (el) {
        opacity = (opacity == 100) ? 99.999 : opacity;
        el.style.filter = "alpha(opacity:" + opacity + ")";
        el.style.KHTMLOpacity = opacity / 100;
        el.style.MozOpacity = opacity / 100;
        el.style.opacity = opacity / 100;
    }
}

function DHFSetOpacities(elementids, opacity) {
    var i, a = elementids.split(',');

    for (i = 0; i < a.length; i++) {
        DHFSetOpacity(a[i], opacity);
    }
}

function StoreObject(el, szFlag, szHolder, szObjectL1, szObjectL2) {
    if (el[szFlag] === undefined || el[szFlag] === false) {
        if (szObjectL2 === undefined) {
            el[szHolder] = el[szObjectL1];
        } else {
            el[szHolder] = el[szObjectL1][szObjectL2];
        }
        
        el[szFlag] = true;
    }
}

function RestoreObject(el, szFlag, szHolder, szObjectL1, szObjectL2) {
    if (el[szFlag]) {
        if (szObjectL2 === undefined) {
            el[szObjectL1] = el[szHolder];
        } else {
            el[szObjectL1][szObjectL2] = el[szHolder];
        }
        
        el[szFlag] = false;
    }
}
    
function DHFDisableElement(elementid, state) {
    var el = document.getElementById(elementid);
    
    if (el) {
        setAlertIfExists('DHFDisableElement ' + elementid + ' ' + state);
        el.disabled = state;
        
        if (state) {
            StoreObject(el, 'flagBorderColorSet', 'dhfOrigBorderColor', 'style', 'borderColor');
            StoreObject(el, 'flagColorSet', 'dhfOrigColor', 'style', 'color');
            StoreObject(el, 'flagCursorSet', 'dhfOrigCursor', 'style', 'cursor');
            StoreObject(el, 'flagOnclickSet', 'dhfOrigOnclick', 'onclick');
            
            el.style.borderColor = '#' + disabledElementBorder;
            el.style.color = '#' + disabledElementForeground;
            el.style.cursor = '';
            el.onclick = '';
            el.tabIndex = -1;
            
            if (el.tagName == 'IMG') {
                StoreObject(el, 'flagFilterSet', 'dhfOrigFilter', 'style', 'filter');
                StoreObject(el, 'flagKHTMLOpacitySet', 'dhfOrigKHTMLOpacity', 'style', 'KHTMLOpacity');
                StoreObject(el, 'flagMozOpacitySet', 'dhfOrigMozOpacity', 'style', 'MozOpacity');
                StoreObject(el, 'flagOrigOpacitySet', 'dhfOrigOpacity', 'style', 'opacity');
                
                el.style.filter = "alpha(opacity:50)";
                el.style.KHTMLOpacity = 0.5;
                el.style.MozOpacity = 0.5;
                el.style.opacity = 0.5;
            }
        } else {
            RestoreObject(el, 'flagBorderColorSet', 'dhfOrigBorderColor', 'style', 'borderColor');
            RestoreObject(el, 'flagColorSet', 'dhfOrigColor', 'style', 'color');
            RestoreObject(el, 'flagCursorSet', 'dhfOrigCursor', 'style', 'cursor');
            RestoreObject(el, 'flagOnclickSet', 'dhfOrigOnclick', 'onclick');
            
            el.tabIndex = 0;
            
            if (el.tagName == 'IMG') {
                RestoreObject(el, 'flagFilterSet', 'dhfOrigFilter', 'style', 'filter');
                RestoreObject(el, 'flagKHTMLOpacitySet', 'dhfOrigKHTMLOpacity', 'style', 'KHTMLOpacity');
                RestoreObject(el, 'flagMozOpacitySet', 'dhfOrigMozOpacity', 'style', 'MozOpacity');
                RestoreObject(el, 'flagOrigOpacitySet', 'dhfOrigOpacity', 'style', 'opacity');
            }
        }
    } else {
        setAlertIfExists('DHFDisableElement failed for element ' + elementid + ' state ' + state);
    }
}
    
function DHFDisableElements(elementids, state) {
    var i, a = elementids.split(',');
    
    for (i = 0; i < a.length; i++) {
        DHFDisableElement(a[i], state);
    }
}

function DHFDisableRadios(id, state) {
    var i,
        el = document.getElementsByName(id);
    
    if (el) {
        for (i = 0; i < el.length; i++) {
            el[i].disabled = state;
        }
    }
}

function DHFReadOnlyElement(elementid, state) {
    var el = document.getElementById(elementid);
    
    if (el) {
        setAlertIfExists('DHFReadOnlyElement ' + elementid + ' ' + state);
        el.style.readOnly = state;
    } else {
        setAlertIfExists('DHFReadOnlyElement failed for element ' + elementid + ' state ' + state);
    }
}

function DHFReadOnlyElements(elementids, state) {
    var i,
        a = elementids.split(',');
    
    for (i = 0; i < a.length; i++) {
        DHFReadOnlyElement(a[i], state);
    }
}

function DHFSetElementHTML(elementid, s, append) {
    var el = document.getElementById(elementid);
    
    if (el) {
        if (append) {
            el.innerHTML += s;
        } else {
            el.innerHTML = s;
        }
    } else {
        setAlertIfExists('DHFSetElementHTML failed for element ' + elementid + ' html ' + s);
    }
}

function DHFSetElementText(elementid, s, append) {
    DHFSetElementHTML(elementid, DHFHTMLEncode(s), append);
}

function DHFSetElementTitle(elementid, s) {
    var el = document.getElementById(elementid);
    
    if (el) {
        el.title = s;
    }
}
    
function DHFSetElementAltText(elementid, s) {
    var el = document.getElementById(elementid);
    
    if (el) {
        el.alt = s;
    }
}

function DHFShowElementsByName(tagname, name, state) {
    var i,
        a = document.getElementsByTagName(tagname),
        aLen = a.length;
    
    for (i = 0; i < aLen; i++) {
        if (a[i].getAttribute('name') == name) {
            if (state) {
                a[i].style.display = '';
            } else {
                a[i].style.display = 'none';
            }
        }
    }
}

function DHFFixHTMLLinks(s) {
    var j,
        i = 0;
    
    while (i < s.length) {
        j = s.toUpperCase().indexOf('<A ', i);
        if (j < 0) {
            break;
        }
        s = s.substring(0, j + 3) + 'target="_blank" ' + s.substring(j + 3);
        i = j + 19;
    }
    return s;
}

function DHFGetElementHTML(elementid) {
    var el = document.getElementById(elementid);
    
    if (el) {
        return el.innerHTML;
    } else {
        setAlertIfExists('DHFGetElementHTML failed for element ' + elementid);
    }
    return undefined;
}

function DHFSetFieldValue(elementid, s) {
    var el = document.getElementById(elementid);
    
    if (el) {
        if (s && s.isDHFDate) {
            s.toFieldValue(elementid);
        } else {
            el.value = s;
        }
    } else {
        setAlertIfExists('DHFSetFieldValue failed for element ' + elementid + ' value ' + s);
    }
}

function DHFGetFieldValue(elementid, defvalordhfdate) {
    var el = document.getElementById(elementid);

    if (el) {
        if (defvalordhfdate && defvalordhfdate.isDHFDate) {
            defvalordhfdate.fromFieldValue(elementid);
        } else {
            return el.value;
        }
    } else {
        setAlertIfExists('DHFGetFieldValue failed for element ' + elementid);

        if (defvalordhfdate !== undefined) {
            return defvalordhfdate;
        }
    }
    return undefined;
}

function DHFSetSelectIndex(elementid, s) {
    var el = document.getElementById(elementid);
    
    if (el) {
        el.selectedIndex = s;
    } else {
        setAlertIfExists('DHFSetSelectIndex failed for element ' + elementid + ' value ' + s);
    }
}

function DHFGetSelectIndex(elementid) {
    var el = document.getElementById(elementid);
    
    if (el) {
        return el.selectedIndex;
    } else {
        setAlertIfExists('DHFGetSelectIndex failed for element ' + elementid);
    }
    return undefined;
}

function DHFGetSelectValue(elementid) {
    var i,
        el = document.getElementById(elementid);
    
    if (el) {
        i = el.selectedIndex;
        
        if (i >= 0) {
            return el.options[i].value;
        } else {
            return undefined;
        }
    } else {
        setAlertIfExists('DHFGetSelectValue failed for element ' + elementid);
        return -1;
    }
}

var ssmString =0;
var ssmNumericAscending = 1;
function DHFSetSelectFromValue(elementid, s, matchmode) {
    var i,
        j = -1,
        el = document.getElementById(elementid);
    
    if (el) {
        for (i = 0; i < el.length; i++) {
            switch (matchmode) {
                case ssmString:
                    if (el.options[i].value == s) {
                        j = i;
                    }
                    break;
                case ssmNumericAscending:
                    if (parseInt(el.options[i].value, 10) <= parseInt(s, 10)) {
                        j = i;
                    }
                    break;
                default:
                    break;
            }
        }
        if (j >= 0) {
            el.selectedIndex = j;
            return true;
        }
    } else {
        setAlertIfExists('DHFSetSelectFromValue failed for element ' + elementid + ' value ' + s + ' mm ' + matchmode);
    }

    return false;
}
    
function DHFSetFieldChecked(elementid, state) {
    var el = document.getElementById(elementid);
    
    if (el) {
        el.checked = state;
        return true;
    } else {
        setAlertIfExists('DHFSetFieldChecked failed for element ' + elementid + ' Checked ' + state);
        return false;
    }
}

function DHFGetFieldChecked(elementid, defval) {
    var el = document.getElementById(elementid);

    if (el) {
        return el.checked;
    } else {
        setAlertIfExists('DHFGetFieldChecked failed for element ' + elementid);
        if (defval !== undefined) {
            return defval;
        }
    }
    return undefined;
}
    
function DHFSetRadioByID(baseelementid, selval) {
    var i, el;
    
    for (i = 0; i < 20; i++) {
        el = document.getElementById(baseelementid + i);
        
        if (el) {
            if (el.value == selval) {
                el.checked = true;
            } else {
                el.checked = false;
            }
        } else {
            return undefined;
        }
    }
}
    
function DHFGetRadioValue(idOrName) {
    var i, input, radios, radiosLen,
        value = null,
        element = document.getElementById(idOrName),
        radioGroupName = null;
    
    // if null, then the id must be the radio group name
    if (element === null) {
        radioGroupName = idOrName;
    } else {
        radioGroupName = element.name;
    }
    
    if (radioGroupName === null) {
        return null;
    }
    
    radios = document.getElementsByTagName('input');
    radiosLen = radios.length;
    for (i = 0; i < radiosLen; i++) {
        input = radios[i];
        if (input.type == 'radio' && input.name == radioGroupName && input.checked) {
            value = input.value;
            break;
        }
    }
    return value;
}

function DHFGetRadioSelectedID(baseelementid) {
    var i, el;
    
    for (i = 0; i < 20; i++) {
        el = document.getElementById(baseelementid + i);
        
        if (el) {
            if (el.checked) {
                return (el.value);
            }
        } else {
            return -1;
        }
    }
    return -1;
}        

function DHFSetDivPosition(elementid, x, y) {
    setAlertIfExists('DHFSetDivPosition ' + elementid + ' ' + x + ' ' + y);
    
    var el = document.getElementById(elementid);

    if (el) {
        el.style.pixelLeft = x;
        el.style.pixelTop = y;
    } else {
        setAlertIfExists('DHFSetDivPosition failed for element ' + elementid);
    }
}

//precondition: element must be position:relative or position:absolute
function DHFGetDivX(elementid) {
    var x,
        el = document.getElementById(elementid);

    if (el) {
        x = el.offsetLeft;
        setAlertIfExists('DHFGetDivX ' + elementid + ' ' + x);
        return x;
    } else {
        setAlertIfExists('DHFGetDivX failed for element ' + elementid);
    }
    return undefined;
}

//precondition: element must be position:relative or position:absolute
function DHFGetDivY(elementid) {
    var y,
        el = document.getElementById(elementid);

    if (el) {
        y = el.offsetTop;
        setAlertIfExists('DHFGetDivY ' + elementid + ' ' + y);
        return y;
    } else {
        setAlertIfExists('DHFGetDivY failed for element ' + elementid);
    }
    return undefined;
}

// Works with all objects, returns x and y position as an object (obj.x, obj.y, obj.width, obj.height)
function DHFGetElementPositionWidthHeight(elementid) {
    var el = document.getElementById(elementid),
        xPos = 0,
        yPos = 0,
        width = 0,
        height = 0,
        retObj = {};

    if (el) {
        retObj.width = el.offsetWidth || el.scrollWidth;
        retObj.height = el.offsetHeight || el.scrollHeight;
    }
    
    while (el) {
        if (el.offsetLeft) {
            xPos += el.offsetLeft;
        }
        if (el.offsetTop) {
            yPos += el.offsetTop;
        }
        el = el.offsetParent;
    }
    
    retObj.x = xPos;
    retObj.y = yPos;
    
    return retObj;
}

function DHFMoveToVisibility(elementid, offsetX, offsetY) {
    var el = document.getElementById(elementid);
    
    if (el) {
        if (offsetX === undefined) {
            offsetX = 80;
        }
        if (offsetY === undefined) {
            offsetY = 30;
        }
        el.style.left = document.body.scrollLeft + offsetX;
        el.style.top = document.body.scrollTop + offsetY;
    }
}

function DHFFormatDuration(d) {
    var n,
        s = '';

    if (d > 0) {
        if (d >= 1440) {
            s = Math.floor(d / 1440) + 'd';
            d = d % 1440;
        }
        if (d) {
            n = Math.floor(d / 60);
            if (n < 10) {
                s += '0';
            }
            s += n + ':';
            n = d % 60;
            if (n < 10) {
                s += '0';
            }
            s += n;
        }
    }
    return s;
}

function DHFParseDuration(val, disableminutesonly) {
    var a,
        d = 0,
        h = 0,
        m = 0,
        hasd = 0,
        s = DHFTrim(val).toLowerCase();
    
    if (!s.length) {
        return -1;
    }
    
    a = s.split('d');
    
    if (a.length > 2) {
        return null;
    }
    
    if (a.length == 2) {
        if (!DHFIsNumeric2(a[0], false, false)) {
            return null;
        }
        d = parseInt(a[0], 10);
        hasd = 1;
        s = a[1] + '';
    }
    
    if (s.length) {
        a = s.split(':');
        if (a.length > 2 || (a.length == 1 && hasd)) {
            return null;
        }
        if (a.length == 2) {
            if (!DHFIsNumeric2(a[0], false, false)) {
                return null;
            }
            h = parseInt(a[0], 10);
            s = a[1] + '';
        } else {
            if (disableminutesonly) {
                return null;
            }
        }
        if (!DHFIsNumeric2(s, false, false)) {
            return null;
        }
        m = parseInt(s, 10);
    }
    return d * 1440 + h * 60 + m;
}

function DHFFormatDateTime(d) {
    return DHFFormatDate(d) + ', ' + DHFFormatTime(d);
}

function DHFFormatDate(d, showWeekday) {
    var sb = [];
    
    if (d && (d.constructor === Date || d.isDHFDate)) {
        if (!d.isDHFDate) {
            d = new DHFDate().setDateFromJSDate(d);
        } else if (d.regDate === '') {
            return '';
        }
                
        if (showWeekday) {
            sb.push(d.getWeekday());
            sb.push(' ');
        }
        sb.push(d.regDate);
        
        return sb.join('');
    } else {
        return '';
    }
}

function DHFGetDayOfWeekName(d) {
    return wdnames[d.getUTCDay()];
}

function DHFFormatTime(d) {
    var m;
    
    if (d && (d.constructor === Date || d.isDHFDate)) {
        if (d.isDHFDate && d.regDate === '') {
            return '';
        }
        
        m = d.getUTCMinutes();
        if (m < 10) {
            m = '0' + m;
        }
        return d.getUTCHours() + ':' + m;
    } else {
        return '';
    }
}

function DHFFormatSecsTime(s) {
    var m, mm;
    
    if (s < 0) {
        return '';
    }
    
    mm = Math.floor(s / 60);
    m = mm % 60;
    
    if (m < 10) {
        m = '0' + m;
    }
    return Math.floor(mm / 60) + ':' + m;
}

function DHFFormatDateRange(d1, d2) {
    var s = '';
    
    if (d1) {
        s += DHFFormatDate(d1);
    }
    
    s += ' - '; // $txt
    
    if (d2) {
        s += DHFFormatDate(d2);
    }
    
    return s;
}

function DHFFormatDateTimeRange(d1, d2) {
    var s = '';
    
    if (d1) {
        s += DHFFormatDateTime(d1);
    }
    
    s += ' - '; // $txt
    
    if (d2) {
        if (d2.getUTCFullYear() == d1.getUTCFullYear() && d2.getUTCMonth() == d1.getUTCMonth() && d2.getUTCDate() == d1.getUTCDate()) {
            s += DHFFormatTime(d2);
        } else {
            s += DHFFormatDateTime(d2);
        }
    }
    
    return s;
}

function DHFIsSameDay(date1, date2) {
    var d1, d2;
    
    if (date1.isDHFDate) {
        d1 = date1.getJSDate();
        d2 = date2.getJSDate();
    } else {
        d1 = date1;
        d2 = date2;
    }
    
    return d1.getUTCFullYear() == d2.getUTCFullYear() && d1.getUTCMonth() == d2.getUTCMonth() && d1.getUTCDate() == d2.getUTCDate();
}

// returns an array. index 0: week number, index 1: year
function DHFGetWeekOfYear(dt) {
    var d0, delta, dow,
        a = [];
    
    if (kFirstWeekJan1) {
        dow = dt.getUTCDay();
        
        if (!kWeekStartsOnSunday) {
            dow = dow ? (dow - 1) : 6;
        }
        
        d0 = new Date(dt.getTime() + (7 - dow) * kSecsPerDay * 1000);
        
        if (d0.getUTCFullYear() > dt.getUTCFullYear()) {
            a[0] = 1;
        } else {
            d0 = DHFNewDate(dt.getUTCFullYear(), 0, 1);
            dow = d0.getDay();
            
            if (!kWeekStartsOnSunday) {
                dow = dow ? (dow - 1) : 6;
            }
            
            a[0] = Math.floor((dt.getTime() - d0.getTime() + (dow + 1) * kSecsPerDay * 1000) / (kSecsPerWeek * 1000)) + 1;
        }
        a[1] = d0.getUTCFullYear();
    } else {
        // first week is the one that contains Jan 4
        d0 = DHFNewDate(dt.getUTCFullYear(), 0, 4);
        dow = d0.getUTCDay();
        
        if (!kWeekStartsOnSunday) {
            dow = dow ? (dow - 1) : 6;
        }
        
        d0 = new Date(d0.getTime() - dow * kSecsPerDay * 1000);
        delta = dt.getTime() - d0.getTime();
        a[1] = dt.getUTCFullYear();
        
        if (delta < 0) {
            d0 = DHFNewDate(dt.getUTCFullYear() - 1, 0, 4);
            dow = d0.getUTCDay();
            
            if (!kWeekStartsOnSunday) {
                dow = dow ? (dow - 1) : 6;
            }
            
            d0 = new Date(d0.getTime() - dow * kSecsPerDay * 1000);
            a[0] = Math.floor((dt.getTime() - d0.getTime()) / (kSecsPerWeek * 1000)) + 1;
            a[1]--;
        } else {
            a[0] = Math.floor(delta / (kSecsPerWeek * 1000)) + 1;
            
            if (a[0] >= 52) {
                d0 = DHFNewDate(dt.getUTCFullYear() + 1, 0, 4);
                dow = d0.getUTCDay();
                
                if (!kWeekStartsOnSunday) {
                    dow = dow ? (dow - 1) : 6;
                }
                
                d0 = new Date(d0.getTime() - dow * kSecsPerDay * 1000);
                delta = dt.getTime() - d0.getTime();
                
                if (delta >= 0) {
                    a[0] = Math.floor(delta / (kSecsPerWeek * 1000)) + 1;
                    a[1]++;
                }
            }
        }
    }
    
    return a;
}

function DHFFormatCredits(c) {
    return (c + 0.0).toFixed(CreditsDecimalDigits);
}

function DHFCheckIDSearchSyntax(val) {
    return (val + '').search(/^ *(((\d{1,9} *(\- *(\d{1,9}){0,1}){0,1})|(\- *\d{1,9})|(\{{0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}\}{0,1}))( *, *((\d{1,9} *(\- *(\d{1,9}){0,1}){0,1})|(\- *\d{1,9})|(\{{0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}\}{0,1})))*){0,1}$/) >= 0;
}

function DHFFileNameSyntax(val) {
    return (val + '').search(/[\\\/\*:\?\"<>|]/) < 0;
}

function DHFSmartHTMLTrim(s, maxlen) {
    return s;
}

// trim leading and trailing empty space and trailing <br> tags
function DHFHTMLTrim(str) {
    var s = (str + '').replace(/^\s*/, '');
    
    while (1) {
        s = s.replace(/\s*$/, '');
        
        if (s.length < 4 || s.substr(s.length - 4).toUpperCase() != '<BR>') {
            break;
        }
        
        s = s.substr(0, s.length - 4);
    }
    
    return s;
}

function DHFHTMLStrip(str) {
    return str.replace(/<\/?.*?>/g, '');
}

function DHFHTMLDecodeUnicode(s) {
    var j, k,
        i = 0,
        r = '';
    
    while (i < s.length) {
        j = s.substring(i).search(/&#[0-9]{1,};/);
        
        if (j < 0) {
            break;
        }
        
        j += i;
        k = s.indexOf(';', j);
        r = r + s.substring(i, j) + String.fromCharCode(parseInt(s.substring(j + 2, k), 10));
        i = k + 1;
    }
    
    return r + s.substring(i);
}

function DHFHTMLEncode(s) {
    return (s + '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}

function DHFEscapeFields(fieldIDs) {
    var el1, el2, i,
        a = fieldIDs.split(',');
    
    for (i = 0; i < a.length; i++) {
        el1 = document.getElementById(a[i]);
        el2 = document.getElementById('H' + a[i]);
        
        if (el1 && el2) {
            el2.value = DHFEscape(el1.value);
        }
    }
}

function DHFEscapeTextFields(formname) {
    var el1, el2, i,
        form = document.forms[formname];
    
    for (i = 0; i < form.elements.length; i++) {
        el1 = form.elements[i];
        
        if (el1.type == 'text') {
            el2 = document.getElementById('H' + el1.id);
            
            if (el2) {
                el2.value = DHFEscape(el1.value);
            }
        }
    }
}

function DHFFocusTextField(id) {
    var el = document.getElementById(id);

    if (el) {
        el.focus();
        el.select();
    }
}

function DHFIsFieldActive(fieldid) {
    return DHFIsFieldElementActive(document.getElementById(fieldid));
}

function DHFIsFieldElementActive(el) {
    if (!el) {
        return false;
    }

    while ((el = el.parentNode) !== undefined && el !== null) {
        if (el.disabled || (el.style && el.style.display == 'none')) {
            return false;
        }
    }

    return true;
}

function DHFFocusFirstTextFieldInForm(form) {
    var i, el;
    
    if (form) {
        for (i = 0; i < form.length; i++) {
            if (((el = form.elements[i]).type == 'text' || el.type == 'textarea') && DHFIsFieldElementActive(el)) {
                el.focus();
                el.select();
                return true;
            }
        }
    }

    return false;
}

function DHFFocusFirstTextField(formname) {
    var j;
    
    if (formname) {
        return DHFFocusFirstTextFieldInForm(document.forms[formname]);
    }

    for (j = 0; j < document.forms.length; j++) {
        if (DHFFocusFirstTextFieldInForm(document.forms[j])) {
            return true;
        }
    }

    return false;
}

function DHFGenProcessingMsg(htmlmsg) {
    var s = '<table cellspacing="8" cellpadding="6" border="0"><tr><td class="pageTitle">' + DHFHTMLEncode(str_procreq) + '</td></tr></table>';
    
    if (htmlmsg && htmlmsg.length) {
        s += '<br><table cellspacing="8" cellpadding="6" border="0"><tr><td class="setWarning">' + htmlmsg + '</td></tr></table>';
    }
    
    return s;
}

var gosStackCounter;
function DHFGenObjString(obj, objname, objpath, oneval, htmlmsg, nowrapper) {
    nowrapper = nowrapper || false;
    oneval = oneval || false;
    
    gosStackCounter = 0;
    if (oneval) {
        return DHFGenObjStringSub(obj, objname, objpath, oneval);
    }
    
    if (nowrapper) {
        return DHFGenObjStringSub(obj, objname, objpath, oneval);
    } else {
        return DHFGenProcessingMsg(htmlmsg) + DHFGenObjStringSub(obj, objname, objpath, oneval);
    }
}

function DHFGenObjStringSub(obj, objname, objpath, oneval) {
    var i,
        s = '',
        t = '';
    
    gosStackCounter++;
    
    if (gosStackCounter > 80) {
        return null;
    }

    if (obj && obj.length !== undefined) {
        if (oneval) {
            s = objpath + '_' + objname + '_len\t' + obj.length + '\t';
        } else if (gosVisible) {
            s = ' ' + objpath + '_' + objname + '_len <input name="' + objpath + '_' + objname + '_len" type="text" value="' + obj.length + '"><br>';
        } else {
            s = '<input name="' + objpath + '_' + objname + '_len" type="hidden" value="' + obj.length + '">';
        }
    }
    
    for (i in obj) {
        if (obj[i] && obj[i].constructor === String) {
            if (DHFGenObjStringSub.spanRegex.test(obj[i])) {
                obj[i] = DHF.mediaStringUtils.placeholdersToContent(obj[i]);
            }
        }
        
        t = DHFGenVarString(obj[i], i, objpath + '_' + objname, oneval);
        
        if (t.length > 0) {
            s += t;
        }
    }
    
    gosStackCounter--;
    return s;
}
DHFGenObjStringSub.spanRegex = /<span class="iqbox_/i;

function DHFGenVarString(obj, objname, objpath, oneval) {
    var i, vl, hasprop, objCon,
        t = '';

    if (DHFGenVarString.ownerRexeg.test(objname)) {
        return '';
    }
    
    if (obj === undefined || obj === null) {
        return '';
    }

    objCon = obj.constructor;
    
    if (objCon === String) {
        vl = DHFEscape(obj);
        
        if (oneval) {
            t = objpath + '_' + objname + '\t' + vl + '\t';
        } else {
            vl = vl.replace(/"/g, '&quot;');

            if (gosVisible) {
                t = ' ' + objpath + '_' + objname + ' <input name="' + objpath + '_' + objname + '" type="text" value="' + vl + '"><br>';
            } else {
                t = '<input name="' + objpath + '_' + objname + '" type="hidden" value="' + vl + '">';
            }
        }
    } else if ((objCon === Number && isFinite(obj)) || objCon === Boolean) {
        if (oneval) {
            t = objpath + '_' + objname + '\t' + obj + '\t';
        } else if (gosVisible) {
            t = ' ' + objpath + '_' + objname + ' <input name="' + objpath + '_' + objname + '" type="text" value="' + obj + '"><br>';
        } else {
            t = '<input name="' + objpath + '_' + objname + '" type="hidden" value="' + obj + '">';
        }
    } else if (objCon !== Function && objCon !== RegExp) {
        hasprop = false;
        
        if (obj.isDHFDate) {
            t = '<input name="' + objpath + '_' + objname + '" type="hidden" value="' + obj.getStdDateAsString() + '">' +
            '<input name="' + objpath + '_' + objname + '_time" type="hidden" value="' + obj.getTime() + '">';
        } else {
            for (i in obj) {
                if (obj[i] && obj[i].constructor !== Function) {
                    hasprop = true;
                    break;
                }
            }
            if (!hasprop || obj.NOSUBMIT === undefined) {
                t = DHFGenObjStringSub(obj, objname, objpath, oneval);
            }
        }
    } else {
        t = '';
    }
    
    if (t && t.length > 0) {
        return t;
    } else {
        return '';
    }
}
DHFGenVarString.ownerRexeg = /^(OWNER|TOPOWNER)$/i;

function DHFIsNumeric(val) {
    var s = val + '',
        l = s.length,
        i = 0,
        valid = false;
    
    while (s.charAt(i) == ' ') {
        i++;
    }
    
    if (s.charAt(i) == '-') {
        i++;
    }
    
    while (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
        valid = true;
        i++;
    }
    
    if (s.charAt(i) == '.') {
        i++;
    }
    
    while (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
        valid = true;
        i++;
    }
    
    while (s.charAt(i) == ' ') {
        i++;
    }
    
    return valid && i >= l;
}

//set the decimalseparator, uses for TIN type.
var decimalseparator=0;

// returns 0 if not numeric, 1 if ok, 2 for too many decimal places
function DHFIsNumeric2(val, allowNegative, allowDecimal) {
    if (allowNegative) {
        if (!allowDecimal) {
            if ((val + '').search(/^ *-?[0-9]+ *$/) < 0) {
                return 0;
            }
            
            if (Math.abs(parseInt(val + '', 10)) > 2147483647) {
                return 0;
            }
            
            return 1;
        }

        if (decimalseparator == 1) //1 = comma
        {
            if ((val + '').search(/^ *-?[0-9]+(,[0-9]*)? *$/) < 0) {
                return 0;
            }
        } else { // point
            if ((val + '').search(/^ *-?[0-9]+(\.[0-9]*)? *$/) < 0) {
                return 0;
            }
        }
    } else {
        if (!allowDecimal) {
            if (((val + '').search(/^ *[0-9]+ *$/) < 0)) {
                return 0;
            }
            
            if (parseInt(val + '', 10) > 2147483647) {
                return 0;
            }
            
            return 1;
        }
        if (decimalseparator == 1)//1 = comma
        {
            if ((val + '').search(/^ *-?[0-9]+(,[0-9]*)? *$/) < 0) {
                return 0;
            }
        } else //point
        {
            if ((val + '').search(/^ *[0-9]+(\.[0-9]*)? *$/) < 0) {
                return 0;
            }
        }
    }
    return ((val + '').replace(/[ -.]/g, '').length > 15) ? 2 : 1;
}

function DHFIsEmail(s) {
    return s && s.match(/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/i);
}

function DHFNewDate(y, m, d, hh, mm, ss) {
    var dt = new Date();
    
    dt.setUTCMonth(0);
    dt.setUTCDate(1);
    dt.setUTCFullYear(y);
    dt.setUTCMonth(m);
    dt.setUTCDate(d);
    dt.setUTCHours(hh ? hh : 0);
    dt.setUTCMinutes(mm ? mm : 0);
    dt.setUTCSeconds(ss ? ss : 0);
    dt.setUTCMilliseconds(0);

    return dt;
}

function DHFGetMilliseconds() {
    return (new Date()).getTime();
}

function DHFTimer() {
    this.Start = DHFGetMilliseconds();
}

DHFTimer.prototype.GetMilliseconds = function() {
    return DHFGetMilliseconds() - this.Start;
};

DHFTimer.prototype.AsString = function() {
    var t = this.GetMilliseconds(),
        s = Math.floor(t / 1000);
        
    return DHFFormatDuration(s) + '.' + (t - s * 1000);
};

function DHFStringToTime(timestring, allowseconds) {
    var h, m, s;
    
    if (!timestring) {
        return -1;
    }
    
    if (timestring.search(/^\s*(\d{1,2}):(\d\d)(:(\d\d)){0,1}\s*$/) < 0) {
        return -1;
    }
    
    h = parseInt(RegExp.$1, 10);
    m = parseInt(RegExp.$2, 10);
    s = 0;
    
    if (RegExp.$4 && RegExp.$4.length) {
        if (!allowseconds) {
            return -1;
        }
        
        s = parseInt(RegExp.$4, 10);
    }
    
    if (h > 23 || m > 59 || s > 59) {
        return -1;
    }
    
    return h * 3600 + m * 60 + s;
}

function DHFIsTime(timestring, allowseconds) {
    return DHFStringToTime(timestring, allowseconds) >= 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    

function DHFTrim(str) {
    return (str + '').replace(/^\s*/, '').replace(/\s*$/, '');
}

function DHFTrimRight(str) {
    return (str + '').replace(/\s*$/, '');
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    

function DHFBudget(id, year, amount, status, amount_spent)
	{
	this.ID = id;
	this.Year = year;
	this.Amount = amount;
	this.Status = status; //0, 1 - insert, 2 - remove
	this.AmountSpent = amount_spent;
	this.Total = amount - amount_spent;
	}

function DHFCalculateSubBudget(node,includingnode)
	{
	var i,j,budget,year,subnode;
	
	node.setSubBudgets(new DHF.collections.Dictionary());
	
	for (i = 0; i < node.Budgets.length; i++)
		{
		budget=node.Budgets[i];
		node.getSubBudgets().upsert(budget.Year, includingnode?budget.Total:0);
		}
	
	for (j = 0; j < node.GetNumItems(); j++)
		{
		subnode=node.List[j];
		DHFCalculateSubBudget(subnode,true);
		for (year in subnode.getSubBudgets().keyArray())
		    {
			node.getSubBudgets().upsert(year, (node.getSubBudgets().item(year) || 0) + subnode.getSubBudgets().item(year));
			}
		}
	}

function DHFCalculateSubOriginalBudget(node,includingnode)
	{
	var i,j,budget,year,subnode;

	node.setSubOrigBudgets(new DHF.collections.Dictionary());
	
	for (i = 0; i < node.Budgets.length; i++)
		{
		budget=node.Budgets[i];
		node.getSubOrigBudgets().upsert(budget.Year, includingnode?budget.Amount:0);
		}
	
	for (j = 0; j < node.GetNumItems(); j++)
		{
		subnode=node.List[j];
		DHFCalculateSubOriginalBudget(subnode,true);
		
		for (year in subnode.getSubOrigBudgets().keyArray())
		    {
			node.getSubOrigBudgets().upsert(year, (node.getSubOrigBudgets().item(year) || 0) + subnode.getSubOrigBudgets().item(year));
			}
		}
	}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    

function DHFGenericList() {}
    
DHFGenericList.prototype.MoveUp = function(which) {
    var p;
    
    if (which > 0 && which < this.List.length) {
        p = this.List[which];
        this.List[which] = this.List[which - 1];
        this.List[which - 1] = p;
    }
};

DHFGenericList.prototype.MoveDn = function(which) {
    var p;

    if (which >= 0 && which < this.List.length - 1) {
        p = this.List[which];
        this.List[which] = this.List[which + 1];
        this.List[which + 1] = p;
    }
};

DHFGenericList.prototype.Delete = function(which) {
    var i;

    if (which >= 0 && which < this.List.length) {
        for (i = which; i < this.List.length - 1; i++) {
            this.List[i] = this.List[i + 1];
        }

        this.List.length--;
    }
};

DHFGenericList.prototype.InsertAfter = function(which) {
    var i;
    
    if (which >= 0 && which < this.List.length) {
        for (i = this.List.length; i > which + 1; i--) {
            this.List[i] = this.List[i - 1];
        }
        this.List[which + 1] = undefined;
    }
};

DHFGenericList.prototype.GetTextForItem = function(language, item) {
    if (this.List[item].GetText) {
        return this.List[item].GetText(language);
    } else {
        return '';
    }
};

DHFGenericList.prototype.SetTextForItem = function(language, item, s) {
    if (this.List[item].SetText) {
        this.List[item].SetText(language, s);
    }
};

DHFGenericList.prototype.GetNumItems = function() {
    setAlertIfExists('DHFGenericList GetNumItems=' + this.List.length);
    return this.List.length;
};

DHFGenericList.prototype.Append = function(which) {
    this.List[this.List.length] = which;
    return this.List.length;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    

//Note: this constructor has a variable number of arguments, of the form
// DHFSelectionList(index0,text0,index1,text1, ...)
function DHFSelectionList() {
    this.RecursionLock = false;
    this.NOSUBMIT = 1;
    this.AssignFromArray(arguments);
}

DHFSelectionList.prototype.AssignFromArray = function(a) {
    var i, n;

    if (!a) {
        return undefined;
    }

    n = a.length / 2;
    this.List = [];

    for (i = 0; i < n * 2; i += 2) {
        this.List[i] = a[i];
        this.List[i + 1] = a[i + 1];
    }
};

DHFSelectionList.prototype.AppendItem = function(value, txt) {
    var i = this.List.length;
    this.List[i] = value;
    this.List[i + 1] = txt;
};

DHFSelectionList.prototype.InsertItem = function(value, txt, index) {
    var j,
        i = this.List.length / 2;
    
    if (index < 0) {
        index = 0;
    }
    
    if (index > i) {
        index = i;
    }
    
    for (j = i; j > index; j -= 1) {
        this.List[j * 2] = this.List[(j - 1) * 2];
        this.List[j * 2 + 1] = this.List[(j - 1) * 2 + 1];
    }
    this.List[index * 2] = value;
    this.List[index * 2 + 1] = txt;
};

DHFSelectionList.prototype.GetIDForItemIndex = function(i) {
    return (this.List[i * 2]);
};

DHFSelectionList.prototype.GetTextForItemIndex = function(i) {
    return (this.List[i * 2 + 1]);
};

DHFSelectionList.prototype.GetItemIndexForID = function(id) {
    var i;
    
    for (i = 0; i < this.List.length; i += 2) {
        if (this.List[i] == id) {
            return (i / 2);
        }
    }
    setAlertIfExists('GetItemIndexForID failed for ' + id);
    return (-1);
};

DHFSelectionList.prototype.GetItemIndexForText = function(itemtext) {
    var i;
    
    for (i = 1; i < this.List.length; i += 2) {
        if (this.List[i] == itemtext) {
            return ((i - 1) / 2);
        }
    }
    setAlertIfExists('GetItemIndexForID failed for ' + itemtext);
    return -1;
};

DHFSelectionList.prototype.GetItemTextForID = function(id) {
    var i;
    
    for (i = 0; i < this.List.length; i += 2) {
        if (this.List[i] == id) {
            return (this.List[i + 1]);
        }
    }
    return '';
};

DHFSelectionList.prototype.LoadIntoSelectTag = function(tagid, selectid) {
    setAlertIfExists('DHFSelectionList.LoadIntoSelectTag ' + tagid + ' ' + selectid);
    var el = document.getElementById(tagid), i;
    
    if (el) {
        el.length = this.GetNumItems;

        for (i = 0; i < this.List.length; i += 2) {
            el.options[i / 2] = new Option();
            el.options[i / 2].value = this.List[i];
            el.options[i / 2].text = this.List[i + 1];
        }

        if (selectid!==undefined) {
            this.PerformSelectForID(tagid, selectid);
        }
    } else {
        setAlertIfExists('DHFSelectionList.LoadIntoSelectTag failed for ' + tagid);
    }
};

DHFSelectionList.prototype.AssertValue = function(id, txt) {
    var i,
        ins = this.List.length,
        firsti = (this.List.length > 0 && this.List[0] == -1 && id != -1) ? 2 : 0;
    
    for (i = firsti; i < this.List.length; i += 2) {
        if (id == this.List[i]) {
            return undefined;
        }
        
        if (i >= this.List.length - 2) {
            if (this.List.length == 2 && id < this.List[i]) {
                ins = 0;
            }
            break;
        }
        
        if (this.List[i] > this.List[i + 2]) {
            if (i == firsti && id > this.List[i]) {
                ins = firsti;
                break;
            }
            if (id > this.List[i + 2] && id < this.List[i]) {
                ins = i + 2;
                break;
            }
        } else {
            if (i == firsti && id < this.List[i]) {
                ins = firsti;
                break;
            }
            if (id > this.List[i] && id < this.List[i + 2]) {
                ins = i + 2;
                break;
            }
        }
    }
    this.List.splice(ins, 0, id, txt);
};

DHFSelectionList.prototype.PerformSelectForID = function(tagid, id) {
    setAlertIfExists('DHFSelectionList.PerformSelectForID ' + tagid + ' ' + id);
    
    var i = this.GetItemIndexForID(id),
        el = document.getElementById(tagid);
    
    if (el) {
        if (i >= 0 && i < el.length) {
            if (!this.RecursionLock) {
                this.RecursionLock = true;
                el.selectedIndex = i;
                this.RecursionLock = false;
            } else {
                setAlertIfExists('DHFSelectionList.PerformSelectForID recursion detected for ' + tagid + ' ' + id + ' ' + i);
            }
        } else {
            setAlertIfExists('DHFSelectionList.PerformSelectForID index out of range for ' + tagid + ' ' + id + ' ' + i);
        }
    } else {
        setAlertIfExists('DHFSelectionList.PerformSelectForID failed for ' + tagid);
    }
};
    
DHFSelectionList.prototype.GetSelectedID = function(tagid) {
    setAlertIfExists('DHFSelectionList.GetSelectedID ' + tagid);
    
    var i, j,
        el = document.getElementById(tagid);

    if (el) {
        i = el.selectedIndex;
        j = this.GetIDForItemIndex(i);
        setAlertIfExists('DHFSelectionList.GetSelectedID ' + tagid + ' ' + i + ' ' + j);
        return j;
    } else {
        setAlertIfExists('DHFSelectionList.GetSelectedID failed for ' + tagid);
    }
    
    return undefined;
};

DHFSelectionList.prototype.GetSelectedIndex = function(tagid) {
    setAlertIfExists('DHFSelectionList.GetSelectedID ' + tagid);
    
    var el = document.getElementById(tagid);

    if (el) {
        return (el.selectedIndex);
    } else {
        setAlertIfExists('DHFSelectionList.GetSelectedID failed for ' + tagid);
    }
    
    return undefined;
};

DHFSelectionList.prototype.GetSelectedText = function(tagid) {
    setAlertIfExists('DHFSelectionList.GetSelectedText ' + tagid);
    var el = document.getElementById(tagid);

    if (el) {
        return (this.List[el.selectedIndex * 2 + 1]);
    }

    setAlertIfExists('DHFSelectionList.GetSelectedText failed for ' + tagid);
    return undefined;
};

DHFSelectionList.prototype.GetNumItems = function() {
    setAlertIfExists('DHFSelectionList GetNumItems=' + this.List.length);
    return this.List.length / 2;
};
    
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class describing one form (or subform)
//
function DHFForm(ownerDHFForm, formID, controlIDList) {
    this.Init(ownerDHFForm, formID, controlIDList);
}

DHFForm.prototype.Init = function(ownerDHFForm, formID, controlIDList) {
    var a, i;
    
    this.FormID = formID;
    this.Owner = ownerDHFForm;
    this.SubFormCount = 0;
    this.FieldCount = 0;
    this.Fields = [];
    
    if (controlIDList) {
        if (controlIDList.length) {
            a = controlIDList.split(',');
            
            for (i = 0; i < a.length; i++) {
                new DHFField(this, a[i], 0);
            }
        }
    }
    
    this.SubForms = [];
    
    if (this.Owner) {
        this.Owner.RegisterSubForm(this);
    }
};

//
// Register subform
//
DHFForm.prototype.RegisterSubForm = function(subDHFForm) {
    this.SubForms[this.SubFormCount] = subDHFForm;
    this.SubFormCount++;
};

//
// Register field
//
DHFForm.prototype.RegisterField = function(subDHFField) {
    this.Fields[this.FieldCount] = subDHFField;
    this.FieldCount++;
    
    AllFields[AllFieldsCount] = subDHFField;
    AllFieldsCount++;
};

//
// Enable fields on form
// 
DHFForm.prototype.EnableFields = function(state, recursive) {
    setAlertIfExists('DHFForm EnableFields ' + this.FormID);
    var i;
    
    for (i = 0; i < this.FieldCount; i++) {
        this.Fields[i].EnableField(state);
    }
    
    if (recursive) {
        for (i = 0; i < this.SubFormCount; i++) {
            this.SubForms[i].EnableFields(state, recursive);
        }
    }
};
    
//
// Find field object on form
// 
DHFForm.prototype.FindField = function(fieldID) {
    var i;
    
    for (i = 0; i < this.FieldCount; i++) {
        if (this.Fields[i].FieldID == fieldID) {
            return (this.Fields[i]);
        }
    }
    
    return null;
};

//
// Find form object on form
// 
DHFForm.prototype.FindForm = function(formID) {
    var i;
    
    for (i = 0; i < this.SubFormCount; i++) {
        if (this.SubForms[i].FormID == formID) {
            return (this.SubForms[i]);
        }
    }
    
    return null;
};   

//
// Get top form
//
DHFForm.prototype.GetTopForm = function() {
    var o = this;
    
    while (o.Owner) {
        o = o.Owner;
    }
    
    return (o);
};

DHFForm.prototype.Show = function(state) {
    setAlertIfExists('DHFForm.Show ' + this.FormID + ' ' + state);
    DHFShowElement(this.FormID, state);
    
    if (this._ShowStateChanged) {
        this._ShowStateChanged(state);
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Class describing one field
//
function DHFField(ownerDHFForm, fieldID, fieldType) {
    this.Owner = ownerDHFForm;
    this.FieldID = fieldID;
    this.FieldType = fieldType;
    
    //Initial value when form was loaded
    this.InitialValue = '';
    
    this.Owner.RegisterField(this);
}
    
//
// Enable field 
//
DHFField.prototype.EnableField = function(state) {
    setAlertIfExists('DHFField EnableField ' + this.FieldID + ' ' + state);
    
    if (state) {
        if (this.SaveState) {
            DHFShowElement(this.FieldID, true);
        }
    } else {
        this.SaveState = DHFIsElementShown(this.FieldID);
        DHFShowElement(this.FieldID, false);
    }
};
    
//
// Set field value (e.g. from popup)
//

DHFField.prototype.SetValue = function(v) {
    //TODO: implement
};

//
// Get field value
//
DHFField.prototype.GetValue = function() {
    //TODO: implement
};

//
// Focus field
//
DHFField.prototype.Focus = function() {
    //TODO: implement
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Page management object
//    

function DHFPageMgr(ownerDHFPageMgr, pagename) {
    if (ownerDHFPageMgr && pagename) {
        this.Init(ownerDHFPageMgr, pagename);
    }
}

DHFPageMgr.prototype.Init = function(ownerDHFPageMgr, pagename) {
    this.Owner = ownerDHFPageMgr;
    this.pageName = pagename;
    this.currentPage = 0;
};

DHFPageMgr.prototype.MenuClicked = function(which) {
    setAlertIfExists('DHFPageMgr MenuClicked ' + which);
    this.SelectPage(which);
};

DHFPageMgr.prototype.SelectPage = function(which) {
    setAlertIfExists('DHFPageMgr SelectPage  ' + which);
    var errmsg = this.PageCanExit(this.currentPage);
    
    if (errmsg.length === 0) {
        this.MenuHighlight(which);
        this._PerformSelectPage(which);
        this.currentPage = which;
        this._PerformPostSelectPage();
    } else {
        alert(errmsg);
    }
};

DHFPageMgr.prototype._PerformSelectPage = function(which) {};

DHFPageMgr.prototype._PerformPostSelectPage = function() {};

DHFPageMgr.prototype.PageCanExit = function(which) {
    return '';
};

DHFPageMgr.prototype.MenuHighlight = function(which) {};

DHFPageMgr.prototype.Show = function(state) {};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    xxx

function DHFRemoveRootUrl(s) {
    s = s.replace(new RegExp(rootUrl, 'g'), '');
    
    return s;
}

function DHFSimpleHTML(s) {
    return s.replace(/<\/?(script|input|textarea|map|area|frameset|frame|base|noframes|form|select|option|meta|applet|iframe).*?>/gi, '');
}

function DHFHTMLEditMgr(numLanguages, disablefieldfunc, enablefieldfunc, offsetX, offsetY) {
    this.numLanguages = numLanguages;
    this.Texts = null;
    this.IsLanguageDependent = false;
    this.currentLanguage = -1;
    this.OnEndModalFunc = null;
    this.customFields = null;
    this.EndState = false;
    this.DisableFieldFunc = disablefieldfunc;
    this.EnableFieldFunc = enablefieldfunc;
    this.IsOpen = false;
    this.OffsetX = offsetX ? offsetX : 80;
    this.OffsetY = offsetY ? offsetY : 30;
}

DHFHTMLEditMgr.prototype.Reset = function(languagedependent, currentlanguage,/*optional*/ validateph) {
    var i, numLang = this.numLanguages;
    
    if (this.IsOpen) {
        return undefined;
    }
    
    this.validatePH = (validateph === undefined) ? true : validateph;
    this.customFields = {};
    this.currentLanguage = currentlanguage;
    this.IsLanguageDependent = languagedependent;
    this.ShowLanguageBar(this.IsLanguageDependent);
    
    if (this.IsLanguageDependent) {
        this.Texts = [];
        for (i = 0; i < numLang; i++) {
            this.Texts[i] = '';
        }
        this.SelectLanguage(this.currentLanguage);
    } else {
        this.Texts = '';
    }
    
    HTMLFieldReset();
};

DHFHTMLEditMgr.prototype.GetEndState = function() {
    return this.EndState;
};

DHFHTMLEditMgr.prototype.GetTextToArray = function(destarray) {
    var i;
    
    if (this.IsLanguageDependent) {
        for (i = 0; i < this.numLanguages; i++) {
            destarray[i] = this.Texts[i];
        }
    }
};

DHFHTMLEditMgr.prototype.SetTextFromArray = function(fromarray) {
    var i;
    
    if (this.IsOpen) {
        return undefined;
    }
    if (this.IsLanguageDependent) {
        for (i = 0; i < this.numLanguages; i++) {
            this.Texts[i] = fromarray[i];
        }
        this.SetEditField(this.Texts[this.currentLanguage]);
    }
};

DHFHTMLEditMgr.prototype.GetText = function(which) {
    if (this.IsLanguageDependent) {
        if (which >= 0 && which < this.Texts.length) {
            return (this.Texts[which]);
        }
    } else {
        return (this.Texts);
    }
    
    return undefined;
};

DHFHTMLEditMgr.prototype.SetText = function(which, s) {
    if (this.IsOpen) {
        return null;
    }
    
    if (this.IsLanguageDependent) {
        if (which >= 0 && which < this.Texts.length) {
            this.Texts[which] = DHF.mediaStringUtils.contentToPlaceholders(s);
            this.SetEditField(this.Texts[this.currentLanguage]);
        }
    } else {
        this.Texts = DHF.mediaStringUtils.contentToPlaceholders(s);
        this.SetEditField(this.Texts);
    }
    
    return null;
};

DHFHTMLEditMgr.prototype.Show = function(state) {
    HTMLEditorShow(state);
};

DHFHTMLEditMgr.prototype.OKClicked = function() {
    setAlertIfExists('DHFHTMLEditMgr OKClicked');
    this.EndModal(true);
};

DHFHTMLEditMgr.prototype.CancelClicked = function() {
    setAlertIfExists('DHFHTMLEditMgr CancelClicked');
    this.EndModal(false);
};

DHFHTMLEditMgr.prototype.DoModal = function(onendmodalfunc) {
    if (this.IsOpen) {
        return null;
    }
    
    setAlertIfExists('DHFHTMLEditMgr DoModal ' + onendmodalfunc);
    this.OnEndModalFunc = onendmodalfunc;
    eval(this.DisableFieldFunc);
    HTMLEditorShow(true);
    HTMLFieldFocus();
    this.IsOpen = true;
    
    return null;
};

DHFHTMLEditMgr.prototype.EndModal = function(endstate) {
    if (!this.IsOpen) {
        return null;
    }
    
    this.EndState = endstate;
    setAlertIfExists('DHFHTMLEditMgr EndModal ' + endstate + ' ' + this.OnEndModalFunc);
    
    if (endstate) {
        this.GetEditFields();
    }
    
    if (!endstate || this.ValidateEditFields()) {
        if (endstate) {
            this.Texts = HTMLEditorTrimEndHTML(this.Texts);
            this.Texts = DHF.mediaStringUtils.placeholdersToContent(this.Texts);
            HTMLEditorFixAbsoluteImagePaths();
            HTMLEditorConvertMediaTags();
        }
    
        eval(this.EnableFieldFunc);
        HTMLEditorShow(false);
    
        if (this.OnEndModalFunc) {
            setAlertIfExists('ENDMODAL ' + this.OnEndModalFunc);
            eval(this.OnEndModalFunc);
        }
    
        this.IsOpen = false;
    }
    return null;
};

DHFHTMLEditMgr.prototype.LanguageClicked = function(which) {
    setAlertIfExists('DHFHTMLEditMgr LanguageClicked ' + which);
    this.SelectLanguage(which);
    
    HTMLEditorSetCulture(which);
    if (window.objGapDropdown && window.objGapDropdown.Populate) {
        window.objGapDropdown.Populate();
    }
    
    HTMLFieldFocus();
};

DHFHTMLEditMgr.prototype.ShowLanguageBar = function(state) {
    setAlertIfExists('DHFHTMLEditMgr ShowLanguageBar ' + state);
    DHFShowElement('htmlLangTD', state);
};

var HTMLEditLanguage = -1;
DHFHTMLEditMgr.prototype.SelectLanguage = function(which) {
    setAlertIfExists('DHFHTMLEditMgr SelectLanguage ' + which);
    this.GetEditFields();
    
    this.currentLanguage = HTMLEditLanguage = which;
    this.LanguageHighlight(this.currentLanguage);
    
    this.SetEditField(this.IsLanguageDependent ? this.Texts[this.currentLanguage] : this.Texts);
};

DHFHTMLEditMgr.prototype.GetEditFields = function() {
    if (this.IsLanguageDependent) {
        if (this.currentLanguage >= 0 && this.currentLanguage < this.numLanguages) {
            this.Texts[this.currentLanguage] = this.GetEditField();
        }
    } else {
        this.Texts = this.GetEditField();
    }
};

DHFHTMLEditMgr.prototype.ValidateEditFields = function() {
    var fv = new DHFFieldVerifier(), s, i;
    
    if (this.IsLanguageDependent) {
        for (i = 0; i < this.numLanguages; i++) {
            s = PHProcessTags(this.Texts[i]);
            if (HTMLCleanerActive) {
                s = DHFSimpleHTML(s);
            }
            s = DHFRemoveRootUrl(s);
            s = this.StripCRLF(s);
            this.Texts[i] = s;
            
            if (!usingLMS) {
                if (this.validatePH) {
                    fv.CheckStringPH(this.Texts[i], true, strobj_textlang.SubstBy(globalContent.languageLabels[i]).GetString());
                }
            }
        }
    } else {
        s = PHProcessTags(this.Texts);
        
        if (HTMLCleanerActive) {
            s = DHFSimpleHTML(s);
        }
        
        s = DHFRemoveRootUrl(s);
        this.Texts = DHFSimpleHTML(s);
        
        if (!usingLMS) {
            fv.CheckStringPH(this.Texts, true, strobj_text.GetString());
        }
    }
    
    if (fv.GetMsgCount(-1) > 0) {
        alert(fv.GetCompoundMsgText());
    }
    
    return (fv.GetMsgCount(msgError) === 0);
};

// The following function is necessary in order to fix problems
// with text copied and pasted from external apps.
//
DHFHTMLEditMgr.prototype.StripCRLF = function(s) {
    var re_nlchar;
    
    s = escape(s);
    
    if (s.indexOf('%0D%0A') > -1) {
        re_nlchar = /%0D%0A/g;
    } else if (s.indexOf('%0A') > -1) {
        re_nlchar = /%0A/g;
    } else if (s.indexOf('%0D') > -1) {
        re_nlchar = /%0D/g;
    }
    
    return unescape(s.replace(re_nlchar, ''));
};

DHFHTMLEditMgr.prototype.SetEditField = function(s) {
    HTMLFieldSetContent(s);
};

DHFHTMLEditMgr.prototype.GetEditField = function() {
    return (DHFHTMLTrim(HTMLFieldGetContent()));
};

DHFHTMLEditMgr.prototype.LanguageHighlight = function(which) {
    var i, el;
    
    setAlertIfExists('DHFHTMLEditMgr LanguageHighlight ' + which);
    
    for (i = 0; i < globalContent.numLanguages; i++) {
        el = document.getElementById('htmlLang_' + i);
        el.className = (i == which) ? 'langFullAct' : 'langSemiOut';
    }
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    

function DHFDialogMgr(title, message, buttons, disablefieldfunc, enablefieldfunc, onendmodalfunc, idprefix, canclosefunc) {
    this.Title = title;
    this.Message = message;
    this.Buttons = buttons;
    this.OnEndModalFunc = onendmodalfunc;
    this.EndState = false;
    this.IDPrefix = idprefix;
    this.DisableFieldFunc = disablefieldfunc;
    this.EnableFieldFunc = enablefieldfunc;
    this.CanCloseFunc = canclosefunc;
    
    if (this.IDPrefix.length === 0) {
        this.IDPrefix = 'msgBox';
    }
}

DHFDialogMgr.prototype.GetEndState = function() {
    return (this.EndState);
};

DHFDialogMgr.prototype.YesClicked = function() {
    setAlertIfExists('DHFDialogMgr YesClicked');
    this.EndModal(msgBoxYes);
};

DHFDialogMgr.prototype.NoClicked = function() {
    setAlertIfExists('DHFDialogMgr NoClicked');
    this.EndModal(msgBoxNo);
};

DHFDialogMgr.prototype.OKClicked = function() {
    setAlertIfExists('DHFDialogMgr OKClicked');
    this.EndModal(msgBoxOK);
};

DHFDialogMgr.prototype.CancelClicked = function() {
    setAlertIfExists('DHFDialogMgr CancelClicked');
    this.EndModal(msgBoxCancel);
};
    
DHFDialogMgr.prototype.Show = function(state) {
    setAlertIfExists('DHFDialogMgr Show ' + state);
    
    //TODO fill in stuff and display buttons
    DHFShowElement(this.IDPrefix + 'OKButton', this.Buttons & msgBoxOK);
    DHFShowElement(this.IDPrefix + 'CancelButton', this.Buttons & msgBoxCancel);
    DHFShowElement(this.IDPrefix + 'YesButton', this.Buttons & msgBoxYes);
    DHFShowElement(this.IDPrefix + 'NoButton', this.Buttons & msgBoxNo);
    
    DHFSetElementText(this.IDPrefix + 'Title', this.Title);
    DHFSetElementText(this.IDPrefix + 'Message', this.Message);
    
    DHFShowElement(this.IDPrefix + 'Popup', state);
};

DHFDialogMgr.prototype.DoModal = function() {
    setAlertIfExists('DHFDialogMgr DoModal ');
    
    if (this.DisableFieldFunc) {
        eval(this.DisableFieldFunc);
    }
    
    DHFMoveToVisibility(this.IDPrefix + 'Popup');
    this.Show(true);
};

DHFDialogMgr.prototype.EndModal = function(endstate) {
    setAlertIfExists('DHFDialogMgr EndModal ' + endstate + ' ' + this.OnEndModalFunc);
    this.EndState = endstate;
    
    if (!this.CanCloseFunc || eval(this.CanCloseFunc)) {
        this.Show(false);
        if (this.EnableFieldFunc) {
            eval(this.EnableFieldFunc);
        }
        
        if (this.OnEndModalFunc) {
            eval(this.OnEndModalFunc);
        }
    } else {
        this.EndState = false;
    }
};

DHFDialogMgr.prototype.PositionRelativeTo = function(elementid, relpos) {
    var w = DHFGetDivWidth(this.IDPrefix + 'Popup'),
        h = DHFGetDivHeight(this.IDPrefix + 'Popup'),
        x0 = DHFGetDivX(elementid),
        y0 = DHFGetDivY(elementid);
    
    if (relpos & msgBoxBelow) {
        y0 += 5;
    }
    
    if (relpos & msgBoxAbove) {
        y0 -= (h + 5);
    }
    
    if (relpos & msgBoxRight) {
        x0 += 5;
    }
    
    if (relpos & msgBoxLeft) {
        x0 -= (w + 5);
    }
    
    DHFSetDivPosition(this.IDPrefix + 'Popup', x0, y0);
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Image Preloader, use comma separated list

var preloadedImages=[];
function DHFPreloadImages(basepath, imagelist, extension) {
    var i,
        a = imagelist.split(','),
        al = a.length;
    
    setAlert('DHFPreloadImages ' + basepath + ' ' + imagelist + ' ' + extension);
    
    for (i = 0; i < al; i++) {
        preloadedImages[a[i]] = new Image();
        preloadedImages[a[i]].src = basepath + a[i] + '.' + extension;
    }
}
    
function DHFPreloadBasicImages(basepath) {
    DHFPreloadImages(basepath, 'bin,edit,details,add,up,dn,up_small,dn_small,up_white,dn_white,open,close,spacer', 'gif');
}

function DHFPatchImages(imglist, start, count) {
    var i, j, el,
        a = imglist.split(','),
        al = a.length,
        tot = start + count;
    
    for (j = 0; j < al; j++) {
        for (i = start; i < tot; i++) {
            el = document.getElementById('img' + a[j] + i);

            if (el) {
                if (preloadedImages[a[j]]) {
                    el.src = preloadedImages[a[j]].src;
                }
            }
        }
    }
}

function DHFPatchBasicImages(start, count) {
    DHFPatchImages('bin,edit,details,add,up,dn,up_small,dn_small,up_white,dn_white,open,close,spacer', start, count);
}

// substitutes all occurrences of "[[_n]]" by the value of the string variable named "n"
function DHFSubstStringPH(s) {
    var j, k,
        r = '',
        i = 0;
    
    while (i < s.length) {
        j = s.indexOf('[[_', i);
        
        if (j < 0) {
            break;
        }
        
        r += s.substring(i, j);
        k = s.indexOf(']]', j);
        
        if (k < 0) {
            break;
        }
        
        r += window[s.substring(j + 3, k)];
        i = k + 2;
    }
    r += s.substr(i);
    
    return r;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Strings

function DHFString(text, encoded) {
    this.Text = encoded ? DHFUnescape(text) : text;
}

DHFString.prototype.GetClone = function() {
    return new DHFString(this.Text);
};

DHFString.prototype.GetString = function() {
    return this.Text;
};

DHFString.prototype.GetStringAsHTML = function() {
    return DHFHTMLEncode(this.Text);
};

// substitute placeholders $$1, $$2 etc. by given strings (either a single array or as separate parameters)
// doesn't change the current instance
// returns a string
DHFString.prototype.SubstStrBy = function() {
    var s, r, i,
        a = arguments[0];

    if (arguments.length !== 1 || (a !== undefined && (a.constructor === Number || a.constructor === String))) {
        a = arguments;
    }
    
    s = this.Text;
    r = new RegExp();
    
    for (i = 0; i < a.length; i++) {
        if (a[i] !== null) {
            r.compile('\\$\\$' + (i + 1), 'g');
            s = s.replace(r, a[i]);
        }
    }
    
    return s;
};

// substitute placeholders $$1, $$2 etc. by given strings (either a single array or as separate parameters)
// doesn't change the current instance
// returns a new DHFString instance
DHFString.prototype.SubstBy = function() {
    return new DHFString(this.SubstStrBy(arguments));
};

// substitute placeholders $$1, $$2 etc. by given strings (either a single array or as separate parameters)
// changes the current instance
// returns the current instance
DHFString.prototype.Subst = function() {
    this.Text = this.SubstStrBy(arguments);
    return this;
};

// substitutes the given placeholder $$n by the given string
// doesn't change the instance
// returns a string
DHFString.prototype.SubstStrBy1 = function(n, s) {
    return this.Text.replace(new RegExp('\\$\\$' + n, 'g'), s);
};

// substitutes the given placeholder $$n by the given string
// doesn't change the instance
// returns a new DHFString instance
DHFString.prototype.SubstBy1 = function(n, s) {
    return new DHFString(this.SubstStrBy1(n, s));
};

// substitutes the given placeholder $$n by the given string
// changes the current instance
// returns the current instance
DHFString.prototype.Subst1 = function(n, s) {
    this.Text = this.SubstStrBy1(n, s);

    return this;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Messages

var msgInfo = 0;
var msgWarning = 1;
var msgError = 2;

function DHFMsg(msgtype, msgtext, encoded) {
    this.MsgType = (msgtype === undefined) ? msgError : msgtype;
    this.MsgText = new DHFString(msgtext, encoded);
}

DHFMsg.prototype.GetClone = function() {
    return new DHFMsg(this.MsgType, this.MsgText.GetString());
};

DHFMsg.prototype.GetText = function() {
    return this.MsgText.GetString();
};

DHFMsg.prototype.GetString = function() {
    return this.MsgText;
};

DHFMsg.prototype.GetType = function() {
    return this.MsgType;
};

// substitute placeholders $$1, $$2 etc. by given strings (either an array or as separate parameters)
// returns this instance
DHFMsg.prototype.Subst = function() {
    this.MsgText.Subst(arguments);
    return this;
};

// substitute placeholders $$1, $$2 etc. by given strings (either an array or as separate parameters)
// returns a new DHFMsg instance
DHFMsg.prototype.SubstBy = function() {
    return new DHFMsg(this.MsgType, this.MsgText.SubstStrBy(arguments));
};

// substitutes the given placeholder $$n by the given string
// returns this instance
DHFMsg.prototype.Subst1 = function(n, s) {
    this.MsgText.Subst1(n, s);
    return this;
};

// substitutes the given placeholder $$n by the given string
// returns a new DHFMsg instance
DHFMsg.prototype.SubstBy1 = function(n, s) {
    return new DHFMsg(this.MsgType, this.MsgText.SubstStrBy1(n, s));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//    Field verification

var ftText = 1;
var ftDate = 2;
var ftNumber = 3;
var ftHTML = 4;
var ftDuration = 5;
var ftIDSearch = 6;
var ftTime = 7;
var ftPassword = 8;
var ftCheckbox = 9;
var ftDurationStrict = 10;  // don't allow just minutes

var fvNotEmpty = 1;
var fvGreaterEqual = 4;
var fvEmptyOK = 8;
var fvNotDecimal = 16; // don't allow decimal digits (only for ftNumber)
var fvMaxLength = 32; // check maximum length (compareval) (only for ftText)
                // error text may contain placeholder [[len]] for current length and [[limit]] for limit
var fvMinLength = 64;
var fvIdentifier = 128; //check to contain only text for identifiers
var fvMoney = 256; // don't allow numeric range out of bounds for money type (only for ftNumber)
var fvLessEqual = 512;
var fvNoPH = 1024;
var fvPH = 2048;
var fvTimeNoSeconds = 4096; // don't allow seconds (only for ftTime)
var fvGreater = 8192;
var fvURL = 16384; // check to contain a valid URL
var fvEmail = 32768;
var fvRegExp = 65536;
var fvChecked = 131072;
var ftDynamic = 262144;

function DHFFieldVerifier() {
    this.List = [];
}
    
DHFFieldVerifier.prototype=new DHFGenericList();

// returns FALSE if bad
// to use this function, phpicker_head_inc.aspx must have been included
DHFFieldVerifier.prototype.CheckStringPH = function(val, phallowed, flddesc) {
    var a, ai, j, c, e, g, k, ident, ix,
        msgobj = null,
        i = 0;
    
    if (!val) {
        return true;
    }
    
    if (phallowed) {
        while (i < val.length) {
            if ((c = val.charAt(i++)) == '[') {
                if (i < val.length && val.charAt(i) == '[') {
                    i++;
                } else {
                    while (i < val.length && val.charAt(i) == ' ') {
                        i++;
                    }

                    if (i < val.length && val.charAt(i) == ']') {
                        msgobj = msgobj_PHEmpty;
                        break;
                    }

                    if (i < val.length && val.charAt(i) == '$') {
                        k = val.indexOf(']', ++i);

                        if (k < 0) {
                            msgobj = msgobj_PHNotClosed;
                            break;
                        } else {
                            ident = val.substring(i, k).toUpperCase();
                            g = ident.indexOf('=');
                            
                            if (g < 0 || ident.substring(0, g) != 'MEDIA') {
                                msgobj = msgobj_PHXSyntax.SubstBy1(2, ident);
                                break;
                            }
                            
                            a = ident.substr(g + 1).split(';');
                            
                            if (a.length < 1 || a[0].length === 0) {
                                msgobj = msgobj_PHXSyntax.SubstBy1(2, ident);
                                break;
                            }
                            
                            for (ai = 1; ai < a.length; ai++) {
                                if (a[ai].length > 0) {
                                    e = a[ai].split('=');

                                    if (e.length != 2 || e[0] != 'ALIGN' || (e[1] != 'FLOW' && e[1] != 'LEFT' && e[1] != 'CENTER' && e[1] != 'RIGHT')) {
                                        msgobj = msgobj_PHXSyntax.SubstBy1(2, ident);
                                        break;
                                    }
                                }
                            }
                            
                            if (msgobj) {
                                break;
                            }
                        }
                    } else {
                        j = i;
                        
                        while (j < val.length && (c = val.charAt(j)) != ' ' && c != ']') {
                            j++;
                        }
                        
                        k = j;
                        
                        while (k < val.length && val.charAt(k) == ' ') {
                            k++;
                        }
                        
                        if (k >= val.length || val.charAt(k) != ']') {
                            msgobj = msgobj_PHNotClosed;
                            break;
                        }
                        
                        ident = val.substring(i, j).toUpperCase();
                        
                        for (ix = 0; ix < phnames.length; ix++) {
                            if (ident == phnames[ix]) {
                                break;
                            }
                        }
                        
                        if (ix >= phnames.length) {
                            msgobj = msgobj_PHUnknown.SubstBy1(2, ident);
                            break;
                        }
                    }

                    i = k + 1;
                }
            } else if (c == ']') {
                if (i >= val.length || val.charAt(i++) != ']') {
                    msgobj = msgobj_PHNotOpened;
                    break;
                }
            }
        }
    } else if (val.search(/[\[\]]/) >= 0) {
        msgobj = msgobj_PHNotAllowed;
    }
    
    if (!msgobj) {
        return true;
    }
    
    this.AddMessage(msgobj.SubstBy1(1, flddesc), 0);
    
    return false;
};

// returns FALSE if bad
// to use this function, phpicker_head_inc.aspx must have been included
// fieldIDs and fieldDescs must be comma delimited lists of fieldIDs or descriptions resp.
DHFFieldVerifier.prototype.CheckFieldsPH = function(fieldIDs, fieldDescs, phallowed) {
    var i,
        result = true,
        a = fieldIDs.split(','),
        b = fieldDescs.split(','),
        len = a.length;
    
    if (b.length < len) {
        len = b.length;
    }
    
    for (i = 0; i < len; i++) {
        if (!this.CheckStringPH(DHFGetFieldValue(a[i], ''), phallowed, b[i])) {
            result = false;
        }
    }
    
    return result;
};

// returns FALSE if bad
DHFFieldVerifier.prototype.CheckValX = function(val, fieldtype, checktype, fielddescORmsgobj, compareval) {
    return this.CheckVal(val, fieldtype, checktype, fielddescORmsgobj, compareval);
};

// returns FALSE if bad
// WARNING: either define msgobj or fielddesc
DHFFieldVerifier.prototype.CheckVal = function(val, fieldtype, checktype, fielddescORmsgobj, compareval) {
    var bad2, d, msgobj, dateErrCode, r, rxs, ss,
        bad = false;
    
    if (fielddescORmsgobj.constructor === String) {
        msgobj = null;
    } else {
        msgobj = fielddescORmsgobj;
    }
    
    if (val === undefined || val === null) {
        val = '';
    }
    
    //check if empty is ok
    if (!bad && (checktype & fvEmptyOK)) {
        if (val && val.isDHFDate && val.isEmpty() && val.getErrorCode() === null) {
            return true;
        } else {
            ss = val + '';
            
            if (ss.length === 0) {
                return true;
            }
        }
    }
    
    if (!bad) {
        switch (fieldtype) {
            case ftPassword:
                if ((checktype & fvMaxLength) && (val + '').length > compareval) {
                    bad = true;
                    
                    if (!msgobj) {
                        msgobj = msgobj_maxTextLength.GetClone();
                        msgobj.Subst1(2, compareval);
                    } else {
                        msgobj.MsgText = msgobj.MsgText.replace(/\[\[len\]\]/g, ((val + '').length) + '');
                        msgobj.MsgText = msgobj.MsgText.replace(/\[\[limit\]\]/g, compareval + '');
                    }
                }
                
                if (!bad && minPasswordChars > 0 && (checktype & fvMinLength) && (val + '').length < minPasswordChars) {
                    bad = true;

                    if (!msgobj) {
                        msgobj = msgobj_minTextLength.GetClone();
                        msgobj.Subst1(2, minPasswordChars);
                    } else {
                        msgobj.MsgText = msgobj.MsgText.replace(/\[\[len\]\]/g, ((val + '').length) + '');
                        msgobj.MsgText = msgobj.MsgText.replace(/\[\[limit\]\]/g, minPasswordChars + '');
                    }
                }
                
                if (!bad && (checktype & fvRegExp)) {
                    rxs = val + '';
                    
                    if (!rxs.match(compareval)) {
                        bad = true;
                        
                        if (!msgobj) {
                            msgobj = msgobj_invalid.GetClone();
                        }
                    }
                }
                break;
            case ftNumber:
                if (checktype & fvMoney) {
                    if ((val + '').search(/^ *[0-9]{1,14}(\.[0-9]{0,4})? *$/) == -1) {
                        if (!msgobj) {
                            msgobj = msgobj_moneySyntax.GetClone();
                        }

                        bad = true;
                    }
                } else if ((r = DHFIsNumeric2(val, true, (checktype & fvNotDecimal) === 0)) != 1) {
                    if (!msgobj) {
                        if (r == 2) {
                            msgobj = msgobj_numberSyntax2.SubstBy1(2, 15);
                        } else {
                            msgobj = msgobj_numberSyntax.GetClone();
                        }
                    }
                    
                    bad = true;
                }
                break;
                
            case ftDate:
                bad2 = false;
                
                if (checktype & ftDynamic) {
                    if (!DHFIsDynamicDate(val)) {
                        if (!msgobj) {
                            msgobj = msgobj_dynamicDateSyntax.GetClone();
                        }
                        
                        bad2 = true;
                    } else {
                        break;
                    }
                }
                
                if (val.isDHFDate) {
                    dateErrCode = val.getErrorCode();
                } else {
                    dateErrCode = DHFValidateGetJSDate(val, 'datecheck');
                }
                
                switch (dateErrCode) {
                    case -1: // Date has wrong number of separators or can't be read
                        if (!msgobj || bad2) {
                            msgobj = msgobj_dateInvalidDate.GetClone();
                            
                            switch (dateinputformat) {
                                case "ddmmyy":
                                    msgobj.Subst1(2, "dd" + datesep + "mm" + datesep + "yy");
                                    break;
                                case "ddmmyyyy":
                                    msgobj.Subst1(2, "dd" + datesep + "mm" + datesep + "yyyy");
                                    break;
                                case "mmddyy":
                                    msgobj.Subst1(2, "mm" + datesep + "dd" + datesep + "yy");
                                    break;
                                case "mmddyyyy":
                                    msgobj.Subst1(2, "mm" + datesep + "dd" + datesep + "yyyy");
                                    break;
                                case "yymmdd":
                                    msgobj.Subst1(2, "yy" + datesep + "mm" + datesep + "dd");
                                    break;
                                case "yyyymmdd":
                                    msgobj.Subst1(2, "yyyy" + datesep + "mm" + datesep + "dd");
                                    break;
                                default: // This should never happen
                                    msgobj.Subst1(2, "Error");
                                    break;
                            }
                        }
                        
                        bad = true;
                        break;
                        
                    case -2: // Invalid Month
                        if (!msgobj || bad2) {
                            msgobj = msgobj_dateInvalidMonth.GetClone();
                        }
                        
                        bad = true;
                        break;
                        
                    case -3: // Invalid Day
                        if (!msgobj || bad2) {
                            msgobj = msgobj_dateInvalidDay.GetClone();
                        }
                        
                        bad = true;
                        break;
                        
                    case -4: // Invalid Year
                        if (!msgobj) {
                            msgobj = msgobj_dateInvalidYear.GetClone();
                        }
                        
                        bad = true;
                        break;
                        
                    case -5: // Invalid Date
                        if (!msgobj || bad2) {
                            msgobj = msgobj_dateSyntax.GetClone();
                        }
                        
                        bad = true;
                        break;
                        
                    default:
                        //Date has no errors, do nothing
                        msgobj = null;
                        break;
                }
                break;

            case ftTime:
                if (!DHFIsTime(val, !(checktype & fvTimeNoSeconds))) {
                    if (!msgobj) {
                        msgobj = msgobj_timeSyntax.GetClone();
                    }
                    
                    bad = true;
                }
                break;
                
            case ftCheckbox:
                if ((checktype & fvChecked) && !val) {
                    if (!msgobj) {
                        msgobj = msgobj_checkboxChecked.GetClone();
                    }
                    
                    bad = true;
                }
                break;
                
            case ftText:
                if ((checktype & fvMaxLength) && (val + '').length > compareval) {
                    bad = true;
                    
                    if (!msgobj) {
                        msgobj = msgobj_maxTextLength.GetClone();
                        msgobj.Subst1(2, compareval);
                    } else {
                        msgobj.MsgText = msgobj.MsgText.replace(/\[\[len\]\]/g, ((val + '').length) + '');
                        msgobj.MsgText = msgobj.MsgText.replace(/\[\[limit\]\]/g, compareval + '');
                    }
                }
                
                if (!bad && (checktype & fvIdentifier)) {
                    //Allow 0..9, A..Z, a..z
                    if (val.search(/^[a-zA-Z]{1}[0-9a-zA-Z]*$/) == -1) {
                        if (!msgobj) {
                            msgobj = msgobj_identSyntax.GetClone();
                        }
                        
                        bad = true;
                    }
                }
                
                if (!bad && (checktype & fvURL)) {
                    if (!DHFIsURL(val)) {
                        if (!msgobj) {
                            msgobj = msgobj_urlSyntax.GetClone();
                        }
                        
                        bad = true;
                    }
                }
                
                if (!bad && (checktype & fvNoPH)) {
                    this.CheckStringPH(val, false, msgobj ? '?' : fielddescORmsgobj);
                }
                
                if (!bad && (checktype & fvPH)) {
                    this.CheckStringPH(val, true, msgobj ? '?' : fielddescORmsgobj);
                }
                
                if (!bad && (checktype & fvEmail)) {
                    if (!DHFIsEmail(val)) {
                        if (!msgobj) {
                            msgobj = msgobj_invalid.GetClone();
                        }
                        
                        bad = true;
                    }
                }
                
                if (!bad && (checktype & fvRegExp)) {
                    rxs = val + '';
                    if (!rxs.match(compareval)) {
                        bad = true;
                        if (!msgobj) {
                            msgobj = msgobj_invalid.GetClone();
                        }
                    }
                }
                break;

            case ftDuration:
                if (DHFParseDuration(val) === null) {
                    if (!msgobj) {
                        msgobj = ((checktype & fvEmptyOK) ? msgobj_durationSyntaxE : msgobj_durationSyntax).GetClone();
                    }
                    
                    bad = true;
                }
                break;
                
            case ftDurationStrict:
                if (DHFParseDuration(val, true) === null) {
                    if (!msgobj) {
                        msgobj = ((checktype & fvEmptyOK) ? msgobj_durationSyntaxEAlt : msgobj_durationSyntaxAlt).GetClone();
                    }
                    
                    bad = true;
                }
                break;
                
            case ftIDSearch:
                if (!DHFCheckIDSearchSyntax(val)) {
                    if (!msgobj) {
                        msgobj = msgobj_idSyntax.SubstBy(fielddescORmsgobj);
                    }
                    
                    bad = true;
                }
                break;
                
            default:
                break;
        }
    }
    
    //empty check
    if (!bad && (checktype & fvNotEmpty)) {
        //convert to string for this check
        if (DHFTrim(val).length === 0) {
            if (!msgobj) {
                msgobj = msgobj_notEmpty.GetClone();
            }
            
            bad = true;
        }
    }
    
    //value check
    if (!bad && (checktype & fvGreaterEqual)) {
        if (fieldtype == ftNumber) {
            if (parseFloat(val) < compareval) {
                if (!msgobj) {
                    if (!compareval) {
                        msgobj = msgobj_notNegative.GetClone();
                    } else {
                        msgobj = msgobj_min.GetClone();
                        msgobj.Subst1(2, compareval);
                    }
                }
                
                bad = true;
            }
        } else if (val < compareval) {
            if (!msgobj) {
                msgobj = msgobj_invalid.GetClone();
            }
            
            bad = true;
        }
    }
    
    if (!bad && (checktype & fvGreater)) {
        if (fieldtype == ftNumber) {
            if (parseFloat(val) <= compareval) {
                if (!msgobj) {
                    if (!compareval) {
                        msgobj = msgobj_positive.GetClone();
                    } else {
                        msgobj = msgobj_greaterThan.GetClone();
                        msgobj.Subst1(2, compareval);
                    }
                }
                
                bad = true;
            }
        } else if (val <= compareval) {
            if (!msgobj) {
                msgobj = msgobj_invalid.GetClone();
            }
            
            bad = true;
        }
    }
    
    if (!bad && (checktype & fvLessEqual)) {
        if (fieldtype == ftNumber) {
            if (parseFloat(val) > compareval) {
                if (!msgobj) {
                    msgobj = msgobj_max.GetClone();
                    msgobj.Subst1(2, compareval);
                }
                
                bad = true;
            }
        } else if (val > compareval) {
            if (!msgobj) {
                msgobj = msgobj_invalid.GetClone();
            }
            
            bad = true;
        }
    }
    
    if (bad) {
        if (fielddescORmsgobj && (fielddescORmsgobj.constructor === Number || fielddescORmsgobj.constructor === String)) {
            d = fielddescORmsgobj + '';
            msgobj.Subst1(1, (d.length > 0) ? d : '???');
        }
        
        this.AddMessage(msgobj);
    }
    return !bad;
};

DHFFieldVerifier.prototype.AddMessage = function(msgobj) {
    this.List[this.List.length] = msgobj;
};

DHFFieldVerifier.prototype.CheckField = function(fieldid, fieldtype, checktype, fielddescORmsgobj, compareval) {
    var el = document.getElementById(fieldid), v = '';
    
    if (el) {
        switch (fieldtype) {
            case ftText:
            case ftPassword:
            case ftDate:
            case ftNumber:
                v = DHFGetFieldValue(fieldid);
                break;
                
            case ftCheckbox:
                v = DHFGetFieldChecked(fieldid, false);
                break;
                
            case ftHTML:
                v = el.innerHTML;
                break;
                
            default:
                break;
        }
        
        return (this.CheckValX(v, fieldtype, checktype, fielddescORmsgobj, compareval));
    } else {
        setAlertIfExists('DHFFieldVerifier.Check: element not found ' + fieldid);
    }
    
    return undefined;
};

DHFFieldVerifier.prototype.CheckFieldX = function(fieldid, fieldtype, checktype, fielddescORmsgobj, compareval) {
    return this.CheckField(fieldid, fieldtype, checktype, fielddescORmsgobj, compareval);
};

DHFFieldVerifier.prototype.IsOK = function() {
    //TODO: no errors or warnings = ok
    return (this.GetMsgCount(msgError) === 0 && this.GetMsgCount(msgWarning) === 0);
};
    
DHFFieldVerifier.prototype.GetMsgCount = function(msgtype) {
    var i, j = 0;
    
    for (i = 0; i < this.List.length; i++) {
        if (this.List[i].GetType) {
            if (msgtype == -1 || this.List[i].GetType() == msgtype) {
                j++;
            }
        }
    }
    return j;
};

DHFFieldVerifier.prototype.GetCompoundMsgText = function() {
    var i, lo, strobj,
        s = '';
    
    for (i = 0; i < this.List.length; i++) {
        lo = this.List[i];
        strobj = null;
        
        switch (lo.GetType && lo.GetType()) {
            case msgInfo:
                strobj = strobj_info;
                break;
            case msgWarning:
                strobj = strobj_warning;
                break;
            case msgError:
                strobj = strobj_error;
                break;
            default:
                break;
        }
        
        if (strobj) {
            s += strobj.SubstBy(lo.GetText()).GetString() + '\r\n';
        } else {
            s += lo.GetText() + '\r\n';
        }
    }
    
    return (s);
};

function DHFIsDynamicDate(val) {
    return (val + '').search(/^([+,-][0-9]+y){0,1}([+,-][0-9]+q){0,1}([+,-][0-9]+m){0,1}([+,-][0-9]+w){0,1}([+,-][0-9]+d){0,1}$/) >= 0;
}
    
// moves all HTML tags inside of PHs before the PH
function PHProcessTags(val) {
    var c, phi, tagi, i = 0;
    
    while (i < val.length) {
        if (val.charAt(i++) == '[') {
            if (i < val.length && val.charAt(i) == '[') {
                i++;
            } else {
                phi = i - 1;
                
                while (i < val.length) {
                    while (i < val.length && (c = val.charAt(i)) != '<' && c != ']') {
                        i++;
                    }
                    
                    if (i < val.length && c == ']') {
                        i++;
                        break;
                    }
                    
                    tagi = i;
                    
                    while (i < val.length && (c = val.charAt(i)) != '>') {
                        i++;
                        if (c == '"') {
                            while (i < val.length) {
                                if ((c = val.charAt(i)) == '"') {
                                    break;
                                }
                                
                                if (c == '\\' && i + 1 < val.length && val.charAt(i + 1) == '"') {
                                    i++;
                                }
                                
                                i++;
                            }
                            
                            i++;
                        }
                    }
                    if (i < val.length) {
                        i++;
                        val = val.substring(0, phi) + val.substring(tagi, i) + val.substring(phi, tagi) + val.substr(i);
                        phi += i - tagi;
                    }
                }
            }
        }
    }
    
    return val;
}

// compatible cursor function

function DHFSetCursor(el, pointer) {
    if (el) {
        if (pointer) {
            el.style.cursor = 'pointer';
        } else {
            el.style.cursor = 'default';
        }
    }
}

// Unicode safe escape/unescape functions

function DHFHexDigit(h) {
    if (h >= 10) {
        return String.fromCharCode(55 + h);
    }
    
    return h;
}

function DHFEscape(s) {
    return encodeURIComponent(s);
}

function DHFHexToNum(h) {
    var c;
    
    return ((c = h.charCodeAt(0)) >= 65) ? (c - 55) : (c - 48);
}

function DHFUnescape(s) {
    try {
        return decodeURIComponent(s);
    } catch (e) {
        return s;
    }
}

function DHFIsURL(s) {
    return (s + '').search(/^(https?:\/\/)?(([0-9a-z_!~\*'\(\)\.&=\+\$%-]+:)?[0-9a-z_!~\*'\(\)\.&=\+\$%-]+@)?(([0-9]{1,3}\.){3}[0-9]{1,3}|([0-9a-z_!~\*'\(\)-]+\.)*([0-9a-z_!~\*'\(\)-]+\.)*(([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z])(:[0-9]{1,4})?((\/?)|(\/[0-9A-Za-z_!~\*'\(\)\.;\?:@&=\+\$,%#-]+)+\/?)$/) >= 0;
}

function DHFEncodeURL(url) {
    return encodeURI(url);
}

function DHFDecodeURL(url) {
    return decodeURI(url);
}

function takeYear(theDate) {
    var x = theDate.getYear(),
        y = x % 100;

    y += (y < 38) ? 2000 : 1900;
    
    return y;
}

function DHFCalcDateChanged(selectFldID, dateFldID) {
    var sel, val, oneDay, nd, y, y2,
        el = document.getElementById(selectFldID);
    
    if (el) {
        sel = el.selectedIndex;
        
        if (sel > 0) {
            val = el.options[sel].value;
            oneDay = 24 * 60 * 60 * 1000;
            nd = new Date(new Date().getTime() + val * oneDay);
            y = takeYear(nd);
            y2 = String(y).substring(String(y).length, String(y).length - 2);
            
            switch (dateinputformat) {
                case 'ddmmyy':
                    DHFSetFieldValue(dateFldID, DHFMakeTwoDigits(nd.getDate()) + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + y2);
                    break;
                case 'ddmmyyyy':
                    DHFSetFieldValue(dateFldID, DHFMakeTwoDigits(nd.getDate()) + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + y);
                    break;
                case 'mmddyy':
                    DHFSetFieldValue(dateFldID, (DHFMakeTwoDigits(nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()) + datesep + y2);
                    break;
                case 'mmddyyyy':
                    DHFSetFieldValue(dateFldID, DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()) + datesep + y);
                    break;
                case 'yymmdd':
                    DHFSetFieldValue(dateFldID, y2 + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()));
                    break;
                case 'yyyymmdd':
                    DHFSetFieldValue(dateFldID, y + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()));
                    break;
                default:
                    DHFSetFieldValue(dateFldID, DHFMakeTwoDigits(nd.getDate()) + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + y);
                    break;
            }
            
            el.selectedIndex = 0;
        }
    }
}

function DHFOpenBlankWindow(url) {
    var win = window.open(url, "", "top=30,left=10,location=yes,menubar=yes,resizable=yes,scrollbars=yes,status=yes,toolbar=yes");
    
    if (win) {
        win.focus();
    }
    
    return win;
}

function DHFFormatDecimal(x, n) {
    var t, s = Math.round(x * Math.pow(10, n)) + '';
    
    while (s.length <= n) {
        s = '0' + s;
    }
    
    if (n > 0) {
        return s.substr(0, t = (s.length - n)) + '.' + s.substr(t, n);
    } else {
        return s.substr(0, t = (s.length - n));
    }
}

function DHFFormatContactName(id, firstname, lastname) {
    var s = firstname || '';
    
    if (lastname && lastname.length) {
        if (s.length) {
            s += ' ';
        }
        
        s += lastname;
    }
    
    if (s.length) {
        return s;
    }
    
    return strobj_contactid.SubstStrBy(id);
}

function DHFFormatUserName(id, firstname, lastname, login) {
    var s = firstname || '';
    
    if (lastname && lastname.length) {
        if (s.length) {
            s += ' ';
        }
        
        s += lastname;
    }
    
    if (login && login.length) {
        if (s.length) {
            s += ' ';
        }
        
        s += '(' + login + ')';
    }
    
    if (s.length) {
        return s;
    }
    
    return strobj_userid.SubstStrBy(id);
}

function DHFMoveDiv(id, x, y) {
    var el = document.getElementById(id);
    
    if (el) {
        el.style.left = x;
        el.style.top = y;
    }
}

function DHFSetDivWidth(id, w) {
    var el = document.getElementById(id);
    
    if (w < 0) {
        w = 0;
    }
    
    if (el) {
        el.style.width = w + 'px';
    }
}

function DHFSetDivHeight(id, h) {
    var el = document.getElementById(id);

    if (h < 0) {
        h = 0;
    }
    
    if (el) {
        el.style.height = h + 'px';
    }
}

function DHFGetDivWidth(id) {
    var el = document.getElementById(id);
    
    if (el) {
        return el.offsetWidth;
    }
    
    return 0;
}

function DHFGetDivHeight(id) {
    var el = document.getElementById(id);
    
    if (el) {
        return el.offsetHeight;
    }
    
    return 0;
}

function DHFSetElementClass(id, cls) {
    var el = document.getElementById(id);
    
    if (el) {
        return (el.className = cls);
    }
    
    return undefined;
}

function DHFGetWindowInnerWidth() {
    if (window.innerWidth) {
        return window.innerWidth;
    }
    
    if (document.documentElement && document.documentElement.clientWidth) {
        return document.documentElement.clientWidth;
    }
    
    return document.body.offsetWidth;
}

function DHFGetWindowInnerHeight() {
    if (window.innerHeight) {
        return window.innerHeight;
    }
    
    if (document.documentElement && document.documentElement.clientHeight) {
        return document.documentElement.clientHeight;
    }
    
    return document.body.offsetHeight;
}

function DHFSetWindowInnerWidth(w){
    if (window.innerWidth) {
        window.innerWidth = w;
    } else if (window.resizeBy) {
        window.resizeBy(w - DHFGetWindowInnerWidth(), 0);
    }
}

function DHFSetWindowInnerHeight(h){
    if (window.innerHeight) {
        window.innerHeight = h;
    } else if (window.resizeBy) {
        window.resizeBy(0, h - DHFGetWindowInnerHeight());
    }
}

function DHFGetWindowInnerDimensions() {
    return {
        "width": DHFGetWindowInnerWidth(),
        "height": DHFGetWindowInnerHeight()
    };
}
    
function DHFSetWindowInnerDimensions(w, h) {
    if (window.innerWidth) {
        window.innerWidth = w;
        window.innerHeight = h;
    } else if (window.resizeBy) {
        window.resizeBy(w - DHFGetWindowInnerWidth(), h - DHFGetWindowInnerHeight());
    }
}

function DHFEscapeRegExpString(s) {
    return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
}

function DHFSetSort(f, s) {
    var el = document.forms['sortform_' + f];
    
    DHFSetFieldValue('newsort_' + f, s);
    
    if (el) {
        el.submit();
    }
}

function DHFStringBuilder() {
    this.strings = [];
}

DHFStringBuilder.prototype.Append = function(value) {
    var v;
    
    if (value!==undefined && value!==null) {
        v = value + '';
        if (v.length) {
            this.strings.push(value);
        }
    }
};

DHFStringBuilder.prototype.Clear = function() {
    this.strings = [];
};

DHFStringBuilder.prototype.ToString = function() {
    return this.strings.join('');
};

DHFStringBuilder.prototype.IsEmpty = function() {
    return !this.strings.length;
};

function DHFIsInteger(s) {
    var c, i;
    
    for (i = 0; i < s.length; i++) {
        // Check that current character is number.
        c = s.charAt(i);
        
        if (((c < '0') || (c > '9'))) {
            return false;
        }
    }

    return true;
}

function DHFIsValidFilePath(path) {
    if (path && path.constructor === String && path.length > 0) {
        if (navigator.userAgent.indexOf("Firefox/3") > -1) {
            return true; // Firefox 3+ will always contain a valid filename
        } else {
            return path.match(/^(([a-zA-Z]:|\\)\\)?(((\.)|(\.\.)|([^\\/:\*\?"\|<>\. ](([^\\/:\*\?"\|<>\. ])|([^\\/:\*\?"\|<>]*[^\\/:\*\?"\|<>\. ]))?))\\)*[^\\/:\*\?"\|<>\. ](([^\\/:\*\?"\|<>\. ])|([^\\/:\*\?"\|<>]*[^\\/:\*\?"\|<>\. ]))?$/);
        }
    } else {
        return false; // No filename was provided or was not a string
    }
}

function DHFStripCharsInBag(s, bag) {
    var i, c,
        returnString = '';
    
    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.
    for (i = 0; i < s.length; i++) {
        c = s.charAt(i);
        
        if (bag.indexOf(c) == -1) {
            returnString += c;
        }
    }
    
    return returnString;
}

function DHFDaysInFebruary(year) {
    // February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (((year % 4 == 0) && ((!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28);
}

function DHFDaysArray(n) {
    var i,
        dayarray = new Array(n);
    
    for (i = 1; i <= n; i++) {
        dayarray[i] = 31;
        if (i == 4 || i == 6 || i == 9 || i == 11) {
            dayarray[i] = 30;
        }
        if (i == 2) {
            this[i] = 29;
        }
    }
    
    return dayarray;
}

function DHFCharCount(strtocount, chartocount) {
    var i,
        m = chartocount,
        s = strtocount,
        c = 0; // count
        
    for (i = 0; i < s.length; i++) {
        if (m == s.substr(i, m.length)) {
            c++;
        }
    }
    
    return c;
}

// This function replaces is used for date validation. If there is an error in the date sent to the function
// an error code is returned. When validating the date set returntype to datecheck, jsdateobj or jsdatestring
// depending what you would like to be returned:
//
// datecheck        - Simple check returns a value as listed below
// jsdateobj        - returns a Javascript date object
// jsdatestring        - returns a Javascript date string (Used by DHFGenVarString)
//
// other return values are as follows:
// 
// null                - Error when creating date object (object creation mode only) - this should never happen.
// true                - validated successfully
// -1                - Date has wrong number of separators or can't be read
// -2                - Invalid Month
// -3                - Invalid Day
// -4                - Invalid Year
// -5                - Invalid Date
//
function DHFValidateGetJSDate(dtStr, returntype) {
    var i, month, day, year, year2, strDay, strMonth, strYear, strYr,
        usedsep = '';

    if (null == dtStr || dtStr.length == 0 && returntype != 'jsdateobj' && returntype != 'jsdatestring') 
        return true;
    
    if (DHFCharCount(dtStr, '.')) {
        usedsep = '.';
    } else if (DHFCharCount(dtStr, '/')) {
        usedsep = '/';
    } else if (DHFCharCount(dtStr, '-')) {
        usedsep = '-';
    } else {
        usedsep = '.';
    }
    
    var daysInMonth = DHFDaysArray(12);
    var pos1 = dtStr.indexOf(usedsep);
    var pos2 = dtStr.indexOf(usedsep, pos1 + 1);
    
    switch (dateinputformat) {
        case 'ddmmyy':
        case 'ddmmyyyy':
            strDay = dtStr.substring(0, pos1);
            strMonth = dtStr.substring(pos1 + 1, pos2);
            strYear = dtStr.substring(pos2 + 1);
            break;
        case 'mmddyy':
        case 'mmddyyyy':
            strMonth = dtStr.substring(0, pos1);
            strDay = dtStr.substring(pos1 + 1, pos2);
            strYear = dtStr.substring(pos2 + 1);
            break;
        case 'yymmdd':
        case 'yyyymmdd':
            strYear = dtStr.substring(0, pos1);
            strMonth = dtStr.substring(pos1 + 1, pos2);
            strDay = dtStr.substring(pos2 + 1);
            break;
        default:
            strDay = dtStr.substring(0, pos1);
            strMonth = dtStr.substring(pos1 + 1, pos2);
            strYear = dtStr.substring(pos2 + 1);
            break;
    }
    
    strYr = strYear;
    
    if (strDay.charAt(0) == '0' && strDay.length > 1) {
        strDay = strDay.substring(1);
    }
    if (strMonth.charAt(0) == '0' && strMonth.length > 1) {
        strMonth = strMonth.substring(1);
    }
    if (strYear.length == 2 && strYear < 50) {
        strYear = '20' + strYear;
    }
    if (strYear.length == 2 && strYear >= 50) {
        strYear = '19' + strYear;
    }
    
    for (i = 1; i <= 3; i++) {
        if (strYr.charAt(0) == '0' && strYr.length > 1) {
            strYr = strYr.substring(1);
        }
    }
    
    month = parseInt(strMonth, 10);
    day = parseInt(strDay, 10);
    year = parseInt(strYr, 10);
    year2 = parseInt(strYear, 10);
    
    if (returntype != 'jsdateobj') {
        if (pos1 == -1 || pos2 == -1) {
            return -1;
        }
        if (strMonth.length < 1 || month < 1 || month > 12) {
            return -2;
        }
        if (strDay.length < 1 || day < 1 || day > 31 || (month == 2 && day > DHFDaysInFebruary(year)) || day > daysInMonth[month]) {
            return -3;
        }
        if ((strYear.length != 2 && strYear.length != 4) || year2 == 0) {
            return -4;
        }
        if (dtStr.indexOf(usedsep, pos2 + 1) != -1 || DHFIsInteger(DHFStripCharsInBag(dtStr, usedsep)) == false) {
            return -5;
        }
    }
    
    switch (returntype) {
        case 'jsdatestring':
            return strDay + '.' + strMonth + '.' + strYear;
            break;
        case 'jsdateobj':
            var dt = DHFNewDate(strYear, strMonth - 1, strDay);
            if (dt.getUTCFullYear() != strYear || dt.getUTCMonth() != strMonth - 1 || dt.getUTCDate() != strDay) {
                return null;
            } else {
                return dt;
            }
            break;
        case 'datecheck':
            return true;
        default:
            break;
    }
    
    return null;
}

function DHFStdDateStrToReg(dtStr) {
    if (!dtStr || dtStr.constructor !== String) 
        return '';
    
    var usedsep = '';
    
    if (DHFCharCount(dtStr, '.')) {
        usedsep = '.';
    } else if (DHFCharCount(dtStr, '/')) {
        usedsep = '/';
    } else if (DHFCharCount(dtStr, '-')) {
        usedsep = '-';
    } else {
        usedsep = '.';
    }
    
    var daysInMonth = DHFDaysArray(12);
    var pos1 = dtStr.indexOf(usedsep);
    var pos2 = dtStr.indexOf(usedsep, pos1 + 1);
    
    var strDay = dtStr.substring(0, pos1);
    var strMonth = dtStr.substring(pos1 + 1, pos2);
    var strYear = dtStr.substring(pos2 + 1);
    
    switch (dateinputformat) {
        case 'ddmmyy':
            return DHFMakeTwoDigits(strDay) + datesep + DHFMakeTwoDigits(strMonth) + datesep + strYear;
            break;
        case 'ddmmyyyy':
            return DHFMakeTwoDigits(strDay) + datesep + DHFMakeTwoDigits(strMonth) + datesep + strYear;
            break;
        case 'mmddyy':
            return DHFMakeTwoDigits(strMonth) + datesep + DHFMakeTwoDigits(strDay) + datesep + strYear;
            break;
        case 'mmddyyyy':
            return DHFMakeTwoDigits(strMonth) + datesep + DHFMakeTwoDigits(strDay) + datesep + strYear;
            break;
        case 'yymmdd':
            return strYear + datesep + DHFMakeTwoDigits(strMonth) + datesep + DHFMakeTwoDigits(strDay);
            break;
        case 'yyyymmdd':
            return strYear + datesep + DHFMakeTwoDigits(strMonth) + datesep + DHFMakeTwoDigits(strDay);
        default:
            break;
    }
    
    return '';
}

/* Useage:
 * var myDate = new DHFDate().setDateFromStdString('07.08.73');
 *
 * Note:
 * Use toElementHTML(element) and toElementText(element) to populate form fields ...
 * this ensures that they are populated by the regional date.
 *
 * Public methods:
 *    compareTo(DHFOrJSDate)
 *    setDateFromStdString(stdDateString)
 *    setDateFromRegString(regDateString)
 *    setDateFromJSDate(JSDateObj)
 *    setDateFromUnixTime(unixSeconds)
 *    setDateToToday()
 *    setDateToNow()
 *    setHours(hour,min,sec,millisec)
 *    addWeeks(numWeeks)
 *    addDays(numDays)
 *    addHours(numHours)
 *    addMinutes(numMinutes)
 *    addSeconds(numSeconds)
 *    addTimeFromString(timeString)
 *    clear
 *    subtractWeeks(numWeeks)
 *    subtractDays(numDays)
 *    subtractHours(numHours)
 *    subtractMinutes(numMinutes)
 *    subtractSeconds(numSeconds)
 *    getRegDateAsString()
 *    getStdDateAsString()
 *    getDay()
 *    getUTCDate()
 *    getUTCMonth()
 *    getUTCHours()
 *    getUTCMinutes()
 *    getUTCSeconds()
 *    getJSDate()
 *    getTime()
 *    getTimeString()
 *    getClone()
 *    isEmpty()
 *    isSameDayAs(DHFOrJSDate)
 *    toElementHTML(element)
 *    toElementText(element)
 *    toFieldValue(element)
 *    fromFieldValue(element)
 *    isValid()
 *    getErrorCode()
 *    getWeekday()
 *    getWeekOfYear() - returns an array. index 0: week number, index 1: year
 *    toString() and valueOf() - an internal hack to get < and > operators working
 *
 * Error Codes:
 * -1                - Date has wrong number of separators
 * -2                - Invalid Month
 * -3                - Invalid Day
 * -4                - Invalid Year
 * -5                - Invalid Date
 */
function DHFDate() {
    // Private methods
    function setErrorCode(errCode, that) {
        that.errorCode = errCode;
        that.stdDate = '';
        that.regDate = '';
        that.JSDate = null;
    }

    function refreshDate(dateStringOrObj, dateType, that) {
        var dt,
            month = '',
            day = '',
            year = '',
            strDay = '',
            strMonth = '',
            strYear = '',
            strYr = '',
            tmp = '',
            daysInMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
            dateArray = [],
            localdateinputformat = dateinputformat,
            regdateinputformat = dateinputformat,
            timeToAdd,
            daysToAdd,
            addUnits;
        
        if (dateType === 'stdDate' || dateType === 'regDate' || dateType === 'JSDate') {
            that.errorCode = null;
        }

        if (dateType.indexOf('.') > 0) {
            tmp = dateType.split('.');
            dateType = tmp[0];
            addUnits = tmp[1];
        }

        if (dateType === 'AddTime') {
            dateType = 'JSDate';
            timeToAdd = dateStringOrObj;
        }

        if (dateType === 'AddDays') {
            dateType = 'JSDate';
            daysToAdd = dateStringOrObj;
        }

        if (dateType !== 'JSDate') {
            dateArray = dateStringOrObj.split(/[\.,;:\s\/\\\-#]/);

            if (dateType === 'stdDate') {
                localdateinputformat = 'ddmmyyyy';
            }

            if (dateArray.length === 3) {
                switch (localdateinputformat) {
                case 'ddmmyy':
                case 'ddmmyyyy':
                    strDay = dateArray[0];
                    strMonth = dateArray[1];
                    strYear = dateArray[2];
                    break;
                case 'mmddyy':
                case 'mmddyyyy':
                    strDay = dateArray[1];
                    strMonth = dateArray[0];
                    strYear = dateArray[2];
                    break;
                case 'yymmdd':
                case 'yyyymmdd':
                    strDay = dateArray[2];
                    strMonth = dateArray[1];
                    strYear = dateArray[0];
                    break;
                default:
                    break;
                }

                if (strYear.length === 2) {
                    strYear = (strYear < 50 ? '20': '19') + strYear;
                }

                strYr = strYear;

                day = parseInt(strDay, 10);
                month = parseInt(strMonth, 10);
                year = parseInt(strYr, 10);

                if (!DHFIsInteger(strMonth) || month < 1 || month > 12) {
                    setErrorCode(-2, that);
                } else if (!DHFIsInteger(strDay) || day < 1 || day > 31 || (month === 2 && day > DHFDaysInFebruary(year)) || day > daysInMonth[month-1]) {
                    setErrorCode(-3, that);
                } else if (!DHFIsInteger(strYear) || (strYear.length !== 2 && strYear.length !== 4) || year === 0) {
                    setErrorCode(-4, that);
                }
            } else {
                setErrorCode(-1, that);
            }
        } else {
            if ((daysToAdd !== undefined)||(timeToAdd !== undefined)) {
                if (daysToAdd !== undefined) {
                    that.JSDate.setDate(that.JSDate.getDate() + daysToAdd);}
                if (timeToAdd !== undefined) {
                    switch (addUnits) {
                    case 'hours':
                        that.JSDate.setHours(that.JSDate.getHours() + timeToAdd);
                        break;
                    case 'minutes':
                        that.JSDate.setMinutes(that.JSDate.getMinutes() + timeToAdd);
                        break;
                    case 'seconds':
                        that.JSDate.setSeconds(that.JSDate.getSeconds() + timeToAdd);
                        break;
                    default:
                        break;
                    }
                }
                dateStringOrObj = that.JSDate;
                strDay = dateStringOrObj.getUTCDate();
                strMonth = dateStringOrObj.getUTCMonth() + 1;
                strYear = dateStringOrObj.getUTCFullYear();
            } else {
                if (dateStringOrObj.constructor !== Date) {
                    setErrorCode(-5, that);
                } else {
                    strDay = dateStringOrObj.getUTCDate();
                    strMonth = dateStringOrObj.getUTCMonth() + 1;
                    strYear = dateStringOrObj.getUTCFullYear();
                }
            }
        }

        if (that.errorCode === null) {
            that.stdDate = strDay + '.' + strMonth + '.' + strYear;

            switch (regdateinputformat) {
            case 'ddmmyy':
            case 'ddmmyyyy':
                that.regDate = DHFMakeTwoDigits(strDay) + datesep + DHFMakeTwoDigits(strMonth) + datesep + strYear;
                break;
            case 'mmddyy':
            case 'mmddyyyy':
                that.regDate = DHFMakeTwoDigits(strMonth) + datesep + DHFMakeTwoDigits(strDay) + datesep + strYear;
                break;
            case 'yymmdd':
            case 'yyyymmdd':
                that.regDate = strYear + datesep + DHFMakeTwoDigits(strMonth) + datesep + DHFMakeTwoDigits(strDay);
                break;
            default:
                break;
            }

            if (dateType !== 'JSDate') {
                dt = DHFNewDate(strYear, strMonth - 1, strDay);
                if (dt.getUTCFullYear() !== parseInt(strYear, 10) || dt.getUTCMonth() !== strMonth - 1 || dt.getUTCDate() !== parseInt(strDay, 10)) {
                    that.stdDate = null;
                } else {
                    that.JSDate = dt;
                }
            } else {
                that.JSDate = dateStringOrObj;
            }
        }
    }

    // Public Variables and Methods
    return {
            constructor: DHFDate,
            regDate: '',
            stdDate: '',
            errorCode: null,
            JSDate: null,
            isDHFDate: true,
        setDateFromStdString: function(stdDateString) {
            if (stdDateString && stdDateString.constructor === String && stdDateString.length > 0) {
                refreshDate(stdDateString, 'stdDate', this);
            } else {
                setErrorCode(null, this);
            }
            return this;
        },
        setDateFromRegString: function(regDateString) {
            if (regDateString && regDateString.constructor === String && regDateString.length > 0) {
                refreshDate(regDateString, 'regDate', this);
            } else {
                setErrorCode(null, this);
            }
            return this;
        },
        setDateFromJSDate: function(JSDateObj) {
            if (JSDateObj && JSDateObj.constructor === Date) {
                if (this.JSDate === null || JSDateObj.getTime() !== this.JSDate.getTime()) {
                    refreshDate(DHFCloneDate(JSDateObj), 'JSDate', this);
                }
            } else {
                setErrorCode(null, this);
            }
            return this;
        },
        setDateToToday: function() {
            var d = new Date();

            d.setHours(0);
            d.setMinutes(0);
            d.setSeconds(0);

            this.setDateFromJSDate(d);
            
            return this;
        },
        setDateToNow: function() {
            this.setDateFromJSDate(new Date());
            
            return this;
        },
        setDateFromUnixTime: function(unixSeconds) {
            if (unixSeconds.constructor === Number && isFinite(unixSeconds)) {
                refreshDate(new Date(unixSeconds), 'JSDate', this);
            }
            return this;
        },
        setHours: function(hour,min,sec,millisec) {
            var jsd = DHFCloneDate(this.JSDate);
            
            if(hour) {
                jsd.setHours(hour);
            }
            
            if(min) {
                jsd.setMinutes(min);
            }
            
            if(sec) {
                jsd.setSeconds(sec);
            }
            
            if(millisec) {
                jsd.setMilliseconds(millisec);
            }
            
            refreshDate(jsd, 'JSDate', this);
        },
        compareTo: function(DHFOrJSDate) {
            compareDateUT = DHFOrJSDate.getTime();
            currDateUT = this.JSDate?this.JSDate.getTime():0;
            
            if(currDateUT < compareDateUT) {
                return -1;
            } else if(currDateUT > compareDateUT) {
                return 1;
            } else {
                return 0;
            }
        },
        addWeeks: function(numWeeks) {
            if (this.isValid() && numWeeks.constructor === Number && isFinite(numWeeks)) {
                refreshDate(numWeeks * 7, 'AddDays', this);
            }
            return this;
        },
        addDays: function(numDays) {
            if (this.isValid() && numDays.constructor === Number && isFinite(numDays)) {
                refreshDate(numDays, 'AddDays', this);
            }
            return this;
        },
        addHours: function(numHours) {
            if (this.isValid() && numHours.constructor === Number && isFinite(numHours)) {
                refreshDate(numHours, 'AddTime.hours', this);
            }
            return this;
        },
        addMinutes: function(numMinutes) {
            if (this.isValid() && numMinutes.constructor === Number && isFinite(numMinutes)) {
                refreshDate(numMinutes, 'AddTime.minutes', this);
            }
            return this;
        },
        addSeconds: function(numSeconds) {
            if (this.isValid() && numSeconds.constructor === Number && isFinite(numSeconds)) {
                refreshDate(numSeconds, 'AddTime.seconds', this);
            }
            return this;
        },
        addTimeFromString: function(timeString) {
            var i, timeInt;
            
            timeString = timeString.replace(/^\s*/, '').replace(/\s*$/, '');

            if(timeString && timeString.length > 0) {
                timeString = timeString.split(':');
                
                if (!this.JSDate) {
                    this.JSDate = new Date();
                }
                
                for(i = 0; i < timeString.length; i++) {
                    timeNum = parseInt(timeString[i], 10);

                    switch(i) {
                        case 0:
                            this.JSDate.setHours(timeNum + this.JSDate.getHours());
                            break;
                        case 1:
                            this.JSDate.setMinutes(timeNum + this.JSDate.getMinutes());
                            break;
                        case 2:
                            this.JSDate.setSeconds(timeNum + this.JSDate.getSeconds());
                            break;
                        case 3:
                            this.JSDate.setMilliseconds(timeNum + this.JSDate.getMilliseconds());
                            break;
                    }
                }
                
                refreshDate(DHFCloneDate(this.JSDate), 'JSDate', this);
            }
            return this;
        },
        subtractWeeks: function(numWeeks) {
            this.addDays(-numWeeks);
            return this;
        },
        subtractDays: function(numDays) {
            this.addDays(-numDays);
            return this;
        },
        subtractHours: function(numHours) {
            this.addHours(-numHours);
            return this;
        },
        subtractMinutes: function(numMinutes) {
            this.addMinutes(-numMinutes);
            return this;
        },
        subtractSeconds: function(numSeconds) {
            this.addSeconds(-numSeconds);
            return this;
        },
        getRegDateAsString: function() {
            return this.regDate;
        },
        getStdDateAsString: function() {
            return this.stdDate;
        },
        getDay: function() {
            if(this.JSDate) {
                return this.JSDate.getDay();
            }
        },
        getUTCDate: function() {
            if(this.JSDate) {
                return this.JSDate.getUTCDate();
            }
        },
        getUTCMonth: function() {
            if(this.JSDate) {
                return this.JSDate.getUTCMonth();
            }
        },
        getUTCHours: function() {
            if(this.JSDate) {
                return this.JSDate.getUTCHours();
            }
        },
        getUTCMinutes: function() {
            if(this.JSDate) {
                return this.JSDate.getUTCMinutes();
            }
        },
        getUTCSeconds: function() {
            if(this.JSDate) {
                return this.JSDate.getUTCSeconds();
            }
        },
        getUTCFullYear: function() {
            if(this.JSDate) {
                return this.JSDate.getUTCFullYear();
            }
        },
        getClone: function() {
            if(this.JSDate) {
                return new DHFDate().setDateFromJSDate(this.JSDate);
            } else {
                return new DHFDate();
            }
        },
        getJSDate: function() {
            if(this.JSDate) {
                return new Date(this.JSDate.getTime());
            } else {
                return null;
            }
        },
        getWeekday: function() {
            if (this.JSDate) {
                return wdnames[this.JSDate.getUTCDay()];
            } else {
                return '';
            }
        },
        getTime: function() {
            if (this.JSDate) {
                return this.JSDate.getTime();
            } else {
                return null;
            }
        },
        getTimeString: function() {
            var m,
                dt = this.JSDate;
            
            if (dt) {
                m = dt.getUTCMinutes();
                
                if (m < 10) {
                    m = '0' + m;
                }
                
                return dt.getUTCHours() + ':' + m;
            } else {
                return '';
            }
        },
        isSameDayAs: function(DHFOrJSDate) {
            var d1,
                d2 = this.JSDate;

            if (!d2) {
                return false;
            }
            
            if(DHFOrJSDate.isDHFDate) {
                d1 = DHFOrJSDate.getJSDate();
            }

            return d1.getUTCFullYear()==d2.getUTCFullYear() && d1.getUTCMonth()==d2.getUTCMonth() && d1.getUTCDate()==d2.getUTCDate();
        },
        toElementHTML: function(elementid) {
            if (this.isValid()) {
                DHFSetElementHTML(elementid, this.regDate, false);
            } else {
                DHFSetElementHTML(elementid, '', false);
            }
        },
        toElementText: function(elementid) {
            if (this.isValid()) {
                DHFSetElementText(elementid, this.regDate, false);
            } else {
                DHFSetElementText(elementid, '', false);
            }
        },
        toFieldValue: function(elementid) {
            if (this.isValid()) {
                DHFSetFieldValue(elementid, this.regDate);
            } else {
                DHFSetFieldValue(elementid, '');
            }
        },
        fromFieldValue: function(elementid) {
            this.setDateFromRegString(DHFGetFieldValue(elementid));
            return this;
        },
        isValid: function() {
            return this.errorCode === null && this.regDate.length > 0;
        },
        isEmpty: function() {
            return this.regDate.length === 0;
        },
        getErrorCode: function() {
            return this.errorCode;
        },
        clear: function() {
            setErrorCode(null, this);
        },
        toString: function() {
            return this.getTime()+'';
        },
        toJSON: function() {
            var dt = this.JSDate;
            
            if(dt) {
                return dt.getUTCFullYear() + '-' +
                    DHFMakeTwoDigits(dt.getUTCMonth() + 1) + '-' +
                    DHFMakeTwoDigits(dt.getUTCDate())      + 'T' +
                    DHFMakeTwoDigits(dt.getUTCHours())     + ':' +
                    DHFMakeTwoDigits(dt.getUTCMinutes())   + ':' +
                    DHFMakeTwoDigits(dt.getUTCSeconds())   + 'Z';
            } else {
                return '';
            }
        },
        valueOf: function() {
            return this.getTime();
        },
        getWeekOfYear: function() {
            var d0, dow, delta,
                a = [],
                dt = this.JSDate;
            
            if (!dt) {
                return 0;
            }
            
            if (kFirstWeekJan1) {
                dow = dt.getUTCDay();
                
                if (!kWeekStartsOnSunday) {
                    dow = dow ? (dow - 1) : 6;
                }
                
                d0 = new Date(dt.getTime() + (7 - dow) * kSecsPerDay * 1000);
                
                if (d0.getUTCFullYear() > dt.getUTCFullYear()) {
                    a[0] = 1;
                } else {
                    d0 = DHFNewDate(dt.getUTCFullYear(), 0, 1);
                    dow = d0.getDay();
                    
                    if (!kWeekStartsOnSunday) {
                        dow = dow ? (dow - 1) : 6;
                    }
                    
                    a[0] = Math.floor((dt.getTime() - d0.getTime() + (dow + 1) * kSecsPerDay * 1000) / (kSecsPerWeek * 1000)) + 1;
                }
                
                a[1] = d0.getUTCFullYear();
            } else {
                // first week is the one that contains Jan 4
                d0 = DHFNewDate(dt.getUTCFullYear(), 0, 4);
                dow = d0.getUTCDay();
                
                if (!kWeekStartsOnSunday) {
                    dow = dow ? (dow - 1) : 6;
                }
                
                d0 = new Date(d0.getTime() - dow * kSecsPerDay * 1000);
                
                delta = dt.getTime() - d0.getTime();
                a[1] = dt.getUTCFullYear();
                
                if (delta < 0) {
                    d0 = DHFNewDate(dt.getUTCFullYear() - 1, 0, 4);
                    dow = d0.getUTCDay();
                    
                    if (!kWeekStartsOnSunday) {
                        dow = dow ? (dow - 1) : 6;
                    }
                    
                    d0 = new Date(d0.getTime() - dow * kSecsPerDay * 1000);
                    a[0] = Math.floor((dt.getTime() - d0.getTime()) / (kSecsPerWeek * 1000)) + 1;
                    a[1]--;
                } else {
                    a[0] = Math.floor(delta / (kSecsPerWeek * 1000)) + 1;
                    if (a[0] >= 52) {
                        d0 = DHFNewDate(dt.getUTCFullYear() + 1, 0, 4);
                        dow = d0.getUTCDay();
                        
                        if (!kWeekStartsOnSunday) {
                            dow = dow ? (dow - 1) : 6;
                        }
                        
                        d0 = new Date(d0.getTime() - dow * kSecsPerDay * 1000);
                        delta = dt.getTime() - d0.getTime();
                        
                        if (delta >= 0) {
                            a[0] = Math.floor(delta / (kSecsPerWeek * 1000)) + 1;
                            a[1]++;
                        }
                    }
                }
            }
            
            return a;
        }
    };
}

function DHFCloneDate(dt) {
    return new Date(dt.getTime());
}

function DHFAddDaysToJSDate(jsdate, daystoadd) {
    jsdate.setDate(jsdate.getDate() + daystoadd);
}

function DHFIsArray(arr) {
    return arr && arr.splice && arr.push;
}

// Adds the days from a dropdown to the contents of a start date element and outputs the result to an end date element.
// The days value should be given in hours.
// 
function DHFAddDaysFromDropdown(elDaysDropdown, elStartDate, elEndDate) {
    var oneMinute, oneHour, el, offset, sel, val, nd, y, y2,
        fd = DHFValidateGetJSDate(DHFGetFieldValue(elStartDate), 'jsdateobj');
    
    if (fd) {
        oneMinute = 60 * 1000;
        oneHour = oneMinute * 60;
        el = document.getElementById(elDaysDropdown);
        offset = fd.getTimezoneOffset();

        fd = new Date(fd.getTime() + offset * oneMinute);
        
        if (el) {
            sel = el.selectedIndex;
            
            if (sel > 0) {
                val = el.options[sel].value.replace(/\\"/g, '');
                nd = new Date(fd.getTime() + val * oneHour - 1);
                y = takeYear(nd);
                y2 = String(y).substring(String(y).length - 2);
                
                switch (dateinputformat) {
                    case 'ddmmyy':
                        DHFSetFieldValue(elEndDate, DHFMakeTwoDigits(nd.getDate()) + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + y2);
                        break;
                    case 'ddmmyyyy':
                        DHFSetFieldValue(elEndDate, DHFMakeTwoDigits(nd.getDate()) + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + y);
                        break;
                    case 'mmddyy':
                        DHFSetFieldValue(elEndDate, (DHFMakeTwoDigits(nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()) + datesep + y2);
                        break;
                    case 'mmddyyyy':
                        DHFSetFieldValue(elEndDate, DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()) + datesep + y);
                        break;
                    case 'yymmdd':
                        DHFSetFieldValue(elEndDate, y2 + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()));
                        break;
                    case 'yyyymmdd':
                        DHFSetFieldValue(elEndDate, y + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + DHFMakeTwoDigits(nd.getDate()));
                        break;
                    default:
                        DHFSetFieldValue(elEndDate, DHFMakeTwoDigits(nd.getDate()) + datesep + DHFMakeTwoDigits((nd.getMonth() + 1)) + datesep + y);
                        break;
                }
            }
        } else {
            DHFSetFieldValue(elEndDate, '');
        }
    }
}

// Pads numbers with zeros to make 2 digits
// e.g. 6 becomes 06
//
function DHFMakeTwoDigits(inValue) {
    if (DHFIsInteger(inValue)) {
        var numVal = parseInt(inValue, 10);
        
        if (numVal < 10) {
            return '0' + numVal;
        } else {
            return numVal;
        }
    } else {
        return -1;
    }
}

function DHFClone(obj) {
    var c, i, j, prop, propLen, match,
        constructorName = '',
        explore = true;
    
    if (obj === null) {
        return null;
    } else if (obj === undefined) {
        return undefined;
    }
    
    constructorName = DHFGetConstructorNameAsString(obj);
    
    switch (constructorName) {
        case 'Number':
        case 'Boolean':
        case 'String':
            c = obj;
            explore = false;
            break;
            
        case 'Date':
            c = new Date(obj.getTime());
            explore = false;
            break;
    }
    
    if (explore && obj.getClone) {
        c = obj.getClone();
        explore = false;
    }
    
    if (explore) {
        if (obj.splice && obj.push) {
            c = [];
        } else {
            c = {};
        }
        
        for (i in obj) {
            prop = obj[i];
            constructorName = DHFGetConstructorNameAsString(prop);
            
            switch (constructorName) {
                case 'Number':
                case 'Boolean':
                case 'String':
                    c[i] = prop;
                    break;
                    
                case 'Array':
                    c[i] = [];

                    for (j = 0, propLen = prop.length; j < propLen; j++) {
                        c[i].push(DHFClone(prop[j]));
                    }
                    break;
                    
                default:
                    if (prop.getClone) {
                        c[i] = prop.getClone();
                    } else {
                        if (constructorName.length > 0) {
                            c[i] = new window[constructorName];
                        } else {
                            c[i] = {};
                        }
                        
                        for (j in prop) {
                            if (DHFGetConstructorNameAsString(prop[j]) !== 'Function') {
                                c[i][j] = DHFClone(prop[j]);
                            }
                        }
                    }
                    break;
            }
        }
    }

    return c;
}

function DHFGetConstructorNameAsString(obj) {
    var match,
        constructorName = '';
    
    if(obj !== null && obj !== undefined) {
        match = DHFGetConstructorNameAsString.constructorNameRegex.exec(obj.constructor.toString());
        
        if (match) {
            constructorName = match[1];
        }
    }

    return constructorName;
}
DHFGetConstructorNameAsString.constructorNameRegex = /function\s+(\w+)\b/;
    
function DHFCloneArray(arr) {
    var i, arrLen,
        clone = [];
    
    if (arr) {
        arrLen = arr.length;
        
        for (i = 0; i < arrLen; i++) {
            clone[i] = arr[i];
        }
    }
    return clone;
}

var Drag = {
    obj: null,

    // The initalization function for the drag object
    // dragHandle = The element to act as the drag handle
    // divToDrag = The element to be dragged, if not specified, 
    //               the handle will be the element dragged.
    // minX, maxX, minY, maxY = The min and max coordinates allowed for the element
    // bSwapHorzRef = Toggle the horizontal coordinate system
    // bSwapVertRef = Toggle the vertical coordinate system
    // fxMapper, fyMapper =  Functions for mapping x and y coordinates to others
    init: function(dragHandle, divToDrag, minX, maxX, minY, maxY, bSwapHorzRef, bSwapVertRef, fXMapper, fYMapper, onDragStart, onDragEnd) {
        var o=document.getElementById(dragHandle),
            oRoot=document.getElementById(divToDrag);

        o.onmousedown = Drag.start;
        o.hmode = bSwapHorzRef ? false : true ;
        o.vmode = bSwapVertRef ? false : true ;
        o.root = oRoot && oRoot != null ? oRoot : o ;
        
        if (o.hmode && isNaN(parseInt(o.root.style.left, 10))) {
            o.root.style.left = "0px";
        }
        
        if (o.vmode && isNaN(parseInt(o.root.style.top, 10))) {
            o.root.style.top = "0px";
        }
        
        if (!o.hmode && isNaN(parseInt(o.root.style.right, 10))) {
            o.root.style.right = "0px";
        }
        
        if (!o.vmode && isNaN(parseInt(o.root.style.bottom, 10))) {
            o.root.style.bottom = "0px";
        }
        
        o.minX = minX !== undefined ? minX : null;
        o.minY = minY !== undefined ? minY : null;
        o.maxX = maxX !== undefined ? maxX : null;
        o.maxY = maxY !== undefined ? maxY : null;
        o.xMapper = fXMapper ? fXMapper : null;
        o.yMapper = fYMapper ? fYMapper : null;
        o.root.onDragStart = onDragStart || new Function();
        o.root.onDragEnd  = onDragEnd || new Function();
        o.root.onDrag = new Function();
    },

    start: function(e) {
        var o, x, y;
        
        o = Drag.obj = this;
        e = Drag.fixE(e);
        y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom,10);
        x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,10);
        o.root.onDragStart(x, y);
        o.lastMouseX = e.clientX;
        o.lastMouseY = e.clientY;
        
        if (o.hmode) {
            if (o.minX != null) {
                o.minMouseX = e.clientX - x + o.minX;
            }
            
            if (o.maxX != null) {
                o.maxMouseX = o.minMouseX + o.maxX - o.minX;
            }
        } else {
            if (o.minX != null) {
                o.maxMouseX = -o.minX + e.clientX + x;
            }
            
            if (o.maxX != null) {
                o.minMouseX = -o.maxX + e.clientX + x;
            }
        }

        if (o.vmode) {
            if (o.minY != null) {
                o.minMouseY = e.clientY - y + o.minY;
            }
            
            if (o.maxY != null) {
                o.maxMouseY = o.minMouseY + o.maxY - o.minY;
            }
        } else {
            if (o.minY != null) {
                o.maxMouseY = -o.minY + e.clientY + y;
            }
            
            if (o.maxY != null) {
                o.minMouseY = -o.maxY + e.clientY + y;
            }
        }

        document.onmousemove = Drag.drag;
        document.onmouseup = Drag.end;

        return false;
    },

    drag: function(e) {
        var o, ex, ey, x, y, nx, ny;
        
        e = Drag.fixE(e);

        o = Drag.obj;
        ey = e.clientY;
        ex = e.clientX;
        y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom,10);
        x = parseInt(o.hmode ? o.root.style.left : o.root.style.right,10);
        
        if (o.minX != null) {
            ex = o.hmode ? Math.max(ex, o.minMouseX) : Math.min(ex, o.maxMouseX);
        }
        
        if (o.maxX != null) {
            ex = o.hmode ? Math.min(ex, o.maxMouseX) : Math.max(ex, o.minMouseX);
        }
        
        if (o.minY != null) {
            ey = o.vmode ? Math.max(ey, o.minMouseY) : Math.min(ey, o.maxMouseY);
        }
        
        if (o.maxY != null) {
            ey = o.vmode ? Math.min(ey, o.maxMouseY) : Math.max(ey, o.minMouseY);
        }

        nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
        ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));

        
        if (o.xMapper) {
            nx = o.xMapper(y);
        } else if (o.yMapper) {
            ny = o.yMapper(x);
        }

        Drag.obj.root.style[o.hmode ? "left" : "right"] = nx + "px";
        Drag.obj.root.style[o.vmode ? "top" : "bottom"] = ny + "px";
        Drag.obj.lastMouseX = ex;
        Drag.obj.lastMouseY = ey;
        Drag.obj.root.onDrag(nx, ny);

        return false;
    },

    end: function() {
        document.onmousemove = null;
        document.onmouseup = null;

        Drag.obj.root.onDragEnd( 
            parseInt(Drag.obj.root.style[Drag.obj.hmode ? "left" : "right"],10), 
            parseInt(Drag.obj.root.style[Drag.obj.vmode ? "top" : "bottom"],10));

        Drag.obj = null;
    },

    fixE: function(e) {
        e = e || window.event;
        
        if (e.layerX === undefined) {
            e.layerX = e.offsetX;
        }

        if (e.layerY === undefined) {
            e.layerY = e.offsetY;
        }

        return e;
    }
};

function DHFShieldContent(percentOpacity, baseColor, elToCover, iframeOrDivID, zindex, useDivNotIframe) {
    var posObj, ifram,
        d = document.body,
        el = document.getElementById(elToCover),
        shieldType = useDivNotIframe ? 'DIV' : 'IFRAME';
    
    iframeOrDivID = iframeOrDivID || '';
    
    zindex = (zindex === undefined ? 2 : zindex)
    
    if (el) {
        posObj = DHFGetElementPositionWidthHeight(elToCover);
    } else {
        posObj = {
            x: 0,
            y: 0,
            width: d.scrollWidth,
            height: d.scrollHeight
        };
    }
    
    ifram = document.createElement(shieldType);
    
    if (shieldType === 'IFRAME') {
        ifram.src = appImageURL + 'spacer.gif';
    }
    
    ifram.frameBorder = '0';
    ifram.style.width = posObj.width + 'px';
    ifram.style.height = (posObj.height) + 'px';
    ifram.style.position = 'absolute';
    ifram.style.left = posObj.x + 'px';
    ifram.style.top = posObj.y + 'px';
    ifram.style.border = 'none';
    ifram.style.backgroundColor = baseColor;
    ifram.style.opacity = percentOpacity / 100;
    ifram.style.filter = 'alpha(opacity=' + percentOpacity + ')';
    ifram.style.zIndex = zindex;
    ifram.unselectable = 'on';
    ifram.onmousedown = 'return false;';
    ifram.id = iframeOrDivID;
    
    d.appendChild(ifram);
    
    return undefined;
}

function DHFRemoveElementByID(elementid) {
    var el = document.getElementById(elementid);
    
    if (el) {
        el.parentNode.removeChild(el);
    }
}

function DHFMakeDivDraggable(divName, handleName, retention) {
    var bod, bodyWidth, bodyHeight, el, maxLeft, maxTop;
    
    retention = retention !== undefined ? retention : 100;
    
    bod = document.body;
    bodyWidth = bod.scrollWidth - 1;
    bodyHeight = bod.scrollHeight;
    el = document.getElementById(divName);
    
    if (el) {
        maxLeft = bodyWidth - el.offsetLeft - el.scrollWidth;
        maxTop = bodyHeight - el.offsetTop - el.scrollHeight;
        
        Drag.init(handleName, divName, -el.offsetLeft - el.scrollWidth + retention, maxLeft + el.scrollWidth - retention, -el.offsetTop, maxTop + el.scrollHeight - retention);
    }
}

function getPageSizeObj() {
    var pageWidth, pageHeight;
    
    if (window.innerHeight && window.scrollMaxY) {
        pageWidth = window.innerWidth + window.scrollMaxX - 17;
        pageHeight = window.innerHeight + window.scrollMaxY;
    } else if (document.body.scrollHeight > document.body.offsetHeight) {
        pageWidth = document.body.scrollWidth;
        pageHeight = document.body.scrollHeight;
    } else {
        pageWidth = document.body.offsetWidth + document.body.offsetLeft;
        pageHeight = document.body.offsetHeight + document.body.offsetTop;
    }
    
    return {
        width: pageWidth,
        height: pageHeight
    };
}

function getScrollOffsetXY() {
    var scrOfX = 0,
        scrOfY = 0;
    
    if (window.pageYOffset !== undefined) {
        //Netscape compliant
        scrOfY = window.pageYOffset;
        scrOfX = window.pageXOffset;
    } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
        //DOM compliant
        scrOfY = document.body.scrollTop;
        scrOfX = document.body.scrollLeft;
    } else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
        //IE6 standards compliant mode
        scrOfY = document.documentElement.scrollTop;
        scrOfX = document.documentElement.scrollLeft;
    }
    
    return {
        X: scrOfX,
        Y: scrOfY
    };
}

function DHFReadFile(url) {
    var xhr = DHFGetXmlHttpRequestObject();
    
    xhr.open("GET", url += (url.match(/\?/) == null ? "?" : "&") + (new Date()).getTime(), false);
    xhr.send(null);
    
    if (xhr.status == 200) {
        return xhr.responseText;
    } else {
        return '';
    }
}

function DHFAJAX(options) {
    var interval = -1,
        state = -1;
    
    options = {
        type: options.type || 'html',
        url: options.url || '',
        params: options.params || '',
        timeout: options.timeout || 5000,
        onTimeout: options.onTimeout || function() {},
        onComplete: options.onComplete || function() {},
        onError: options.onError || function() {},
        onSuccess: options.onSuccess || function() {},
        onCreateXmlHttpError: options.onCreateXmlHttpError || function() {},
        disableAllElements: options.disableAllElements || false,
        progressBar: options.progressBar || false,
        progressBarCustomMessage: options.progressBarCustomMessage || '',
        notasyncronous: options.async === false
    };
    
    if (options.disableAllElements) {
        DHFShieldContent(0, 'FFFFFF', 'XXXDUMMYXXX', 'AJAXShield');
    }
    
    var xmlHttp = DHFGetXmlHttpRequestObject(options.onCreateXmlHttpError);
    
    if (options.progressBar) {
        DHFCreateProgressBarDiv(options.progressBarCustomMessage);
        DHFProgressBarValue(40);
    }
    
    xmlHttp.open('POST', options.url, !options.notasyncronous);
    xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    
    if (xmlHttp.overrideMimeType) {
        switch (options.type) {
            case 'html':
            case 'text/html':
                xmlHttp.overrideMimeType('text/html');
                break;
            case 'xml':
            case 'text/xml':
                xmlHttp.overrideMimeType('text/xml');
                break;
            default:
                break;
        }
        xmlHttp.setRequestHeader('Connection', 'close');
    }
    
    var timeoutLength = options.timeout;
    var requestDone = false;
    
    setTimeout(function() {
        requestDone = true;
    }, timeoutLength);
    
    var interval = setInterval(OnReadyStateChange, 10);
    function OnReadyStateChange() // Note that this is not a real onreadystatechange
    {
        if (requestDone) {
            clearInterval(interval);
            debug.log("Timeout!");
            options.onTimeout();
            
            if (options.progressBar) {
                DHFDestroyProgressBarDiv();
            }
            
            if (options.disableAllElements) {
                DHFRemoveElementByID('AJAXShield');
            }
            
            xmlHttp = null;
            return undefined;
        }
        
        if (!xmlHttp) {
            clearInterval(interval);
            
            if (options.progressBar) {
                DHFDestroyProgressBarDiv();
            }
            
            if (options.disableAllElements) {
                DHFRemoveElementByID('AJAXShield');
            }
            
            xmlHttp = null;
            return undefined;
        }
        
        if (state != xmlHttp.readyState) {
            debug.log("xmlHttp.readyState: " + xmlHttp.readyState);
        }
        
        state = xmlHttp.readyState;
        
        if (options.progressBar) {
            DHFProgressBarValue((xmlHttp.readyState + 1) * 40);
        }
        
        if (xmlHttp.readyState == 4) {
            if (!requestDone) {
                clearInterval(interval);
                
                if (httpSuccess(xmlHttp)) {
                    debug.log("Success!");
                    options.onSuccess(httpData(xmlHttp, options.type));
                } else {
                    debug.log("Error!");
                    
                    if (options.progressBar) {
                        DHFDestroyProgressBarDiv();
                    }
                    
                    options.onError('Error ' + xmlHttp.status + ': ' + xmlHttp.statusText);
                }
            } else {
                clearInterval(interval);
                debug.log("Timeout!");
                options.onTimeout();
            }
            
            xmlHttp = null;
            if (options.progressBar) {
                DHFDestroyProgressBarDiv();
            }
            
            options.onComplete();
            
            if (options.disableAllElements) {
                DHFRemoveElementByID('AJAXShield');
            }
        }
    };
    
    xmlHttp.send(options.params);
    
    function httpSuccess(r) {
        try {
            return !r.status && location.protocol == 'file:' || (r.status >= 200 && r.status < 300) ||r.status == 304 ||
            navigator.userAgent.indexOf('Safari') >= 0 && r.status == undefined;
        } catch (e) {}
        
        return false;
    }
    
    function httpData(r, type) {
        var ct = r.getResponseHeader('content-type'),
            data = !type && ct && ct.indexOf('xml') >= 0;

        data = type == 'xml' || data ? r.responseXML : r.responseText;
        
        if (type == 'script') {
            eval.call(window, data);
        }
        
        return data;
    }
}
    
function DHFGetXmlHttpRequestObject(pOnError) {
    var i, xmlHttp,
        onError = pOnError || function() {};
    
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        var aVersions = ["Msxml2.XMLHTTP.6.0", "MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp", "Microsoft.XMLHttp"];
        
        for (i = 0; i < aVersions.length; i++) {
            try {
                xmlHttp = new ActiveXObject(aVersions[i]);
                return xmlHttp;
            } catch (oError) {
                onError();
            }
        }
    }
    if (xmlHttp) {
        return xmlHttp;
    } else {
        onError();
        return undefined;
    }
}

function DHFJSObjToURLParams(obj) {
    var j,
        s = [];
    
    if (obj.constructor === String) {
        return 'singlestringparamstring=' + encodeURIComponent(obj);
    } else {
        for (j in obj) {
            s.push(j + '=' + encodeURIComponent(obj[j]));
        }
        
        return s.join('&');
    }
}


function DHFCreateProgressBarDiv(customMessage) {
    var d, pbDIV1, pbDIV2, pbDIV3, pbDIV4, pbDIV5, pbDIV6, el;
    
    pbDIV1 = document.createElement('DIV');
    pbDIV1.id = 'AJAXProcessingDiv';
    pbDIV1.className = 'AJAXProcessingBG';
    pbDIV1.style.visibility = 'hidden';
    document.body.appendChild(pbDIV1);
    
    pbDIV2 = document.createElement('DIV');
    pbDIV2.id = 'AJAXProcessingContent';
    pbDIV2.className = 'AJAXProcessingBorder';
    document.getElementById('AJAXProcessingDiv').appendChild(pbDIV2);
    
    pbDIV3 = document.createElement('DIV');
    pbDIV3.className = 'AJAXProcessingText';
    pbDIV3.id = 'AJAXProcessingText';
    document.getElementById('AJAXProcessingContent').appendChild(pbDIV3);
    document.getElementById('AJAXProcessingText').innerHTML = customMessage != undefined && customMessage.length > 0 ? customMessage : str_ProcessingRequest;
    
    pbDIV4 = document.createElement('DIV');
    pbDIV4.className = 'AJAXProcessingProgressBarBox';
    pbDIV4.id = 'AJAXProcessingProgressBarBox';
    document.getElementById('AJAXProcessingContent').appendChild(pbDIV4);
    
    pbDIV5 = document.createElement('DIV');
    pbDIV5.id = 'AJAXProgressBar';
    pbDIV5.className = 'AJAXProcessingProgressBar';
    pbDIV5.style.width = '0px';
    document.getElementById('AJAXProcessingProgressBarBox').appendChild(pbDIV5);
    
    pbDIV6 = document.createElement('DIV');
    pbDIV6.className = 'AJAXProcessingText';
    pbDIV6.id = 'AJAXProcessingCloseButtonDiv';
    pbDIV6.style.align = 'right';
    document.getElementById('AJAXProcessingContent').appendChild(pbDIV6);
    
    el = document.getElementById('AJAXProcessingDiv');
    if (el) {
        el.style.left = (document.body.clientWidth - el.offsetWidth) / 2;
        el.style.top = (document.body.clientHeight - el.offsetHeight) / 2 + document.body.scrollTop;
        el.style.visibility = '';
    }
}
    
function DHFDestroyProgressBarDiv() {
    var n, currentNode;
    
    for (n = document.body.childNodes.length - 1; n >= 0; n--) {
        currentNode = document.body.childNodes[n];
        
        if (currentNode.id == "AJAXProcessingDiv") {
            document.body.removeChild(currentNode);
            break;
        }
    }
}

function DHFProgressBarValue(val) {
    var el = document.getElementById('AJAXProgressBar');
    
    if (el) {
        el.style.width = val;
    }
}

function DHFFixWindowSize(maxwidth) {
    // Fixing width and adding 5 to height because when IE added vertical scrollbar it will never go away again (T14714)
    var divwidth = DHFGetDivWidth("dhfbody") + 25,
        divheight = DHFGetDivHeight("dhfbody") + 5,
        windowwidth = DHFGetWindowInnerWidth(),
        windowheight = DHFGetWindowInnerHeight();
    
    if (divwidth > 0 && divwidth > windowwidth && (!maxwidth || divwidth <= maxwidth)) {
        DHFSetWindowInnerWidth(divwidth);
    }
        
    if (divheight > 0 && divheight > windowheight) {
        DHFSetWindowInnerHeight(divheight);
    }
}

function DHFPadNumber(str, places, padChar) {
    while (str.length < places) {
        str = padChar + str;
    }
    
    return str;
}

function DHFGetViewportSize() {
    var sizeObj = {
        'width': window.innerWidth || document.body.clientWidth,
        'height': window.innerHeight || document.body.clientHeight
    };
    
    return sizeObj;
}

function DHFAddEventListener(el, evnt, func) {
    var r;
    
    if (el.addEventListener) {
        el.addEventListener(evnt, func, false);
    } else if (el.attachEvent) {
        r = el.attachEvent("on" + evnt, func);
        return r;
    }
}

function DHFGenerateGuid(alphaNumericOnly) {
    var i, j,
        result = '';
    
    for (j = 0; j < 32; j++) {
        if (!alphaNumericOnly && (j === 8 || j === 12 || j === 16 || j === 20)) {
            result += '-';
        }
        
        i = Math.floor(Math.random() * 16).toString(16).toUpperCase();
        result += i;
    }
    
    return result
}

var DHFFormulaEditor = {
    mathML: '',
    backgroundColor: '#ffffff',
    imgMathML: '',
    editor: undefined,
    isLanguageDependent: false,
    currentLanguageIndex: -1,
    origWinWidthHeight: null,
    inPopupWindow: DHFGetURLParam('showaspopup') === "1",
    
    clear: function() {
        if (this.isReady()) {
            this.editor.clear();
        }
    },
    
    init: function() {
        if (!this.editor) {
            this.editor = this.getEditor();
        }
    },
    
    getEditor: function() {
        return window.formulaeditor || document.formulaeditor;
    },
    
    save: function() {
        if (this.isReady()) {
            this.editor.save();
        }
    },
    
    setEditorMathML: function(txt) {
        txt = txt || '';
        
        if (this.isReady()) {
            if (txt.length > 0) {
                if (usingOldFormulaEditor) {
                    this.editor.SetVariable("mathMLFromJs", txt);
                } else {
                    this.editor.setMathML(txt);
                }
            } else {
                this.editor.clear();
            }
        }
    },
    
    getEditorMathML: function() {
        if (this.isReady()) {
            return this.editor.getMathML();
        }
    },
    
    updateMathMLFromEditor: function() {
        if (this.isReady()) {
            this.mathML = this.getEditorMathML();
        }
    },
    
    show: function(langIndex) {
        var objXYWH, winWH,
            el = document.getElementById('formulaEditorDiv');
        
        this.currentLanguageIndex = langIndex;
        
        DHFShieldContent(60, '#ffffff', 'adminMainContent', 'formulaEditorShield', 2, true);
        
        if (this.inPopupWindow) {
            el.style.top = '1px';
            el.style.left = '1px';
            objXYWH = DHFGetElementPositionWidthHeight('formulaEditorDiv');
            
            if (this.origWinWidthHeight === null) {
                this.origWinWidthHeight = DHFGetWindowInnerDimensions();
            }
            
            DHFSetWindowInnerDimensions(objXYWH.width, objXYWH.height);
        } else {
            el.style.top = (document.body.scrollTop + 50) + 'px';
            el.style.left = '200px';
        }
        
        DHFMakeDivDraggable('formulaEditorDiv', 'formulaEditorHandle');
        
        if (this.isLanguageDependent) {
            this.normaliseMathML();
            this.setEditorMathML(this.mathML[langIndex]);
            DHFSetColorPickerSwatchColor(this.backgroundColor[langIndex]);
        } else if (this.mathML.length > 0) {
            this.setEditorMathML(this.mathML);
            DHFSetColorPickerSwatchColor(this.backgroundColor);
        }
    },
    
    normaliseMathML: function() {
        var i;
        
        if (this.isLanguageDependent) {
            for (i = 0; i < this.mathML.length; i++) {
                if (this.mathML[i] && this.mathML[i].length === 0) {
                    this.mathML[i] = '';
                    this.imgMathML[i] = '';
                }
            }
        } else if (this.mathML.length === 0) {
            this.mathML = '';
            this.imgMathML = '';
        }
    },
    
    hide: function() {
        var el = document.getElementById('formulaEditorDiv');
        
        el.style.top = "-1000px";
        
        DHFRemoveElementByID('formulaEditorShield');
        
        if (this.inPopupWindow) {
            DHFSetWindowInnerDimensions(this.origWinWidthHeight.width, this.origWinWidthHeight.height);
        }
    },
    
    saveClicked: function(txt) {
        var swatch, swatchBackgroundColor;
        
        if (window.DHFFormulaReceptor) {
            swatch = document.getElementById('swatch');
            
            if (swatch) {
                swatchBackgroundColor = DHF.rgbToHex(swatch.style.backgroundColor);
                
                if (this.isLanguageDependent) {
                    this.backgroundColor[this.currentLanguageIndex] = swatchBackgroundColor;
                } else {
                    this.backgroundColor = swatchBackgroundColor;
                }
            }
            
            // The formula editor adds extra tags to MathML strings ... lets remove them
            txt = txt.replace(/<math>\n.*<mrow>\n.*<math>\n.*<mrow>/, '<math>\n    <mrow>\n    ');
            txt = txt.replace(/<\/mrow>\n.*<\/math>\n.*<\/mrow>\n.*<\/math>/, '  </mrow>\n<math>');
            
            txt = DHF.stringUtils.mathMLToValidMathML(txt, true);
            DHFFormulaReceptor(txt);
        }
        
        this.hide();
    },
    
    getImage: function(langIndex) {
        var mML, bgCol;
        
        if (this.isLanguageDependent) {
            mML = DHFEscape(this.mathML[langIndex]).replace('+', '%2B');
            bgCol = DHFEscape(this.backgroundColor[langIndex]);
        } else {
            mML = DHFEscape(this.mathML).replace('+', '%2B');
            bgCol = DHFEscape(this.backgroundColor);
        }
        
        mML = mML || "<math><mrow><mtext>...</mtext></mrow></math>";
        
        var ajaxObj = {
            url: appURL + 'ajax/createMathMLImage.aspx',
            type: 'html',
            params: "mathml=" + mML + '&backgroundColor=' + bgCol,
            timeout: 10000,
            onSuccess: function(imgurl) {
                imgurl = '<img src="' + imgurl + '" />';
                
                DHFMathMLImageReceptor(langIndex, imgurl);
            }
        };
        
        DHFAJAX(ajaxObj);
    },
    
    setLanguageDependent: function(state, currLangIndex, numLangs) {
        var i,
            langArr = [],
            imgArr = [],
            backgroundColorArr = [];
        
        if (this.isLanguageDependent != state) {
            if (state) {
                for (i = 0; i < numLangs; i++) {
                    langArr.push(this.mathML);
                    imgArr.push(this.imgMathML);
                    backgroundColorArr.push(this.backgroundColor);
                }
                
                this.mathML = langArr;
                this.imgMathML = imgArr;
                this.backgroundColor = backgroundColorArr;
            } else {
                this.mathML = this.mathML[currLangIndex];
                this.imgMathML = this.imgMathML[currLangIndex];
                this.backgroundColor = this.backgroundColor[currLangIndex];
                this.currentLanguageIndex = -1;
            }
            
            this.isLanguageDependent = state;
        }
    },
    
    isReady: function() {
        this.editor = this.getEditor();
        
        return this.editor;
    }
};
    
//========================== 
// DHFValidatePasswordByUserIds function
// The function calls the ajax page in order to validate password 
// The function is called from the UserActions page       
// Developer: Yulia
//========================== 
function DHFValidatePasswordByUserIds(password, userIds) {
    var result,
        ajaxObj = {
            url: appURL + '/ajax/validatePasswordByUserIds.aspx',
            type: 'html',
            params: "password=" + DHFEscape(password) + "&userids=" + userIds,
            timeout: 10000,
            onSuccess: function(result) {
                DHFAJAXComplete(result);
            }
        };
    
    DHFAJAX(ajaxObj);
}
    
//========================== 
// DHFValidateUserPassword function
// The function calls the ajax page in order to validate password  
// The function is called from the Register lms page       
// Developer: Yulia
//========================== 
function DHFValidateUserPassword(password, login, firstName, lastName, userId) {
    var result,
        ajaxObj = {
            url: appURL + '/ajax/validatePasswordSignup.aspx',
            type: 'html',
            params: "password=" + DHFEscape(password) + "&username=" + DHFEscape(login) + "&firstname=" + DHFEscape(firstName) + "&lastname=" + DHFEscape(lastName) + "&userid=" + userId,
            timeout: 10000,
            onSuccess: function(result) {
                DHFAJAXComplete(result);
            }
        };
    
    DHFAJAX(ajaxObj);
}
//========================== 
// DHFValidateUserPasswordAddEdit function
// The function calls the ajax page in order to validate password  
// The function is called from the Add User (Admin) page       
// Developer: Yulia
//========================== 
function DHFValidateUserPasswordAddEdit(password, login, firstName, lastName, userId) {
    var result,
        ajaxObj = {
            url: appURL + '/ajax/validatePassword.aspx',
            type: 'html',
            params: "password=" + DHFEscape(password) + "&username=" + DHFEscape(login) + "&firstname=" + DHFEscape(firstName) + "&lastname=" + DHFEscape(lastName) + "&userid=" + userId,
            timeout: 10000,
            onSuccess: function(result) {
                DHFAJAXComplete(result);
            }
        };
    
    DHFAJAX(ajaxObj);
}
//========================== 
// DHFValidatePasswordAdmin function
// The function calls the ajax page in order to validate password  
// The function is called from the Add User (Admin) page       
// Developer: Yulia
//========================== 
function DHFValidatePasswordAdmin(admPassword) {
    var result,
        ajaxObj = {
            url: appURL + '/ajax/validatePasswordAdmin.aspx',
            type: 'html',
            params: "password=" + DHFEscape(admPassword),
            timeout: 10000,
            onSuccess: function(result) {
                DHFAJAXComplete(result);
            }
        };
    
    DHFAJAX(ajaxObj);
}
//========================== 
// DHFValidatePasswordMyProfile function
// The function calls the ajax page in order to validate password  
// The function is called from the LMS My Profile page       
// Developer: Yulia
//========================== 
function DHFValidatePasswordMyProfile(password) {
    var result,
        ajaxObj = {
            url: appURL + '/ajax/validatePasswordMyProfile.aspx',
            type: 'html',
            params: "password=" + DHFEscape(password),
            timeout: 10000,
            onSuccess: function(result) {
                DHFAJAXComplete(result);
            }
        };
    
    DHFAJAX(ajaxObj);
}

function DHFUpdateUserLoginValidationImage(login, imageContainer, noImgForValid, stringAlwaysValid) {
    var context,
        doc = document,
        el = doc.getElementById(imageContainer);
    
    login = login.replace(/^\s*/, '').replace(/\s*$/, '');
    
    if (!el) {
        return undefined;
    }
    
    if (login === '') {
        el.innerHTML = '';
        return undefined;
    }
    
    var ajaxObj = {
        url: appURL + '/ajax/checkUserExists.aspx',
        type: 'html',
        params: "login=" + login,
        timeout: 10000,
        onSuccess: function(state) {
            el.style.verticalAlign = 'text-bottom';
            
            if (window.globalContent) {
                context = globalContent;
            } else {
                context = window;
            }
            
            if (state === "0" || stringAlwaysValid === login) {
                if (noImgForValid) {
                    el.innerHTML = '';
                } else {
                    el.innerHTML = '<img src="' + appImageURLPlusPrefix + 'valid.png" width="14" height="14" alt="' + str_userisvalid + '" title="' + str_userisvalid + '" />';
                }
                
                context.LoginIsValid = true;
            } else {
                el.innerHTML = '<img src="' + appImageURLPlusPrefix + 'invalid.png" width="14" height="14" alt="' + str_usernotvalid + '" title="' + str_usernotvalid + '" />';
                
                context.LoginIsValid = false;
            }
        }
    };
    
    DHFAJAX(ajaxObj);
}
    
function DHFGetURLParam(strParamName) {
    var i, strQueryString, aQueryString, param,
        strReturn = '',
        strHref = window.location.href;
    
    if (strHref.indexOf('?') > -1) {
        strQueryString = strHref.substr(strHref.indexOf('?')).toLowerCase();
        aQueryString = strQueryString.split('&');
        
        for (i = 0; i < aQueryString.length; i++) {
            if (aQueryString[i].indexOf(strParamName + '=') > -1) {
                param = aQueryString[i].split('=');
                strReturn = param[1];
                break;
            }
        }
    }
    
    return strReturn;
}

// vertices is a string 'x0,y0,x1,x2...'
function DHFIsPointInPolygon(x, y, vertices) {
    var a, c, i, j, l;
    
    if (vertices) {
        a = vertices.split(',');
        
        if (a.length >= 6) {
            for (i = 0; i < a.length; i++) {
                a[i] = parseInt(a[i], 10);
            }
            
            c = false;
            l = a.length / 2;
            j = l - 1;
            
            for (i = -1; ++i < l; j = i) {
                if (((a[i * 2 + 1] <= y && y < a[j * 2 + 1]) || (a[j * 2 + 1] <= y && y < a[i * 2 + 1])) && (x < (a[j * 2] - a[i * 2]) * (y - a[i * 2 + 1]) / (a[j * 2 + 1] - a[i * 2 + 1]) + a[i * 2])) {
                    c = !c;
                }
            }
                
            return c;
        }
    }
    
    return false;
}

function DHFPoint(x, y) {
    this.x = x;
    this.y = y;
}

function DHFGetMouseXY(e, objID) {
    var x, y, el,
        ev = e || window.event;

    if (ev) {
        x = ev.clientX;
        y = ev.clientY;
    } else {
        if (!e) {
            return null;
        }
        
        x = e.pageX;
        y = e.pageY;
    }
    if (objID) {
        el = document.getElementById(objID);
        
        if (!el) {
            return null;
        }
        
        while (el) {
            x -= el.offsetLeft - el.scrollLeft;
            y -= el.offsetTop - el.scrollTop;
            el = el.offsetParent;
        }
    }
    
    return new DHFPoint(x, y);
}

function DHFGetMouseXYOverObject(e, objID) {
    var loc = DHFGetMouseXY(e, objID);
    
    if (!loc || loc.x < 0 || loc.y < 0 || loc.x >= DHFGetDivWidth(objID) || loc.y >= DHFGetDivHeight(objID)) {
        return null;
    }
    
    return loc;
}

function DHFSign(f) {
    return f ? ((f > 0.0) ? 1 : -1) : 0;
}

function DHFRound(f, dec) {
    var n;
    
    if (!dec || dec < 0) {
        return Math.round(f);
    }
    
    n = Math.pow(10, dec);
    
    return Math.round(f * n) / n;
}

function DHFDistance(x1, y1, x2, y2) {
    return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}

function DHFIndexToChar(i) {
    if (i < 0) {
        return '';
    }
    
    if (i < 26) {
        return String.fromCharCode(i + 65);
    }
    
    return String.fromCharCode(Math.floor((i - 26) / 26) + 65, i % 26 + 65);
}

function DHFGetLayer(strID) {
    if (document.all && !window.opera) {
        return document.all[strID];
    } else {
        return document.getElementById(strID);
    }
}

function DHFMoveFooter() {
    var obj, y;
    
    if (navigator.appName === "Microsoft Internet Explorer" && navigator.appVersion.indexOf("MSIE") > 0) {
        try {
            obj = DHFGetLayer('divFooter');
            y = DHFGetViewportSize().height + document.body.scrollTop - DHFGetDivHeight('divFooter');
            obj.style.top = y;
        } catch (e) {}
    }
}

function DHFIntDiv(x, y) {
    return (x / y) - (x % y);
}

DHF.mediaStringUtils = (function() {
    var DHFProcessMediaStringsAndPlaceholders = function(mediaString, contentToPlaceholder) {
        var i, j, n, matches, classMatches, matchesLen, classMatch, classesArr, classesArrLen, name,
            value, nameValPair, mediaType, GUID, title, lang, langCode, width, height,
            matchObj = {},
            matchObjArr = [];

        if (mediaString && mediaString.length > 0) {
            mediaString = mediaString.replace(/\n/g, ' ');
        }
        
        if (contentToPlaceholder) {
            matches = mediaString.match(/<span.*?<\/span>/gi);
        } else {
            matches = mediaString.match(/<img[^>]*?>/gi);
        }

        if (!matches || matches.length === 0 || !/\sclass="iqbox_/i.test(mediaString)) {
            return mediaString;
        }

        // First we create an array to hold matched objects
        matchesLen = matches.length;
        for (i = 0; i < matchesLen; i++) {
            if (matches[i].match(/\sclass="iqbox_/i)) {
                matchObj = {
                    'originalString': matches[i],
                    'processedString': ''
                };
                
                matchObjArr.push(matchObj);
            }
        }

        matchesLen = matchObjArr.length;
        for(i = 0; i < matchesLen; i++) {
            classMatch = matchObjArr[i].originalString.match(/class="(.+?)"/);
            
            if(classMatch.length == 2) {
                classesArr = classMatch[1].split(" ");
                
                classesArrLen = classesArr.length;
                for(j=0; j<classesArrLen; j++) {
                    nameValPair = classesArr[j].split("_");
                    
                    name = nameValPair[0];
                    value = nameValPair[1];
                    
                    switch(name) {
                        case 'iqbox':
                            mediaType = value;
                            break;
                        case 'GUID':
                            GUID = value;
                            break;
                        case 'T':
                            title = value.replace('[[space]]', ' ');
                            break;
                        case 'L':
                            lang = value;
                            break;
                        case 'LC':
                            langCode = value;
                            break;
                        case 'W':
                            width = value;
                            break;
                        case 'H':
                            height = value;
                            break;
                    }
                }
            }
            
            if(contentToPlaceholder) {
                // Direction = content -> placeholder
                switch(mediaType) {
                    case 'EmbeddedSWF':
                        matchObjArr[i].processedString = '<img class="iqbox_EmbeddedSWF GUID_' + GUID + ' T_' + title + ' L_' + lang +
                            ' LC_' + langCode + ' W_' + width + ' H_' + height + '" style="border:1px dotted #000; '+
                            'background-image: url(' + playerURL + '/CuteSoft_Client/CuteEditor/images/flash32.gif); '+
                            'background-position:center center; background-repeat:no-repeat; background-color:#C0C0C0;" src="' +
                            playerURL + '/CuteSoft_Client/CuteEditor/images/1x1.gif" width="' + width + '" height="' + height + '" alt="" />';
                        break;
                    case 'EmbeddedVideo':
                        matchObjArr[i].processedString = '<img class="iqbox_EmbeddedVideo GUID_' + GUID + ' T_' + title + ' L_' + lang +
                        ' LC_' + langCode + '" style="border:1px dotted #000; background-image: url(' + playerURL +
                            '/CuteSoft_Client/CuteEditor/images/flash32.gif); background-position:center center; '+
                            'background-repeat:no-repeat; background-color:#C0C0C0;" src="' + playerURL +
                            '/CuteSoft_Client/CuteEditor/images/1x1.gif" width="' + flashMedia.flv.width +
                            '" height="' + flashMedia.flv.height + '" alt="" />';
                        break;
                    case 'EmbeddedAudio':
                        matchObjArr[i].processedString = '<img class="iqbox_EmbeddedAudio GUID_' + GUID + ' T_' + title + ' L_' + lang +
                            ' LC_' + langCode + '" style="border:1px dotted #000; background-image: url(' + playerURL +
                            '/CuteSoft_Client/CuteEditor/images/flash32.gif); background-position:center center; '+
                            'background-repeat:no-repeat; background-color:#C0C0C0;" src="' + playerURL +
                            '/CuteSoft_Client/CuteEditor/images/1x1.gif" width="' + flashMedia.mp3.width +
                            '" height="' + flashMedia.mp3.height + '" alt="" />';
                        break;
                }
            } else {
                // Direction = placeholder -> content
                switch(mediaType)
                    {
                    case 'EmbeddedSWF':
                        matchObjArr[i].processedString = '<span class="iqbox_EmbeddedSWF GUID_' + GUID + ' T_' + title + ' W_' + width +
                            ' H_' + height + ' L_' + lang + ' LC_' + langCode +
                            '"><object xcodebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" width="' + width +
                            '" height="' + height + '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000">'+
                            '<param name="Movie" value="mediaaccess.aspx?id=' + GUID + '&lang=' + lang + '&langc=' + langCode +
                            '" /><param name="Quality" value="high"/><param name="wmode" value="transparent"/><embed src="mediaaccess.aspx?id=' + GUID +
                            '&lang=' + lang + '&langc=' + langCode + '" width="' + width + '" height="' + height +
                            '" quality="high" wmode="transparent" type="application/x-shockwave-flash" '+
                            'pluginspage="http://www.macromedia.com/go/getflashplayer"></embed></object></span>';
                        break;
                    case 'EmbeddedVideo':
                        matchObjArr[i].processedString = '<span class="iqbox_EmbeddedVideo GUID_' + GUID + ' T_' + title + ' L_' + lang +
                            ' LC_' + langCode + '"><object height="' + flashMedia.flv.height + '" width="' + flashMedia.flv.width +
                            '" data="mediaaccess.aspx?id=' + flashMedia.flv.filename + '&fileFromResourceFolder=1&guid=' + GUID +
                            '&lang=' + lang + '&langc=' + langCode +
                            '" type="application/x-shockwave-flash"><param value="high" name="quality"/><param value="true" name="play"/>'+
                            '<param value="true" name="loop"/><param value="false" name="menu"/><param value="exactfit" name="scale"/>'+
                            '<param value="transparent" name="wmode"/><param value="BL" name="salign"/>'+
                            '<param value="videoVolume=' +flashMedia.flv.volume + '&amp;spacePlayPause=' + flashMedia.flv.SpaceTogglesPlayPause +
                            '&amp;showPlayButton=' + flashMedia.flv.ShowPlayButton + '&amp;showTimeline=' + flashMedia.flv.ShowTimeline +
                            '&amp;showTimePlayed=' + flashMedia.flv.ShowTimePlayed + '&amp;showMuteButton=' + flashMedia.flv.ShowMuteButton +
                            '&amp;showVolume=' + flashMedia.flv.ShowVolume + '&amp;autoplay=' + flashMedia.flv.autoplay + '&amp;lng=' + lang +
                            '&amp;langc=' + langCode + '&amp;vidURL=mediaaccess.aspx?id=' + GUID + '&amp;lng=' + lang + '&amp;langc=' + langCode +
                            '" name="flashvars"/><param value="mediaaccess.aspx?id=' + flashMedia.flv.filename +
                            '&fileFromResourceFolder=1&amp;guid=' + GUID + '&amp;lng=' + lang + '&amp;langc=' + langCode +
                            '" name="movie"/></object></span>';
                        break;
                    case 'EmbeddedAudio':
                        matchObjArr[i].processedString = '<span class="iqbox_EmbeddedAudio GUID_' + GUID + ' T_' + title + ' L_' + lang +
                            ' LC_' + langCode + '"><object height="' + flashMedia.mp3.height + '" width="' + flashMedia.mp3.width +
                            '" data="mediaaccess.aspx?id=' + flashMedia.mp3.filename + '&fileFromResourceFolder=1&guid=' + GUID +
                            '&lang=' + lang + '&langc=' + langCode +
                            '" type="application/x-shockwave-flash"><param value="high" name="quality"/><param value="true" name="play"/>'+
                            '<param value="true" name="loop"/><param value="false" name="menu"/><param value="noscale" name="scale"/>'+
                            '<param value="transparent" name="wmode"/><param value="BL" name="salign"/>'+
                            '<param value="videoVolume=' + flashMedia.mp3.volume + '&amp;spacePlayPause=' + flashMedia.mp3.SpaceTogglesPlayPause +
                            '&amp;showPlayButton=' + flashMedia.mp3.ShowPlayButton + '&amp;showTimeline=' + flashMedia.mp3.ShowTimeline +
                            '&amp;showTimePlayed=' + flashMedia.mp3.ShowTimePlayed + '&amp;showMuteButton=' + flashMedia.mp3.ShowMuteButton +
                            '&amp;showVolume=' + flashMedia.mp3.ShowVolume + '&amp;autoplay=' + flashMedia.mp3.autoplay + '&amp;lng=' + lang +
                            '&amp;langc=' + langCode + '&amp;vidURL=mediaaccess.aspx?id=' + GUID + '&amp;lng=' + lang + '&amp;langc=' + langCode +
                            '" name="flashvars"/><param value="mediaaccess.aspx?id=' + flashMedia.mp3.filename +
                            '&fileFromResourceFolder=1&amp;guid=' + GUID + '&amp;lng=' + lang + '&amp;langc=' + langCode +
                            '" name="movie"/></object></span>';
                        break;
                }
            }
        }
        
        // Now we simply replace the original strings with the adjusted ones
        for (i = 0; i < matchesLen; i++) {
            proc = matchObjArr[i].processedString;
            
            if (proc.length > 0) {
                orig = matchObjArr[i].originalString;
                mediaString = mediaString.replace(orig, proc);
            }
        }
            
        return mediaString;
    }
    
    return {
        contentToPlaceholders: function(mediaString) {
            var n;
            
            if (mediaString.length === 0) {
                return '';
            } else {
                if (mediaString.constructor === String) {
                    mediaString = DHFProcessMediaStringsAndPlaceholders(mediaString, true);
                } else {
                    for (n in mediaString) {
                        mediaString[n] = DHFProcessMediaStringsAndPlaceholders(mediaString[n], true);
                    }
                }
                
                return mediaString;
            }
        },
        
        placeholdersToContent: function(mediaString) {
            var n;
            
            if (mediaString.length === 0) {
                return '';
            } else {
                if (mediaString.constructor === String) {
                    mediaString = DHFProcessMediaStringsAndPlaceholders(mediaString, false);
                } else {
                    for (n in mediaString) {
                        mediaString[n] = DHFProcessMediaStringsAndPlaceholders(mediaString[n], false);
                    }
                }
                
                return mediaString;
            }
        }
    }
})();
    
DHF.stringUtils = (function() {
var htmlEntityArray = ['&lt;','&gt;','&amp;','&phi;','&ShortLeftArrow;','&slarr;','&ShortUpArrow;','&ShortRightArrow;',
               '&srarr;','&ShortDownArrow;','&OverParenthesis;','&UnderParenthesis;','&OverBrace;','&UnderBrace;',
               '&trpezium;','&elinters;','&lbbrk;','&rbbrk;','&lobrk;','&LeftDoubleBracket;','&robrk;',
               '&RightDoubleBracket;','&lang;','&LeftAngleBracket;','&langle;','&rang;','&RightAngleBracket;',
               '&rangle;','&Lang;','&Rang;','&loang;','&roang;','&imath;','&inodot;','&jmath;','&Tab;','&NewLine;',
               '&excl;','&quot;','&num;','&dollar;','&percnt;','&nvlt;','&apos;','&lpar;','&rpar;','&midast;','&ast;',
               '&plus;','&comma;','&period;','&sol;','&colon;','&semi;','&equals;','&bne;','&nvgt;','&quest;','&commat;',
               '&lsqb;','&lbrack;','&bsol;','&bsolhsub;','&rsqb;','&rbrack;','&Hat;','&lowbar;','&grave;',
               '&DiacriticalGrave;','&lcub;','&lbrace;','&verbar;','&VerticalLine;','&vert;','&rcub;','&rbrace;',
               '&nbsp;','&NonBreakingSpace;','&iexcl;','&cent;','&pound;','&curren;','&yen;','&brvbar;','&sect;',
               '&uml;','&Dot;','&die;','&DoubleDot;','&copy;','&ordf;','&laquo;','&not;','&shy;','&reg;','&circledR;',
               '&macr;','&strns;','&OverBar;','&deg;','&plusmn;','&PlusMinus;','&pm;','&sup2;','&sup3;','&acute;',
               '&DiacriticalAcute;','&micro;','&para;','&middot;','&CenterDot;','&centerdot;','&cedil;','&Cedilla;',
               '&sup1;','&ordm;','&raquo;','&frac14;','&frac12;','&half;','&frac34;','&iquest;','&Agrave;','&Aacute;',
               '&Acirc;','&Atilde;','&Auml;','&Aring;','&AElig;','&Ccedil;','&Egrave;','&Eacute;','&Ecirc;','&Euml;',
               '&Igrave;','&Iacute;','&Icirc;','&Iuml;','&ETH;','&Ntilde;','&Ograve;','&Oacute;','&Ocirc;','&Otilde;',
               '&Ouml;','&times;','&Oslash;','&Ugrave;','&Uacute;','&Ucirc;','&Uuml;','&Yacute;','&THORN;','&szlig;',
               '&agrave;','&aacute;','&acirc;','&atilde;','&auml;','&aring;','&aelig;','&ccedil;','&egrave;','&eacute;',
               '&ecirc;','&euml;','&igrave;','&iacute;','&icirc;','&iuml;','&eth;','&ntilde;','&ograve;','&oacute;',
               '&ocirc;','&otilde;','&ouml;','&divide;','&div;','&oslash;','&ugrave;','&uacute;','&ucirc;','&uuml;',
               '&yacute;','&thorn;','&yuml;','&Amacr;','&amacr;','&Abreve;','&abreve;','&Aogon;','&aogon;','&Cacute;',
               '&cacute;','&Ccirc;','&ccirc;','&Cdot;','&cdot;','&Ccaron;','&ccaron;','&Dcaron;','&dcaron;','&Dstrok;',
               '&dstrok;','&Emacr;','&emacr;','&Edot;','&edot;','&Eogon;','&eogon;','&Ecaron;','&ecaron;','&Gcirc;',
               '&gcirc;','&Gbreve;','&gbreve;','&Gdot;','&gdot;','&Gcedil;','&Hcirc;','&hcirc;','&Hstrok;','&hstrok;',
               '&Itilde;','&itilde;','&Imacr;','&imacr;','&Iogon;','&iogon;','&Idot;','&IJlig;','&ijlig;','&Jcirc;',
               '&jcirc;','&Kcedil;','&kcedil;','&kgreen;','&Lacute;','&lacute;','&Lcedil;','&lcedil;','&Lcaron;',
               '&lcaron;','&Lmidot;','&lmidot;','&Lstrok;','&lstrok;','&Nacute;','&nacute;','&Ncedil;','&ncedil;',
               '&Ncaron;','&ncaron;','&napos;','&ENG;','&eng;','&Omacr;','&omacr;','&Odblac;','&odblac;','&OElig;',
               '&oelig;','&Racute;','&racute;','&Rcedil;','&rcedil;','&Rcaron;','&rcaron;','&Sacute;','&sacute;',
               '&Scirc;','&scirc;','&Scedil;','&scedil;','&Scaron;','&scaron;','&Tcedil;','&tcedil;','&Tcaron;',
               '&tcaron;','&Tstrok;','&tstrok;','&Utilde;','&utilde;','&Umacr;','&umacr;','&Ubreve;','&ubreve;',
               '&Uring;','&uring;','&Udblac;','&udblac;','&Uogon;','&uogon;','&Wcirc;','&wcirc;','&Ycirc;','&ycirc;',
               '&Yuml;','&Zacute;','&zacute;','&Zdot;','&zdot;','&Zcaron;','&zcaron;','&fnof;','&imped;','&gacute;',
               '&circ;','&caron;','&Hacek;','&breve;','&Breve;','&dot;','&DiacriticalDot;','&ring;','&ogon;','&tilde;',
               '&DiacriticalTilde;','&dblac;','&DiacriticalDoubleAcute;','&DownBreve;','&UnderBar;','&Alpha;','&Beta;',
               '&Gamma;','&Delta;','&Epsilon;','&Zeta;','&Eta;','&Theta;','&Iota;','&Kappa;','&Lambda;','&Mu;','&Nu;',
               '&Xi;','&Omicron;','&Pi;','&Rho;','&Sigma;','&Tau;','&Upsilon;','&Phi;','&Chi;','&Psi;','&Omega;',
               '&alpha;','&beta;','&gamma;','&delta;','&epsilon;','&epsiv;','&varepsilon;','&zeta;','&eta;','&theta;',
               '&iota;','&kappa;','&lambda;','&mu;','&nu;','&xi;','&omicron;','&pi;','&rho;','&sigmaf;','&sigmav;',
               '&varsigma;','&sigma;','&tau;','&upsilon;','&upsi;','&phiv;','&varphi;','&chi;','&psi;','&omega;',
               '&thetasym;','&thetav;','&vartheta;','&upsih;','&Upsi;','&straightphi;','&piv;','&varpi;','&Gammad;',
               '&gammad;','&digamma;','&kappav;','&varkappa;','&rhov;','&varrho;','&epsi;','&straightepsilon;',
               '&bepsi;','&backepsilon;','&IOcy;','&DJcy;','&GJcy;','&Jukcy;','&DScy;','&Iukcy;','&YIcy;','&Jsercy;',
               '&LJcy;','&NJcy;','&TSHcy;','&KJcy;','&Ubrcy;','&DZcy;','&Acy;','&Bcy;','&Vcy;','&Gcy;','&Dcy;','&IEcy;',
               '&ZHcy;','&Zcy;','&Icy;','&Jcy;','&Kcy;','&Lcy;','&Mcy;','&Ncy;','&Ocy;','&Pcy;','&Rcy;','&Scy;','&Tcy;',
               '&Ucy;','&Fcy;','&KHcy;','&TScy;','&CHcy;','&SHcy;','&SHCHcy;','&HARDcy;','&Ycy;','&SOFTcy;','&Ecy;',
               '&YUcy;','&YAcy;','&acy;','&bcy;','&vcy;','&gcy;','&dcy;','&iecy;','&zhcy;','&zcy;','&icy;','&jcy;',
               '&kcy;','&lcy;','&mcy;','&ncy;','&ocy;','&pcy;','&rcy;','&scy;','&tcy;','&ucy;','&fcy;','&khcy;',
               '&tscy;','&chcy;','&shcy;','&shchcy;','&hardcy;','&ycy;','&softcy;','&ecy;','&yucy;','&yacy;','&iocy;',
               '&djcy;','&gjcy;','&jukcy;','&dscy;','&iukcy;','&yicy;','&jsercy;','&ljcy;','&njcy;','&tshcy;','&kjcy;',
               '&ubrcy;','&dzcy;','&ensp;','&emsp;','&emsp13;','&emsp14;','&numsp;','&puncsp;','&thinsp;','&ThinSpace;',
               '&ThickSpace;','&hairsp;','&VeryThinSpace;','&ZeroWidthSpace;','&NegativeMediumSpace;',
               '&NegativeThickSpace;','&NegativeThinSpace;','&NegativeVeryThinSpace;','&zwnj;','&zwj;','&lrm;','&rlm;',
               '&hyphen;','&dash;','&ndash;','&mdash;','&horbar;','&Verbar;','&Vert;','&lsquo;','&OpenCurlyQuote;',
               '&rsquo;','&rsquor;','&CloseCurlyQuote;','&sbquo;','&lsquor;','&ldquo;','&OpenCurlyDoubleQuote;',
               '&rdquo;','&rdquor;','&CloseCurlyDoubleQuote;','&bdquo;','&ldquor;','&dagger;','&Dagger;','&ddagger;',
               '&bull;','&bullet;','&nldr;','&hellip;','&mldr;','&permil;','&pertenk;','&prime;','&Prime;','&tprime;',
               '&bprime;','&backprime;','&lsaquo;','&rsaquo;','&oline;','&caret;','&hybull;','&frasl;','&bsemi;',
               '&qprime;','&MediumSpace;','&NoBreak;','&af;','&ApplyFunction;','&it;','&InvisibleTimes;','&ic;',
               '&InvisibleComma;','&euro;','&tdot;','&TripleDot;','&DotDot;','&Copf;','&complexes;','&incare;',
               '&gscr;','&Hscr;','&hamilt;','&HilbertSpace;','&Hfr;','&Poincareplane;','&Hopf;','&quaternions;',
               '&planckh;','&planck;','&plankv;','&hbar;','&hslash;','&Iscr;','&imagline;','&image;','&Ifr;','&Im;',
               '&imagpart;','&Lscr;','&lagran;','&Laplacetrf;','&ell;','&Nopf;','&naturals;','&numero;','&copysr;',
               '&weierp;','&wp;','&Popf;','&primes;','&Qopf;','&rationals;','&Rscr;','&realine;','&real;','&Rfr;',
               '&Re;','&realpart;','&Ropf;','&reals;','&rx;','&trade;','&Zopf;','&integers;','&ohm;','&mho;','&Zfr;',
               '&zeetrf;','&iiota;','&angst;','&Bscr;','&bernou;','&Bernoullis;','&Cfr;','&Cayleys;','&escr;','&Escr;',
               '&expectation;','&Fscr;','&Fouriertrf;','&Mscr;','&phmmat;','&Mellintrf;','&oscr;','&order;',
               '&orderof;','&alefsym;','&aleph;','&beth;','&gimel;','&daleth;','&DD;','&CapitalDifferentialD;','&dd;',
               '&DifferentialD;','&ee;','&ExponentialE;','&exponentiale;','&ii;','&ImaginaryI;','&frac13;','&frac23;',
               '&frac15;','&frac25;','&frac35;','&frac45;','&frac16;','&frac56;','&frac18;','&frac38;','&frac58;',
               '&frac78;','&larr;','&LeftArrow;','&leftarrow;','&uarr;','&UpArrow;','&uparrow;','&rarr;','&RightArrow;',
               '&rightarrow;','&darr;','&DownArrow;','&downarrow;','&harr;','&LeftRightArrow;','&leftrightarrow;',
               '&varr;','&UpDownArrow;','&updownarrow;','&nwarr;','&nwarrow;','&UpperLeftArrow;','&nearr;','&nearrow;',
               '&UpperRightArrow;','&searr;','&LowerRightArrow;','&searrow;','&swarr;','&LowerLeftArrow;','&swarrow;',
               '&nlarr;','&nleftarrow;','&nrarr;','&nrightarrow;','&rarrw;','&rightsquigarrow;','&nrarrw;','&Larr;',
               '&twoheadleftarrow;','&Uarr;','&Rarr;','&twoheadrightarrow;','&Darr;','&larrtl;','&leftarrowtail;',
               '&rarrtl;','&rightarrowtail;','&mapstoleft;','&LeftTeeArrow;','&mapstoup;','&UpTeeArrow;','&map;',
               '&mapsto;','&RightTeeArrow;','&mapstodown;','&DownTeeArrow;','&larrhk;','&hookleftarrow;','&rarrhk;',
               '&hookrightarrow;','&larrlp;','&looparrowleft;','&rarrlp;','&looparrowright;','&harrw;',
               '&leftrightsquigarrow;','&nharr;','&nleftrightarrow;','&lsh;','&Lsh;','&rsh;','&Rsh;','&ldsh;','&rdsh;',
               '&crarr;','&cularr;','&curvearrowleft;','&curarr;','&curvearrowright;','&olarr;','&circlearrowleft;',
               '&orarr;','&circlearrowright;','&lharu;','&leftharpoonup;','&LeftVector;','&lhard;','&DownLeftVector;',
               '&leftharpoondown;','&uharr;','&RightUpVector;','&upharpoonright;','&uharl;','&LeftUpVector;',
               '&upharpoonleft;','&rharu;','&rightharpoonup;','&RightVector;','&rhard;','&DownRightVector;',
               '&rightharpoondown;','&dharr;','&downharpoonright;','&RightDownVector;','&dharl;','&downharpoonleft;',
               '&LeftDownVector;','&rlarr;','&RightArrowLeftArrow;','&rightleftarrows;','&udarr;','&UpArrowDownArrow;',
               '&lrarr;','&LeftArrowRightArrow;','&leftrightarrows;','&llarr;','&leftleftarrows;','&uuarr;',
               '&upuparrows;','&rrarr;','&rightrightarrows;','&ddarr;','&downdownarrows;','&lrhar;',
               '&leftrightharpoons;','&ReverseEquilibrium;','&rlhar;','&Equilibrium;','&rightleftharpoons;','&nlArr;',
               '&nLeftarrow;','&nhArr;','&nLeftrightarrow;','&nrArr;','&nRightarrow;','&lArr;','&DoubleLeftArrow;',
               '&Leftarrow;','&uArr;','&DoubleUpArrow;','&Uparrow;','&rArr;','&DoubleRightArrow;','&Implies;',
               '&Rightarrow;','&dArr;','&DoubleDownArrow;','&Downarrow;','&hArr;','&iff;','&DoubleLeftRightArrow;',
               '&Leftrightarrow;','&vArr;','&DoubleUpDownArrow;','&Updownarrow;','&nwArr;','&neArr;','&seArr;',
               '&swArr;','&lAarr;','&Lleftarrow;','&rAarr;','&Rrightarrow;','&zigrarr;','&larrb;','&LeftArrowBar;',
               '&rarrb;','&RightArrowBar;','&duarr;','&DownArrowUpArrow;','&loarr;','&roarr;','&hoarr;','&forall;',
               '&ForAll;','&comp;','&complement;','&part;','&PartialD;','&npart;','&exist;','&Exists;','&nexist;',
               '&nexists;','&NotExists;','&empty;','&emptyv;','&emptyset;','&varnothing;','&nabla;','&Del;','&isin;',
               '&isinv;','&Element;','&in;','&notin;','&notinva;','&NotElement;','&ni;','&niv;','&ReverseElement;',
               '&SuchThat;','&notni;','&notniva;','&NotReverseElement;','&prod;','&Product;','&coprod;','&Coproduct;',
               '&sum;','&Sum;','&minus;','&mnplus;','&MinusPlus;','&mp;','&plusdo;','&dotplus;','&setmn;','&ssetmn;',
               '&Backslash;','&setminus;','&smallsetminus;','&lowast;','&compfn;','&SmallCircle;','&radic;','&Sqrt;',
               '&prop;','&vprop;','&Proportional;','&propto;','&varpropto;','&infin;','&angrt;','&ang;','&angle;',
               '&nang;','&angmsd;','&measuredangle;','&angsph;','&mid;','&smid;','&shortmid;','&VerticalBar;','&nmid;',
               '&nsmid;','&NotVerticalBar;','&nshortmid;','&spar;','&par;','&DoubleVerticalBar;','&parallel;',
               '&shortparallel;','&npar;','&nspar;','&NotDoubleVerticalBar;','&nparallel;','&nshortparallel;','&and;',
               '&wedge;','&or;','&vee;','&cap;','&caps;','&cup;','&cups;','&int;','&Integral;','&Int;','&tint;',
               '&iiint;','&conint;','&ContourIntegral;','&oint;','&Conint;','&DoubleContourIntegral;','&Cconint;',
               '&cwint;','&cwconint;','&ClockwiseContourIntegral;','&awconint;','&CounterClockwiseContourIntegral;',
               '&there4;','&Therefore;','&therefore;','&becaus;','&Because;','&because;','&ratio;','&Colon;',
               '&Proportion;','&minusd;','&dotminus;','&mDDot;','&homtht;','&sim;','&thksim;','&thicksim;','&Tilde;',
               '&nvsim;','&bsim;','&backsim;','&ac;','&mstpos;','&acE;','&acd;','&wreath;','&VerticalTilde;','&wr;',
               '&nsim;','&NotTilde;','&esim;','&eqsim;','&EqualTilde;','&nesim;','&NotEqualTilde;','&sime;','&simeq;',
               '&TildeEqual;','&nsime;','&NotTildeEqual;','&nsimeq;','&cong;','&TildeFullEqual;','&simne;','&ncong;',
               '&NotTildeFullEqual;','&asymp;','&thkap;','&ap;','&approx;','&thickapprox;','&TildeTilde;','&nap;',
               '&napprox;','&NotTildeTilde;','&ape;','&approxeq;','&apid;','&napid;','&bcong;','&backcong;','&asympeq;',
               '&CupCap;','&nvap;','&bump;','&Bumpeq;','&HumpDownHump;','&nbump;','&NotHumpDownHump;','&bumpe;',
               '&bumpeq;','&HumpEqual;','&nbumpe;','&NotHumpEqual;','&esdot;','&doteq;','&DotEqual;','&nedot;','&eDot;',
               '&doteqdot;','&efDot;','&fallingdotseq;','&erDot;','&risingdotseq;','&colone;','&Assign;','&coloneq;',
               '&ecolon;','&eqcolon;','&ecir;','&eqcirc;','&cire;','&circeq;','&wedgeq;','&veeeq;','&trie;',
               '&triangleq;','&equest;','&questeq;','&ne;','&NotEqual;','&equiv;','&Congruent;','&bnequiv;','&nequiv;',
               '&NotCongruent;','&le;','&leq;','&nvle;','&ge;','&geq;','&GreaterEqual;','&nvge;','&lE;','&leqq;',
               '&LessFullEqual;','&nlE;','&nleqq;','&NotGreaterFullEqual;','&gE;','&geqq;','&GreaterFullEqual;','&ngE;',
               '&ngeqq;','&lnE;','&lneqq;','&lvnE;','&lvertneqq;','&gnE;','&gneqq;','&gvnE;','&gvertneqq;','&Lt;',
               '&ll;','&NestedLessLess;','&nLt;','&nLtv;','&NotLessLess;','&Gt;','&gg;','&NestedGreaterGreater;',
               '&nGt;','&nGtv;','&NotGreaterGreater;','&twixt;','&between;','&NotCupCap;','&nlt;','&nless;','&NotLess;',
               '&ngt;','&ngtr;','&NotGreater;','&nle;','&nleq;','&NotLessEqual;','&nge;','&ngeq;','&NotGreaterEqual;',
               '&lsim;','&lesssim;','&LessTilde;','&gsim;','&GreaterTilde;','&gtrsim;','&nlsim;','&NotLessTilde;',
               '&ngsim;','&NotGreaterTilde;','&lg;','&LessGreater;','&lessgtr;','&gl;','&GreaterLess;','&gtrless;',
               '&ntlg;','&NotLessGreater;','&ntgl;','&NotGreaterLess;','&pr;','&prec;','&Precedes;','&sc;','&succ;',
               '&Succeeds;','&prcue;','&preccurlyeq;','&PrecedesSlantEqual;','&sccue;','&succcurlyeq;',
               '&SucceedsSlantEqual;','&prsim;','&PrecedesTilde;','&precsim;','&scsim;','&SucceedsTilde;','&succsim;',
               '&NotSucceedsTilde;','&npr;','&NotPrecedes;','&nprec;','&nsc;','&NotSucceeds;','&nsucc;','&sub;',
               '&subset;','&vnsub;','&NotSubset;','&nsubset;','&sup;','&Superset;','&supset;','&vnsup;','&NotSuperset;',
               '&nsupset;','&suphsol;','&nsub;','&nsup;','&sube;','&subseteq;','&SubsetEqual;','&supe;',
               '&SupersetEqual;','&supseteq;','&nsube;','&NotSubsetEqual;','&nsubseteq;','&nsupe;','&NotSupersetEqual;',
               '&nsupseteq;','&subne;','&subsetneq;','&vsubne;','&varsubsetneq;','&supne;','&supsetneq;','&vsupne;',
               '&varsupsetneq;','&cupdot;','&uplus;','&UnionPlus;','&sqsub;','&sqsubset;','&SquareSubset;',
               '&NotSquareSubset;','&sqsup;','&sqsupset;','&SquareSuperset;','&NotSquareSuperset;','&sqsube;',
               '&sqsubseteq;','&SquareSubsetEqual;','&sqsupe;','&sqsupseteq;','&SquareSupersetEqual;','&sqcap;',
               '&SquareIntersection;','&sqcaps;','&sqcup;','&SquareUnion;','&sqcups;','&oplus;','&CirclePlus;',
               '&ominus;','&CircleMinus;','&otimes;','&CircleTimes;','&osol;','&odot;','&CircleDot;','&ocir;',
               '&circledcirc;','&oast;','&circledast;','&odash;','&circleddash;','&plusb;','&boxplus;','&minusb;',
               '&boxminus;','&timesb;','&boxtimes;','&sdotb;','&dotsquare;','&vdash;','&RightTee;','&dashv;',
               '&LeftTee;','&top;','&DownTee;','&perp;','&bottom;','&bot;','&UpTee;','&models;','&vDash;',
               '&DoubleRightTee;','&Vdash;','&Vvdash;','&VDash;','&nvdash;','&nvDash;','&nVdash;','&nVDash;','&prurel;',
               '&vltri;','&LeftTriangle;','&vartriangleleft;','&vrtri;','&RightTriangle;','&vartriangleright;',
               '&ltrie;','&LeftTriangleEqual;','&trianglelefteq;','&nvltrie;','&rtrie;','&RightTriangleEqual;',
               '&trianglerighteq;','&nvrtrie;','&origof;','&imof;','&mumap;','&multimap;','&hercon;','&intcal;',
               '&intercal;','&veebar;','&barvee;','&angrtvb;','&lrtri;','&xwedge;','&bigwedge;','&Wedge;','&xvee;',
               '&bigvee;','&Vee;','&xcap;','&bigcap;','&Intersection;','&xcup;','&bigcup;','&Union;','&diam;',
               '&Diamond;','&diamond;','&sdot;','&sstarf;','&Star;','&divonx;','&divideontimes;','&bowtie;','&ltimes;',
               '&rtimes;','&lthree;','&leftthreetimes;','&rthree;','&rightthreetimes;','&bsime;','&backsimeq;','&cuvee;',
               '&curlyvee;','&cuwed;','&curlywedge;','&Sub;','&Subset;','&Sup;','&Supset;','&Cap;','&Cup;','&fork;',
               '&pitchfork;','&epar;','&ltdot;','&lessdot;','&gtdot;','&gtrdot;','&Ll;','&nLl;','&Gg;','&ggg;','&nGg;',
               '&leg;','&lesseqgtr;','&LessEqualGreater;','&lesg;','&gel;','&GreaterEqualLess;','&gtreqless;','&gesl;',
               '&cuepr;','&curlyeqprec;','&cuesc;','&curlyeqsucc;','&nprcue;','&NotPrecedesSlantEqual;','&nsccue;',
               '&NotSucceedsSlantEqual;','&nsqsube;','&NotSquareSubsetEqual;','&nsqsupe;','&NotSquareSupersetEqual;',
               '&lnsim;','&gnsim;','&prnsim;','&precnsim;','&scnsim;','&succnsim;','&nltri;','&NotLeftTriangle;',
               '&ntriangleleft;','&nrtri;','&NotRightTriangle;','&ntriangleright;','&nltrie;','&NotLeftTriangleEqual;',
               '&ntrianglelefteq;','&nrtrie;','&NotRightTriangleEqual;','&ntrianglerighteq;','&vellip;','&ctdot;',
               '&utdot;','&dtdot;','&disin;','&isinsv;','&isins;','&isindot;','&notindot;','&notinvc;','&notinvb;',
               '&isinE;','&notinE;','&nisd;','&xnis;','&nis;','&notnivc;','&notnivb;','&barwed;','&barwedge;','&Barwed;',
               '&doublebarwedge;','&lceil;','&LeftCeiling;','&rceil;','&RightCeiling;','&lfloor;','&LeftFloor;',
               '&rfloor;','&RightFloor;','&drcrop;','&dlcrop;','&urcrop;','&ulcrop;','&bnot;','&profline;','&profsurf;',
               '&telrec;','&target;','&ulcorn;','&ulcorner;','&urcorn;','&urcorner;','&dlcorn;','&llcorner;','&drcorn;',
               '&lrcorner;','&frown;','&sfrown;','&smile;','&ssmile;','&cylcty;','&profalar;','&topbot;','&ovbar;',
               '&solbar;','&angzarr;','&lmoust;','&lmoustache;','&rmoust;','&rmoustache;','&tbrk;','&OverBracket;',
               '&bbrk;','&UnderBracket;','&bbrktbrk;','&blank;','&oS;','&circledS;','&boxh;','&HorizontalLine;','&boxv;',
               '&boxdr;','&boxdl;','&boxur;','&boxul;','&boxvr;','&boxvl;','&boxhd;','&boxhu;','&boxvh;','&boxH;',
               '&boxV;','&boxdR;','&boxDr;','&boxDR;','&boxdL;','&boxDl;','&boxDL;','&boxuR;','&boxUr;','&boxUR;',
               '&boxuL;','&boxUl;','&boxUL;','&boxvR;','&boxVr;','&boxVR;','&boxvL;','&boxVl;','&boxVL;','&boxHd;',
               '&boxhD;','&boxHD;','&boxHu;','&boxhU;','&boxHU;','&boxvH;','&boxVh;','&boxVH;','&uhblk;','&lhblk;',
               '&block;','&blk14;','&blk12;','&blk34;','&square;','&squ;','&Square;','&squarf;','&squf;',
               '&FilledVerySmallSquare;','&blacksquare;','&EmptyVerySmallSquare;','&rect;','&marker;','&fltns;',
               '&xutri;','&bigtriangleup;','&utrif;','&blacktriangle;','&utri;','&triangle;','&rtrif;',
               '&blacktriangleright;','&rtri;','&triangleright;','&xdtri;','&bigtriangledown;','&dtrif;',
               '&blacktriangledown;','&dtri;','&triangledown;','&ltrif;','&blacktriangleleft;','&ltri;','&triangleleft;',
               '&loz;','&lozenge;','&cir;','&tridot;','&xcirc;','&bigcirc;','&ultri;','&urtri;','&lltri;',
               '&EmptySmallSquare;','&FilledSmallSquare;','&starf;','&bigstar;','&star;','&phone;','&female;','&male;',
               '&spades;','&spadesuit;','&clubs;','&clubsuit;','&hearts;','&heartsuit;','&diams;','&diamondsuit;',
               '&sung;','&flat;','&natur;','&natural;','&sharp;','&check;','&checkmark;','&cross;','&malt;','&maltese;',
               '&sext;','&VerticalSeparator;','&xlarr;','&LongLeftArrow;','&longleftarrow;','&xrarr;','&LongRightArrow;',
               '&longrightarrow;','&xharr;','&LongLeftRightArrow;','&longleftrightarrow;','&xlArr;',
               '&DoubleLongLeftArrow;','&Longleftarrow;','&xrArr;','&DoubleLongRightArrow;','&Longrightarrow;','&xhArr;',
               '&DoubleLongLeftRightArrow;','&Longleftrightarrow;','&xmap;','&longmapsto;','&dzigrarr;','&nvlArr;',
               '&nvrArr;','&nvHarr;','&Map;','&lbarr;','&rbarr;','&bkarow;','&lBarr;','&rBarr;','&dbkarow;','&RBarr;',
               '&drbkarow;','&DDotrahd;','&UpArrowBar;','&DownArrowBar;','&Rarrtl;','&latail;','&ratail;','&lAtail;',
               '&rAtail;','&larrfs;','&rarrfs;','&larrbfs;','&rarrbfs;','&nwarhk;','&nearhk;','&searhk;','&hksearow;',
               '&swarhk;','&hkswarow;','&nwnear;','&nesear;','&toea;','&seswar;','&tosa;','&swnwar;','&rarrc;',
               '&nrarrc;','&cudarrr;','&ldca;','&rdca;','&cudarrl;','&larrpl;','&curarrm;','&cularrp;','&rarrpl;',
               '&harrcir;','&Uarrocir;','&lurdshar;','&ldrushar;','&LeftRightVector;','&RightUpDownVector;',
               '&DownLeftRightVector;','&LeftUpDownVector;','&LeftVectorBar;','&RightVectorBar;','&RightUpVectorBar;',
               '&RightDownVectorBar;','&DownLeftVectorBar;','&DownRightVectorBar;','&LeftUpVectorBar;',
               '&LeftDownVectorBar;','&LeftTeeVector;','&RightTeeVector;','&RightUpTeeVector;','&RightDownTeeVector;',
               '&DownLeftTeeVector;','&DownRightTeeVector;','&LeftUpTeeVector;','&LeftDownTeeVector;','&lHar;','&uHar;',
               '&rHar;','&dHar;','&luruhar;','&ldrdhar;','&ruluhar;','&rdldhar;','&lharul;','&llhard;','&rharul;',
               '&lrhard;','&udhar;','&UpEquilibrium;','&duhar;','&ReverseUpEquilibrium;','&RoundImplies;','&erarr;',
               '&simrarr;','&larrsim;','&rarrsim;','&rarrap;','&ltlarr;','&gtrarr;','&subrarr;','&suplarr;','&lfisht;',
               '&rfisht;','&ufisht;','&dfisht;','&lopar;','&ropar;','&lbrke;','&rbrke;','&lbrkslu;','&rbrksld;',
               '&lbrksld;','&rbrkslu;','&langd;','&rangd;','&lparlt;','&rpargt;','&gtlPar;','&ltrPar;','&vzigzag;',
               '&vangrt;','&angrtvbd;','&ange;','&range;','&dwangle;','&uwangle;','&angmsdaa;','&angmsdab;','&angmsdac;',
               '&angmsdad;','&angmsdae;','&angmsdaf;','&angmsdag;','&angmsdah;','&bemptyv;','&demptyv;','&cemptyv;',
               '&raemptyv;','&laemptyv;','&ohbar;','&omid;','&opar;','&operp;','&olcross;','&odsold;','&olcir;',
               '&ofcir;','&olt;','&ogt;','&cirscir;','&cirE;','&solb;','&bsolb;','&boxbox;','&trisb;','&rtriltri;',
               '&LeftTriangleBar;','&NotLeftTriangleBar;','&RightTriangleBar;','&NotRightTriangleBar;','&race;',
               '&iinfin;','&infintie;','&nvinfin;','&eparsl;','&smeparsl;','&eqvparsl;','&lozf;','&blacklozenge;',
               '&RuleDelayed;','&dsol;','&xodot;','&bigodot;','&xoplus;','&bigoplus;','&xotime;','&bigotimes;',
               '&xuplus;','&biguplus;','&xsqcup;','&bigsqcup;','&qint;','&iiiint;','&fpartint;','&cirfnint;','&awint;',
               '&rppolint;','&scpolint;','&npolint;','&pointint;','&quatint;','&intlarhk;','&pluscir;','&plusacir;',
               '&simplus;','&plusdu;','&plussim;','&plustwo;','&mcomma;','&minusdu;','&loplus;','&roplus;','&Cross;',
               '&timesd;','&timesbar;','&smashp;','&lotimes;','&rotimes;','&otimesas;','&Otimes;','&odiv;','&triplus;',
               '&triminus;','&tritime;','&iprod;','&intprod;','&amalg;','&capdot;','&ncup;','&ncap;','&capand;',
               '&cupor;','&cupcap;','&capcup;','&cupbrcap;','&capbrcup;','&cupcup;','&capcap;','&ccups;','&ccaps;',
               '&ccupssm;','&And;','&Or;','&andand;','&oror;','&orslope;','&andslope;','&andv;','&orv;','&andd;','&ord;',
               '&wedbar;','&sdote;','&simdot;','&congdot;','&ncongdot;','&easter;','&apacir;','&apE;','&napE;','&eplus;',
               '&pluse;','&Esim;','&Colone;','&Equal;','&eDDot;','&ddotseq;','&equivDD;','&ltcir;','&gtcir;','&ltquest;',
               '&gtquest;','&les;','&leqslant;','&LessSlantEqual;','&nles;','&nleqslant;','&NotLessSlantEqual;','&ges;',
               '&geqslant;','&GreaterSlantEqual;','&nges;','&ngeqslant;','&NotGreaterSlantEqual;','&lesdot;','&gesdot;',
               '&lesdoto;','&gesdoto;','&lesdotor;','&gesdotol;','&lap;','&lessapprox;','&gap;','&gtrapprox;','&lne;',
               '&lneq;','&gne;','&gneq;','&lnap;','&lnapprox;','&gnap;','&gnapprox;','&lEg;','&lesseqqgtr;','&gEl;',
               '&gtreqqless;','&lsime;','&gsime;','&lsimg;','&gsiml;','&lgE;','&glE;','&lesges;','&gesles;','&els;',
               '&eqslantless;','&egs;','&eqslantgtr;','&elsdot;','&egsdot;','&el;','&eg;','&siml;','&simg;','&simlE;',
               '&simgE;','&LessLess;','&NotNestedLessLess;','&GreaterGreater;','&NotNestedGreaterGreater;','&glj;',
               '&gla;','&ltcc;','&gtcc;','&lescc;','&gescc;','&smt;','&lat;','&smte;','&smtes;','&late;','&lates;',
               '&bumpE;','&pre;','&PrecedesEqual;','&preceq;','&npre;','&NotPrecedesEqual;','&npreceq;','&sce;',
               '&SucceedsEqual;','&succeq;','&nsce;','&NotSucceedsEqual;','&nsucceq;','&prE;','&scE;','&prnE;',
               '&precneqq;','&scnE;','&succneqq;','&prap;','&precapprox;','&scap;','&succapprox;','&prnap;',
               '&precnapprox;','&scnap;','&succnapprox;','&Pr;','&Sc;','&subdot;','&supdot;','&subplus;','&supplus;',
               '&submult;','&supmult;','&subedot;','&supedot;','&subE;','&subseteqq;','&nsubE;','&nsubseteqq;','&supE;',
               '&supseteqq;','&nsupE;','&nsupseteqq;','&subsim;','&supsim;','&subnE;','&subsetneqq;','&vsubnE;',
               '&varsubsetneqq;','&supnE;','&supsetneqq;','&vsupnE;','&varsupsetneqq;','&csub;','&csup;','&csube;',
               '&csupe;','&subsup;','&supsub;','&subsub;','&supsup;','&suphsub;','&supdsub;','&forkv;','&topfork;',
               '&mlcp;','&Dashv;','&DoubleLeftTee;','&Vdashl;','&Barv;','&vBar;','&vBarv;','&Vbar;','&Not;','&bNot;',
               '&rnmid;','&cirmid;','&midcir;','&topcir;','&nhpar;','&parsim;','&parsl;','&nparsl;','&fflig;','&filig;',
               '&fllig;','&ffilig;','&ffllig;','&Ascr;','&Cscr;','&Dscr;','&Gscr;','&Jscr;','&Kscr;','&Nscr;','&Oscr;',
               '&Pscr;','&Qscr;','&Sscr;','&Tscr;','&Uscr;','&Vscr;','&Wscr;','&Xscr;','&Yscr;','&Zscr;','&ascr;',
               '&bscr;','&cscr;','&dscr;','&fscr;','&hscr;','&iscr;','&jscr;','&kscr;','&lscr;','&mscr;','&nscr;',
               '&pscr;','&qscr;','&rscr;','&sscr;','&tscr;','&uscr;','&vscr;','&wscr;','&xscr;','&yscr;','&zscr;',
               '&Afr;','&Bfr;','&Dfr;','&Efr;','&Ffr;','&Gfr;','&Jfr;','&Kfr;','&Lfr;','&Mfr;','&Nfr;','&Ofr;','&Pfr;',
               '&Qfr;','&Sfr;','&Tfr;','&Ufr;','&Vfr;','&Wfr;','&Xfr;','&Yfr;','&afr;','&bfr;','&cfr;','&dfr;','&efr;',
               '&ffr;','&gfr;','&hfr;','&ifr;','&jfr;','&kfr;','&lfr;','&mfr;','&nfr;','&ofr;','&pfr;','&qfr;','&rfr;',
               '&sfr;','&tfr;','&ufr;','&vfr;','&wfr;','&xfr;','&yfr;','&zfr;','&Aopf;','&Bopf;','&Dopf;','&Eopf;',
               '&Fopf;','&Gopf;','&Iopf;','&Jopf;','&Kopf;','&Lopf;','&Mopf;','&Oopf;','&Sopf;','&Topf;','&Uopf;',
               '&Vopf;','&Wopf;','&Xopf;','&Yopf;','&aopf;','&bopf;','&copf;','&dopf;','&eopf;','&fopf;','&gopf;',
               '&hopf;','&iopf;','&jopf;','&kopf;','&lopf;','&mopf;','&nopf;','&oopf;','&popf;','&qopf;','&ropf;',
               '&sopf;','&topf;','&uopf;','&vopf;','&wopf;','&xopf;','&yopf;','&zopf;'];

var numArray = ['&#60;','&#62;','&#38;','&#981;','&#8592;','&#8592;','&#8593;','&#8594;','&#8594;','&#8595;','&#9180;','&#9181;',
                '&#9182;','&#9183;','&#9186;','&#9191;','&#10098;','&#10099;','&#10214;','&#10214;','&#10215;','&#10215;',
                '&#10216;','&#10216;','&#10216;','&#10217;','&#10217;','&#10217;','&#10218;','&#10219;','&#10220;','&#10221;',
                '&#120484;','&#120484;','&#120485;','&#9;','&#10;','&#33;','&#34;','&#35;','&#36;','&#37;','&#38;','&#39;','&#40;',
                '&#41;','&#42;','&#42;','&#43;','&#44;','&#46;','&#47;','&#58;','&#59;','&#61;','&#61;','&#62;','&#63;','&#64;',
                '&#91;','&#91;','&#92;','&#92;','&#93;','&#93;','&#94;','&#95;','&#96;','&#96;','&#123;','&#123;','&#124;',
                '&#124;','&#124;','&#125;','&#125;','&#160;','&#160;','&#161;','&#162;','&#163;','&#164;','&#165;','&#166;',
                '&#167;','&#168;','&#168;','&#168;','&#168;','&#169;','&#170;','&#171;','&#172;','&#173;','&#174;','&#174;',
                '&#175;','&#175;','&#175;','&#176;','&#177;','&#177;','&#177;','&#178;','&#179;','&#180;','&#180;','&#181;',
                '&#182;','&#183;','&#183;','&#183;','&#184;','&#184;','&#185;','&#186;','&#187;','&#188;','&#189;','&#189;',
                '&#190;','&#191;','&#192;','&#193;','&#194;','&#195;','&#196;','&#197;','&#198;','&#199;','&#200;','&#201;',
                '&#202;','&#203;','&#204;','&#205;','&#206;','&#207;','&#208;','&#209;','&#210;','&#211;','&#212;','&#213;',
                '&#214;','&#215;','&#216;','&#217;','&#218;','&#219;','&#220;','&#221;','&#222;','&#223;','&#224;','&#225;',
                '&#226;','&#227;','&#228;','&#229;','&#230;','&#231;','&#232;','&#233;','&#234;','&#235;','&#236;','&#237;',
                '&#238;','&#239;','&#240;','&#241;','&#242;','&#243;','&#244;','&#245;','&#246;','&#247;','&#247;','&#248;',
                '&#249;','&#250;','&#251;','&#252;','&#253;','&#254;','&#255;','&#256;','&#257;','&#258;','&#259;','&#260;',
                '&#261;','&#262;','&#263;','&#264;','&#265;','&#266;','&#267;','&#268;','&#269;','&#270;','&#271;','&#272;',
                '&#273;','&#274;','&#275;','&#278;','&#279;','&#280;','&#281;','&#282;','&#283;','&#284;','&#285;','&#286;',
                '&#287;','&#288;','&#289;','&#290;','&#292;','&#293;','&#294;','&#295;','&#296;','&#297;','&#298;','&#299;',
                '&#302;','&#303;','&#304;','&#306;','&#307;','&#308;','&#309;','&#310;','&#311;','&#312;','&#313;','&#314;',
                '&#315;','&#316;','&#317;','&#318;','&#319;','&#320;','&#321;','&#322;','&#323;','&#324;','&#325;','&#326;',
                '&#327;','&#328;','&#329;','&#330;','&#331;','&#332;','&#333;','&#336;','&#337;','&#338;','&#339;','&#340;',
                '&#341;','&#342;','&#343;','&#344;','&#345;','&#346;','&#347;','&#348;','&#349;','&#350;','&#351;','&#352;',
                '&#353;','&#354;','&#355;','&#356;','&#357;','&#358;','&#359;','&#360;','&#361;','&#362;','&#363;','&#364;',
                '&#365;','&#366;','&#367;','&#368;','&#369;','&#370;','&#371;','&#372;','&#373;','&#374;','&#375;','&#376;',
                '&#377;','&#378;','&#379;','&#380;','&#381;','&#382;','&#402;','&#437;','&#501;','&#710;','&#711;','&#711;',
                '&#728;','&#728;','&#729;','&#729;','&#730;','&#731;','&#732;','&#732;','&#733;','&#733;','&#785;','&#818;',
                '&#913;','&#914;','&#915;','&#916;','&#917;','&#918;','&#919;','&#920;','&#921;','&#922;','&#923;','&#924;',
                '&#925;','&#926;','&#927;','&#928;','&#929;','&#931;','&#932;','&#933;','&#934;','&#935;','&#936;','&#937;',
                '&#945;','&#946;','&#947;','&#948;','&#949;','&#949;','&#949;','&#950;','&#951;','&#952;','&#953;','&#954;',
                '&#955;','&#956;','&#957;','&#958;','&#959;','&#960;','&#961;','&#962;','&#962;','&#962;','&#963;','&#964;',
                '&#965;','&#965;','&#966;','&#966;','&#967;','&#968;','&#969;','&#977;','&#977;','&#977;','&#978;','&#978;',
                '&#981;','&#982;','&#982;','&#988;','&#989;','&#989;','&#1008;','&#1008;','&#1009;','&#1009;','&#1013;',
                '&#1013;','&#1014;','&#1014;','&#1025;','&#1026;','&#1027;','&#1028;','&#1029;','&#1030;','&#1031;','&#1032;',
                '&#1033;','&#1034;','&#1035;','&#1036;','&#1038;','&#1039;','&#1040;','&#1041;','&#1042;','&#1043;','&#1044;',
                '&#1045;','&#1046;','&#1047;','&#1048;','&#1049;','&#1050;','&#1051;','&#1052;','&#1053;','&#1054;','&#1055;',
                '&#1056;','&#1057;','&#1058;','&#1059;','&#1060;','&#1061;','&#1062;','&#1063;','&#1064;','&#1065;','&#1066;',
                '&#1067;','&#1068;','&#1069;','&#1070;','&#1071;','&#1072;','&#1073;','&#1074;','&#1075;','&#1076;','&#1077;',
                '&#1078;','&#1079;','&#1080;','&#1081;','&#1082;','&#1083;','&#1084;','&#1085;','&#1086;','&#1087;','&#1088;',
                '&#1089;','&#1090;','&#1091;','&#1092;','&#1093;','&#1094;','&#1095;','&#1096;','&#1097;','&#1098;','&#1099;',
                '&#1100;','&#1101;','&#1102;','&#1103;','&#1105;','&#1106;','&#1107;','&#1108;','&#1109;','&#1110;','&#1111;',
                '&#1112;','&#1113;','&#1114;','&#1115;','&#1116;','&#1118;','&#1119;','&#8194;','&#8195;','&#8196;','&#8197;',
                '&#8199;','&#8200;','&#8201;','&#8201;','&#8201;','&#8202;','&#8202;','&#8203;','&#8203;','&#8203;','&#8203;',
                '&#8203;','&#8204;','&#8205;','&#8206;','&#8207;','&#8208;','&#8208;','&#8211;','&#8212;','&#8213;','&#8214;',
                '&#8214;','&#8216;','&#8216;','&#8217;','&#8217;','&#8217;','&#8218;','&#8218;','&#8220;','&#8220;','&#8221;',
                '&#8221;','&#8221;','&#8222;','&#8222;','&#8224;','&#8225;','&#8225;','&#8226;','&#8226;','&#8229;','&#8230;',
                '&#8230;','&#8240;','&#8241;','&#8242;','&#8243;','&#8244;','&#8245;','&#8245;','&#8249;','&#8250;','&#8254;',
                '&#8257;','&#8259;','&#8260;','&#8271;','&#8279;','&#8287;','&#8288;','&#8289;','&#8289;','&#8290;','&#8290;',
                '&#8291;','&#8291;','&#8364;','&#8411;','&#8411;','&#8412;','&#8450;','&#8450;','&#8453;','&#8458;','&#8459;',
                '&#8459;','&#8459;','&#8460;','&#8460;','&#8461;','&#8461;','&#8462;','&#8463;','&#8463;','&#8463;','&#8463;',
                '&#8464;','&#8464;','&#8465;','&#8465;','&#8465;','&#8465;','&#8466;','&#8466;','&#8466;','&#8467;','&#8469;',
                '&#8469;','&#8470;','&#8471;','&#8472;','&#8472;','&#8473;','&#8473;','&#8474;','&#8474;','&#8475;','&#8475;',
                '&#8476;','&#8476;','&#8476;','&#8476;','&#8477;','&#8477;','&#8478;','&#8482;','&#8484;','&#8484;','&#8486;',
                '&#8487;','&#8488;','&#8488;','&#8489;','&#8491;','&#8492;','&#8492;','&#8492;','&#8493;','&#8493;','&#8495;',
                '&#8496;','&#8496;','&#8497;','&#8497;','&#8499;','&#8499;','&#8499;','&#8500;','&#8500;','&#8500;','&#8501;',
                '&#8501;','&#8502;','&#8503;','&#8504;','&#8517;','&#8517;','&#8518;','&#8518;','&#8519;','&#8519;','&#8519;',
                '&#8520;','&#8520;','&#8531;','&#8532;','&#8533;','&#8534;','&#8535;','&#8536;','&#8537;','&#8538;','&#8539;',
                '&#8540;','&#8541;','&#8542;','&#8592;','&#8592;','&#8592;','&#8593;','&#8593;','&#8593;','&#8594;','&#8594;',
                '&#8594;','&#8595;','&#8595;','&#8595;','&#8596;','&#8596;','&#8596;','&#8597;','&#8597;','&#8597;','&#8598;',
                '&#8598;','&#8598;','&#8599;','&#8599;','&#8599;','&#8600;','&#8600;','&#8600;','&#8601;','&#8601;','&#8601;',
                '&#8602;','&#8602;','&#8603;','&#8603;','&#8605;','&#8605;','&#8605;','&#8606;','&#8606;','&#8607;','&#8608;',
                '&#8608;','&#8609;','&#8610;','&#8610;','&#8611;','&#8611;','&#8612;','&#8612;','&#8613;','&#8613;','&#8614;',
                '&#8614;','&#8614;','&#8615;','&#8615;','&#8617;','&#8617;','&#8618;','&#8618;','&#8619;','&#8619;','&#8620;',
                '&#8620;','&#8621;','&#8621;','&#8622;','&#8622;','&#8624;','&#8624;','&#8625;','&#8625;','&#8626;','&#8627;',
                '&#8629;','&#8630;','&#8630;','&#8631;','&#8631;','&#8634;','&#8634;','&#8635;','&#8635;','&#8636;','&#8636;',
                '&#8636;','&#8637;','&#8637;','&#8637;','&#8638;','&#8638;','&#8638;','&#8639;','&#8639;','&#8639;','&#8640;',
                '&#8640;','&#8640;','&#8641;','&#8641;','&#8641;','&#8642;','&#8642;','&#8642;','&#8643;','&#8643;','&#8643;',
                '&#8644;','&#8644;','&#8644;','&#8645;','&#8645;','&#8646;','&#8646;','&#8646;','&#8647;','&#8647;','&#8648;',
                '&#8648;','&#8649;','&#8649;','&#8650;','&#8650;','&#8651;','&#8651;','&#8651;','&#8652;','&#8652;','&#8652;',
                '&#8653;','&#8653;','&#8654;','&#8654;','&#8655;','&#8655;','&#8656;','&#8656;','&#8656;','&#8657;','&#8657;',
                '&#8657;','&#8658;','&#8658;','&#8658;','&#8658;','&#8659;','&#8659;','&#8659;','&#8660;','&#8660;','&#8660;',
                '&#8660;','&#8661;','&#8661;','&#8661;','&#8662;','&#8663;','&#8664;','&#8665;','&#8666;','&#8666;','&#8667;',
                '&#8667;','&#8669;','&#8676;','&#8676;','&#8677;','&#8677;','&#8693;','&#8693;','&#8701;','&#8702;','&#8703;',
                '&#8704;','&#8704;','&#8705;','&#8705;','&#8706;','&#8706;','&#8706;','&#8707;','&#8707;','&#8708;','&#8708;',
                '&#8708;','&#8709;','&#8709;','&#8709;','&#8709;','&#8711;','&#8711;','&#8712;','&#8712;','&#8712;','&#8712;',
                '&#8713;','&#8713;','&#8713;','&#8715;','&#8715;','&#8715;','&#8715;','&#8716;','&#8716;','&#8716;','&#8719;',
                '&#8719;','&#8720;','&#8720;','&#8721;','&#8721;','&#8722;','&#8723;','&#8723;','&#8723;','&#8724;','&#8724;',
                '&#8726;','&#8726;','&#8726;','&#8726;','&#8726;','&#8727;','&#8728;','&#8728;','&#8730;','&#8730;','&#8733;',
                '&#8733;','&#8733;','&#8733;','&#8733;','&#8734;','&#8735;','&#8736;','&#8736;','&#8736;','&#8737;','&#8737;',
                '&#8738;','&#8739;','&#8739;','&#8739;','&#8739;','&#8740;','&#8740;','&#8740;','&#8740;','&#8741;','&#8741;',
                '&#8741;','&#8741;','&#8741;','&#8742;','&#8742;','&#8742;','&#8742;','&#8742;','&#8743;','&#8743;','&#8744;',
                '&#8744;','&#8745;','&#8745;','&#8746;','&#8746;','&#8747;','&#8747;','&#8748;','&#8749;','&#8749;','&#8750;',
                '&#8750;','&#8750;','&#8751;','&#8751;','&#8752;','&#8753;','&#8754;','&#8754;','&#8755;','&#8755;','&#8756;',
                '&#8756;','&#8756;','&#8757;','&#8757;','&#8757;','&#8758;','&#8759;','&#8759;','&#8760;','&#8760;','&#8762;',
                '&#8763;','&#8764;','&#8764;','&#8764;','&#8764;','&#8764;','&#8765;','&#8765;','&#8766;','&#8766;','&#8766;',
                '&#8767;','&#8768;','&#8768;','&#8768;','&#8769;','&#8769;','&#8770;','&#8770;','&#8770;','&#8770;','&#8770;',
                '&#8771;','&#8771;','&#8771;','&#8772;','&#8772;','&#8772;','&#8773;','&#8773;','&#8774;','&#8775;','&#8775;',
                '&#8776;','&#8776;','&#8776;','&#8776;','&#8776;','&#8776;','&#8777;','&#8777;','&#8777;','&#8778;','&#8778;',
                '&#8779;','&#8779;','&#8780;','&#8780;','&#8781;','&#8781;','&#8781;','&#8782;','&#8782;','&#8782;','&#8782;',
                '&#8782;','&#8783;','&#8783;','&#8783;','&#8783;','&#8783;','&#8784;','&#8784;','&#8784;','&#8784;','&#8785;',
                '&#8785;','&#8786;','&#8786;','&#8787;','&#8787;','&#8788;','&#8788;','&#8788;','&#8789;','&#8789;','&#8790;',
                '&#8790;','&#8791;','&#8791;','&#8793;','&#8794;','&#8796;','&#8796;','&#8799;','&#8799;','&#8800;','&#8800;',
                '&#8801;','&#8801;','&#8801;','&#8802;','&#8802;','&#8804;','&#8804;','&#8804;','&#8805;','&#8805;','&#8805;',
                '&#8805;','&#8806;','&#8806;','&#8806;','&#8806;','&#8806;','&#8806;','&#8807;','&#8807;','&#8807;','&#8807;',
                '&#8807;','&#8808;','&#8808;','&#8808;','&#8808;','&#8809;','&#8809;','&#8809;','&#8809;','&#8810;','&#8810;',
                '&#8810;','&#8810;','&#8810;','&#8810;','&#8811;','&#8811;','&#8811;','&#8811;','&#8811;','&#8811;','&#8812;',
                '&#8812;','&#8813;','&#8814;','&#8814;','&#8814;','&#8815;','&#8815;','&#8815;','&#8816;','&#8816;','&#8816;',
                '&#8817;','&#8817;','&#8817;','&#8818;','&#8818;','&#8818;','&#8819;','&#8819;','&#8819;','&#8820;','&#8820;',
                '&#8821;','&#8821;','&#8822;','&#8822;','&#8822;','&#8823;','&#8823;','&#8823;','&#8824;','&#8824;','&#8825;',
                '&#8825;','&#8826;','&#8826;','&#8826;','&#8827;','&#8827;','&#8827;','&#8828;','&#8828;','&#8828;','&#8829;',
                '&#8829;','&#8829;','&#8830;','&#8830;','&#8830;','&#8831;','&#8831;','&#8831;','&#8831;','&#8832;','&#8832;',
                '&#8832;','&#8833;','&#8833;','&#8833;','&#8834;','&#8834;','&#8834;','&#8834;','&#8834;','&#8835;','&#8835;',
                '&#8835;','&#8835;','&#8835;','&#8835;','&#8835;','&#8836;','&#8837;','&#8838;','&#8838;','&#8838;','&#8839;',
                '&#8839;','&#8839;','&#8840;','&#8840;','&#8840;','&#8841;','&#8841;','&#8841;','&#8842;','&#8842;','&#8842;',
                '&#8842;','&#8843;','&#8843;','&#8843;','&#8843;','&#8845;','&#8846;','&#8846;','&#8847;','&#8847;','&#8847;',
                '&#8847;','&#8848;','&#8848;','&#8848;','&#8848;','&#8849;','&#8849;','&#8849;','&#8850;','&#8850;','&#8850;',
                '&#8851;','&#8851;','&#8851;','&#8852;','&#8852;','&#8852;','&#8853;','&#8853;','&#8854;','&#8854;','&#8855;',
                '&#8855;','&#8856;','&#8857;','&#8857;','&#8858;','&#8858;','&#8859;','&#8859;','&#8861;','&#8861;','&#8862;',
                '&#8862;','&#8863;','&#8863;','&#8864;','&#8864;','&#8865;','&#8865;','&#8866;','&#8866;','&#8867;','&#8867;',
                '&#8868;','&#8868;','&#8869;','&#8869;','&#8869;','&#8869;','&#8871;','&#8872;','&#8872;','&#8873;','&#8874;',
                '&#8875;','&#8876;','&#8877;','&#8878;','&#8879;','&#8880;','&#8882;','&#8882;','&#8882;','&#8883;','&#8883;',
                '&#8883;','&#8884;','&#8884;','&#8884;','&#8884;','&#8885;','&#8885;','&#8885;','&#8885;','&#8886;','&#8887;',
                '&#8888;','&#8888;','&#8889;','&#8890;','&#8890;','&#8891;','&#8893;','&#8894;','&#8895;','&#8896;','&#8896;',
                '&#8896;','&#8897;','&#8897;','&#8897;','&#8898;','&#8898;','&#8898;','&#8899;','&#8899;','&#8899;','&#8900;',
                '&#8900;','&#8900;','&#8901;','&#8902;','&#8902;','&#8903;','&#8903;','&#8904;','&#8905;','&#8906;','&#8907;',
                '&#8907;','&#8908;','&#8908;','&#8909;','&#8909;','&#8910;','&#8910;','&#8911;','&#8911;','&#8912;','&#8912;',
                '&#8913;','&#8913;','&#8914;','&#8915;','&#8916;','&#8916;','&#8917;','&#8918;','&#8918;','&#8919;','&#8919;',
                '&#8920;','&#8920;','&#8921;','&#8921;','&#8921;','&#8922;','&#8922;','&#8922;','&#8922;','&#8923;','&#8923;',
                '&#8923;','&#8923;','&#8926;','&#8926;','&#8927;','&#8927;','&#8928;','&#8928;','&#8929;','&#8929;','&#8930;',
                '&#8930;','&#8931;','&#8931;','&#8934;','&#8935;','&#8936;','&#8936;','&#8937;','&#8937;','&#8938;','&#8938;',
                '&#8938;','&#8939;','&#8939;','&#8939;','&#8940;','&#8940;','&#8940;','&#8941;','&#8941;','&#8941;','&#8942;',
                '&#8943;','&#8944;','&#8945;','&#8946;','&#8947;','&#8948;','&#8949;','&#8949;','&#8950;','&#8951;','&#8953;',
                '&#8953;','&#8954;','&#8955;','&#8956;','&#8957;','&#8958;','&#8965;','&#8965;','&#8966;','&#8966;','&#8968;',
                '&#8968;','&#8969;','&#8969;','&#8970;','&#8970;','&#8971;','&#8971;','&#8972;','&#8973;','&#8974;','&#8975;',
                '&#8976;','&#8978;','&#8979;','&#8981;','&#8982;','&#8988;','&#8988;','&#8989;','&#8989;','&#8990;','&#8990;',
                '&#8991;','&#8991;','&#8994;','&#8994;','&#8995;','&#8995;','&#9005;','&#9006;','&#9014;','&#9021;','&#9023;',
                '&#9084;','&#9136;','&#9136;','&#9137;','&#9137;','&#9140;','&#9140;','&#9141;','&#9141;','&#9142;','&#9251;',
                '&#9416;','&#9416;','&#9472;','&#9472;','&#9474;','&#9484;','&#9488;','&#9492;','&#9496;','&#9500;','&#9508;',
                '&#9516;','&#9524;','&#9532;','&#9552;','&#9553;','&#9554;','&#9555;','&#9556;','&#9557;','&#9558;','&#9559;',
                '&#9560;','&#9561;','&#9562;','&#9563;','&#9564;','&#9565;','&#9566;','&#9567;','&#9568;','&#9569;','&#9570;',
                '&#9571;','&#9572;','&#9573;','&#9574;','&#9575;','&#9576;','&#9577;','&#9578;','&#9579;','&#9580;','&#9600;',
                '&#9604;','&#9608;','&#9617;','&#9618;','&#9619;','&#9633;','&#9633;','&#9633;','&#9642;','&#9642;','&#9642;',
                '&#9642;','&#9643;','&#9645;','&#9646;','&#9649;','&#9651;','&#9651;','&#9652;','&#9652;','&#9653;','&#9653;',
                '&#9656;','&#9656;','&#9657;','&#9657;','&#9661;','&#9661;','&#9662;','&#9662;','&#9663;','&#9663;','&#9666;',
                '&#9666;','&#9667;','&#9667;','&#9674;','&#9674;','&#9675;','&#9708;','&#9711;','&#9711;','&#9720;','&#9721;',
                '&#9722;','&#9723;','&#9724;','&#9733;','&#9733;','&#9734;','&#9742;','&#9792;','&#9794;','&#9824;','&#9824;',
                '&#9827;','&#9827;','&#9829;','&#9829;','&#9830;','&#9830;','&#9834;','&#9837;','&#9838;','&#9838;','&#9839;',
                '&#10003;','&#10003;','&#10007;','&#10016;','&#10016;','&#10038;','&#10072;','&#10229;','&#10229;','&#10229;',
                '&#10230;','&#10230;','&#10230;','&#10231;','&#10231;','&#10231;','&#10232;','&#10232;','&#10232;','&#10233;',
                '&#10233;','&#10233;','&#10234;','&#10234;','&#10234;','&#10236;','&#10236;','&#10239;','&#10498;','&#10499;',
                '&#10500;','&#10501;','&#10508;','&#10509;','&#10509;','&#10510;','&#10511;','&#10511;','&#10512;','&#10512;',
                '&#10513;','&#10514;','&#10515;','&#10518;','&#10521;','&#10522;','&#10523;','&#10524;','&#10525;','&#10526;',
                '&#10527;','&#10528;','&#10531;','&#10532;','&#10533;','&#10533;','&#10534;','&#10534;','&#10535;','&#10536;',
                '&#10536;','&#10537;','&#10537;','&#10538;','&#10547;','&#10547;','&#10549;','&#10550;','&#10551;','&#10552;',
                '&#10553;','&#10556;','&#10557;','&#10565;','&#10568;','&#10569;','&#10570;','&#10571;','&#10574;','&#10575;',
                '&#10576;','&#10577;','&#10578;','&#10579;','&#10580;','&#10581;','&#10582;','&#10583;','&#10584;','&#10585;',
                '&#10586;','&#10587;','&#10588;','&#10589;','&#10590;','&#10591;','&#10592;','&#10593;','&#10594;','&#10595;',
                '&#10596;','&#10597;','&#10598;','&#10599;','&#10600;','&#10601;','&#10602;','&#10603;','&#10604;','&#10605;',
                '&#10606;','&#10606;','&#10607;','&#10607;','&#10608;','&#10609;','&#10610;','&#10611;','&#10612;','&#10613;',
                '&#10614;','&#10616;','&#10617;','&#10619;','&#10620;','&#10621;','&#10622;','&#10623;','&#10629;','&#10630;',
                '&#10635;','&#10636;','&#10637;','&#10638;','&#10639;','&#10640;','&#10641;','&#10642;','&#10643;','&#10644;',
                '&#10645;','&#10646;','&#10650;','&#10652;','&#10653;','&#10660;','&#10661;','&#10662;','&#10663;','&#10664;',
                '&#10665;','&#10666;','&#10667;','&#10668;','&#10669;','&#10670;','&#10671;','&#10672;','&#10673;','&#10674;',
                '&#10675;','&#10676;','&#10677;','&#10678;','&#10679;','&#10681;','&#10683;','&#10684;','&#10686;','&#10687;',
                '&#10688;','&#10689;','&#10690;','&#10691;','&#10692;','&#10693;','&#10697;','&#10701;','&#10702;','&#10703;',
                '&#10703;','&#10704;','&#10704;','&#10714;','&#10716;','&#10717;','&#10718;','&#10723;','&#10724;','&#10725;',
                '&#10731;','&#10731;','&#10740;','&#10742;','&#10752;','&#10752;','&#10753;','&#10753;','&#10754;','&#10754;',
                '&#10756;','&#10756;','&#10758;','&#10758;','&#10764;','&#10764;','&#10765;','&#10768;','&#10769;','&#10770;',
                '&#10771;','&#10772;','&#10773;','&#10774;','&#10775;','&#10786;','&#10787;','&#10788;','&#10789;','&#10790;',
                '&#10791;','&#10793;','&#10794;','&#10797;','&#10798;','&#10799;','&#10800;','&#10801;','&#10803;','&#10804;',
                '&#10805;','&#10806;','&#10807;','&#10808;','&#10809;','&#10810;','&#10811;','&#10812;','&#10812;','&#10815;',
                '&#10816;','&#10818;','&#10819;','&#10820;','&#10821;','&#10822;','&#10823;','&#10824;','&#10825;','&#10826;',
                '&#10827;','&#10828;','&#10829;','&#10832;','&#10835;','&#10836;','&#10837;','&#10838;','&#10839;','&#10840;',
                '&#10842;','&#10843;','&#10844;','&#10845;','&#10847;','&#10854;','&#10858;','&#10861;','&#10861;','&#10862;',
                '&#10863;','&#10864;','&#10864;','&#10865;','&#10866;','&#10867;','&#10868;','&#10869;','&#10871;','&#10871;',
                '&#10872;','&#10873;','&#10874;','&#10875;','&#10876;','&#10877;','&#10877;','&#10877;','&#10877;','&#10877;',
                '&#10877;','&#10878;','&#10878;','&#10878;','&#10878;','&#10878;','&#10878;','&#10879;','&#10880;','&#10881;',
                '&#10882;','&#10883;','&#10884;','&#10885;','&#10885;','&#10886;','&#10886;','&#10887;','&#10887;','&#10888;',
                '&#10888;','&#10889;','&#10889;','&#10890;','&#10890;','&#10891;','&#10891;','&#10892;','&#10892;','&#10893;',
                '&#10894;','&#10895;','&#10896;','&#10897;','&#10898;','&#10899;','&#10900;','&#10901;','&#10901;','&#10902;',
                '&#10902;','&#10903;','&#10904;','&#10905;','&#10906;','&#10909;','&#10910;','&#10911;','&#10912;','&#10913;',
                '&#10913;','&#10914;','&#10914;','&#10916;','&#10917;','&#10918;','&#10919;','&#10920;','&#10921;','&#10922;',
                '&#10923;','&#10924;','&#10924;','&#10925;','&#10925;','&#10926;','&#10927;','&#10927;','&#10927;','&#10927;',
                '&#10927;','&#10927;','&#10928;','&#10928;','&#10928;','&#10928;','&#10928;','&#10928;','&#10931;','&#10932;',
                '&#10933;','&#10933;','&#10934;','&#10934;','&#10935;','&#10935;','&#10936;','&#10936;','&#10937;','&#10937;',
                '&#10938;','&#10938;','&#10939;','&#10940;','&#10941;','&#10942;','&#10943;','&#10944;','&#10945;','&#10946;',
                '&#10947;','&#10948;','&#10949;','&#10949;','&#10949;','&#10949;','&#10950;','&#10950;','&#10950;','&#10950;',
                '&#10951;','&#10952;','&#10955;','&#10955;','&#10955;','&#10955;','&#10956;','&#10956;','&#10956;','&#10956;',
                '&#10959;','&#10960;','&#10961;','&#10962;','&#10963;','&#10964;','&#10965;','&#10966;','&#10967;','&#10968;',
                '&#10969;','&#10970;','&#10971;','&#10980;','&#10980;','&#10982;','&#10983;','&#10984;','&#10985;','&#10987;',
                '&#10988;','&#10989;','&#10990;','&#10991;','&#10992;','&#10993;','&#10994;','&#10995;','&#11005;','&#11005;',
                '&#64256;','&#64257;','&#64258;','&#64259;','&#64260;','&#119964;','&#119966;','&#119967;','&#119970;',
                '&#119973;','&#119974;','&#119977;','&#119978;','&#119979;','&#119980;','&#119982;','&#119983;','&#119984;',
                '&#119985;','&#119986;','&#119987;','&#119988;','&#119989;','&#119990;','&#119991;','&#119992;','&#119993;',
                '&#119995;','&#119997;','&#119998;','&#119999;','&#120000;','&#120001;','&#120002;','&#120003;','&#120005;',
                '&#120006;','&#120007;','&#120008;','&#120009;','&#120010;','&#120011;','&#120012;','&#120013;','&#120014;',
                '&#120015;','&#120068;','&#120069;','&#120071;','&#120072;','&#120073;','&#120074;','&#120077;','&#120078;',
                '&#120079;','&#120080;','&#120081;','&#120082;','&#120083;','&#120084;','&#120086;','&#120087;','&#120088;',
                '&#120089;','&#120090;','&#120091;','&#120092;','&#120094;','&#120095;','&#120096;','&#120097;','&#120098;',
                '&#120099;','&#120100;','&#120101;','&#120102;','&#120103;','&#120104;','&#120105;','&#120106;','&#120107;',
                '&#120108;','&#120109;','&#120110;','&#120111;','&#120112;','&#120113;','&#120114;','&#120115;','&#120116;',
                '&#120117;','&#120118;','&#120119;','&#120120;','&#120121;','&#120123;','&#120124;','&#120125;','&#120126;',
                '&#120128;','&#120129;','&#120130;','&#120131;','&#120132;','&#120134;','&#120138;','&#120139;','&#120140;',
                '&#120141;','&#120142;','&#120143;','&#120144;','&#120146;','&#120147;','&#120148;','&#120149;','&#120150;',
                '&#120151;','&#120152;','&#120153;','&#120154;','&#120155;','&#120156;','&#120157;','&#120158;','&#120159;',
                '&#120160;','&#120161;','&#120162;','&#120163;','&#120164;','&#120165;','&#120166;','&#120167;','&#120168;',
                '&#120169;','&#120170;','&#120171;'];

    // Regular Expressions for parsing tags and attributes
    var startTag = /^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
        endTag = /^<\/(\w+)[^>]*>/,
        attr = /(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
        
    var makeMap = function(str){
        var i, obj = {}, items = str.split(','), itemsLen = items.length;

        for (i=0; i<itemsLen; i++)
            obj[items[i]] = true;

        return obj;
    }

    var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');
    
    var block = makeMap('address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,'+
        'li,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul,math,mtable,mrow,mtr,mtd,mfrac,msqrt,msub');
        
    var inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,'+
        'object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var,mi,mo,mn,mtext');

    // Elements that you can, intentionally, leave open
    // (and which close themselves)
    var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');

    // Attributes that have their values filled in disabled="disabled"
    var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');

    // Special Elements (can contain anything)
    var special = makeMap('script,style');
    
    var indexOf = DHF.indexOf;
    
    var lookup = function(s, htmlToNum){
        var index;
        
        if(htmlToNum) {
            index = indexOf(s, htmlEntityArray);
            if(index >= 0)
                return numArray[index];
        } else {
            index = indexOf(s, numArray);
            if(index >= 0)
                return htmlEntityArray[index];
        }
        return s;
    };
    
    var lookupNumeric = function(s){
        return lookup(s, true);
    };
    
    var lookupHTMLEnt = function(s){
        return lookup(s, false);
    };
    
    var correctEncoding = function(s){
        return s.replace(/(&amp;)(amp;)+/, '$1');
    };
    
    var encodedHandler = function(s) {
        if(indexOf(s, htmlEntityArray) > 0)
            return '';
            
        if(indexOf(s, numArray) > 0)
            return '';

        return s;
    };

    var HTMLParser = function(html, handler) {
        var index, chars, match, stack = [], last = html;
        stack.last = function(){
            return this[this.length - 1];
        };

        while (html) {
            chars = true;

            // Make sure we're not in a script or style element
            if (!stack.last() || !special[stack.last()]) {

                // Comment
                if (html.indexOf('<!--') == 0) {
                    index = html.indexOf('-->');
    
                    if (index >= 0) {
                        if (handler.comment)
                            handler.comment(html.substring(4, index));
                        html = html.substring(index + 3);
                        chars = false;
                    }
    
                // end tag
                } else if (html.indexOf('</') == 0) {
                    match = html.match(endTag);
    
                    if (match) {
                        html = html.substring(match[0].length);
                        match[0].replace(endTag, parseEndTag);
                        chars = false;
                    }
    
                // start tag
                } else if (html.indexOf('<') == 0) {
                    match = html.match(startTag);
    
                    if (match) {
                        html = html.substring(match[0].length);
                        match[0].replace(startTag, parseStartTag);
                        chars = false;
                    }
                }

                if (chars) {
                    index = html.indexOf('<');
                    
                    var text = index < 0 ? html : html.substring(0, index);
                    html = index < 0 ? '' : html.substring(index);
                    
                    if (handler.chars)
                        handler.chars(text);
                }
            } else {
                html = html.replace(new RegExp("(.*)<\/" + stack.last() + "[^>]*>"), function(all, text){
                    text = text.replace(/<!--(.*?)-->/g, '$1')
                        .replace(/<!\[CDATA\[(.*?)]]>/g, '$1');

                    if (handler.chars)
                        handler.chars(text);

                    return '';
                });

                parseEndTag('', stack.last());
            }

            if (html == last)
                throw 'Parse Error: ' + html;
            last = html;
        }
        
        // Clean up any remaining tags
        parseEndTag();

        function parseStartTag(tag, tagName, rest, unary) {
            if (block[tagName]) {
                while (stack.last() && inline[stack.last()]) {
                    parseEndTag('', stack.last());
                }
            }

            if (closeSelf[tagName] && stack.last() == tagName) {
                parseEndTag('', tagName);
            }

            unary = empty[tagName] || !!unary;

            if (!unary)
                stack.push(tagName);
            
            if (handler.start) {
                var value, attrs = [];
    
                rest.replace(attr, function(match, name) {
                    value = arguments[2] ? arguments[2] :
                        arguments[3] ? arguments[3] :
                        arguments[4] ? arguments[4] :
                        fillAttrs[name] ? name : '';
                    
                    attrs.push({
                        name: name,
                        value: value,
                        escaped: value.replace(/(^|[^\\])"/g, '$1\\\"')
                    });
                });
    
                if (handler.start)
                    handler.start(tagName, attrs, unary);
            }
        }

        function parseEndTag(tag, tagName) {
            var i, pos;

            // If no tag name is provided, clean shop
            if (!tagName)
                pos = 0;
                
            // Find the closest opened tag of the same type
            else
                for (pos = stack.length - 1; pos >= 0; pos--)
                    if (stack[pos] == tagName)
                        break;
            
            if (pos >= 0) {
                // Close all the open elements, up the stack
                for (i = stack.length - 1; i >= pos; i--)
                    if (handler.end)
                        handler.end(stack[i]);
                
                // Remove the open elements from the stack
                stack.length = pos;
            }
        }
    };
    
    return {
        // When encoding do we convert characters into html or Numeric entities
        EncodeType: 'entity', // entity OR Numeric
    
        // Convert HTML entities into Numeric entities
        HTML2Numeric: function(s){
            return s.replace(/(&[^#]\w+;)/g, lookupNumeric);
        },

        // Convert Numeric entities into HTML entities
        NumericToHTML: function(s){
            return s.replace(/(&#\w+;)/g, lookupHTMLEnt);
        },

        // Numerically encodes all unicode characters
        numEncode: function(s){
            if(!s) return '';

            var i, c,
                e = '',
                stringLen = s.length;

            for (i = 0; i < stringLen; i++)
            {
                c = s.charAt(i);
                if (c < ' ' || c > '~' || '+*/='.indexOf(c) >= 0)
                {
                    c = '&#' + c.charCodeAt() + ';';
                }
                e += c;
            }
            return e;
        },
        
        // HTML Decode Numeric and HTML entities back to original values
        htmlDecode: function(s){
            var c, m, d = s,
                arrayLen;

            if(!s) return '';

            // convert HTML entites back to Numeric entites first
            d = this.HTML2Numeric(d);
            
            // look for Numeric entities &#34;
            arr=d.match(/&#[0-9]{1,5};/g);
            
            // if no matches found in string then skip
            if(arr){
                arrayLen = arr.length;
                for(var x = 0; x < arrayLen; x++){
                    m = arr[x];
                    c = m.substring(2, m.length-1); //get numeric part which is reference to unicode character
                    // if its a valid number we can decode
                    if(c >= -32768 && c <= 65535)
                        d = d.replace(m, String.fromCharCode(c)); // decode every single match within string
                    else
                        d = d.replace(m, ''); //invalid so replace with nada
                }            
            }

            return d;
        },        

        // encode an input string into either Numeric or HTML entities
        htmlEncode: function(s, EncodeType){
            if(!s) return '';

            s = s.replace(/&amp;/g, '&');

            // convert the xss chars to Numeric entities ' ' < >
            s = this.XSSEncode(s, false);            
            s = this.HTML2Numeric(s);

            // Now encode all chars above 127 e.g unicode
            s = this.numEncode(s);

            // we don't want double encoded entities so we ignore the & in existing entities
            s = s.replace(/&#/g,'##AMPHASH##');
        
            if(EncodeType === 'Numeric')
                s = s.replace(/&/g, '&#38;');
            else
                s = s.replace(/&/g, '&amp;');

            // replace any malformed entities
            s = s.replace(/&#\d*([^\d;]|$)/g, '$1');

            s = s.replace(/##AMPHASH##/g,'&#');

            s = correctEncoding(s);

            // now do we need to convert our Numeric encoded string into entities
            if(EncodeType === 'entity')
                s = this.NumericToHTML(s);

            return s;                    
        },

        // Encodes the basic 4 characters used to malform HTML in XSS hacks
        XSSEncode: function(s, en){
            if(s){
                en = en || true;
                // do we convert to Numeric or html entity?
                if(en)
                    s = s.replace(/\"/g,'&quot;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
                else
                    s = s.replace(/\'/g,'&#39;').replace(/\"/g,'&#34;').replace(/</g,'&#60;').replace(/>/g,'&#62;');
                
                return s;
            }else
                return '';
        },

        // returns true if a string contains html or Numeric encoded entities
        containsEntities: function(s){
            if(s !== s.replace(/&(?:[A-Z]|[[a-z]|#[0-9]+)+;/g, encodedHandler))
                return true;
            else
                return false;
        },
        
        MakeHTMLValid: function(html, contentToHTMLEntities) {
            var results = '';
            
            HTMLParser(html, {
                start: function(tag, attrs, unary) {
                    var i,
                        attrLen = attrs.length;

                    results += '<' + tag;
            
                    for (i=0; i<attrLen; i++)
                        results += ' ' + attrs[i].name + '="' + attrs[i].escaped + '"';
            
                    results += (unary ? '/' : '') + '>';
                },
                end: function(tag) {
                    results += '</' + tag + '>';
                },
                chars: function(text) {
                    if(contentToHTMLEntities && !/\n/.test(text))
                        results += DHF.stringUtils.htmlEncode(text, 'entity');
                    else
                        results += text;
                },
                comment: function(text) {
                    results += '<!--' + text + '-->';
                }
            });
            
            return results;
        },

        mathMLToValidMathML: function(html, contentToHTMLEntities) {
            var results = '';
            
            html = html.replace(/^\s*/, '').replace(/^<(?:\/)?(?:m:)?\s*math(?:\s+xmlns.*)?>/, '').replace(/<(?:\/)?(?:m:)?math\/?>/, '');
                
            HTMLParser(html, {
                start: function(tag, attrs, unary) {
                    var i,
                        attrLen = attrs.length;

                    results += '<' + tag;
            
                    for (i = 0; i < attrLen; i++)
                        results += ' ' + attrs[i].name + '="' + attrs[i].escaped + '"';
            
                    results += (unary ? '/' : '') + '>';
                },
                end: function(tag) {
                    results += '</' + tag + '>';
                },
                chars: function(text) {
                    if(contentToHTMLEntities && !/\n/.test(text)){
                        results += DHF.stringUtils.htmlEncode(text, 'entity');}
                    else
                        results += text;
                },
                comment: function(text) {
                    results += '<!--' + text + '-->';
                }
            });

            results = results.replace('<mo>(</mo>','<mfenced>').replace('<mo>)</mo>','</mfenced>').replace('&nbsp;',' ');
            return '<math>'+results+'</math>';
        }
    }
})();

DHF.collections = {
    'Dictionary': function Dictionary() {
        // Private
        var indexArray=[],
            indexOf = DHF.indexOf;

        var cloneArray = function(arr) {
            var i, clone=[];

            if (DHFIsArray(arr))
                {
                for(i in arr)
                    clone[i]=arr[i];
                }
            return clone;
        };
        
        // Public
        return {
            isDictionary: true,
            constructor: DHF.collections.Dictionary,
            count: 0,
            innerArray: [],
            
            insert: function(key, value) {
                var idx = this.indexOf(key),
                    innerObj={};

                innerObj[key] = value;
                
                if(idx === -1)
                    idx = indexArray.length;

                indexArray[idx] = key;
                this.innerArray[idx] = innerObj;
                
                this.count = indexArray.length;

                return this;
            },
            
            add: function(key, value) {
                this.insert(key, value);
                
                return this;
            },
            
            upsert: function(key, value) {
                if(this.contains(key))
                    this.changeItem(key, value);
                else
                    this.insert(key, value);
                
                return this;
            },
            
            remove: function(key) {
                var idx = this.indexOf(key);
                
                if(idx >= 0)
                {
                    indexArray.splice(idx,1);
                    this.innerArray.splice(idx,1);
                    this.count--;
                }
                
                return this;
            },
            
            item: function(key) {
                var obj = this.innerArray[this.indexOf(key)];
                
                if(obj)
                    return obj[key];
                else
                    return undefined;
            },
            
            getItem: function(key, defaultValue) {
                var theItem = this.item(key);
            
                if(theItem !== undefined)
                    return theItem;
                else
                    return defaultValue;
            },
            
            keyArray: function() {
                return cloneArray(indexArray);
            },
            
            isEmpty: function() {
                return this.count === 0;
            },
            
            removeAll: function() {
                indexArray = [];
                this.innerArray = [];
                this.count = 0;
                
                return this;
            },
            
            changeItem: function(key, value) {
                var idx = this.indexOf(key);
            
                if(idx >= 0)
                    this.innerArray[idx][key] = value;
                else
                    debug.log('changeItem(' + key + ', ' + value + ') failed');

                return this;
            },
            
            contains: function(key) {
                return this.indexOf(key) >= 0;
            },
            
            exists: function(key) {
                return this.contains(key);
            },
            
            getKeyListAsString: function(delim, firstIndex, numEntries) {
                var i,
                    endIndex = indexArray.length - 1,
                    result = '';
                    
                delim = delim || ',';
                firstIndex = firstIndex || 0;
                numEntries = numEntries || -1;
                
                if(numEntries > 0 && firstIndex + numEntries - 1 < endIndex)
                    endIndex = firstIndex + numEntries - 1;
                
                for(i = firstIndex; i <= endIndex; i++) {
                    if(result.length>0)
                        result += delim;

                    result += indexArray[i];
                }
                
                return result;
            },
            
            getInnerArray: function() {
                return this.innerArray;
            },
            
            getIndexArray: function() {
                return indexArray;
            },
            
            indexOf: function(key) {
                return indexOf(key, indexArray);
            },
            getClone: function() {
                var i, key,
                    arrayLen = this.innerArray.length,
                    dict = new DHF.collections.Dictionary();
                
                for(i=0; i<arrayLen; i++) {
                    for(key in this.innerArray[i]) {
                        dict.add(key, DHFClone(this.innerArray[i][key]));
                    }
                }
                
                return dict;
            }
        };
    }
};

DHF.rgbToHex = function(value) {
    return value.replace(/\brgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)/gi, function(_, r, g, b) {
        return '#' + ((1 << 24) + (r << 16) + (g << 8) + (b << 0)).toString(16).substr(-6).toUpperCase();
    });
}

function DHFNodeCredits(typeid, typename, pass, mastery) {
    this.TypeID = typeid;
    this.TypeName = typename;
    this.Pass = pass;
    this.Mastery = mastery;
}

DHFNodeCredits.prototype.Clone = function() {
    return new DHFNodeCredits(this.TypeID, this.TypeName, this.Pass, this.Mastery);
}

function DHFCertificate(certtype, mediaid, mediatitle, scriptguid) {
    this.CertType = certtype;
    this.MediaId = mediaid;
    this.MediaTitle = mediatitle;
    this.ScriptGUID = scriptguid;
    this.TypeName = [];
    this.Credits = [];
}
    
DHFCertificate.prototype.SetTypeName = function(langindex, name) {
    this.TypeName[langindex] = name;
}

DHFCertificate.prototype.GetTypeName = function(langindex) {
    if (this.TypeName[langindex] && this.TypeName[langindex].length > 0) {
        return this.TypeName[langindex];
    }
    
    return str_cert_type_id.SubstBy(this.CertType).GetString();
}

DHFCertificate.prototype.AddCredit = function(credit) {
    this.Credits[this.Credits.length] = credit;
}

DHFCertificate.prototype.RemoveCredit = function(index) {
    this.Credits.splice(index, 1);
}

function DHFCertCredit(credittypeid, credittypename, credits) {
    this.CreditTypeId = credittypeid;
    this.CreditTypeName = credittypename;
    this.Credits = credits;
}

DHF.fixReceptorParams = function(args, excludedIndexes) {
    var i,
        indexOf = DHF.indexOf;
        
    if(excludedIndexes) {
        if(excludedIndexes.constructor === String) {
            excludedIndexes = excludedIndexes.split(",");
        }
    } else {
        excludedIndexes = [];
    }
    
    for(i=0; i < args.length; i++) {
        if(args[i] !== undefined && args[i] !== null && args[i].constructor !== Number && args[i].constructor !== String &&
            args[i].constructor !== Boolean && indexOf(i, excludedIndexes) === -1) {
            
            args[i] = DHFClone(args[i]);
        }
    }
}

DHF.getContentWidth = function(el) {
    var width, oldOverflow;

    if(el && el.constructor === String) {
        el = document.getElementById(el);
    }
    
    if(!el) {
        debug.log('DHF.getContentWidth called using an null or undefined parameter');
        return 0;
    }
    
    oldOverflow = el.style.overflow;
    el.style.overflow = 'auto';
    width = el.scrollWidth;
    el.style.overflow = oldOverflow;
    
    return width;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// BEGIN JSON UTILS
//
if(!window.JSON) {
    window.JSON = {};
}

(function () {

    function f(n) {
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {
        Date.prototype.toJSON = function (key) {
            return isFinite(this.valueOf()) ?
                   this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z' : null;
        };

        String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;

    function quote(string) {		
        var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            meta = {    // table of character substitutions
                '\b': '\\b',
                '\t': '\\t',
                '\n': '\\n',
                '\f': '\\f',
                '\r': '\\r',
                '"' : '\\"',
                '\\': '\\\\'
            };

        escapable.lastIndex = 0;

        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' : '"' + string + '"';	
    }

    function str(key, holder, rep, gap, indent, seen) {
        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            thomas,
            value = holder[key];

        if (value && typeof value === 'object' && typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }
        
        switch (typeof value) {
            case 'string':
                return quote(value);

            case 'number':
                return isFinite(value) ? String(value) : 'null';

            case 'boolean':
            case 'null':
                return String(value);
                
            case 'object':
                if (!value) {
                    return 'null';
                }

                if (DHF.indexOf(value, seen) != -1)  {
                    return undefined;
                }

                seen.push(value); 

                gap += indent;
                partial = [];
                
                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value, rep, gap, indent, seen.slice(0)) || 'null';
                    }

                    v = partial.length === 0 ? '[]' :
                        gap ? '[\n' + gap +
                                partial.join(',\n' + gap) + '\n' +
                                    mind + ']' :
                              '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }

                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        k = rep[i];
                        if (typeof k === 'string') {
                            v = str(k, value, rep, gap, indent, seen.slice(0));
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {

                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = str(k, value, rep, gap, indent, seen.slice(0));
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }
                v = partial.length === 0 ? '{}' :
                    gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                            mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
            break;
        }
    }


    JSON.stringify = function(value, replacer, space) {
        var i, seen,
            gap = '',
            indent = '';
        
        if (typeof space === 'number') {
            for (i = 0; i < space; i += 1) {
                indent += ' ';
            }
        } else if (typeof space === 'string') {
            indent = space;
        }

        if (replacer && typeof replacer !== 'function' &&
                (typeof replacer !== 'object' ||
                 typeof replacer.length !== 'number')) {
            throw new Error('JSON.stringify');
        }

        seen = new Array(25);
        
        return str('', {'': value}, replacer, gap, indent, seen);
    }
        
    JSON.fromISO2Date = function(k,v) {
        if (typeof v != 'string' || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(v))
            return v;
        
        eval("var d = new Date('"+v.replace(/(-|T|:)/g,"','").replace(/Z/,"")+"')");
        
        return d;
    };

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {
            var j;
            
            reviver = reviver || JSON.fromISO2Date;

            function walk(holder, key) {
                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }

            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }
            
            if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
               replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
               replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
                j = eval('(' + text + ')');

                if(typeof reviver === 'function') {
                    return walk({'': j}, '');
                } else {
                    return j;
                } 
            }
        };
    }
}());
//
// END JSON UTILS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




function DHFAjaxRunLO(loid,langid,resume,classid,currnode,loiltinst,startplayer,callback,extendedparams)
	{
	
	var ajaxurl = 'ajax/startaiccsession.aspx?loid='+loid+'&lang'+langid;
	if(startplayer) ajaxurl += '&startplayer=1';
	if(resume) ajaxurl += '&resm=1';
	if(classid) ajaxurl += '&class='+classid;
	if(currnode) ajaxurl += '&currnode='+currnode; 
	if(loiltinst) ajaxurl += '&loiltinst='+loiltinst;
	if(extendedparams) ajaxurl += '&extendedparams='+extendedparams;
	
	DHFAJAX(
			{
			url: ajaxurl,
			type: "script",
			timeout: 60000,
			onSuccess: callback || function(){alert(player_params);}
			});
			
	}

var DBMaxFieldLength=100000;

var msgobj_dynamicDateSyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20does%20not%20contain%20a%20valid%20dynamic%20date%20value.'));
var msgobj_moneySyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20does%20not%20contain%20a%20valid%20money%20value.'));
var msgobj_numberSyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20does%20not%20contain%20a%20valid%20numeric%20value.'));
var msgobj_numberSyntax2=new DHFMsg(msgError,DHFUnescape('%24%241%20consists%20of%20too%20many%20digits%20(%24%242%20is%20the%20limit)'));
var msgobj_dateSyntax=new DHFMsg(msgError,DHFUnescape('%22%24%241%22%20does%20not%20contain%20a%20valid%20date%20value.'));
var msgobj_dateInvalidMonth=new DHFMsg(msgError,DHFUnescape('%22%24%241%22%20does%20not%20contain%20a%20valid%20month%20value.'));
var msgobj_dateInvalidDay=new DHFMsg(msgError,DHFUnescape('%22%24%241%22%20does%20not%20contain%20a%20valid%20day%20value.'));
var msgobj_dateInvalidYear=new DHFMsg(msgError,DHFUnescape('%22%24%241%22%20does%20not%20contain%20a%20valid%20year.'));
var msgobj_dateInvalidDate=new DHFMsg(msgError,DHFUnescape('The%20date%20in%20%22%24%241%22%20should%20be%20in%20the%20following%20format%3a%20%22%24%242%22.'));
var msgobj_timeSyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20doesn\'t%20contain%20a%20valid%20time%20value.%20Format%20hh%3amm'));
var msgobj_urlSyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20doesn\'t%20contain%20a%20valid%20URL.'));
var msgobj_durationSyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20doesn\'t%20contain%20a%20valid%20duration%20value%3a%20mm%2c%20hh%3amm%2c%20or%20DDdhh%3amm.'));
var msgobj_durationSyntaxE=new DHFMsg(msgError,DHFUnescape('%24%241%20doesn\'t%20contain%20a%20valid%20duration%20value%3a%20mm%2c%20hh%3amm%2c%20DDdhh%3amm%2c%20or%20empty%20field.'));
var msgobj_durationSyntaxAlt=new DHFMsg(msgError,DHFUnescape('%24%241%20doesn\'t%20contain%20a%20valid%20duration%20value%3a%20hh%3amm%2c%20or%20DDdhh%3amm.'));
var msgobj_durationSyntaxEAlt=new DHFMsg(msgError,DHFUnescape('%24%241%20doesn\'t%20contain%20a%20valid%20duration%20value%3a%20hh%3amm%2c%20DDdhh%3amm%2c%20or%20empty%20field.'));
var msgobj_idSyntax=new DHFMsg(msgError,DHFUnescape('Incorrect%20%24%241%20syntax.%0d%0a%0d%0aExamples%3a%0d%0a10%3a%20%24%241%2010%0d%0a20-%3a%20%24%241%2020%20or%20greater%0d%0a-10%3a%20%24%241%2010%20or%20less%0d%0a10-20%3a%20%24%241%20from%2010%20to%2020%0d%0a10%2c11%2c15%2c20-30%2c90-%3a%20Combination%0d%0a%7b11111111-1111-1111-1111-111111111111%7d%3a%20GUID'));
var msgobj_minTextLength=new DHFMsg(msgError,DHFUnescape('%24%241%20cannot%20be%20shorter%20than%20%24%242%20characters.'));
var msgobj_maxTextLength=new DHFMsg(msgError,DHFUnescape('%24%241%20cannot%20be%20longer%20than%20%24%242%20characters.'));
var msgobj_checkboxChecked=new DHFMsg(msgError,DHFUnescape('%24%241%20has%20to%20be%20checked.'));
var msgobj_identSyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20can%20only%20contain%20A..Z%20and%200..9%2c%20and%20must%20start%20with%20a%20letter.'));
var msgobj_notEmpty=new DHFMsg(msgError,DHFUnescape('%24%241%20cannot%20be%20left%20empty.'));
var msgobj_notNegative=new DHFMsg(msgError,DHFUnescape('%24%241%20cannot%20be%20negative.'));
var msgobj_positive=new DHFMsg(msgError,DHFUnescape('%24%241%20must%20be%20greater%20than%20zero.'));
var msgobj_greaterThan=new DHFMsg(msgError,DHFUnescape('%24%241%20must%20be%20greater%20than%20%24%242.'));
var msgobj_min=new DHFMsg(msgError,DHFUnescape('%24%241%20cannot%20be%20less%20than%20%24%242.'));
var msgobj_max=new DHFMsg(msgError,DHFUnescape('%24%241%20cannot%20be%20greater%20than%20%24%242.'));
var msgobj_invalid=new DHFMsg(msgError,DHFUnescape('%24%241%20is%20not%20valid.'));
var msgobj_PHEmpty=new DHFMsg(msgError,DHFUnescape('%24%241%20contains%20%5b%5d%20without%20a%20placeholder%20identifier.'));
var msgobj_PHNotClosed=new DHFMsg(msgError,DHFUnescape('%24%241%20contains%20what%20looks%20like%20a%20placeholder.%20But%20the%20placeholder%20needs%20to%20be%20a%20single%20unbroken%20word%20enclosed%20by%20square%20brackets%2c%20for%20example%20%5bname%5d'));
var msgobj_PHUnknown=new DHFMsg(msgError,DHFUnescape('%24%241%20contains%20unknown%20placeholder%20identifier%20%22%24%242%22.'));
var msgobj_PHNotOpened=new DHFMsg(msgError,DHFUnescape('%24%241%20contains%20%5d%20without%20corresponding%20%5b.'));
var msgobj_PHNotAllowed=new DHFMsg(msgError,DHFUnescape('%24%241%20doesn\'t%20support%20placeholders%20(%5b%20and%20%5d%20are%20not%20allowed).'));
var msgobj_PHXSyntax=new DHFMsg(msgError,DHFUnescape('%24%241%20contains%20illegal%20placeholder%20syntax%20%5b%24%242%5d.'));
var strobj_text=new DHFString('Text');
var strobj_textlang=new DHFString(DHFUnescape('Text%20(%24%241)'));
var strobj_userid=new DHFString(DHFUnescape('User%20ID%20%24%241'));
var strobj_contactid=new DHFString(DHFUnescape('Contact%20ID%20%24%241'));
var strobj_info=new DHFString(DHFUnescape('Info%3a%20%24%241'));
var strobj_warning=new DHFString(DHFUnescape('Warning%3a%20%24%241'));
var strobj_error=new DHFString(DHFUnescape('Error%3a%20%24%241'));
var str_procreq=DHFUnescape('Processing%20request...');
var rootUrl = DHFUnescape('http%3a%2f%2fkdmcuniversity.kdmc.net%2fadmin%2ftask%2ftedit_new%2f');
var msgBoxCancel = 1;
var msgBoxOK = 2;
var msgBoxYes = 4;
var msgBoxNo = 8;
var msgBoxBelow = 1;
var msgBoxAbove = 2;
var msgBoxLeft = 4;
var msgBoxRight = 8;
var fldMaxPerForm = 99;
var fldMax = 999;
var formMaxPerForm = 19;
var AllFields=new Array(fldMax);
var AllFieldsCount=0;
var targetgrouponly=0
var targetgroupororganization=1
var organizationonly=2
var userType_admin=1;
var userType_user=3;
var userType_tempuser=5;
var userType_editor=6;
var userType_viewer=7;
var userType_sleeper=9;
var credittype_defaultid=1;
var credittype_defaultname='Default';
var qt_TMC = 0;
var qt_TSC = 1;
var qt_TTF = 2;
var qt_TSP = 3;
var qt_TGI = 4;
var qt_TST = 5;
var qt_TIN = 6;
var qt_TDD = 7;
var qt_TGP = 8;
var qt_TCC = 9;
var qt_CO = 10;
var qt_CR = 11;
var qt_SLSC = 12;
var qt_STIF = 13;
var qt_TIF = 23;
var qt_STMC = 14;
var qt_STSC = 15;
var qt_STCC = 16;
var qt_TMM = 17;
var qt_TSM = 18;
var qt_IHS = 19;
var qt_SCO = 20;
var qt_IDD = 21;
var qt_CAPT = 22;
var qt_FMU = 25;
var qt_SFMU = 26;
var qt_TGDD = 27;
var qt_SEQ = 29;
var qt_GRD = 30;
var qt_CNV = 31;
var qt_MRK = 32;
var qt_TTF = 2;
var lot_IQTST = 0;
var lot_IQWBT = 1;
var lot_IQQUE = 2;
var lot_TST = 10;
var lot_WBT = 11;
var lot_ILT = 50;
var lot_XMAT = 52;
var lot_ILE = 56;
var lot_XTST = 54;
var lot_XLBL = 55;
var lot_WORKFLOW = 60;
var qst_tmc_behaviour_normal = 0;
var ihs_areatype_rect=0;
var ihs_areatype_polygon=1;
var ihsqt_single=0;
var ihsqt_multiple=1;
var dodm_normal=0;
var dodm_frame=1;
var dodm_transparent=2;
var xmattype_medium = 0;
var xmattype_link = 1;
var xmattype_other = 2;
var xmattype_cd = 3;
var xmattype_book = 4;
var xmattype_video = 5;
var xmattype_dvd = 6;
var xmattype_audio = 7;
var xmattype_cdrom = 8;
var xmattype_dvdrom = 9;
var xmattype_software = 10;
var ilttype_vclass = 0;
var ilttype_seminar = 1;
var tddgrp_none=0;
var tddgrp_active=1;
var ttfdisptype_radio=0;
var ttfdisptype_pulldown=1;
var ttftextdisptype_truefalse=0;
var ttftextdisptype_yesno=1;
var ttf_true=1;
var ttf_false=0;
var ttf_MAX=1;
var cm_NONE = 0;
var cm_ABS = 1;
var cm_STEPPED = 2;
var cm_PCREL = 3;
var cm_PASSTHROUGH = 4;
var cm_ONRUN = 5;
var cm_ONFINISH = 6;
var cm_MAX = 6;
var dm_NONE = 0;
var dm_REL = 1;
var dm_YSREL = 2;
var dm_MSREL = 3;
var dm_DSREL = 5;
var dm_WSREL = 4;
var dm_MAX = 5;
var rcm_last = 0;
var rcm_first = 1;
var rcm_best = 2;
var rcm_average = 3;
var rcm_sum = 4;
var rcm_MAX = 4;
var flowm_none = 0;
var flowm_pass = 1;
var flowm_master = 2;
var flowm_run = 3;
var sflowm_none = 0;
var sflowm_apply = 1;
var cst_stud = 1;
var cst_inst = 2;
var cst_waitlist = 3;
var cst_cancel = 4;
var cst_pending = 5;
var cst_interrupted = 6;
var rs_planned = 0;
var rs_unplanned = 1;
var stat_Public = 1;
var stat_Restricted = 2;
var stat_Unreleased = 3;
var stat_Cancelled = 4;
var ftype_resource = -1;
var ftype_room = 0;
var ftype_vehicle = 1;
var scm_normal = 0;
var scm_perchoice = 1;
var scm_qti = 2;
var loscm_pool = 0;
var loscm_poolandtest = 1;
var loscm_test = 2;
var trt_TOPIC = 0;
var trt_TARGETGROUP = 1;
var trt_MEDIACAT = 2;
var trt_CATALOG = 3;
var trt_TASKCAT = 4;
var trt_TOPICBROWSER = 5;
var trt_ORG = 6;
var trt_REPORT = 7;
var trt_FM = 8;
var trt_SKILL = 9;
var trt_FORUM = 10;
var trt_SECURITYGROUP = 11;
var trt_ACCOUNTING = 12;
var trt_MEDIATYPEFILTER = 13;
var trt_COMPCAT = 14;
var wfppojtype_lo = 1;
var news_type_news = 0;
var news_type_mail = 1;
var news_type_dossier = 2;
var news_subtype_news_normal = 0;
var news_subtype_news_compact = 1;
var news_subtype_news_catalog = 2;
var news_subtype_news_topiccatalog = 3;
var news_subtype_news_admincompact = 4;
var newst_normal = 0;
var newst_compact = 1;
var newst_catalog = 2;
var newst_topiccatalog = 3;
var newst_history = 4;
var newst_admincompact = 5;
var accr_all = 4096;
var accr_organisation = 1;
var accr_groups = 2;
var otcstat_active = 1;
var otcstat_inactive = 0;
var rot_sessionleader = 1;
var rot_sessionmanager = 2;
var rot_orgdeliveryaddress = 3;
var rot_orgbillingaddress = 4;
var rot_edumanager = 6;
var rot_homecontact = 7;
var rot_workcontact = 8;
var rot_billingcontact = 9;
var rot_businesscontact = 10;
var lopoolmode_normal = 0;
var lopoolmode_random = 1;
var lopoolmode_adaptive = 2;
var qm_mm_none = 0;
var qm_mm_auto = 1;
var qm_mm_section = 2;
var qm_mm_custom = 3;
var cntarget_user = 0;
var cntarget_supervisor = 1;
var cntarget_360feedback = 2;
var qm_mc_iltinst = 1;
var cnregmode_onlyone = 0;
var cnregmode_multiple = 1;
var cnregmode_all = 2;
var cnregmode_default = 0;
var rtt_generic = 0;
var rtt_usergen = 1;
var cpet_skill = 0;
var cpet_comp = 1;
var usks_test = 0;
var usks_selfassessment = 1;
var usks_supervisorassessment = 2;
var usks_wbt = 3;
var usks_ilt = 4;
var usks_xmat = 5;
var usks_subordinateassessment = 6;
var usks_peerassessment = 7;
var usks_assessment = 8;
var usks_externalassessment = 9;
var usks_externaltraining = 10;
var sgit_user = 0;
var sgit_org = 1;
var sgit_group = 2;
var sgit_COUNT = 3;
var sgir_allow = 0;
var sgir_default = 0;
var gosVisible=false;
var kMaxLODimensions=4;
var kbyte_factor=1000;
var automparam_integerbox=1;
var automparam_staticdropdown=2;
var automparam_currnodedropdown=3;
var automparam_textbox=4;
var automparam_checkbox=5;
var automparam_qmfilter_all=0;
var automparam_qmfilter_qmonly=1;
var automparam_qmfilter_noqm=2;
var automparam_picker=6;
var ortobjtype_test=0;
var ortobjtype_survey=1;
var ortobjtype_wbt=2;
var ortobjtype_ilt=3;
var ortobjtype_training=4;
var ortobjtype_xmat=5;
var ortobjtype_inflearn=6;
var ortobjtype_curriculum=7;
var ortobjtype_class=8;
var ortobjtype_user=9;
var mrktyp_underline=0;
var mrktyp_italic=1;
var mrktyp_strikethru=2;
var mrktyp_firstcolor=10;
var mrktyp_lastcolor=14;
var mrktyp_delete=99;
var mti_none=0;
var mti_img=1;
var mti_flash=2;
var mti_video=3;
var mti_audio=4;
var cf_comment_above=1;
var cf_comment_below=2;
var certmode_usecurrcert=1;
var certmode_disabled=1;
var certmode_enabled=0;
var certmode_normal=0;
var kWeekStartsOnSunday = false;
var kFirstWeekJan1 = false;
var wdnames=[];
wdnames[0]='Sun';
wdnames[1]='Mon';
wdnames[2]='Tue';
wdnames[3]='Wed';
wdnames[4]='Thu';
wdnames[5]='Fri';
wdnames[6]='Sat';
var HTMLCleanerActive=false;
var datePickerWindow=null;
var datePickerTargetFieldID;
function DHFDatePicker(tgtfieldid,past,pastandfuture,enabledynamicdates)
{
 var dynamicdates = '';
 if (enabledynamicdates) dynamicdates = '&dynamicdates=1'; 
if (past)
 {
 datePickerWindow = window.open('http://kdmcuniversity.kdmc.net/lms/popup_calendar.aspx?showaspopup=1&past=1'+dynamicdates,'DHFDATEPICKER','top=0,left=-143,width=286,height=205,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,alwaysRaised=yes,false');
 }
else if(pastandfuture) {
 datePickerWindow = window.open('http://kdmcuniversity.kdmc.net/lms/popup_calendar.aspx?showaspopup=1&pastandfuture=1'+dynamicdates,'DHFDATEPICKER','top=0,left=-143,width=286,height=205,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,alwaysRaised=yes,false');
 }else
 {
 datePickerWindow = window.open('http://kdmcuniversity.kdmc.net/lms/popup_calendar.aspx?showaspopup=1&'+dynamicdates,'DHFDATEPICKER','top=0,left=-143,width=286,height=205,directories=no,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no,alwaysRaised=yes,false');
 }

datePickerWindow.focus();
datePickerTargetFieldID=tgtfieldid;
}
function DHFUnderlineAccessKeyChars()
	{
	}