Show:
                            /**
                            * @for DOM
                            * @module dom
                            */
                            var documentElement = Y.config.doc.documentElement,
                                Y_DOM = Y.DOM,
                                TAG_NAME = 'tagName',
                                OWNER_DOCUMENT = 'ownerDocument',
                                EMPTY_STRING = '',
                                addFeature = Y.Features.add,
                                testFeature = Y.Features.test;
                            
                            Y.mix(Y_DOM, {
                                /**
                                 * Returns the text content of the HTMLElement.
                                 * @method getText
                                 * @param {HTMLElement} element The html element.
                                 * @return {String} The text content of the element (includes text of any descending elements).
                                 */
                                getText: (documentElement.textContent !== undefined) ?
                                    function(element) {
                                        var ret = '';
                                        if (element) {
                                            ret = element.textContent;
                                        }
                                        return ret || '';
                                    } : function(element) {
                                        var ret = '';
                                        if (element) {
                                            ret = element.innerText || element.nodeValue; // might be a textNode
                                        }
                                        return ret || '';
                                    },
                            
                                /**
                                 * Sets the text content of the HTMLElement.
                                 * @method setText
                                 * @param {HTMLElement} element The html element.
                                 * @param {String} content The content to add.
                                 */
                                setText: (documentElement.textContent !== undefined) ?
                                    function(element, content) {
                                        if (element) {
                                            element.textContent = content;
                                        }
                                    } : function(element, content) {
                                        if ('innerText' in element) {
                                            element.innerText = content;
                                        } else if ('nodeValue' in element) {
                                            element.nodeValue = content;
                                        }
                                },
                            
                                CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
                                    'for': 'htmlFor',
                                    'class': 'className'
                                } : { // w3c
                                    'htmlFor': 'for',
                                    'className': 'class'
                                },
                            
                                /**
                                 * Provides a normalized attribute interface.
                                 * @method setAttribute
                                 * @param {HTMLElement} el The target element for the attribute.
                                 * @param {String} attr The attribute to set.
                                 * @param {String} val The value of the attribute.
                                 */
                                setAttribute: function(el, attr, val, ieAttr) {
                                    if (el && attr && el.setAttribute) {
                                        attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
                                        el.setAttribute(attr, val, ieAttr);
                                    }
                                    else { Y.log('bad input to setAttribute', 'warn', 'dom'); }
                                },
                            
                            
                                /**
                                 * Provides a normalized attribute interface.
                                 * @method getAttribute
                                 * @param {HTMLElement} el The target element for the attribute.
                                 * @param {String} attr The attribute to get.
                                 * @return {String} The current value of the attribute.
                                 */
                                getAttribute: function(el, attr, ieAttr) {
                                    ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
                                    var ret = '';
                                    if (el && attr && el.getAttribute) {
                                        attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
                                        // BUTTON value issue for IE < 8
                                        ret = (el.tagName === "BUTTON" && attr === 'value') ? Y_DOM.getValue(el) : el.getAttribute(attr, ieAttr);
                            
                                        if (ret === null) {
                                            ret = ''; // per DOM spec
                                        }
                                    }
                                    else { Y.log('bad input to getAttribute', 'warn', 'dom'); }
                                    return ret;
                                },
                            
                                VALUE_SETTERS: {},
                            
                                VALUE_GETTERS: {},
                            
                                getValue: function(node) {
                                    var ret = '', // TODO: return null?
                                        getter;
                            
                                    if (node && node[TAG_NAME]) {
                                        getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
                            
                                        if (getter) {
                                            ret = getter(node);
                                        } else {
                                            ret = node.value;
                                        }
                                    }
                            
                                    // workaround for IE8 JSON stringify bug
                                    // which converts empty string values to null
                                    if (ret === EMPTY_STRING) {
                                        ret = EMPTY_STRING; // for real
                                    }
                            
                                    return (typeof ret === 'string') ? ret : '';
                                },
                            
                                setValue: function(node, val) {
                                    var setter;
                            
                                    if (node && node[TAG_NAME]) {
                                        setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
                                        val = (val === null) ? '' : val;
                                        if (setter) {
                                            setter(node, val);
                                        } else {
                                            node.value = val;
                                        }
                                    }
                                },
                            
                                creators: {}
                            });
                            
                            addFeature('value-set', 'select', {
                                test: function() {
                                    var node = Y.config.doc.createElement('select');
                                    node.innerHTML = '<option>1</option><option>2</option>';
                                    node.value = '2';
                                    return (node.value && node.value === '2');
                                }
                            });
                            
                            if (!testFeature('value-set', 'select')) {
                                Y_DOM.VALUE_SETTERS.select = function(node, val) {
                                    for (var i = 0, options = node.getElementsByTagName('option'), option;
                                            option = options[i++];) {
                                        if (Y_DOM.getValue(option) === val) {
                                            option.selected = true;
                                            //Y_DOM.setAttribute(option, 'selected', 'selected');
                                            break;
                                        }
                                    }
                                };
                            }
                            
                            Y.mix(Y_DOM.VALUE_GETTERS, {
                                button: function(node) {
                                    return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
                                }
                            });
                            
                            Y.mix(Y_DOM.VALUE_SETTERS, {
                                // IE: node.value changes the button text, which should be handled via innerHTML
                                button: function(node, val) {
                                    var attr = node.attributes.value;
                                    if (!attr) {
                                        attr = node[OWNER_DOCUMENT].createAttribute('value');
                                        node.setAttributeNode(attr);
                                    }
                            
                                    attr.value = val;
                                }
                            });
                            
                            
                            Y.mix(Y_DOM.VALUE_GETTERS, {
                                option: function(node) {
                                    var attrs = node.attributes;
                                    return (attrs.value && attrs.value.specified) ? node.value : node.text;
                                },
                            
                                select: function(node) {
                                    var val = node.value,
                                        options = node.options;
                            
                                    if (options && options.length) {
                                        // TODO: implement multipe select
                                        if (node.multiple) {
                                            Y.log('multiple select normalization not implemented', 'warn', 'DOM');
                                        } else if (node.selectedIndex > -1) {
                                            val = Y_DOM.getValue(options[node.selectedIndex]);
                                        }
                                    }
                            
                                    return val;
                                }
                            });