window.Rich = (function () {
    //settings
    var debugMode = false;
    var isRichText = false;
    var defaultHeight = 200;
    var currentEditor = "";
    var selectionText = "";
    var rng;
    var lastCommand;
    var maxLoops = 20;
    var loopAttempt = 0;
    var baseUrl = window.location.protocol + "//" + document.domain + "/";

    var imagesPath = "";
    var includesPath = "";
    var cssFile = "";
    var generateXHTML = true;
    var encodeHTML = false;

    //browser info
    var ua = navigator.userAgent.toLowerCase();
    var isIE = ((ua.indexOf("msie") != -1) && (ua.indexOf("opera") == -1) && (ua.indexOf("webtv") == -1));
    var ieVersion = parseFloat(ua.substring(ua.indexOf('msie ') + 5));
    var isGecko = (navigator.product == 'Gecko');
    var geckoRv = geckoGetRv();
    var isSafari = (ua.indexOf("safari") != -1);
    var isIphone = (ua.indexOf("iphone") != -1);
    var isIpad = (ua.indexOf("ipad") != -1);
    var webkitVersion = getWebkitVersion();
    if (webkitVersion)
        webkitVersion = webkitVersion["major"];
    else
        webkitVersion = null;

    var isKonqueror = (ua.indexOf("konqueror") != -1);
    var isOpera = (ua.indexOf("opera") != -1);
    var isNetscape = (ua.indexOf("netscape") != -1);
    var netscapeVersion = parseFloat(ua.substring(ua.lastIndexOf('/') + 1));

    //commands
    var formatBarEnabled = true;

    var cmdFormatBlockEnabled = true;
    var cmdFontNameEnabled = true;
    var cmdFontSizeEnabled = true;

    var cmdBoldEnabled = true;
    var cmdItalicEnabled = true;
    var cmdUnderlineEnabled = true;
    var cmdStrikethroughEnabled = true;
    var cmdSuperscriptEnabled = true;
    var cmdSubscriptEnabled = true;

    var cmdJustifyLeftEnabled = true;
    var cmdJustifyCenterEnabled = true;
    var cmdJustifyRightEnabled = true;
    var cmdJustifyFullEnabled = true;

    var cmdInsertHorizontalRuleEnabled = true;
    var cmdInsertOrderedListEnabled = true;
    var cmdInsertUnorderedListEnabled = true;

    var cmdOutdentEnabled = true;
    var cmdIndentEnabled = true;
    var cmdForeColorEnabled = true;
    var cmdHiliteColorEnabled = true;
    var cmdInsertHTMLEnabled = true;
    var cmdCreateLinkEnabled = true;
    var cmdInsertImageEnabled = true;

    var cmdUndoEnabled = true;
    var cmdRedoEnabled = true;
    var cmdRemoveFormatEnabled = true;
    var cmdUnlinkEnabled = true;

    function initialize(options) {
        try {
            if (options) {
                debugMode = options.debug ? true : false;
                imagesPath = options.iconsPath ? options.iconsPath : 'Attachment/';
                cssFile = options.bodyCssUrl ? options.bodyCssUrl : '';
                encodeHTML = options.encodeHtml ? true : false;
                generateXHTML = !encodeHTML;
            } else {
                debugMode = false;
                imagesPath = 'Attachment/';
                cssFile = '';
                encodeHTML = false;
                generateXHTML = true;
            }
            includesPath = 'Attachment/';


            if (document.designMode) {
                if (document.getElementById && !isIE && !isSafari && !isKonqueror) {
                    isRichText = true;
                    if (isNetscape && netscapeVersion < 8) {
                        cmdInsertHTMLEnabled = false;
                    }
                } else if (isIE && ieVersion >= 5.5) {
                    isRichText = true;
                } else if (isSafari) {
                    if (isIphone || isIpad) {
                        if (webkitVersion >= 534) {
                            isRichText = true;
                            //formatBarEnabled = false; // and next two lines
                            cmdForeColorEnabled = false;
                            cmdHiliteColorEnabled = false;
                            cmdStrikethroughEnabled = false;
                            cmdJustifyFullEnabled = false;
                            cmdInsertHorizontalRuleEnabled = false;
                            cmdInsertOrderedListEnabled = false;
                            cmdInsertUnorderedListEnabled = false;
                            cmdOutdentEnabled = false;
                            cmdIndentEnabled = false;
                            cmdInsertImageEnabled = false;
                            cmdInsertHTMLEnabled = false;
                            cmdCreateLinkEnabled = false;
                            cmdUnlinkEnabled = false;
                            cmdRemoveFormatEnabled = false;
                        }
                    } else if (webkitVersion >= 420) {
                        isRichText = true;
                    } else if (webkitVersion >= 312) {
                        isRichText = true;
                        formatBarEnabled = false;
                        cmdStrikethroughEnabled = false;
                        cmdJustifyFullEnabled = false;
                        cmdInsertHorizontalRuleEnabled = false;
                        cmdInsertOrderedListEnabled = false;
                        cmdInsertUnorderedListEnabled = false;
                        cmdOutdentEnabled = false;
                        cmdIndentEnabled = false;
                        cmdInsertImageEnabled = false;
                        cmdInsertHTMLEnabled = false;
                        cmdCreateLinkEnabled = false;
                        cmdUnlinkEnabled = false;
                        cmdRemoveFormatEnabled = false;
                    }
                }
            }
            if (isRichText) {
                var colors = document.getElementById('color-palette');
                if (colors != null)
                    return;
                colors = document.createElement('iframe');
                colors.id = 'color-palette';
                colors.width = '150';
                colors.height = '100';
                colors.src = includesPath + 'incolor_palette.htm';
                colors.marginWidth = '0';
                colors.marginHeight = '0';
                colors.scrolling = 'no';
                colors.frameBorder = '0';
                colors.style.visibility = 'hidden';
                colors.style.position = 'absolute';
                document.body.appendChild(colors);
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    TextEditor = function (id) {
        //creates a TextEditor object
        this.rtId = id;

        this.html = "";
        this.height = defaultHeight;
        this.readOnly = false;
        this.formatBar = true;
        this.toolBar = true;

        this.cmdFormatBlock = true;
        this.cmdFontName = true;
        this.cmdFontSize = true;

        this.cmdBold = true;
        this.cmdItalic = true;
        this.cmdUnderline = true;
        this.cmdStrikethrough = true;
        this.cmdSuperscript = true;
        this.cmdSubscript = true;

        this.cmdJustifyLeft = true;
        this.cmdJustifyCenter = true;
        this.cmdJustifyRight = true;
        this.cmdJustifyFull = true;

        this.cmdInsertHorizontalRule = true;
        this.cmdInsertOrderedList = true;
        this.cmdInsertUnorderedList = true;

        this.cmdOutdent = true;
        this.cmdIndent = true;
        this.cmdForeColor = true;
        this.cmdHiliteColor = true;
        this.cmdInsertLink = true;
        this.cmdUnlink = true;
        this.cmdInsertImage = true;
        this.cmdInsertSpecialChars = true;
        this.cmdInsertTable = true;

        this.cmdUndo = true;
        this.cmdRedo = true;
        this.cmdRemoveFormat = true;

        this.toggleSource = true;
        this.toggleHeight = true;


        //add events
        this.changeListener = null;

        //add method
        this.drawIn = drawIn;
        this.setValue = setValue;
        this.getValue = getValue;
        this.setDisabled = setDisabled;
    };

    function drawIn(container) {
        if (typeof container === 'string')
            container = document.getElementById(container);
        with (this) {
            if (isRichText) {
                if (readOnly) {
                    this.formatBar = false;
                    this.toolBar = false;
                    this.toggleSource = false;
                }
                writeRichText(this, container);
                enableDesignMode(this.rtId, htmlDecode(this.html), this.readOnly, this.changeListener);

                if (isGecko && !this.readOnly) {
                    //set focus on the Editor
                    currentEditor = this.rtId;
                    if (geckoRv < 1.09) {
                        insertHTML("<br/>");
                        runCommand(this.rtId, "undo");
                    }
                }

                if (this.toggleSource) document.getElementById("src_" + this.rtId).checked = false;
            } else {
                //Plain Text
                container.innerHTML = '<textarea name="' + this.rtId + '" id="' + this.rtId + '" class="el" style="height: ' + this.height + 'px;"' + (this.readOnly ? ' readonly>' : '>') + htmlEncode(this.html) + '</textarea>';
                var trt = document.getElementById(rtId);

                if (this.changeListener) {
                    if (trt.addEventListener) {
                        trt.addEventListener("keypress", this.changeListener, true);
                        trt.addEventListener("cut", this.changeListener, true);
                        trt.addEventListener("paste", this.changeListener, true);
                    }
                    else if (trt.attachEvent) {
                        trt.attachEvent("onkeypress", this.changeListener);
                        trt.attachEvent("oncut", this.changeListener);
                        trt.attachEvent("onpaste", this.changeListener);
                    }
                }
            }
        }
    }

    function writeRichText(rt, container) {
        try {
            var htmlContent = '<div class="richWrapperDiv">';
            if (formatBarEnabled && rt.formatBar) {
                htmlContent += '<div class="richFormatBarDiv" id="fbar_' + rt.rtId + '">';
                htmlContent += '<span class="richFormatBarSpan">';
                if (cmdFontNameEnabled && rt.cmdFontName) {
                    htmlContent += '<select onchange="Rich.selectFont(\'' + rt.rtId + '\', this, \'fontname\')">';
                    htmlContent += '	<option value="">-Font-</option>';
                    htmlContent += '	<option value="Arial, Helvetica, sans-serif">Arial</option>';
                    htmlContent += '	<option value="Comic Sans MS, cursive, sans-serif">Comic Sans</option>';
                    htmlContent += '	<option value="Courier New, Courier, monospace">Courier</option>';
                    htmlContent += '	<option value="Georgia, serif">Georgia</option>';
                    htmlContent += '	<option value="Impact, Charcoal, sans-serif">Impact</option>';
                    htmlContent += '	<option value="Lucida Sans Unicode, Lucida Grande, sans-serif">Lucida</option>';
                    htmlContent += '	<option value="Palatino Linotype, Book Antiqua, Palatino, serif">Palatino</option>';
                    htmlContent += '	<option value="Times New Roman, Times, serif">Times</option>';
                    htmlContent += '	<option value="Trebuchet MS, Helvetica, sans-serif">Trebuchet</option>';
                    htmlContent += '	<option value="Verdana, Geneva, sans-serif">Verdana</option>';
                    htmlContent += '</select>';
                }
                if (cmdFontSizeEnabled && rt.cmdFontSize) {
                    htmlContent += '<select onchange="Rich.selectFont(\'' + rt.rtId + '\', this, \'fontsize\');">';
                    htmlContent += '	<option value="">-Size-</option>';
                    htmlContent += '	<option value="1">1</option>';
                    htmlContent += '	<option value="2">2</option>';
                    htmlContent += '	<option value="3">3</option>';
                    htmlContent += '	<option value="4">4</option>';
                    htmlContent += '	<option value="5">5</option>';
                    htmlContent += '	<option value="6">6</option>';
                    htmlContent += '	<option value="7">7</option>';
                    htmlContent += '</select>';
                }
                htmlContent += '</span>';
                htmlContent += '<span class="richFormatBarSpan">';
                if (cmdFormatBlockEnabled && rt.cmdFormatBlock) {
                    htmlContent += '<select onchange="Rich.selectFont(\'' + rt.rtId + '\', this, \'formatblock\');">';
                    htmlContent += '	<option value="">-Format-</option>';
                    htmlContent += '	<option value="<p>">Paragraph &lt;p&gt;</option>';
                    htmlContent += '	<option value="<h1>">Heading 1 &lt;h1&gt;</option>';
                    htmlContent += '	<option value="<h2>">Heading 2 &lt;h2&gt;</option>';
                    htmlContent += '	<option value="<h3>">Heading 3 &lt;h3&gt;</option>';
                    htmlContent += '	<option value="<h4>">Heading 4 &lt;h4&gt;</option>';
                    htmlContent += '	<option value="<h5>">Heading 5 &lt;h5&gt;</option>';
                    htmlContent += '	<option value="<h6>">Heading 6 &lt;h6&gt;</option>';
                    htmlContent += '	<option value="<pre>">Formatted &lt;pre&gt;</option>';
                    htmlContent += '	<option value="<address>">Address &lt;addr&gt;</option>';
                    htmlContent += '</select>';
                }
                if (!rt.readOnly && rt.toggleSource)
                    htmlContent += '<input type="button" style="margin-left:4px" id="src_' + rt.rtId + '" onclick="Rich.toggleHTMLSource(\'' + rt.rtId + '\',' + rt.formatBar + ',' + rt.toolBar + ');" value="&lt;/&gt;" />';
                if (rt.toggleHeight)
                    htmlContent += '<input type="button" style="margin-left:4px" id="tht_' + rt.rtId + '" onclick="Rich.toggleHeight(\'' + rt.rtId + '\');" value="&darr;/&uarr;" />';
                htmlContent += '</span>';
                htmlContent += '</div>';
            }
            if (rt.toolBar) {
                htmlContent += '<div class="richToolBarDiv" id="tbar_' + rt.rtId + '">';
                htmlContent += '<span class="richToolBarSpan">';
                if (cmdBoldEnabled && rt.cmdBold)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_style_bold.gif" alt="Bold" title="Bold" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'bold\');"/></span>';
                if (cmdItalicEnabled && rt.cmdItalic)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_style_italic.gif" alt="Italic" title="Italic" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'italic\');"/></span>';
                if (cmdUnderlineEnabled && rt.cmdUnderline)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_style_underline.gif" alt="Underline" title="Underline" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'underline\');"/></span>';
                if (cmdStrikethroughEnabled && rt.cmdStrikethrough)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_style_strikethrough.gif" alt="Strikethrough" title="Strikethrough" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'strikethrough\', \'\');"/></span>';
                if (cmdSuperscriptEnabled && rt.cmdSuperscript)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_style_superscript.gif" alt="Superscript" title="Superscript" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'superscript\');"/></span>';
                htmlContent += '</span>';
                htmlContent += '<span class="richToolBarSpan">';
                if (cmdJustifyLeftEnabled && rt.cmdJustifyLeft)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_align_left.gif" alt="Left Align" title="Left Align" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'justifyleft\');"/></span>';
                if (cmdJustifyCenterEnabled && rt.cmdJustifyCenter)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_align_center.gif" alt="Center Align" title="Center Align" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'justifycenter\');"/></span>';
                if (cmdJustifyRightEnabled && rt.cmdJustifyRight)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_align_right.gif" alt="Right Align" title="Right Align" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'justifyright\');"/></span>';
                if (cmdJustifyFullEnabled && rt.cmdJustifyFull)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_align_justify.gif" alt="Justify Full" title="Justify Full" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'justifyfull\');"/></span>';
                if (cmdSubscriptEnabled && rt.cmdSubscript)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_align_subscript.gif" alt="Subscript" title="Subscript" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'subscript\');"/></span>';
                htmlContent += '</span>';
                htmlContent += '<span class="richToolBarSpan">';
                if (cmdInsertOrderedListEnabled && rt.cmdInsertOrderedList)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_list_number.gif" alt="Ordered List" title="Ordered List" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'insertorderedlist\');"/></span>';
                if (cmdInsertUnorderedListEnabled && rt.cmdInsertUnorderedList)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_list_bullet.gif" alt="Unordered List" title="Unordered List" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'insertunorderedlist\');"/></span>';
                if (cmdOutdentEnabled && rt.cmdOutdent)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_shift_outdent.gif" alt="Outdent" title="Outdent" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'outdent\');"/></span>';
                if (cmdIndentEnabled && rt.cmdIndent)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_shift_indent.gif" alt="Indent" title="Indent" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'indent\');"/></span>';
                if (cmdInsertHorizontalRuleEnabled && rt.cmdInsertHorizontalRule)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_in_hr.gif" alt="Horizontal Rule" title="Horizontal Rule" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'inserthorizontalrule\');"/></span>';
                htmlContent += '</span>';
                htmlContent += '<span class="richToolBarSpan">';
                if ((cmdInsertHTMLEnabled || cmdCreateLinkEnabled) && rt.cmdInsertLink)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_in_link.gif" alt="Insert Link" title="Insert Link" onmousedown="Rich.dlgInsertLink(\'' + rt.rtId + '\');"/></span>';
                if (cmdUnlinkEnabled && rt.cmdUnlink)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_in_unlink.gif" alt="Remove Link" title="Remove Link" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'unlink\');"/></span>';
                if (cmdInsertImageEnabled && rt.cmdInsertImage)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_in_image.gif" alt="Insert Image" title="Insert Image" onmousedown="Rich.dlgInsertImage(\'' + rt.rtId + '\');"/></span>';
                if (cmdInsertHTMLEnabled && rt.cmdInsertSpecialChars)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_in_special_chars.gif" alt="Insert Special Character" title="Insert Special Character" onmousedown="Rich.dlgInsertSpecialChar(\'' + rt.rtId + '\');"/></span>';
                if (cmdInsertHTMLEnabled && rt.cmdInsertTable && !isOpera)
                    htmlContent += '<span id="table_' + rt.rtId + '"><img class="richIcon" src="' + imagesPath + 'rich_in_table.gif" alt="Insert Table" title="Insert Table" onmousedown="Rich.dlgInsertTable(\'' + rt.rtId + '\');"/></span>';
                htmlContent += '</span>';
                htmlContent += '<span class="richToolBarSpan">';
                if (cmdForeColorEnabled && rt.cmdForeColor)
                    htmlContent += '<span id="forecolor_' + rt.rtId + '"><img class="richIcon" src="' + imagesPath + 'rich_color_text.gif" alt="Text Color" title="Text Color" onmousedown="Rich.dlgColorPalette(\'' + rt.rtId + '\', \'forecolor\'); return false;"/></span>';
                if (cmdHiliteColorEnabled && rt.cmdHiliteColor)
                    htmlContent += '<span id="hilitecolor_' + rt.rtId + '"><img class="richIcon" src="' + imagesPath + 'rich_color_back.gif" alt="Background Color" title="Background Color" onmousedown="Rich.dlgColorPalette(\'' + rt.rtId + '\', \'hilitecolor\'); return false;"/></span>';
                if (cmdRemoveFormatEnabled && rt.cmdRemoveFormat)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_act_removeformat.gif" alt="Remove Formatting" title="Remove Formatting" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'removeformat\');"/></span>';
                if (cmdUndoEnabled && rt.cmdUndo)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_act_undo.gif" alt="Undo" title="Undo" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'undo\');"/></span>';
                if (cmdRedoEnabled && rt.cmdRedo)
                    htmlContent += '<span><img class="richIcon" src="' + imagesPath + 'rich_act_redo.gif" alt="Redo" title="Redo" onmousedown="Rich.runCommand(\'' + rt.rtId + '\', \'redo\');"/></span>';
                htmlContent += '</span>';
                htmlContent += '</div>';
            }
            htmlContent += '<iframe id="' + rt.rtId + '" name="' + rt.rtId + '" src="about:blank" frameborder="0" class="richFrame" style="height: ' + rt.height + 'px;"></iframe>';
            htmlContent += '</div>';
            htmlContent += '<div style="margin: 0; padding: 0;">';
            htmlContent += '<input type="hidden" id="hdn_' + rt.rtId + '" name="' + rt.rtId + '" value=""/>';
            htmlContent += '</div>';
            container.innerHTML = htmlContent;
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function enableDesignMode(rt, html, readOnly, changeListener) {
        try {
            var frameStyle;
            if (cssFile.length > 0) {
                frameStyle = "<style type=\"text/css\">@import url(" + cssFile + ");</style>\n";
            } else {
                frameStyle = "<style type=\"text/css\">\n";
                frameStyle += "html, body {\n";
                frameStyle += "	background: #fff;\n";
                frameStyle += "	height: 100%;\n";
                frameStyle += "	-webkit-user-select: text;\n";
                frameStyle += "	user-select: text;\n";
                frameStyle += "}\n";
                frameStyle += "</style>\n";
            }

            var frameHtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
            frameHtml += "<html id=\"" + rt + "\" xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n";
            frameHtml += "<head>\n";
            frameHtml += "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n";
            frameHtml += "<base href=\"" + baseUrl + "\" />\n";
            frameHtml += frameStyle;
            frameHtml += "</head>\n";
            frameHtml += "<body style=\"margin: 0; padding: 0;\" spellcheck=\"true\">\n";
            frameHtml += html + "\n";
            frameHtml += "</body>\n";
            frameHtml += "</html>";

            var ort = document.getElementById(rt);
            ort.changeListener = changeListener;

            try {
                var ortDoc;

                if (isGecko) {
                    if (!readOnly) ort.contentDocument.designMode = "on";
                    try {
                        ortDoc = ort.contentWindow.document;
                        ortDoc.open("text/html", "replace");
                        ortDoc.write(frameHtml);
                        ortDoc.close();
                        if (!readOnly && changeListener) {
                            ortDoc.addEventListener("keyup", changeListener, true);
                            ortDoc.addEventListener("cut", changeListener, true);
                            ortDoc.addEventListener("paste", changeListener, true);
                        }
                    } catch (e) {
                        alert("Error preloading content.");
                    }
                    loopAttempt = 0;
                } else if (ort.contentWindow) {
                    try {
                        ortDoc = ort.contentWindow.document;
                        ortDoc.open("text/html", "replace");
                        ortDoc.write(frameHtml);
                        ortDoc.close();
                        if (!readOnly) {
                            ortDoc.designMode = "on";
                            if (isIE && changeListener) {
                                ortDoc.attachEvent("onkeyup", changeListener);
                                ortDoc.attachEvent("oncut", changeListener);
                                ortDoc.attachEvent("onpaste", changeListener);
                            }
                        }
                    } catch (e) {
                        alert("Error preloading content.");
                    }
                    loopAttempt = 0;
                } else {
                    ortDoc = ort.contentDocument;
                    ortDoc.open("text/html", "replace");
                    ortDoc.write(frameHtml);
                    ortDoc.close();
                    if (!readOnly) {
                        ortDoc.designMode = "on";
                        if (isIE && changeListener) {
                            ortDoc.attachEvent("onkeyup", changeListener);
                            ortDoc.attachEvent("oncut", changeListener);
                            ortDoc.attachEvent("onpaste", changeListener);
                        }
                    }
                    loopAttempt = 0;
                }
            } catch (e) {
                if (loopAttempt < maxLoops) {
                    setTimeout("enableDesignMode('" + rt + "', '" + html + "', " + readOnly + ");", 100);
                    loopAttempt += 1;
                } else {
                    alert("Error enabling designMode.");
                }
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function getValue() {
        try {
            if (isRichText) {
                setHiddenVal(this.rtId);
                var oHdnField = document.getElementById('hdn_' + this.rtId);
                return oHdnField.value;
            } else {
                return document.getElementById(this.rtId).value;
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
        return null;
    }

    function setValue(val) {
        try {
            if (isRichText) {
                var ort = document.getElementById(this.rtId);
                var ortDoc = ort.contentDocument || ort.contentWindow.document;

                if (isIE) { //fix for IE
                    var output = htmlEncode(val);
                    output = output.replace("%3CP%3E%0D%0A%3CHR%3E", "%3CHR%3E");
                    output = output.replace("%3CHR%3E%0D%0A%3C/P%3E", "%3CHR%3E");
                    ortDoc.body.innerHTML = htmlDecode(output);
                } else {
                    //replace char 160 with space '160 &nbsp; space'
                    val = strip160(val);
                    ortDoc.body.innerHTML = val;
                }
            } else {
                document.getElementById(this.rtId).value = val;
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function setDisabled(isTrue) {
        try {
            if (isRichText) {
                var ort = document.getElementById(this.rtId);
                var ortDoc = ort.contentDocument || ort.contentWindow.document;
                ortDoc.body.contentEditable = !isTrue;
                if (!isIE)
                    ortDoc.designMode = isTrue ? 'Off' : 'On';
                ortDoc.body.style.background = isTrue ? '#ccc' : '#fff';
                var prt = document.getElementById('put_' + this.rtId);
                var skipEnableTools = false;
                if (prt != null) {
                    var nprtDoc = prt.contentDocument || prt.contentWindow.document;
                    nprtDoc.body.contentEditable = !isTrue;
                    if (!isIE)
                        nprtDoc.designMode = isTrue ? 'Off' : 'On';
                    nprtDoc.body.style.background = isTrue ? '#ccc' : '#fff';
                    skipEnableTools = (prt.style.display == 'block');
                }
                if (this.formatBar) {
                    var bar = document.getElementById("fbar_" + this.rtId);
                    var sels = bar.getElementsByTagName('input');
                    var i;
                    for (i = 0; i < sels.length; i++)
                        sels[i].disabled = isTrue;
                    if (skipEnableTools)
                        return;
                    sels = bar.getElementsByTagName('select');
                    for (i = 0; i < sels.length; i++)
                        sels[i].disabled = isTrue;
                }
                if (this.toolBar) {
                    if (isTrue)
                        disableToolbar("tbar_" + this.rtId);
                    else
                        enableToolbar("tbar_" + this.rtId);
                }
            } else {
                var txt = document.getElementById(this.rtId);
                txt.disabled = isTrue;
                txt.style.background = isTrue ? '#ccc' : '#fff';
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function runCommand(rt, command, option) {
        try {
            var ort = document.getElementById(rt);
            if (ort.contentWindow) {
                ort.contentWindow.focus();
                ort.contentWindow.document.execCommand(command, false, option);
            } else {
                ort.contentDocument.focus();
                ort.contentDocument.execCommand(command, false, option);
            }
            loopAttempt = 0;
            if (ort.changeListener)
                ort.changeListener();
            return false;
        } catch (e) {
            if (debugMode) alert(e);
            if (loopAttempt < maxLoops) {
                setTimeout("Rich.runCommand('" + rt + "', '" + command + "', '" + option + "');", 100);
                loopAttempt += 1;
            } else {
                alert("Error executing command.");
            }
        }
        return null;
    }

    function dlgColorPalette(rt, command) {
        try {
            setRange(rt);

            var buttonElement = document.getElementById(command + '_' + rt);
            var iLeftPos = findPosX(buttonElement);
            var iTopPos = findPosY(buttonElement) + buttonElement.offsetHeight;
            var oDialog = document.getElementById('color-palette');
            oDialog.style.left = iLeftPos + "px";
            oDialog.style.top = iTopPos + "px";

            if ((command == lastCommand) && (rt == currentEditor)) {
                if (oDialog.style.visibility == "hidden")
                    showHideElement('color-palette', 'show');
                else
                    showHideElement('color-palette', 'hide');
            } else {
                showHideElement('color-palette', 'show');
            }

            lastCommand = command;
            currentEditor = rt;
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function dlgInsertTable(rt) {
        try {
            setRange(rt);
            currentEditor = rt;
            Rich._insertTable = popUpWin(includesPath + 'insert_table.htm', 'insert-table', 220, 200, '');
            if (Rich._insertTable)
                setTimeout("Rich._insertTable.focus()", 100);
            else
                alert("Error launching dialog window!");
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function dlgInsertImage(rt) {
        try {
            if (cmdInsertHTMLEnabled) {
                setRange(rt);
                currentEditor = rt;
                Rich._insertImage = popUpWin(includesPath + 'insert_image.htm', 'insert-image', 220, 160, '');
                if (Rich._insertImage)
                    setTimeout("Rich._insertImage.focus()", 100);
                else
                    alert("Error launching dialog window!");
            } else {
                var imagePath = prompt('Enter Image URL:', 'http://');
                if (imagePath != null && imagePath != "")
                    runCommand(rt, 'insertimage', imagePath);
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function dlgInsertLink(rt) {
        try {
            if (cmdInsertHTMLEnabled) {
                setRange(rt);
                currentEditor = rt;
                Rich._insertLink = popUpWin(includesPath + 'insert_link.htm?selectionText=' + encodeURIComponent(selectionText), 'insert-link', 220, 160, '');
                if (Rich._insertLink)
                    setTimeout("Rich._insertLink.focus()", 100);
                else
                    alert("Error launching dialog window!");
            } else {
                var url = prompt("Enter URL", "http://");
                if (url != null && url != "")
                    runCommand(rt, "createlink", url);
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function dlgInsertSpecialChar(rt) {
        try {
            setRange(rt);
            currentEditor = rt;
            Rich._insertSpecialChar = popUpWin(includesPath + 'insert_special_char.htm', 'insert-special-char', 220, 460, '');
            if (Rich._insertSpecialChar)
                setTimeout("Rich._insertSpecialChar.focus()", 100);
            else
                alert("Error launching dialog window!");
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function popUpWin(url, win, width, height, options, popUp) {
        try {

            if (popUp) {
                var leftPos = (screen.availWidth - width) / 2;
                var topPos = (screen.availHeight - height) / 2;
                options += 'width=' + width + ',height=' + height + ',top=' + topPos + ',left=' + leftPos;
                return window.open(url, win, options);
            }

            var frame = document.getElementById(win);
            if (frame == null) {
                frame = document.createElement('iframe');
                frame.id = win;
                frame.marginWidth = '0';
                frame.marginHeight = '0';
                frame.scrolling = 'no';
                frame.frameBorder = '0';
                frame.style.visibility = 'hidden';
                frame.style.position = 'absolute';
                frame.style.border = '1px solid #333';
                frame.style.left = '50%';
                frame.style.top = '50%';
                document.body.appendChild(frame);
            }

            frame.style.width = width + 'px';
            frame.style.height = height + 'px';
            frame.style.marginLeft = -(width / 2) + 'px';
            frame.style.marginTop = -(height / 2) + 'px';
            frame.src = url;
            if (frame.style.visibility == 'hidden')
                showHideElement(win, 'show');
            else
                showHideElement(win, 'hide');
            return frame;

        } catch (e) {
            if (debugMode) alert(e);
        }
        return null;
    }

    function setColor(color) {
        try {
            var rt = currentEditor;
            if (isSafari || isIE) {
                if (lastCommand == "hilitecolor") lastCommand = "backcolor";

                if (!isSafari) rng.select();
            }

            runCommand(rt, lastCommand, color);
            showHideElement('color-palette', "hide");
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function findPosX(obj) {
        var curleft = 0;
        if (obj.offsetParent) {
            curleft = obj.offsetLeft;
            while (obj = obj.offsetParent) {
                curleft += obj.offsetLeft;
            }
        }
        return curleft;
    }

    function findPosY(obj) {
        var curtop = 0;
        if (obj.offsetParent) {
            curtop = obj.offsetTop;
            while (obj = obj.offsetParent) {
                curtop += obj.offsetTop;
            }
        }
        return curtop;
    }

    function selectFont(rt, sel, selCom) {
        try {
            if (sel.selectedIndex > 0) {
                runCommand(rt, selCom, sel.value);
                sel.selectedIndex = 0;
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function insertHTML(html) {
        try {
            if (document.all && !isOpera) {
                rng.pasteHTML(html);
                rng.collapse(false);
                rng.select();
                var ort = document.getElementById(currentEditor);
                if (ort.changeListener)
                    ort.changeListener();
            } else {
                runCommand(currentEditor, 'inserthtml', html);
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function showHideElement(element, showHide) {
        try {
            if (typeof element === 'string')
                element = document.getElementById(element);

            if (showHide == "show")
                element.style.visibility = "visible";
            else if (showHide == "hide")
                element.style.visibility = "hidden";

        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function setRange(rt) {
        try {
            var ort = document.getElementById(rt);
            var ortDoc;
            if (ort.contentWindow) {
                ortDoc = ort.contentWindow.document;
                ort.contentWindow.focus();
            } else {
                ortDoc = ort.contentDocument;
                ortDoc.focus();
            }

            if (document.all) {
                var sel = ortDoc.selection;
                rng = sel.createRange();
                if (encodeHTML) {
                    selectionText = htmlEncode(rng.text.toString());
                } else {
                    selectionText = rng.text.toString();
                }
            } else if (document.getSelection) {
                rng = ortDoc.createRange();
                if (encodeHTML) {
                    selectionText = htmlEncode(ortDoc.getSelection());
                } else {
                    selectionText = ortDoc.getSelection();
                }
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function stripHTML(oldString) {
        try {
            var newString = oldString.replace(/(<([^>]+)>)/ig, "");

            //replace carriage returns and line feeds
            newString = newString.replace(/\r\n/g, " ");
            newString = newString.replace(/\n/g, " ");
            newString = newString.replace(/\r/g, " ");

            //trim string
            newString = trim(newString);

            return newString;
        } catch (e) {
            if (debugMode) alert(e);
        }
        return null;
    }

    function trim(sInString) {
        try {
            sInString = sInString.replace(/^\s+/g, "");
            return sInString.replace(/\s+$/g, "");
        } catch (e) {
            if (debugMode) alert(e);
        }
        return null;
    }

    function cleanWordContent(wordContent) {
        //strip comments
        //wordContent = String(wordContent).replace(/<!--(.|\n)*?-->/g, "");

        //strip word tags
        //wordContent = String(wordContent).replace(/<\\?\?xml[^>]*>/g, "");
        //wordContent = String(wordContent).replace(/<\/?(.*?):[^>]*>/g, "");

        //strip other dangerous tags
        //wordContent = String(wordContent).replace(/<\/?xml[^>]*>/g, "");
        //wordContent = String(wordContent).replace(/<\/?meta[^>]*>/g, "");
        //wordContent = String(wordContent).replace(/<\/?link[^>]*>/g, "");
        //wordContent = String(wordContent).replace(/<\/?style[^>]*>/g, "");
        //	wordContent = String(wordContent).replace(/&nbsp;/g,"");//<p>&nbsp;</p>
        //	wordContent = String(wordContent).replace(/<\/?SPAN[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?FONT[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?STRONG[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?P[^>]*><\/P>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?H1[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?H2[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?H3[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?H4[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?H5[^>]*>/g,"");
        //	wordContent = String(wordContent).replace(/<\/?H6[^>]*>/g,"");

        //replace line breaks
        wordContent = String(wordContent).replace(/\n/g, " ");

        return trim(wordContent);
    }

    function toggleHeight(rt) {
        var ht = document.getElementById("tht_" + rt);
        ht.disabled = true;
        if (ht.showIncreased === undefined)
            ht.showIncreased = true;
        try {
            var ort = document.getElementById(rt);
            var prt = document.getElementById('put_' + rt);

            var drt = ort.style.display != 'none' ? ort : prt;
            if (ht.showIncreased) {
                drt.style.height = (drt.offsetHeight * 3) + 'px';
                ht.showIncreased = false;
            } else {
                drt.style.height = (drt.offsetHeight / 3) + 'px';
                ht.showIncreased = true;
            }
            var dis = document.getElementById('dis_tbar_' + rt);
            if (dis != null)
                dis.setScreenSize();
        } catch (e) {
            if (debugMode) alert(e);
        }
        ht.disabled = false;
    }

    function toggleHTMLSource(rt, formatBar, toolBar) {
        var btnSrc = document.getElementById("src_" + rt);
        btnSrc.disabled = true;
        if (btnSrc.showHtml === undefined)
            btnSrc.showHtml = true;
        try {
            var ort = document.getElementById(rt);
            var prt = document.getElementById('put_' + rt);
            if (prt == null) {
                prt = document.createElement('iframe');
                prt.id = 'put_' + ort.id;
                prt.name = 'put_' + ort.id;
                prt.src = 'about:blank';
                prt.frameBorder = '0';
                prt.className = 'richFrame';
                prt.style.height = ort.offsetHeight + 'px';
                prt.style.display = 'none';
                ort.parentNode.appendChild(prt);
                var nprtDoc = prt.contentDocument || prt.contentWindow.document;
                nprtDoc.designMode = "on";
                var frameHtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
                frameHtml += "<html id=\"put_" + ort.id + "\" xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n";
                frameHtml += "<head>\n";
                frameHtml += "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />\n";
                frameHtml += "<base href=\"" + baseUrl + "\" />\n";
                frameHtml += "</head>\n";
                frameHtml += "<body style=\"margin: 0; padding: 0;\" spellcheck=\"false\">\n";
                frameHtml += "</body>\n";
                frameHtml += "</html>";
                nprtDoc.open("text/html", "replace");
                nprtDoc.write(frameHtml);
                nprtDoc.close();
                if (ort.changeListener) {
                    if (nprtDoc.addEventListener) {
                        nprtDoc.addEventListener("keypress", ort.changeListener, true);
                        nprtDoc.addEventListener("cut", ort.changeListener, true);
                        nprtDoc.addEventListener("paste", ort.changeListener, true);
                    }
                    else if (nprtDoc.attachEvent) {
                        nprtDoc.attachEvent("onkeypress", ort.changeListener);
                        nprtDoc.attachEvent("oncut", ort.changeListener);
                        nprtDoc.attachEvent("onpaste", ort.changeListener);
                    }
                }
            }
            var prtDoc = prt.contentDocument || prt.contentWindow.document;
            var htmlSrc;

            if (btnSrc.showHtml) {
                if (formatBar)
                    disableFormatBar("fbar_" + rt, true);
                if (toolBar)
                    disableToolbar("tbar_" + rt);

                setHiddenVal(rt);
                var oHdnField = document.getElementById('hdn_' + rt);
                if (encodeHTML) {
                    //htmlSrc = ortDoc.createTextNode(htmlDecode(oHdnField.value));
                    htmlSrc = htmlDecode(oHdnField.value);
                } else {
                    //htmlSrc = ortDoc.createTextNode(oHdnField.value);
                    htmlSrc = oHdnField.value;
                    htmlSrc = htmlSrc.replace(/&/ig, '&amp;').replace(/</ig, '<font color="#800303":&lt;').replace(/>/ig, '&gt;</font>').replace(/color="#800303":&lt;/ig, 'color="#800303">&lt;');
                }

                //prtDoc.body.innerHTML = "";
                //prtDoc.body.appendChild(htmlSrc);
                prtDoc.body.innerHTML = htmlSrc;

                prt.style.display = 'block';
                prt.style.height = ort.offsetHeight + 'px';
                ort.style.display = 'none';
                btnSrc.showHtml = false;
            } else {
                if (formatBar)
                    disableFormatBar("fbar_" + rt, false);
                if (toolBar)
                    enableToolbar("tbar_" + rt);

                if (isIE) {
                    htmlSrc = prtDoc.body.innerText;
                } else {
                    htmlSrc = prtDoc.body.ownerDocument.createRange();
                    htmlSrc.selectNodeContents(prtDoc.body);
                    htmlSrc = htmlSrc.toString();
                }

                var ortDoc = ort.contentDocument || ort.contentWindow.document;

                if (isIE) { //fix for IE
                    var output = htmlEncode(htmlSrc);
                    output = output.replace("%3CP%3E%0D%0A%3CHR%3E", "%3CHR%3E");
                    output = output.replace("%3CHR%3E%0D%0A%3C/P%3E", "%3CHR%3E");
                    ortDoc.body.innerHTML = htmlDecode(output);
                } else {
                    //replace char 160 with space '160 &nbsp; space'
                    htmlSrc = strip160(htmlSrc);
                    ortDoc.body.innerHTML = htmlSrc;
                }

                ort.style.display = 'block';
                ort.style.height = prt.offsetHeight + 'px';
                prt.style.display = 'none';
                btnSrc.showHtml = true;
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
        btnSrc.disabled = false;
    }

    function disableFormatBar(barId, state) {
        var bar = document.getElementById(barId);
        var sels = bar.getElementsByTagName('select');
        for (var i = 0; i < sels.length; i++)
            sels[i].disabled = state;
    }

    function disableToolbar(barId) {
        var bar = document.getElementById(barId);
        var dis = document.getElementById('dis_' + barId);
        if (dis != null)
            return;
        dis = document.createElement('div');
        dis.id = 'dis_' + barId;
        dis.style.background = '#fff';
        dis.style.position = 'relative';
        dis.style.zIndex = '99';
        dis.style.opacity = '0.6';
        dis.style.left = '0';
        dis.style.top = '0';
        dis.style.width = bar.clientWidth + 'px';
        dis.style.height = bar.clientHeight + 'px';

        dis.setScreenSize = function () {
            dis.style.height = '2px';
            dis.style.width = bar.clientWidth + 'px';
            dis.style.height = bar.clientHeight + 'px';
        };

        bar.appendChild(dis);
        if (window.addEventListener)
            window.addEventListener('resize', dis.setScreenSize);
        else if (window.attachEvent)
            window.attachEvent('onresize', dis.setScreenSize);
    }

    function enableToolbar(barId) {
        var bar = document.getElementById(barId);
        var dis = document.getElementById('dis_' + barId);
        if (dis == null)
            return;
        if (window.removeEventListener)
            window.removeEventListener('resize', dis.setScreenSize);
        else if (window.detachEvent)
            window.detachEvent('onresize', dis.setScreenSize);
        bar.removeChild(dis);
    }

    function setHiddenVal(rt) {
        try {
            var oHdnField = document.getElementById('hdn_' + rt);
            if (oHdnField.value == null) oHdnField.value = "";

            var html = getHtmlSrc(rt);
            html = cleanWordContent(html);

            if (generateXHTML)
                html = new Xhtml(html).parse();

            //if there is no content (other than formatting) set value to empty
            if (stripHTML(html.replace("&nbsp;", " ")) == "" &&
			html.toLowerCase().search("<hr") == -1 &&
			html.toLowerCase().search("<img") == -1) html = "";

            if (encodeHTML) {
                oHdnField.value = htmlEncode(html);
            } else {
                oHdnField.value = html;
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
    }

    function getHtmlSrc(rt) {
        try {
            var ort = document.getElementById(rt);
            var ortDoc;
            if (ort.contentWindow)
                ortDoc = ort.contentWindow.document;
            else
                ortDoc = ort.contentDocument;
            return ortDoc.body.innerHTML;
        } catch (e) {
            if (debugMode) alert(e);
        }
        return null;
    }

    function strip160(strHTML) {
        var newString = '';
        for (var i = 0; i < strHTML.length; i++) {
            if (strHTML.charCodeAt(i) == 160) {
                newString = newString + ' ';
            } else {
                newString = newString + strHTML.charAt(i);
            }
        }
        return newString;
    }

    function htmlEncode(text) {
        return text.replace(/\&/ig, '&amp;').replace(/\</ig, '&lt;').replace(/\>/ig, '&gt;').replace(/\"/ig, '&quot;');
    }

    function htmlDecode(text) {
        return text.replace(/\&amp\;/ig, '&').replace(/\&lt\;/ig, '<').replace(/\&gt\;/ig, '>').replace(/\&quot\;/ig, '"');
    }

    function parseWebkitVersion(version) {
        try {
            var bits = version.split(".");
            var isNightly = (version[version.length - 1] == "+");
            var minor;
            if (isNightly) {
                minor = "+";
            } else {
                minor = parseInt(bits[1]); // If minor is Not a Number (NaN) return an empty string
                if (isNaN(minor)) {
                    minor = "";
                }
            }
            return { major: parseInt(bits[0]), minor: minor, is_nightly: isNightly };
        } catch (e) {
            if (debugMode) alert(e);
        }
        return null;
    }

    function getWebkitVersion() {
        try {
            var regex = new RegExp("\\(.*\\) AppleWebKit/(.*) \\((.*)");
            var matches = regex.exec(navigator.userAgent);
            if (matches) {
                var webkitVer = parseWebkitVersion(matches[1]);
                return { major: webkitVer['major'], minor: webkitVer['minor'], is_nightly: webkitVer['is_nightly'] };
            } else {
                return false;
            }
        } catch (e) {
            if (debugMode) alert(e);
        }
        return null;
    }

    function geckoGetRv() {
        if (navigator.product != 'Gecko') {
            return -1;
        }
        var rvValue = 0;
        var gua = navigator.userAgent.toLowerCase();
        var rvStart = gua.indexOf('rv:');
        var rvEnd = gua.indexOf(')', rvStart);
        var rv = gua.substring(rvStart + 3, rvEnd);
        var rvParts = rv.split('.');
        var exp = 1;

        for (var i = 0; i < rvParts.length; i++) {
            var val = parseInt(rvParts[i]);
            rvValue += val / exp;
            exp *= 100;
        }

        return rvValue;
    }

    return {
        initialize: initialize,
        TextEditor: TextEditor,
        selectFont: selectFont,
        runCommand: runCommand,
        dlgColorPalette: dlgColorPalette,
        dlgInsertLink: dlgInsertLink,
        dlgInsertSpecialChar: dlgInsertSpecialChar,
        dlgInsertTable: dlgInsertTable,
        dlgInsertImage: dlgInsertImage,
        setColor: setColor,
        insertHTML: insertHTML,
        toggleHTMLSource: toggleHTMLSource,
        toggleHeight: toggleHeight,
        showHideElement: showHideElement
    };
} ());

function Xhtml(data) {
    this.data = data || "";
}
Xhtml.prototype.setHTML = function (data) {
    this.data = data || this.data;
};
Xhtml.prototype.parse = function () {
    var state = 0;
    var xhtml = "";
    var p = 0;
    var unget = false;
    var tagname = "";
    var attrname = "";
    var attrval = "";
    var quot = "";
    var data = this.data;
    var len = data.length;
    var phpval = "";
    var tagtype = 0;
    var insidepre = false;
    while (1) {
        if (p >= len && !unget) {
            return xhtml;
        }
        if (unget) {
            unget = false;
        } else {
            var c = data.substr(p++, 1);
        }
        switch (state) {
            case 0:
                if (c == "<") {
                    state = 1;
                    break;
                }
                var cc = c.charCodeAt();
                if (Xhtml.charEntities[cc]) {
                    xhtml += "&" + Xhtml.charEntities[cc] + ";";
                } else {
                    xhtml += c;
                }
                break;
            case 1:
                if (/[a-zA-Z]/.test(c)) {
                    state = 2;
                    tagtype = 1;
                    tagname = c.toLowerCase();
                    break;
                }
                if (c == "/") {
                    state = 2;
                    tagtype = -1;
                    break;
                }
                if (c == "!") {
                    if (data.substr(p, 2) == "--") {
                        xhtml += "<!--";
                        p += 2;
                        state = 9;
                        break;
                    }
                    xhtml += "<!";
                    state = 10;
                    break;
                }
                if (c == "?") {
                    state = 11;
                    xhtml += "<" + "?";
                    break;
                }
                xhtml += "&lt;";
                unget = true;
                state = 0;
                break;
            case 2:
                if (Xhtml.isSpaceChar[c]) {
                    xhtml += (!insidepre && tagtype > 0 && Xhtml.hasNLBefore[tagname] && xhtml.length && xhtml.substr(xhtml.length - 1, 1) != "\n" ? "\n" : "") + (tagtype > 0 ? "<" : "</") + tagname;
                    state = 3;
                    break;
                }
                if (c == "/") {
                    xhtml += (!insidepre && tagtype > 0 && Xhtml.hasNLBefore[tagname] && xhtml.length && xhtml.substr(xhtml.length - 1, 1) != "\n" ? "\n" : "") + (tagtype > 0 ? "<" : "</") + tagname;
                    if (data.substr(p, 1) != ">") {
                        state = 3;
                        break;
                    }
                    state = 4;
                    break;
                }
                if (c == ">") {
                    xhtml += (!insidepre && tagtype > 0 && Xhtml.hasNLBefore[tagname] && xhtml.length && xhtml.substr(xhtml.length - 1, 1) != "\n" ? "\n" : "") + (tagtype > 0 ? "<" : "</") + tagname;
                    unget = true;
                    state = 4;
                    break;
                }
                tagname += c.toLowerCase();
                break;
            case 3:
                if (Xhtml.isSpaceChar[c]) {
                    break;
                }
                if (c == "/") {
                    if (data.substr(p, 1) != ">") {
                        break;
                    }
                    state = 4;
                    break;
                }
                if (c == ">") {
                    unget = true;
                    state = 4;
                    break;
                }
                attrname = c.toLowerCase();
                attrval = "";
                state = 5;
                break;
            case 4:
                xhtml += (Xhtml.isEmptyTag[tagname] ? " />" : ">") + (!insidepre && tagtype < 0 && Xhtml.hasNLAfter[tagname] && p < len && data.substr(p, 1) != "\n" ? "\n" : "");
                if (tagtype > 0 && Xhtml.dontAnalyzeContent[tagname]) {
                    state = 13;
                    attrname = attrval = quot = "";
                    tagtype = 0;
                    break;
                }
                if (tagname == "pre") {
                    insidepre = !insidepre;
                }
                state = 0;
                tagname = attrname = attrval = quot = "";
                tagtype = 0;
                break;
            case 5:
                if (Xhtml.isSpaceChar[c]) {
                    xhtml += " " + attrname;
                    if (Xhtml.isEmptyAttr[attrname]) {
                        xhtml += "=\"" + attrname + "\"";
                    }
                    state = 3;
                    break;
                }
                if (c == "/") {
                    xhtml += " " + attrname;
                    if (Xhtml.isEmptyAttr[attrname]) {
                        xhtml += "=\"" + attrname + "\"";
                    }
                    if (data.substr(p, 1) != ">") {
                        state = 3;
                        break;
                    }
                    state = 4;
                    break;
                }
                if (c == ">") {
                    xhtml += " " + attrname;
                    if (Xhtml.isEmptyAttr[attrname]) {
                        xhtml += "=\"" + attrname + "\"";
                    }
                    unget = true;
                    state = 4;
                    break;
                }
                if (c == "=") {
                    xhtml += " " + attrname + "=";
                    state = 6;
                    break;
                }
                if (c == "\"" || c == "'") {
                    attrname += "?";
                } else {
                    attrname += c.toLowerCase();
                }
                break;
            case 6:
                if (Xhtml.isSpaceChar[c]) {
                    xhtml += (Xhtml.isEmptyAttr[attrname] ? "\"" + attrname + "\"" : "\"\"");
                    state = 3;
                    break;
                }
                if (c == ">") {
                    xhtml += (Xhtml.isEmptyAttr[attrname] ? "\"" + attrname + "\"" : "\"\"");
                    unget = true;
                    state = 4;
                    break;
                }
                if (c == "/" && data.substr(p, 1) == ">") {
                    xhtml += (Xhtml.isEmptyAttr[attrname] ? "\"" + attrname + "\"" : "\"\"");
                    state = 4;
                    break;
                }
                if (c == "\"" || c == "'") {
                    quot = c;
                    state = 8;
                    break;
                }
                attrval = c;
                state = 7;
                break;
            case 7:
                if (Xhtml.isSpaceChar[c]) {
                    xhtml += "\"" + Xhtml.escapeQuot(attrval, "\"") + "\"";
                    state = 3;
                    break;
                }
                if (c == "/" && data.substr(p, 1) == ">") {
                    xhtml += "\"" + Xhtml.escapeQuot(attrval, "\"") + "\"";
                    state = 4;
                    break;
                }
                if (c == ">") {
                    unget = true;
                    xhtml += "\"" + Xhtml.escapeQuot(attrval, "\"") + "\"";
                    state = 4;
                    break;
                }
                attrval += c;
                break;
            case 8:
                if (c == quot) {
                    xhtml += "\"" + Xhtml.escapeQuot(attrval, "\"") + "\"";
                    state = 3;
                    break;
                }
                attrval += c;
                break;
            case 9:
                if (c == "-" && data.substr(p, 2) == "->") {
                    p += 2;
                    xhtml += "-->";
                    state = 0;
                    break;
                }
                xhtml += c;
                break;
            case 10:
                if (c == ">") {
                    state = 0;
                }
                xhtml += c;
                break;
            case 11:
                if (c == "'" || c == "\"") {
                    quot = c;
                    state = 12;
                    break;
                }
                if (c == "?" && data.substr(p, 1) == ">") {
                    state = 0;
                    xhtml += "?" + ">";
                    p++;
                    break;
                }
                xhtml += c;
                break;
            case 12:
                if (c == quot) {
                    state = 11;
                    xhtml += quot + Xhtml.escapeQuot(phpval, quot) + quot;
                    phpval = quot = "";
                    break;
                }
                phpval += c;
                break;
            case 13:
                if (c == "<" && data.substr(p, tagname.length + 1).toLowerCase() == "/" + tagname) {
                    unget = true;
                    state = 0;
                    tagname = "";
                    break;
                }
                if (tagname == "textarea") {
                    xhtml += Xhtml.escapeHTMLChar(c);
                } else {
                    xhtml += c;
                }
                break;
        }
    }
    return xhtml;
};
Xhtml.escapeQuot = function (str, quot) {
    if (!quot) {
        quot = "\"";
    }
    if (quot == "\"") {
        return str.replace(/"/ig, "\\\"");
    }
    return str.replace(/'/ig, "\\'");
};
Xhtml.escapeHTMLChar = function (c) {
    if (c == "&") {
        return "&amp;";
    }
    if (c == "<") {
        return "&lt;";
    }
    if (c == ">") {
        return "&gt;";
    }
    var cc = c.charCodeAt();
    if (Xhtml.charEntities[cc]) {
        return "&" + Xhtml.charEntities[cc] + ";";
    } else {
        return c;
    }
};
Xhtml.isSpaceChar = { " ": 1, "\r": 1, "\n": 1, "\t": 1 };
Xhtml.isEmptyTag = { "area": 1, "base": 1, "basefont": 1, "br": 1, "hr": 1, "img": 1, "input": 1, "link": 1, "meta": 1, "param": 1 };
Xhtml.isEmptyAttr = { "checked": 1, "compact": 1, "declare": 1, "defer": 1, "disabled": 1, "ismap": 1, "multiple": 1, "noresize": 1, "nosave": 1, "noshade": 1, "nowrap": 1, "readonly": 1, "selected": 1 };
Xhtml.hasNLBefore = { "div": 1, "p": 1, "table": 1, "tbody": 1, "tr": 1, "td": 1, "th": 1, "title": 1, "head": 1, "body": 1, "script": 1, "comment": 1, "li": 1, "meta": 1, "h1": 1, "h2": 1, "h3": 1, "h4": 1, "h5": 1, "h6": 1, "hr": 1, "ul": 1, "ol": 1, "option": 1, "link": 1 };
Xhtml.hasNLAfter = { "html": 1, "head": 1, "body": 1, "p": 1, "th": 1, "style": 1 };
Xhtml.dontAnalyzeContent = { "textarea": 1, "script": 1, "style": 1 };
Xhtml.charEntities = { 160: "nbsp", 161: "iexcl", 162: "cent", 163: "pound", 164: "curren", 165: "yen", 166: "brvbar", 167: "sect", 168: "uml", 169: "copy", 170: "ordf", 171: "laquo", 172: "not", 173: "shy", 174: "reg", 175: "macr", 176: "deg", 177: "plusmn", 178: "sup2", 179: "sup3", 180: "acute", 181: "micro", 182: "para", 183: "middot", 184: "cedil", 185: "sup1", 186: "ordm", 187: "raquo", 188: "frac14", 189: "frac12", 190: "frac34", 191: "iquest", 192: "Agrave", 193: "Aacute", 194: "Acirc", 195: "Atilde", 196: "Auml", 197: "Aring", 198: "AElig", 199: "Ccedil", 200: "Egrave", 201: "Eacute", 202: "Ecirc", 203: "Euml", 204: "Igrave", 205: "Iacute", 206: "Icirc", 207: "Iuml", 208: "ETH", 209: "Ntilde", 210: "Ograve", 211: "Oacute", 212: "Ocirc", 213: "Otilde", 214: "Ouml", 215: "times", 216: "Oslash", 217: "Ugrave", 218: "Uacute", 219: "Ucirc", 220: "Uuml", 221: "Yacute", 222: "THORN", 223: "szlig", 224: "agrave", 225: "aacute", 226: "acirc", 227: "atilde", 228: "auml", 229: "aring", 230: "aelig", 231: "ccedil", 232: "egrave", 233: "eacute", 234: "ecirc", 235: "euml", 236: "igrave", 237: "iacute", 238: "icirc", 239: "iuml", 240: "eth", 241: "ntilde", 242: "ograve", 243: "oacute", 244: "ocirc", 245: "otilde", 246: "ouml", 247: "divide", 248: "oslash", 249: "ugrave", 250: "uacute", 251: "ucirc", 252: "uuml", 253: "yacute", 254: "thorn", 255: "yuml", 338: "oelig", 339: "oelig", 352: "scaron", 353: "scaron", 376: "yuml", 710: "circ", 732: "tilde", 8194: "ensp", 8195: "emsp", 8201: "thinsp", 8204: "zwnj", 8205: "zwj", 8206: "lrm", 8207: "rlm", 8211: "ndash", 8212: "mdash", 8216: "lsquo", 8217: "rsquo", 8218: "sbquo", 8220: "ldquo", 8221: "rdquo", 8222: "bdquo", 8224: "dagger", 8225: "dagger", 8240: "permil", 8249: "lsaquo", 8250: "rsaquo", 8364: "euro", 402: "fnof", 913: "alpha", 914: "beta", 915: "gamma", 916: "delta", 917: "epsilon", 918: "zeta", 919: "eta", 920: "theta", 921: "iota", 922: "kappa", 923: "lambda", 924: "mu", 925: "nu", 926: "xi", 927: "omicron", 928: "pi", 929: "rho", 931: "sigma", 932: "tau", 933: "upsilon", 934: "phi", 935: "chi", 936: "psi", 937: "omega", 945: "alpha", 946: "beta", 947: "gamma", 948: "delta", 949: "epsilon", 950: "zeta", 951: "eta", 952: "theta", 953: "iota", 954: "kappa", 955: "lambda", 956: "mu", 957: "nu", 958: "xi", 959: "omicron", 960: "pi", 961: "rho", 962: "sigmaf", 963: "sigma", 964: "tau", 965: "upsilon", 966: "phi", 967: "chi", 968: "psi", 969: "omega", 977: "thetasym", 978: "upsih", 982: "piv", 8226: "bull", 8230: "hellip", 8242: "prime", 8243: "prime", 8254: "oline", 8260: "frasl", 8472: "weierp", 8465: "image", 8476: "real", 8482: "trade", 8501: "alefsym", 8592: "larr", 8593: "uarr", 8594: "rarr", 8595: "darr", 8596: "harr", 8629: "crarr", 8656: "larr", 8657: "uarr", 8658: "rarr", 8659: "darr", 8660: "harr", 8704: "forall", 8706: "part", 8707: "exist", 8709: "empty", 8711: "nabla", 8712: "isin", 8713: "notin", 8715: "ni", 8719: "prod", 8721: "sum", 8722: "minus", 8727: "lowast", 8730: "radic", 8733: "prop", 8734: "infin", 8736: "ang", 8743: "and", 8744: "or", 8745: "cap", 8746: "cup", 8747: "int", 8756: "there4", 8764: "sim", 8773: "cong", 8776: "asymp", 8800: "ne", 8801: "equiv", 8804: "le", 8805: "ge", 8834: "sub", 8835: "sup", 8836: "nsub", 8838: "sube", 8839: "supe", 8853: "oplus", 8855: "otimes", 8869: "perp", 8901: "sdot", 8968: "lceil", 8969: "rceil", 8970: "lfloor", 8971: "rfloor", 9001: "lang", 9002: "rang", 9426: "copy", 9674: "loz", 9824: "spades", 9827: "clubs", 9829: "hearts", 9830: "diams" };
