
 // ##### GLOBALS #####

    var form_dragging = false;
    var form_target;
    var form_mouse_x;
    var form_mouse_y;
    var form_mouse_pos_x;
    var form_mouse_pos_y;
    var form_mouse_up_old;
    var form_expires = new Date();
    form_expires.setTime(form_expires.getTime() + 3600000 * 24 * 30);


    // ##### POPUP MOUSEDOWN #####

    function form_mouse_down (e)
    {
        var ie = navigator.appName == "Microsoft Internet Explorer";

        form_mouse_pos_x = ie ? window.event.clientX : e.clientX;
        form_mouse_pos_y = ie ? window.event.clientY : e.clientY;
    };

    // ##### POPUP MOUSEDOWN WINDOW #####

    function form_mouse_down_window (e)
    {
        var ie = navigator.appName == "Microsoft Internet Explorer";

        if (ie && window.event.button!=1)
        {
            return;
        };
        if (!ie && e.button!=0)
        {
            return;
        };

        form_dragging = true;
        form_target = this ['target'];
        form_mouse_x = ie ? window.event.clientX : e.clientX;
        form_mouse_y = ie ? window.event.clientY : e.clientY;

        if (ie)
        {
            form_mouse_up_old = document.onselectstart;
        }
        else
        {
            form_mouse_up_old = document.onmousedown;
        };

        if (ie)
        {
            document.onselectstart = new Function ("return false;");
        }
        else
        {
            document.onmousedown = new Function ("return false;");
        };
    };


    // ##### POPUP MOUSEMOVE #####

    function form_mouse_move (e)
    {
        var ie = navigator.appName == "Microsoft Internet Explorer";
        var element = document.getElementById (form_target);
        var mouse_x = ie ? window.event.clientX : e.clientX;
        var mouse_y = ie ? window.event.clientY : e.clientY;

        if (!form_dragging) return;

        element.style.left = (element.offsetLeft+mouse_x-form_mouse_x) + 'px';
        element.style.top  = (element.offsetTop +mouse_y-form_mouse_y) + 'px';

        form_mouse_x = ie ? window.event.clientX : e.clientX;
        form_mouse_y = ie ? window.event.clientY : e.clientY;
    };

    // ##### POPUP MOUSEUP #####

    function form_mouse_up (e)
    {
        var ie = navigator.appName == "Microsoft Internet Explorer";
        var element = document.getElementById(form_target);

        if (!form_dragging) return;

        form_dragging = false;

        if (ie)
        {
           document.onselectstart = form_mouse_up_old;
        }
        else
        {
            document.onmousedown   = form_mouse_up_old;
        };

        //alert (form_target+': '+ element.style.left +', '+element.style.top);
        cookie_set (form_target+'.x', element.style.left, form_expires);
        cookie_set (form_target+'.y', element.style.top, form_expires);
    };

    // ##### POPUP EXIT #####

    function form_exit (e)
    {
        var ie = navigator.appName == "Microsoft Internet Explorer";
        var element = document.getElementById(form_target);

        form_mouse_up (e);
        element.style.display = 'none';
        cookie_set (form_target+'.x', '', 0);
        cookie_set (form_target+'.y', '', 0);
    };


    // ##### POPUP SHOW #####

    function form_show (form_name, position, x, y, position_id)
    {
        var element = document.getElementById(form_name);
        var form_postfix = '_' + after_last ('_', form_name);
        var drag_element = document.getElementById('drag'+form_postfix);
        var exit_element = document.getElementById('close'+form_postfix);

        var width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth;
        var height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight;

        element.style.position = "absolute";
        element.style.display = "block";

        if (position == "element" || position == "element-right" || position == "element-bottom")
        {
            var position_element = document.getElementById (position_id);

            for (var p = position_element; p; p = p.offsetParent)
            {
                if (p.style.position != 'absolute')
                {
                    x += p.offsetLeft;
                    y += p.offsetTop;
                };
            };

            if (position=="element-right" )
            {
                x += position_element.clientWidth;
            };
            if (position=="element-bottom")
            {
                y += position_element.clientHeight;
            };

            element.style.left = x + 'px';
            element.style.top = y + 'px';
        };

        if (position == "mouse")
        {
            //element.style.left = (document.documentElement.scrollLeft+form_mouse_pos_x+x)+'px';
            //element.style.top  = (document.documentElement.scrollTop +form_mouse_pos_y+y)+'px';
        };

        if (position == "restore")
        {
            element.style.left = x;
            element.style.top  = y;
        };

        if (position == "screen-top-left")
        {
            element.style.left = (document.documentElement.scrollLeft+x) + 'px';
            element.style.top  = (document.documentElement.scrollTop+y) + 'px';
        };

        if (position == "screen-center")
        {
            element.style.left = (document.documentElement.scrollLeft + (width -element.clientWidth )/2+x) + 'px';
            element.style.top  = (document.documentElement.scrollTop + (height-element.clientHeight)/2+y) + 'px';
        };

        if (position == "screen-bottom-right")
        {
            element.style.left = (document.documentElement.scrollLeft + (width-element.clientWidth)+x) + 'px';
            element.style.top  = (document.documentElement.scrollTop + (height-element.clientHeight)+y) + 'px';
        };

        drag_element ['target'] = form_name;
        drag_element.onmousedown = form_mouse_down_window;

        exit_element.onclick = form_exit;
    };


    // ##### ATTACH EVENTS #####

    if (navigator.appName=="Microsoft Internet Explorer")
    {
         document.attachEvent ('onmousedown', form_mouse_down);
    }
    else
    {
        document.addEventListener ('mousedown', form_mouse_down, false);
    };

    if (navigator.appName=="Microsoft Internet Explorer")
    {
         document.attachEvent ('onmousemove', form_mouse_move);
    }
    else
    {
        document.addEventListener ('mousemove', form_mouse_move, false);
    };

    if (navigator.appName=="Microsoft Internet Explorer")
    {
         document.attachEvent ('onmouseup', form_mouse_up);
    }
    else
    {
        document.addEventListener ('mouseup', form_mouse_up, false);
    };

    function form_restore (form_name)
    {
        if (cookie_get(form_name+'.x') && cookie_get(form_name+'.y'))
        {
            //alert ('restoring '+form_name);
            form_show (form_name, 'restore', cookie_get(form_name+'.x'), cookie_get(form_name+'.y'));
        };
    };

    function cookie_set (name, value, expires, path, domain, secure)
    {
        var curCookie = name + "=" + escape(value) +
            ((expires) ? "; expires=" + expires.toGMTString() : "") +
            ((path) ? "; path=" + escape(path) : "") +
            ((domain) ? "; domain=" + domain : "") +
            ((secure) ? "; secure" : "");
        document.cookie = curCookie;
    };

    function cookie_get (name)
    {
        var dc = document.cookie;
        var prefix = name + "=";
        var begin = dc.indexOf("; " + prefix);

        if (begin == -1)
        {
            begin = dc.indexOf(prefix);
            if (begin != 0) return null;
        }
        else
        {
            begin += 2;
        };

        var end = document.cookie.indexOf(";", begin);

        if (end == -1)
        {
            end = dc.length;
        };

        return unescape(dc.substring(begin + prefix.length, end));
    };

    function strpos (haystack, needle, offset)
    {
        var i = (haystack+'').indexOf(needle, (offset || 0));
        return i === -1 ? false : i;
    };

    function strrpos (haystack, needle, offset)
    {
        var i = -1;
        if (offset)
        {
            i = (haystack+'').slice(offset).lastIndexOf(needle);
            if (i !== -1)
            {
                i += offset;
            };
        }
        else
        {
            i = (haystack+'').lastIndexOf(needle);
        };
        return i >= 0 ? i : false;
    };

    function is_bool (mixed_var)
    {
        return (typeof mixed_var === 'boolean');
    };

    function after (this_, inthat)
    {
        if (!is_bool(strpos(inthat, this_)))
        return substr(inthat, strpos(inthat,this_)+this_.length);
    };

    function after_last (this_, inthat)
    {
        if (!is_bool(strrpos(inthat, this_)))
        return substr(inthat, strrpos(inthat, this_)+this_.length);
    };

    function before (this_, inthat)
    {
        return substr(inthat, 0, strpos(inthat, this_));
    };

    function before_last (this_, inthat)
    {
        return substr(inthat, 0, strrpos(inthat, this_));
    };

    function between (this_, that, inthat)
    {
        return before(that, after(this_, inthat));
    };

    function between_last (this_, that, inthat)
    {
        return after_last(this_, before_last(that, inthat));
    };

    function substr (str, start, len)
    {

        var i = 0, allBMP = true, es = 0, el = 0, se = 0, ret = '';
        str += '';
        var end = str.length;

        // BEGIN REDUNDANT
        this.php_js = this.php_js || {};
        this.php_js.ini = this.php_js.ini || {};
        // END REDUNDANT
        switch(
            (this.php_js.ini['unicode.semantics'] &&
                this.php_js.ini['unicode.semantics'].local_value.toLowerCase())) {
            case 'on': // Full-blown Unicode including non-Basic-Multilingual-Plane characters
                // strlen()
                for (i=0; i < str.length; i++) {
                    if (/[\uD800-\uDBFF]/.test(str.charAt(i)) && /[\uDC00-\uDFFF]/.test(str.charAt(i+1))) {
                        allBMP = false;
                        break;
                    }
                }

                if (!allBMP) {
                    if (start < 0) {
                        for (i = end - 1, es = (start += end); i >= es; i--) {
                            if (/[\uDC00-\uDFFF]/.test(str.charAt(i)) && /[\uD800-\uDBFF]/.test(str.charAt(i-1))) {
                                start--;
                                es--;
                            }
                        }
                    }
                    else {
                        var surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
                        while ((surrogatePairs.exec(str)) != null) {
                            var li = surrogatePairs.lastIndex;
                            if (li - 2 < start) {
                                start++;
                            }
                            else {
                                break;
                            }
                        }
                    }

                    if (start >= end || start < 0) {
                        return false;
                    }
                    if (len < 0) {
                        for (i = end - 1, el = (end += len); i >= el; i--) {
                            if (/[\uDC00-\uDFFF]/.test(str.charAt(i)) && /[\uD800-\uDBFF]/.test(str.charAt(i-1))) {
                                end--;
                                el--;
                            }
                        }
                        if (start > end) {
                            return false;
                        }
                        return str.slice(start, end);
                    }
                    else {
                        se = start + len;
                        for (i = start; i < se; i++) {
                            ret += str.charAt(i);
                            if (/[\uD800-\uDBFF]/.test(str.charAt(i)) && /[\uDC00-\uDFFF]/.test(str.charAt(i+1))) {
                                se++; // Go one further, since one of the "characters" is part of a surrogate pair
                            }
                        }
                        return ret;
                    }
                    break;
                }
                // Fall-through
            case 'off': // assumes there are no non-BMP characters;
                               //    if there may be such characters, then it is best to turn it on (critical in true XHTML/XML)
            default:
                if (start < 0) {
                    start += end;
                }
                end = typeof len === 'undefined' ? end : (len < 0 ? len + end : len + start);
                // PHP returns false if start does not fall within the string.
                // PHP returns false if the calculated end comes before the calculated start.
                // PHP returns an empty string if start and end are the same.
                // Otherwise, PHP returns the portion of the string from start to end.
                return start >= str.length || start < 0 || start > end ? !1 : str.slice(start, end);
        }
        return undefined; // Please Netbeans
    };
