/***

ncBPFramework.DOM 1.3.1

See <http://ncBPFramework.com/> for documentation, downloads, license, etc.

(c) 2005 Bob Ippolito.  All rights Reserved.

***/

if (typeof(dojo) != 'undefined') {
    dojo.provide("ncBPFramework.DOM");
    dojo.require("ncBPFramework.Iter");
}
if (typeof(JSAN) != 'undefined') {
    JSAN.use("ncBPFramework.Iter", []);
}

try {
    if (typeof(ncBPFramework.Iter) == 'undefined') {
        throw "";
    }
} catch (e) {
    throw "ncBPFramework.DOM depends on ncBPFramework.Iter!";
}

if (typeof(ncBPFramework.DOM) == 'undefined') {
    ncBPFramework.DOM = {};
}

ncBPFramework.DOM.NAME = "ncBPFramework.DOM";
ncBPFramework.DOM.VERSION = "1.3.1";
ncBPFramework.DOM.__repr__ = function () {
    return "[" + this.NAME + " " + this.VERSION + "]";
};
ncBPFramework.DOM.toString = function () {
    return this.__repr__();
};

ncBPFramework.DOM.EXPORT = [
    "formContents",
    "currentWindow",
    "currentDocument",
    "withWindow",
    "withDocument",
    "registerDOMConverter",
    "coerceToDOM",
    "createDOM",
    "createDOMFunc",
    "getNodeAttribute",
    "setNodeAttribute",
    "updateNodeAttributes",
    "appendChildNodes",
    "replaceChildNodes",
    "removeElement",
    "swapDOM",
    "BUTTON",
    "TT",
    "PRE",
    "H1",
    "H2",
    "H3",
    "BR",
    "CANVAS",
    "HR",
    "LABEL",
    "TEXTAREA",
    "FORM",
    "STRONG",
    "SELECT",
    "OPTION",
    "OPTGROUP",
    "LEGEND",
    "FIELDSET",
    "P",
    "UL",
    "OL",
    "LI",
    "TD",
    "TR",
    "THEAD",
    "TBODY",
    "TFOOT",
    "TABLE",
    "TH",
    "INPUT",
    "SPAN",
    "A",
    "DIV",
    "IMG",
    "getElement",
    "$",
    "computedStyle",
    "getElementsByTagAndClassName",
    /* START: Custom Netcat */
        "getElementsById",
        "setElementOuterHTML",
        "getElementOuterHTML",
        "getNonTextChildNodes",
        /* END: Custom Netcat */
    "addToCallStack",
    "addLoadEvent",
    "focusOnLoad",
    "setElementClass",
    "toggleElementClass",
    "addElementClass",
    "removeElementClass",
    "swapElementClass",
    "hasElementClass",
    "escapeHTML",
    "toHTML",
    "emitHTML",
    "setDisplayForElement",
    "hideElement",
    "showElement",
    "scrapeText",
    "elementDimensions",
    "elementPosition",
    "setElementDimensions",
    "setElementPosition",
        "getScrollPosition",
    "getViewportDimensions",
        "getWindowDimensions",
    "setOpacity"
];

ncBPFramework.DOM.EXPORT_OK = [
    "domConverters"
];

ncBPFramework.DOM.Dimensions = function (w, h) {
    this.w = w;
    this.h = h;
};

ncBPFramework.DOM.Dimensions.prototype.repr = function () {
    var repr = ncBPFramework.Base.repr;
    return "{w: "  + repr(this.w) + ", h: " + repr(this.h) + "}";
};

ncBPFramework.DOM.Coordinates = function (x, y) {
    this.x = x;
    this.y = y;
};

ncBPFramework.DOM.Coordinates.prototype.repr = function () {
    var repr = ncBPFramework.Base.repr;
    return "{x: "  + repr(this.x) + ", y: " + repr(this.y) + "}";
};

ncBPFramework.DOM.Coordinates.prototype.toString = function () {
    return this.repr();
};

ncBPFramework.Base.update(ncBPFramework.DOM, {

    setOpacity: function(elem, o) {
        elem = ncBPFramework.DOM.getElement(elem);
        ncBPFramework.DOM.updateNodeAttributes(elem, {'style': {
                'opacity': o, 
                '-moz-opacity': o,
                '-khtml-opacity': o,
                'filter':' alpha(opacity=' + (o * 100) + ')'
            }});
    },
    
    getViewportDimensions: function() {
        var d = new ncBPFramework.DOM.Dimensions();
        
        var w = ncBPFramework.DOM._window;
        var b = ncBPFramework.DOM._document.body;
        
        if (w.innerWidth) {
            d.w = w.innerWidth;
            d.h = w.innerHeight;
        } else if (b.parentElement.clientWidth) {
            d.w = b.parentElement.clientWidth;
            d.h = b.parentElement.clientHeight;
        } else if (b && b.clientWidth) {
            d.w = b.clientWidth;
            d.h = b.clientHeight;
        }
        return d;
    },
        
        // Custom Netcat
        getWindowDimensions: function(theWin) {
        var d = new ncBPFramework.DOM.Dimensions();
        
        var w = theWin;
        var b = theWin.document.body;
        
        if (w.innerWidth) {
            d.w = w.innerWidth;
            d.h = w.innerHeight;
        } else if (b.parentElement.clientWidth) {
            d.w = b.parentElement.clientWidth;
            d.h = b.parentElement.clientHeight;
        } else if (b && b.clientWidth) {
            d.w = b.clientWidth;
            d.h = b.clientHeight;
        }
        return d;
    },
        
        // Custom Netcat
        // xScrollTop, Copyright 2001-2007 Michael Foster (Cross-Browser.com)
        // Part of X, a Cross-Browser Javascript Library, Distributed under the terms of the GNU LGPL
        
        getScrollPosition: function (e, bWin) {
                var d = new ncBPFramework.DOM.Dimensions();
          var offset=0;
          if (!(e) || bWin || e == document || e.tagName.toLowerCase() == 'html' || e.tagName.toLowerCase() == 'body') {
                var w = window;
                if (bWin && e) w = e;
                if(w.document.documentElement && w.document.documentElement.scrollTop) offset=w.document.documentElement.scrollTop;
                else if(w.document.body && (w.document.body.scrollTop)) offset=w.document.body.scrollTop;
          }
          else {
                e = getElementById(e);
                if (e && parseInt(e.scrollTop)) offset = e.scrollTop;
          }
          d.w = 0;
      d.h = offset;
          
          return d;
        },
        
        getViewportOffset: function() {
                var d = new ncBPFramework.DOM.Dimensions();
                
                var w = ncBPFramework.DOM._window;
        var b = ncBPFramework.DOM._document.body;
        
                try {
        if (w.pageXOffset) {
            d.w = w.pageXOffset;
            d.h = w.pageYOffset;
        } else if (b.parentElement.scrollLeft) {
            d.w = b.parentElement.scrollLeft;
            d.h = b.parentElement.scrollTop;
        } else if (b && b.scrollLeft) {
            d.w = b.scrollLeft;
            d.h = b.scrollTop;
        }
                } catch (e) {}
        return d;
        },

    elementDimensions: function (elem) {
        var self = ncBPFramework.DOM;
        if (typeof(elem.w) == 'number' || typeof(elem.h) == 'number') {
            return new self.Dimensions(elem.w || 0, elem.h || 0);
        }
        elem = self.getElement(elem);
        if (!elem) {
            return undefined;
        }
        if (self.computedStyle(elem, 'display') != 'none') {
            return new self.Dimensions(elem.offsetWidth || 0, 
                elem.offsetHeight || 0);
        }
        var s = elem.style;
        var originalVisibility = s.visibility;
        var originalPosition = s.position;
        s.visibility = 'hidden';
        s.position = 'absolute';
        s.display = '';
        var originalWidth = elem.offsetWidth;
        var originalHeight = elem.offsetHeight;
        s.display = 'none';
        s.position = originalPosition;
        s.visibility = originalVisibility;
        return new self.Dimensions(originalWidth, originalHeight);
    },

    /* 

        elementPosition is adapted from YAHOO.util.Dom.getXY, version 0.9.0.
        Copyright: Copyright (c) 2006, Yahoo! Inc. All rights reserved.
        License: BSD, http://developer.yahoo.net/yui/license.txt

    */
    elementPosition: function (elem, /* optional */relativeTo) {
        var self = ncBPFramework.DOM;        
        elem = self.getElement(elem);
        
        if (!elem) { 
            return undefined;
        }

        var c = new self.Coordinates(0, 0);
        
        if (elem.x && elem.y) {
            /* it's just a ncBPFramework.DOM.Coordinates object */
            c.x += elem.x || 0;
            c.y += elem.y || 0;
            return c;
        } else if (elem.parentNode === null || self.computedStyle(elem, 'display') == 'none') {
            return undefined;
        }
        
        var box = null;
        var parent = null;
        
        var d = ncBPFramework.DOM._document;
        var de = d.documentElement;
        var b = d.body;            
    
        if (elem.getBoundingClientRect) { // IE shortcut
            
            /*
            
                The IE shortcut is off by two:
                http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/getboundingclientrect.asp
                
            */
            box = elem.getBoundingClientRect();
                        
            c.x += box.left + 
                (de.scrollLeft || b.scrollLeft) - 
                (de.clientLeft || b.clientLeft);
            
            c.y += box.top + 
                (de.scrollTop || b.scrollTop) - 
                (de.clientTop || b.clientTop);
            
        } else if (d.getBoxObjectFor) { // Gecko shortcut
            box = d.getBoxObjectFor(elem);
            c.x += box.x;
            c.y += box.y;
        } else if (elem.offsetParent) {
            c.x += elem.offsetLeft;
            c.y += elem.offsetTop;
            parent = elem.offsetParent;
            
            if (parent != elem) {
                while (parent) {
                    c.x += parent.offsetLeft;
                    c.y += parent.offsetTop;
                    parent = parent.offsetParent;
                }
            }

            /*
                
                Opera < 9 and old Safari (absolute) incorrectly account for 
                body offsetTop and offsetLeft.
                
            */            
            var ua = navigator.userAgent.toLowerCase();
            if ((typeof(opera) != "undefined" && 
                parseFloat(opera.version()) < 9) || 
                (ua.indexOf('safari') != -1 && 
                self.computedStyle(elem, 'position') == 'absolute')) {
                                
                c.x -= b.offsetLeft;
                c.y -= b.offsetTop;
                
            }
        }
        
        if (typeof(relativeTo) != 'undefined') {
            relativeTo = arguments.callee(relativeTo);
            if (relativeTo) {
                c.x -= (relativeTo.x || 0);
                c.y -= (relativeTo.y || 0);
            }
        }
        
        if (elem.parentNode) {
            parent = elem.parentNode;
        } else {
            parent = null;
        }
        
        while (parent && parent.tagName != 'BODY' && 
            parent.tagName != 'HTML') {
            c.x -= parent.scrollLeft;
            c.y -= parent.scrollTop;        
            if (parent.parentNode) {
                parent = parent.parentNode;
            } else {
                parent = null;
            }
        }
        
        return c;
    },
    
    setElementDimensions: function (elem, newSize/* optional */, units) {
        elem = ncBPFramework.DOM.getElement(elem);
        if (typeof(units) == 'undefined') {
            units = 'px';
        }
        ncBPFramework.DOM.updateNodeAttributes(elem, {'style': {
            'width': newSize.w + units, 
            'height': newSize.h + units
        }});
    },
    
    setElementPosition: function (elem, newPos/* optional */, units) {
        elem = ncBPFramework.DOM.getElement(elem);
        if (typeof(units) == 'undefined') {
            units = 'px';
        }
        ncBPFramework.DOM.updateNodeAttributes(elem, {'style': {
            'left': newPos.x + units,
            'top': newPos.y + units
        }});
    },
    
    currentWindow: function () {
        return ncBPFramework.DOM._window;
    },

    currentDocument: function () {
        return ncBPFramework.DOM._document;
    },

    withWindow: function (win, func) {
        var self = ncBPFramework.DOM;
        var oldDoc = self._document;
        var oldWin = self._win;
        var rval;
        try {
            self._window = win;
            self._document = win.document;
            rval = func();
        } catch (e) {
            self._window = oldWin;
            self._document = oldDoc;
            throw e;
        }
        self._window = oldWin;
        self._document = oldDoc;
        return rval;
    },

    formContents: function (elem/* = document */) {
        var names = [];
        var values = [];
        var m = ncBPFramework.Base;
        var self = ncBPFramework.DOM;
        if (typeof(elem) == "undefined" || elem === null) {
            elem = self._document;
        } else {
            elem = self.getElement(elem);
        }
        m.nodeWalk(elem, function (elem) {
            var name = elem.name;
            if (m.isNotEmpty(name)) {
                var tagName = elem.nodeName;
                if (tagName == "INPUT"
                    && (elem.type == "radio" || elem.type == "checkbox")
                    && !elem.checked
                ) {
                    return null;
                }
                if (tagName == "SELECT") {
                    if (elem.selectedIndex >= 0) {
                        var opt = elem.options[elem.selectedIndex];
                        names.push(name);
                        values.push((opt.value) ? opt.value : opt.text);
                        return null;
                    }
                    // no form elements?
                    names.push(name);
                    values.push("");
                    return null;
                }
                if (tagName == "FORM" || tagName == "P" || tagName == "SPAN"
                    || tagName == "DIV"
                ) {
                    return elem.childNodes;
                }
                names.push(name);
                values.push(elem.value || '');
                return null;
            }
            return elem.childNodes;
        });
        return [names, values];
    },

    withDocument: function (doc, func) {
        var self = ncBPFramework.DOM;
        var oldDoc = self._document;
        var rval;
        try {
            self._document = doc;
            rval = func();
        } catch (e) {
            self._document = oldDoc;
            throw e;
        }
        self._document = oldDoc;
        return rval;
    },

    registerDOMConverter: function (name, check, wrap, /* optional */override) {
        ncBPFramework.DOM.domConverters.register(name, check, wrap, override);
    },

    coerceToDOM: function (node, ctx) {
        var im = ncBPFramework.Iter;
        var self = ncBPFramework.DOM;
        var iter = im.iter;
        var repeat = im.repeat;
        var imap = im.imap;
        var domConverters = self.domConverters;
        var coerceToDOM = self.coerceToDOM;
        var NotFound = ncBPFramework.Base.NotFound;
        while (true) {
            if (typeof(node) == 'undefined' || node === null) {
                return null;
            }
            if (typeof(node.nodeType) != 'undefined' && node.nodeType > 0) {
                return node;
            }
            if (typeof(node) == 'number' || typeof(node) == 'boolean') {
                node = node.toString();
                // FALL THROUGH
            }
            if (typeof(node) == 'string') {
                return self._document.createTextNode(node);
            }
            if (typeof(node.toDOM) == 'function') {
                node = node.toDOM(ctx);
                continue;
            }
            if (typeof(node) == 'function') {
                node = node(ctx);
                continue;
            }

            // iterable
            var iterNodes = null;
            try {
                iterNodes = iter(node);
            } catch (e) {
                // pass
            }
            if (iterNodes) {
                return imap(
                    coerceToDOM,
                    iterNodes,
                    repeat(ctx)
                );
            }

            // adapter
            try {
                node = domConverters.match(node, ctx);
                continue;
            } catch (e) {
                if (e != NotFound) {
                    throw e;
                }
            }

            // fallback
            return self._document.createTextNode(node.toString());
        }
        // mozilla warnings aren't too bright
        return undefined;
    },
        
    setNodeAttribute: function (node, attr, value) {
        var o = {};
        o[attr] = value;
        try {
            return ncBPFramework.DOM.updateNodeAttributes(node, o);
        } catch (e) {
            // pass
        }
        return null;
    },

    getNodeAttribute: function (node, attr) {
        var self = ncBPFramework.DOM;
        var rename = self.attributeArray.renames[attr];
        node = self.getElement(node);
        try {
            if (rename) {
                return node[rename];
            }
            return node.getAttribute(attr);
        } catch (e) {
            // pass
        }
        return null;
    },

    updateNodeAttributes: function (node, attrs) {
        var elem = node;
        var self = ncBPFramework.DOM;
        if (typeof(node) == 'string') {
            elem = self.getElement(node);
        }
        if (attrs) {
            var updatetree = ncBPFramework.Base.updatetree;
            if (self.attributeArray.compliant) {
                // not IE, good.
                for (var k in attrs) {
                    var v = attrs[k];
                    if (typeof(v) == 'object' && typeof(elem[k]) == 'object') {
                        updatetree(elem[k], v);
                    } else if (k.substring(0, 2) == "on") {
                        if (typeof(v) == "string") {
                            v = new Function(v);
                        }
                        elem[k] = v;
                    } else {
                        elem.setAttribute(k, v);
                    }
                }
            } else {
                // IE is insane in the membrane
                var renames = self.attributeArray.renames;
                for (k in attrs) {
                    v = attrs[k];
                    var renamed = renames[k];
                    if (k == "style" && typeof(v) == "string") {
                        elem.style.cssText = v;
                    } else if (typeof(renamed) == "string") {
                        elem[renamed] = v;
                    } else if (typeof(elem[k]) == 'object'
                            && typeof(v) == 'object') {
                        updatetree(elem[k], v);
                    } else if (k.substring(0, 2) == "on") {
                        if (typeof(v) == "string") {
                            v = new Function(v);
                        }
                        elem[k] = v;
                    } else {
                        elem.setAttribute(k, v);
                    }
                }
            }
        }
        return elem;
    },

    appendChildNodes: function (node/*, nodes...*/) {
        var elem = node;
        var self = ncBPFramework.DOM;
        if (typeof(node) == 'string') {
            elem = self.getElement(node);
        }
        var nodeStack = [
            self.coerceToDOM(
                ncBPFramework.Base.extend(null, arguments, 1),
                elem
            )
        ];
        var concat = ncBPFramework.Base.concat;
        while (nodeStack.length) {
            var n = nodeStack.shift();
            if (typeof(n) == 'undefined' || n === null) {
                // pass
            } else if (typeof(n.nodeType) == 'number') {
                elem.appendChild(n);
            } else {
                nodeStack = concat(n, nodeStack);
            }
        }
        return elem;
    },

    replaceChildNodes: function (node/*, nodes...*/) {
        var elem = node;
        var self = ncBPFramework.DOM;
        if (typeof(node) == 'string') {
            elem = self.getElement(node);
            arguments[0] = elem;
        }
        var child;
        while ((child = elem.firstChild)) {
            elem.removeChild(child);
        }
        if (arguments.length < 2) {
            return elem;
        } else {
            return self.appendChildNodes.apply(this, arguments);
        }
    },

    createDOM: function (name, attrs/*, nodes... */) {
        /*

            Create a DOM fragment in a really convenient manner, much like
            Nevow's <http://nevow.com> stan.

        */

        var elem;
        var self = ncBPFramework.DOM;
        var m = ncBPFramework.Base;
        if (typeof(attrs) == "string" || typeof(attrs) == "number") {
            var args = m.extend([name, null], arguments, 1);
            return arguments.callee.apply(this, args);
        }
        if (typeof(name) == 'string') {
            // Internet Explorer is dumb
            if (attrs && "name" in attrs && !self.attributeArray.compliant) {
                // http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/name_2.asp
                name = ('<' + name + ' name="' + self.escapeHTML(attrs.name)
                    + '">');
            }
            elem = self._document.createElement(name);
        } else {
            elem = name;
        }
        if (attrs) {
            self.updateNodeAttributes(elem, attrs);
        }
        if (arguments.length <= 2) {
            return elem;
        } else {
            var args = m.extend([elem], arguments, 2);
            return self.appendChildNodes.apply(this, args);
        }
    },

    createDOMFunc: function (/* tag, attrs, *nodes */) {
        var m = ncBPFramework.Base;
        return m.partial.apply(
            this,
            m.extend([ncBPFramework.DOM.createDOM], arguments)
        );
    },

    swapDOM: function (dest, src) {
        var self = ncBPFramework.DOM;
        dest = self.getElement(dest);
        var parent = dest.parentNode;
        if (src) {
            src = self.getElement(src);
            parent.replaceChild(src, dest);
        } else {
            parent.removeChild(dest);
        }
        return src;
    },

    getElement: function (id) {
        var self = ncBPFramework.DOM;
        if (arguments.length == 1) {
            return ((typeof(id) == "string") ?
                self._document.getElementById(id) : id);
        } else {
            return ncBPFramework.Base.map(self.getElement, arguments);
        }
    },

    computedStyle: function (htmlElement, cssProperty, mozillaEquivalentCSS) {
        if (arguments.length == 2) {
            mozillaEquivalentCSS = cssProperty;
        }   
        var self = ncBPFramework.DOM;
        var el = self.getElement(htmlElement);
        var document = self._document;
        if (!el || el == document) {
            return undefined;
        }
        if (el.currentStyle) {
            return el.currentStyle[cssProperty];
        }
        if (typeof(document.defaultView) == 'undefined') {
            return undefined;
        }
        if (document.defaultView === null) {
            return undefined;
        }
        var style = document.defaultView.getComputedStyle(el, null);
        if (typeof(style) == "undefined" || style === null) {
            return undefined;
        }
        return style.getPropertyValue(mozillaEquivalentCSS);
    },

    getElementsByTagAndClassName: function (tagName, className,
            /* optional */parent) {
        var self = ncBPFramework.DOM;
        if (typeof(tagName) == 'undefined' || tagName === null) {
            tagName = '*';
        }
        if (typeof(parent) == 'undefined' || parent === null) {
            parent = self._document;
        }
        parent = self.getElement(parent);
        var children = (parent.getElementsByTagName(tagName)
            || self._document.all);
        if (typeof(className) == 'undefined' || className === null) {
            return ncBPFramework.Base.extend(null, children);
        }

        var elements = [];
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            var classNames = child.className.split(' ');
            for (var j = 0; j < classNames.length; j++) {
                if (classNames[j] == className) {
                    elements.push(child);
                    break;
                }
            }
        }

        return elements;
    },
    
    /* START: Custom Netcat */
    getElementsById: function (id, /*optional*/parent) {
        var self = ncBPFramework.DOM;
        if (typeof(id) == 'undefined' || id === null) {
            id = '*';
        }
        if (typeof(parent) == 'undefined' || parent === null) {
            parent = self._document;
        }
        parent = self.getElement(parent);
        var children = (parent.getElementsByTagName('*')
            || self._document.all);
        if (id == '*') {
            return ncBPFramework.Base.extend(null, children);
        }

        var elements = [];
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child.id == id) {
                elements.push(child);
            }
        }

        return elements;
    },
        _emptyTags: {
                "IMG":   true,
                "BR":    true,
                "INPUT": true,
                "META":  true,
                "LINK":  true,
                "PARAM": true,
                "HR":    true
        },
        getElementOuterHTML: function (elem) {
                if (typeof(elem.outerHTML) == 'undefined') {
                        var s = ncBPFramework.DOM;
                        var attrs = elem.attributes;
                        var str = "<" + elem.tagName;
                        for (var i = 0; i < attrs.length; i++)
                                str += " " + attrs[i].name + "=\"" + attrs[i].value + "\"";
                        if (s._emptyTags[elem.tagName])
                                return str + " />";
                        
                        return str + ">" + elem.innerHTML + "</" + elem.tagName + ">";
                        
                } else {
                        return elem.outerHTML;
                }
        },
        setElementOuterHTML: function (elem, sHTML) {
                if (typeof(elem.outerHTML) == 'undefined') {
                        var r = elem.ownerDocument.createRange();
                        r.setStartBefore(elem);
                        var df = r.createContextualFragment(sHTML);
                        elem.parentNode.replaceChild(df, elem);
                        return df;
                } else {
                        elem.outerHTML = sHTML;
                        return elem;
                }
        },
        getNonTextChildNodes: function (parent) {
                var children = [];
                for (var i=0;i<parent.childNodes.length;i++) {
                        if (parent.childNodes[i].nodeType != 3) {
                                children[children.length]=parent.childNodes[i];
                        }
                }
                return ncBPFramework.Base.extend(null, children);
        },
        /* END: Custom Netcat */


    _newCallStack: function (path, once) {
        var rval = function () {
            var callStack = arguments.callee.callStack;
            for (var i = 0; i < callStack.length; i++) {
                if (callStack[i].apply(this, arguments) === false) {
                    break;
                }
            }
            if (once) {
                try {
                    this[path] = null;
                } catch (e) {
                    // pass
                }
            }
        };
        rval.callStack = [];
        return rval;
    },

    addToCallStack: function (target, path, func, once) {
        var self = ncBPFramework.DOM;
        var existing = target[path];
        var regfunc = existing;
        if (!(typeof(existing) == 'function'
                && typeof(existing.callStack) == "object"
                && existing.callStack !== null)) {
            regfunc = self._newCallStack(path, once);
            if (typeof(existing) == 'function') {
                regfunc.callStack.push(existing);
            }
            target[path] = regfunc;
        }
        regfunc.callStack.push(func);
    },

    addLoadEvent: function (func) {
        var self = ncBPFramework.DOM;
        self.addToCallStack(self._window, "onload", func, true);
        
    },

    focusOnLoad: function (element) {
        var self = ncBPFramework.DOM;
        self.addLoadEvent(function () {
            element = self.getElement(element);
            if (element) {
                element.focus();
            }
        });
    },
            
    setElementClass: function (element, className) {
        var self = ncBPFramework.DOM;
        var obj = self.getElement(element);
        if (self.attributeArray.compliant) {
            obj.setAttribute("class", className);
        } else {
            obj.setAttribute("className", className);
        }
    },
            
    toggleElementClass: function (className/*, element... */) {
        var self = ncBPFramework.DOM;
        for (var i = 1; i < arguments.length; i++) {
            var obj = self.getElement(arguments[i]);
            if (!self.addElementClass(obj, className)) {
                self.removeElementClass(obj, className);
            }
        }
    },

    addElementClass: function (element, className) {
        var self = ncBPFramework.DOM;
        var obj = self.getElement(element);
        var cls = obj.className;
        // trivial case, no className yet
        if (cls.length === 0) {
            self.setElementClass(obj, className);
            return true;
        }
        // the other trivial case, already set as the only class
        if (cls == className) {
            return false;
        }
        var classes = obj.className.split(" ");
        for (var i = 0; i < classes.length; i++) {
            // already present
            if (classes[i] == className) {
                return false;
            }
        }
        // append class
        self.setElementClass(obj, cls + " " + className);
        return true;
    },

    removeElementClass: function (element, className) {
        var self = ncBPFramework.DOM;
        var obj = self.getElement(element);
        var cls = obj.className;
        // trivial case, no className yet
        if (cls.length === 0) {
            return false;
        }
        // other trivial case, set only to className
        if (cls == className) {
            self.setElementClass(obj, "");
            return true;
        }
        var classes = obj.className.split(" ");
        for (var i = 0; i < classes.length; i++) {
            // already present
            if (classes[i] == className) {
                // only check sane case where the class is used once
                classes.splice(i, 1);
                self.setElementClass(obj, classes.join(" "));
                return true;
            }
        }
        // not found
        return false;
    },

    swapElementClass: function (element, fromClass, toClass) {
        var obj = ncBPFramework.DOM.getElement(element);
        var res = ncBPFramework.DOM.removeElementClass(obj, fromClass);
        if (res) {
            ncBPFramework.DOM.addElementClass(obj, toClass);
        }
        return res;
    },

    hasElementClass: function (element, className/*...*/) {
        var obj = ncBPFramework.DOM.getElement(element);
        var classes = obj.className.split(" ");
        for (var i = 1; i < arguments.length; i++) {
            var good = false;
            for (var j = 0; j < classes.length; j++) {
                if (classes[j] == arguments[i]) {
                    good = true;
                    break;
                }
            }
            if (!good) {
                return false;
            }
        }
        return true;
    },

    escapeHTML: function (s) {
        return s.replace(/&/g, "&amp;"
            ).replace(/"/g, "&quot;"
            ).replace(/</g, "&lt;"
            ).replace(/>/g, "&gt;");
    },

    toHTML: function (dom) {
        return ncBPFramework.DOM.emitHTML(dom).join("");
    },

    emitHTML: function (dom, /* optional */lst) {
        if (typeof(lst) == 'undefined' || lst === null) {
            lst = [];
        }
        // queue is the call stack, we're doing this non-recursively
        var queue = [dom];
        var self = ncBPFramework.DOM;
        var escapeHTML = self.escapeHTML;
        var attributeArray = self.attributeArray;
        while (queue.length) {
            dom = queue.pop();
            if (typeof(dom) == 'string') {
                lst.push(dom);
            } else if (dom.nodeType == 1) {
                // we're not using higher order stuff here
                // because safari has heisenbugs.. argh.
                //
                // I think it might have something to do with
                // garbage collection and function calls.
                lst.push('<' + dom.nodeName.toLowerCase());
                var attributes = [];
                var domAttr = attributeArray(dom);
                for (var i = 0; i < domAttr.length; i++) {
                    var a = domAttr[i];
                    attributes.push([
                        " ",
                        a.name,
                        '="',
                        escapeHTML(a.value),
                        '"'
                    ]);
                }
                attributes.sort();
                for (i = 0; i < attributes.length; i++) {
                    var attrs = attributes[i];
                    for (var j = 0; j < attrs.length; j++) {
                        lst.push(attrs[j]);
                    }
                }
                if (dom.hasChildNodes()) {
                    lst.push(">");
                    // queue is the FILO call stack, so we put the close tag
                    // on first
                    queue.push("</" + dom.nodeName.toLowerCase() + ">");
                    var cnodes = dom.childNodes;
                    for (i = cnodes.length - 1; i >= 0; i--) {
                        queue.push(cnodes[i]);
                    }
                } else {
                    lst.push('/>');
                }
            } else if (dom.nodeType == 3) {
                lst.push(escapeHTML(dom.nodeValue));
            }
        }
        return lst;
    },

    setDisplayForElement: function (display, element/*, ...*/) {
        var m = ncBPFramework.Base;
        var elements = m.extend(null, arguments, 1);
        ncBPFramework.Iter.forEach(
            m.filter(null, m.map(ncBPFramework.DOM.getElement, elements)),
            function (element) {
                element.style.display = display;
            }
        );
    },

    scrapeText: function (node, /* optional */asArray) {
        var rval = [];
        (function (node) {
            var cn = node.childNodes;
            if (cn) {
                for (var i = 0; i < cn.length; i++) {
                    arguments.callee.call(this, cn[i]);
                }
            }
            var nodeValue = node.nodeValue;
            if (typeof(nodeValue) == 'string') {
                rval.push(nodeValue);
            }
        })(ncBPFramework.DOM.getElement(node));
        if (asArray) {
            return rval;
        } else {
            return rval.join("");
        }
    },


    __new__: function (win) {

        var m = ncBPFramework.Base;
        this._document = document;
        this._window = win;

        this.domConverters = new m.AdapterRegistry(); 
        
        var __tmpElement = this._document.createElement("span");
        var attributeArray;
        if (__tmpElement && __tmpElement.attributes &&
                __tmpElement.attributes.length > 0) {
            // for braindead browsers (IE) that insert extra junk
            var filter = m.filter;
            attributeArray = function (node) {
                return filter(attributeArray.ignoreAttrFilter, node.attributes);
            };
            attributeArray.ignoreAttr = {};
            ncBPFramework.Iter.forEach(__tmpElement.attributes, function (a) {
                attributeArray.ignoreAttr[a.name] = a.value;
            });
            attributeArray.ignoreAttrFilter = function (a) {
                return (attributeArray.ignoreAttr[a.name] != a.value);
            };
            attributeArray.compliant = false;
            attributeArray.renames = {
                "class": "className",
                "checked": "defaultChecked",
                "usemap": "useMap",
                "for": "htmlFor"
            };
        } else {
            attributeArray = function (node) {
                /***
                    
                    Return an array of attributes for a given node,
                    filtering out attributes that don't belong for
                    that are inserted by "Certain Browsers".

                ***/
                return node.attributes;
            };
            attributeArray.compliant = true;
            attributeArray.renames = {};
        }
        this.attributeArray = attributeArray;


        // shorthand for createDOM syntax
        var createDOMFunc = this.createDOMFunc;
        this.UL = createDOMFunc("ul");
        this.OL = createDOMFunc("ol");
        this.LI = createDOMFunc("li");
        this.TD = createDOMFunc("td");
        this.TR = createDOMFunc("tr");
        this.TBODY = createDOMFunc("tbody");
        this.THEAD = createDOMFunc("thead");
        this.TFOOT = createDOMFunc("tfoot");
        this.TABLE = createDOMFunc("table");
        this.TH = createDOMFunc("th");
        this.INPUT = createDOMFunc("input");
        this.SPAN = createDOMFunc("span");
        this.A = createDOMFunc("a");
        this.DIV = createDOMFunc("div");
        this.IMG = createDOMFunc("img");
        this.BUTTON = createDOMFunc("button");
        this.TT = createDOMFunc("tt");
        this.PRE = createDOMFunc("pre");
        this.H1 = createDOMFunc("h1");
        this.H2 = createDOMFunc("h2");
        this.H3 = createDOMFunc("h3");
        this.BR = createDOMFunc("br");
        this.HR = createDOMFunc("hr");
        this.LABEL = createDOMFunc("label");
        this.TEXTAREA = createDOMFunc("textarea");
        this.FORM = createDOMFunc("form");
        this.P = createDOMFunc("p");
        this.SELECT = createDOMFunc("select");
        this.OPTION = createDOMFunc("option");
        this.OPTGROUP = createDOMFunc("optgroup");
        this.LEGEND = createDOMFunc("legend");
        this.FIELDSET = createDOMFunc("fieldset");
        this.STRONG = createDOMFunc("strong");
        this.CANVAS = createDOMFunc("canvas");

        this.hideElement = m.partial(this.setDisplayForElement, "none");
        this.showElement = m.partial(this.setDisplayForElement, "block");
        this.removeElement = this.swapDOM;
        
        this.$ = this.getElement;

        this.EXPORT_TAGS = {
            ":common": this.EXPORT,
            ":all": m.concat(this.EXPORT, this.EXPORT_OK)
        };

        m.nameFunctions(this);

    }
});

ncBPFramework.DOM.__new__(((typeof(window) == "undefined") ? this : window));

//
// XXX: Internet Explorer blows
//
if (!ncBPFramework.__compat__) {
    withWindow = ncBPFramework.DOM.withWindow;
    withDocument = ncBPFramework.DOM.withDocument;
}

ncBPFramework.Base._exportSymbols(this, ncBPFramework.DOM);