/**
 * App Framework  query selector class for HTML5 mobile apps on a Webkit or IE 10 browser.
 * We are able to increase the speed greatly by removing support for legacy desktop browsers and taking advantage of browser features, like native JSON parsing and querySelectorAll


 * MIT License
 * @author AppMobi
 * @copyright Intel
 * @api private
 */
if (!window.af || typeof(af) !== "function") {

    /**
     *  This is our master af object that everything is built upon.
     * $ is a pointer to this object
     * @title appframework
     * @api private
     */
    var af = (function(window) {
        "use strict";
        var nundefined, document = window.document,
            emptyArray = [],
            slice = emptyArray.slice,
            classCache = {},
            eventHandlers = [],
            _eventID = 1,
            jsonPHandlers = [],
            _jsonPID = 1,
            fragmentRE = /<(\w+)[^>]*>/,
            classSelectorRE = /^\.([\w-]+)$/,
            tagSelectorRE = /^[\w-]+$/,
            _attrCache = {},
            _propCache = {},
            cssNumber = {
                "columncount": true,
                "fontweight": true,
                "lineheight": true,
                "column-count": true,
                "font-weight": true,
                "line-height": true,
                "opacity": true,
                "orphans": true,
                "widows": true,
                "zIndex": true,
                "z-index": true,
                "zoom": true
            },
            isWin8 = (typeof(MSApp) === "object");

        /**
         * internal function used for $().css - checks to see if it's a number and the css property
         * needs "px" added to it
         * @api private
         */

        function _addPx(prop, val) {
            return (typeof(val) === "number") && !cssNumber[prop.toLowerCase()] ? val + "px" : val;
        }

        /**
         * internal function to use domfragments for insertion
         *
         * @api private
         */

        function _insertFragments(afm, container, insert) {
            var frag = document.createDocumentFragment();
            if (insert) {
                for (var j = afm.length - 1; j >= 0; j--) {
                    frag.insertBefore(afm[j], frag.firstChild);
                }
                container.insertBefore(frag, container.firstChild);

            } else {

                for (var k = 0; k < afm.length; k++)
                    frag.appendChild(afm[k]);
                container.appendChild(frag);
            }
            frag = null;
        }



        /**
         * Internal function to test if a class name fits in a regular expression
         * @param {String} name to search against
         * @return {Boolean}
         * @api private
         */

        function classRE(name) {
            return name in classCache ? classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'));
        }

        /**
         * Internal function that returns a array of unique elements
         * @param {Array} array to compare against
         * @return {Array} array of unique elements
         * @api private
         */

        function unique(arr) {
            for (var i = 0; i < arr.length; i++) {
                if (arr.indexOf(arr[i]) != i) {
                    arr.splice(i, 1);
                    i--;
                }
            }
            return arr;
        }

        /**
         * Given a set of nodes, it returns them as an array.  Used to find
         * siblings of an element
         * @param {Nodelist} Node list to search
         * @param {Object} [element] to find siblings off of
         * @return {Array} array of sibblings
         * @api private
         */

        function siblings(nodes, element) {
            var elems = [];
            if (nodes == nundefined)
                return elems;

            for (; nodes; nodes = nodes.nextSibling) {
                if (nodes.nodeType == 1 && nodes !== element) {
                    elems.push(nodes);
                }
            }
            return elems;
        }

        /**
         * This is the internal appframework object that gets extended and added on to it
         * This is also the start of our query selector engine
         * @param {String|Element|Object|Array} selector
         * @param {String|Element|Object} [context]
         */
        var $afm = function(toSelect, what) {
            this.length = 0;
            if (!toSelect) {
                return this;
            } else if (toSelect instanceof $afm && what == nundefined) {
                return toSelect;
            } else if (af.isFunction(toSelect)) {
                return af(document).ready(toSelect);
            } else if (af.isArray(toSelect) && toSelect.length != nundefined) { //Passing in an array or object
                for (var i = 0; i < toSelect.length; i++)
                    this[this.length++] = toSelect[i];
                return this;
            } else if (af.isObject(toSelect) && af.isObject(what)) { //var tmp=$("span");  $("p").find(tmp);
                if (toSelect.length == nundefined) {
                    if (toSelect.parentNode == what)
                        this[this.length++] = toSelect;
                } else {
                    for (var j = 0; j < toSelect.length; j++)
                        if (toSelect[j].parentNode == what)
                            this[this.length++] = toSelect[j];
                }
                return this;
            } else if (af.isObject(toSelect) && what == nundefined) { //Single object
                this[this.length++] = toSelect;
                return this;
            } else if (what !== nundefined) {
                if (what instanceof $afm) {
                    return what.find(toSelect);
                }

            } else {
                what = document;
            }

            return this.selector(toSelect, what);

        };

        /**
         * This calls the $afm function
         * @param {String|Element|Object|Array} selector
         * @param {String|Element|Object} [context]
         */
        var $ = function(selector, what) {
            return new $afm(selector, what);
        };

        /**
         * this is the engine for "all" and is only exposed internally
         * @api private
         */

        function _selectorAll(selector, what) {
            try {
                return what.querySelectorAll(selector);

            } catch (e) {
                return [];
            }
        }
        /**
         * this is the query selector engine for elements
         * @param {String} selector
         * @param {String|Element|Object} [context]
         * @api private
         */

        function _selector(selector, what) {


            selector = selector.trim();

            if (selector[0] === "#" && selector.indexOf(".") == -1 &&selector.indexOf(",") == -1 && selector.indexOf(" ") === -1 && selector.indexOf(">") === -1) {
                if (what == document)
                    _shimNodes(what.getElementById(selector.replace("#", "")), this);
                else
                    _shimNodes(_selectorAll(selector, what), this);
            } else if ((selector[0] === "<" && selector[selector.length - 1] === ">") || (selector.indexOf("<") !== -1 && selector.indexOf(">") !== -1)) //html

            {
                var tmp = document.createElement("div");
                if (isWin8) {
                    MSApp.execUnsafeLocalFunction(function() {
                        tmp.innerHTML = selector.trim();
                    });
                } else
                    tmp.innerHTML = selector.trim();
                _shimNodes(tmp.childNodes, this);
            } else {
                _shimNodes((_selectorAll(selector, what)), this);
            }
            return this;
        }

        function _shimNodes(nodes, obj) {
            if (!nodes)
                return;
            if (nodes.nodeType) {
                obj[obj.length++] = nodes;
                return;
            }
            for (var i = 0, iz = nodes.length; i < iz; i++)
                obj[obj.length++] = nodes[i];
        }
        /**
        * Checks to see if the parameter is a $afm object
            ```
            var foo=$('#header');
            $.is$(foo);
            ```

        * @param {Object} element
        * @return {Boolean}
        * @title $.is$(param)
        */
        $.is$ = function(obj) {
            return obj instanceof $afm;
        };
        /**
        * Map takes in elements and executes a callback function on each and returns a collection
        ```
        $.map([1,2],function(ind){return ind+1});
        ```

        * @param {Array|Object} elements
        * @param {Function} callback
        * @return {Object} appframework object with elements in it
        * @title $.map(elements,callback)
        */
        $.map = function(elements, callback) {
            var value, values = [],
                i, key;
            if ($.isArray(elements))
                for (i = 0; i < elements.length; i++) {
                    value = callback.apply(elements[i],[i,elements[i]]);
                    if (value !== nundefined)
                        values.push(value);
            } else if ($.isObject(elements))
                for (key in elements) {
                    if (!elements.hasOwnProperty(key) || key == "length")
                        continue;
                    value = callback(elements[key],[key,elements[key]]);
                    if (value !== nundefined)
                        values.push(value);
            }
            return af(values);
        };

        /**
        * Iterates through elements and executes a callback.  Returns if false
        ```
        $.each([1,2],function(ind){console.log(ind);});
        ```

        * @param {Array|Object} elements
        * @param {Function} callback
        * @return {Array} elements
        * @title $.each(elements,callback)
        */
        $.each = function(elements, callback) {
            var i, key;
            if ($.isArray(elements))
                for (i = 0; i < elements.length; i++) {
                    if (callback(i, elements[i]) === false)
                        return elements;
            } else if ($.isObject(elements))
                for (key in elements) {
                    if (!elements.hasOwnProperty(key) || key == "length")
                        continue;
                    if (callback(key, elements[key]) === false)
                        return elements;
            }
            return elements;
        };

        /**
        * Extends an object with additional arguments
            ```
            $.extend({foo:'bar'});
            $.extend(element,{foo:'bar'});
            ```

        * @param {Object} [target] element
        * @param any number of additional arguments
        * @return {Object} [target]
        * @title $.extend(target,{params})
        */
        $.extend = function(target) {
            if (target == nundefined)
                target = this;
            if (arguments.length === 1) {
                for (var key in target)
                    this[key] = target[key];
                return this;
            } else {
                slice.call(arguments, 1).forEach(function(source) {
                    for (var key in source)
                        target[key] = source[key];
                });
            }
            return target;
        };

        /**
        * Checks to see if the parameter is an array
            ```
            var arr=[];
            $.isArray(arr);
            ```

        * @param {Object} element
        * @return {Boolean}
        * @example $.isArray([1]);
        * @title $.isArray(param)
        */
        $.isArray = function(obj) {
            return obj instanceof Array && obj.push != nundefined; //ios 3.1.3 doesn't have Array.isArray
        };

        /**
        * Checks to see if the parameter is a function
            ```
            var func=function(){};
            $.isFunction(func);
            ```

        * @param {Object} element
        * @return {Boolean}
        * @title $.isFunction(param)
        */
        $.isFunction = function(obj) {
            return typeof obj === "function" && !(obj instanceof RegExp);
        };
        /**
        * Checks to see if the parameter is a object
            ```
            var foo={bar:'bar'};
            $.isObject(foo);
            ```

        * @param {Object} element
        * @return {Boolean}
        * @title $.isObject(param)
        */
        $.isObject = function(obj) {
            return typeof obj === "object" && obj !== null;
        };

        /**
         * Prototype for afm object.  Also extens $.fn
         */
        $.fn = $afm.prototype = {
            namepsace:"appframework",
            constructor: $afm,
            forEach: emptyArray.forEach,
            reduce: emptyArray.reduce,
            push: emptyArray.push,
            indexOf: emptyArray.indexOf,
            concat: emptyArray.concat,
            selector: _selector,
            oldElement: undefined,
            slice: emptyArray.slice,
            length: 0,
            /**
             * This is a utility function for .end()
             * @param {Object} params
             * @return {Object} an appframework with params.oldElement set to this
             * @api private
             */
            setupOld: function(params) {
                if (params == nundefined)
                    return $();
                params.oldElement = this;
                return params;

            },
            /**
            * This is a wrapper to $.map on the selected elements
                ```
                $().map(function(){this.value+=ind});
                ```

            * @param {Function} callback
            * @return {Object} an appframework object
            * @title $().map(function)
            */
            map: function(fn) {
                var value, values = [],
                    i;
                for (i = 0; i < this.length; i++) {
                    value = fn.apply(this[i],[i,this[i]]);
                    if (value !== nundefined)
                        values.push(value);
                }
                return $(values);
            },
            /**
            * Iterates through all elements and applys a callback function
                ```
                $().each(function(){console.log(this.value)});
                ```

            * @param {Function} callback
            * @return {Object} an appframework object
            * @title $().each(function)
            */
            each: function(callback) {
                this.forEach(function(el, idx) {
                    callback.call(el, idx, el);
                });
                return this;
            },
            /**
            * This is executed when DOMContentLoaded happens, or after if you've registered for it.
                ```
                $(document).ready(function(){console.log('I'm ready');});
                ```

            * @param {Function} callback
            * @return {Object} an appframework object
            * @title $().ready(function)
            */

            ready: function(callback) {
                if (document.readyState === "complete" || document.readyState === "loaded" || (!$.os.ie && document.readyState === "interactive")) //IE10 fires interactive too early
                    callback();
                else
                    document.addEventListener("DOMContentLoaded", callback, false);
                return this;
            },
            /**
            * Searches through the collection and reduces them to elements that match the selector
                ```
                $("#foo").find('.bar');
                $("#foo").find($('.bar'));
                $("#foo").find($('.bar').get(0));
                ```

            * @param {String|Object|Array} selector
            * @return {Object} an appframework object filtered
            * @title $().find(selector)

            */
            find: function(sel) {
                if (this.length === 0)
                    return this;
                var elems = [];
                var tmpElems;
                for (var i = 0; i < this.length; i++) {
                    tmpElems = ($(sel, this[i]));

                    for (var j = 0; j < tmpElems.length; j++) {
                        elems.push(tmpElems[j]);
                    }
                }
                return $(unique(elems));
            },
            /**
            * Gets or sets the innerHTML for the collection.
            * If used as a get, the first elements innerHTML is returned
                ```
                $("#foo").html(); //gets the first elements html
                $("#foo").html('new html');//sets the html
                $("#foo").html('new html',false); //Do not do memory management cleanup
                ```

            * @param {String} html to set
            * @param {Bool} [cleanup] - set to false for performance tests and if you do not want to execute memory management cleanup
            * @return {Object} an appframework object
            * @title $().html([html])
            */
            html: function(html, cleanup) {
                if (this.length === 0)
                    return this;
                if (html === nundefined)
                    return this[0].innerHTML;

                for (var i = 0; i < this.length; i++) {
                    if (cleanup !== false)
                        $.cleanUpContent(this[i], false, true);
                    if (isWin8) {
                        var item=this[i];
                        MSApp.execUnsafeLocalFunction(function() {
                            item.innerHTML = html;
                        });
                    } else
                        this[i].innerHTML = html;
                }
                return this;
            },


            /**
            * Gets or sets the innerText for the collection.
            * If used as a get, the first elements innerText is returned
                ```
                $("#foo").text(); //gets the first elements text;
                $("#foo").text('new text'); //sets the text
                ```

            * @param {String} text to set
            * @return {Object} an appframework object
            * @title $().text([text])
            */
            text: function(text) {
                if (this.length === 0)
                    return this;
                if (text === nundefined)
                    return this[0].textContent;
                for (var i = 0; i < this.length; i++) {
                    this[i].textContent = text;
                }
                return this;
            },
            /**
            * Gets or sets a css property for the collection
            * If used as a get, the first elements css property is returned
            * This will add px to properties that need it.
                ```
                $().css("background"); // Gets the first elements background
                $().css("background","red")  //Sets the elements background to red
                ```

            * @param {String} attribute to get
            * @param {String} value to set as
            * @return {Object} an appframework object
            * @title $().css(attribute,[value])
            */
            css: function(attribute, value, obj) {
                var toAct = obj != nundefined ? obj : this[0];
                if (this.length === 0)
                    return this;
                if (value == nundefined && typeof(attribute) === "string") {
                    var styles = window.getComputedStyle(toAct);
                    return toAct.style[attribute] ? toAct.style[attribute] : window.getComputedStyle(toAct)[attribute];
                }
                for (var i = 0; i < this.length; i++) {
                    if ($.isObject(attribute)) {
                        for (var j in attribute) {
                            this[i].style[j] = _addPx(j, attribute[j]);
                        }
                    } else {
                        this[i].style[attribute] = _addPx(attribute, value);
                    }
                }
                return this;
            },
            /**
             * Gets or sets css vendor specific css properties
            * If used as a get, the first elements css property is returned
                ```
                $().css("background"); // Gets the first elements background
                $().css("background","red")  //Sets the elements background to red
                ```

            * @param {String} attribute to get
            * @param {String} value to set as
            * @return {Object} an appframework object
            * @title $().css(attribute,[value])
            */
            vendorCss: function(attribute, value, obj) {
                return this.css($.feat.cssPrefix + attribute, value, obj);
            },
            /**
             * Performs a css vendor specific transform:translate operation on the collection.
             *
             ```
                $("#main").cssTranslate('200px,0,0');
             ```
             * @param {String} Transform values
             * @return {Object} an appframework object
             * @title $().vendorCss(value)
             */
            cssTranslate: function(val) {
                return this.vendorCss("Transform", "translate" + $.feat.cssTransformStart + val + $.feat.cssTransformEnd);
            },
            /**
             * Gets the computed style of CSS values
             *
            ```
               $("#main").computedStyle('display');
            ```
             * @param {String} css property
             * @return {Int|String|Float|} css vlaue
             * @title $().computedStyle()
             */
            computedStyle: function(val) {
                if (this.length === 0 || val == nundefined) return;
                return window.getComputedStyle(this[0], '')[val];
            },
            /**
            * Sets the innerHTML of all elements to an empty string
                ```
                $().empty();
                ```

            * @return {Object} an appframework object
            * @title $().empty()
            */
            empty: function() {
                for (var i = 0; i < this.length; i++) {
                    $.cleanUpContent(this[i], false, true);
                    this[i].textContent = '';
                }
                return this;
            },
            /**
            * Sets the elements display property to "none".
            * This will also store the old property into an attribute for hide
                ```
                $().hide();
                ```

            * @return {Object} an appframework object
            * @title $().hide()
            */
            hide: function() {
                if (this.length === 0)
                    return this;
                for (var i = 0; i < this.length; i++) {
                    if (this.css("display", null, this[i]) != "none") {
                        this[i].setAttribute("afmOldStyle", this.css("display", null, this[i]));
                        this[i].style.display = "none";
                    }
                }
                return this;
            },
            /**
            * Shows all the elements by setting the css display property
            * We look to see if we were retaining an old style (like table-cell) and restore that, otherwise we set it to block
                ```
                $().show();
                ```

            * @return {Object} an appframework object
            * @title $().show()
            */
            show: function() {
                if (this.length === 0)
                    return this;
                for (var i = 0; i < this.length; i++) {
                    if (this.css("display", null, this[i]) == "none") {
                        this[i].style.display = this[i].getAttribute("afmOldStyle") ? this[i].getAttribute("afmOldStyle") : 'block';
                        this[i].removeAttribute("afmOldStyle");
                    }
                }
                return this;
            },
            /**
            * Toggle the visibility of a div
                ```
                $().toggle();
                $().toggle(true); //force showing
                ```

            * @param {Boolean} [show] -force the hiding or showing of the element
            * @return {Object} an appframework object
            * @title $().toggle([show])
            */
            toggle: function(show) {
                if(this.length === 0)
                    return this;
                var show2 = !!(show === true);
                for (var i = 0; i < this.length; i++) {
                    if (this.css("display", null, this[i]) != "none" && (show == nundefined || show2 === false)) {
                        this[i].setAttribute("afmOldStyle", this.css("display", null, this[i]));
                        this[i].style.display = "none";
                    } else if (this.css("display", null, this[i]) == "none" && (show == nundefined || show2 === true)) {
                        this[i].style.display = this[i].getAttribute("afmOldStyle") ? this[i].getAttribute("afmOldStyle") : 'block';
                        this[i].removeAttribute("afmOldStyle");
                    }
                }
                return this;
            },
            /**
            * Gets or sets an elements value
            * If used as a getter, we return the first elements value.  If nothing is in the collection, we return undefined
                ```
                $().value; //Gets the first elements value;
                $().value="bar"; //Sets all elements value to bar
                ```

            * @param {String} [value] to set
            * @return {String|Object} A string as a getter, appframework object as a setter
            * @title $().val([value])
            */
            val: function(value) {
                if (this.length === 0)
                    return (value === nundefined) ? undefined : this;
                if (value == nundefined)
                    return this[0].value;
                for (var i = 0; i < this.length; i++) {
                    this[i].value = value;
                }
                return this;
            },
            /**
            * Gets or sets an attribute on an element
            * If used as a getter, we return the first elements value.  If nothing is in the collection, we return undefined
                ```
                $().attr("foo"); //Gets the first elements 'foo' attribute
                $().attr("foo","bar");//Sets the elements 'foo' attribute to 'bar'
                $().attr("foo",{bar:'bar'}) //Adds the object to an internal cache
                ```

            * @param {String|Object} attribute to act upon.  If it's an object (hashmap), it will set the attributes based off the kvp.
            * @param {String|Array|Object|function} [value] to set
            * @return {String|Object|Array|Function} If used as a getter, return the attribute value.  If a setter, return an appframework object
            * @title $().attr(attribute,[value])
            */
            attr: function(attr, value) {
                if (this.length === 0)
                    return (value === nundefined) ? undefined : this;
                if (value === nundefined && !$.isObject(attr)) {
                    var val = (this[0].afmCacheId && _attrCache[this[0].afmCacheId][attr]) ? (this[0].afmCacheId && _attrCache[this[0].afmCacheId][attr]) : this[0].getAttribute(attr);
                    return val;
                }
                for (var i = 0; i < this.length; i++) {
                    if ($.isObject(attr)) {
                        for (var key in attr) {
                            $(this[i]).attr(key, attr[key]);
                        }
                    } else if ($.isArray(value) || $.isObject(value) || $.isFunction(value)) {

                        if (!this[i].afmCacheId)
                            this[i].afmCacheId = $.uuid();

                        if (!_attrCache[this[i].afmCacheId])
                            _attrCache[this[i].afmCacheId] = {};
                        _attrCache[this[i].afmCacheId][attr] = value;
                    } else if (value === null) {
                        this[i].removeAttribute(attr);
                        if (this[i].afmCacheId && _attrCache[this[i].afmCacheId][attr])
                            delete _attrCache[this[i].afmCacheId][attr];
                    } else {
                        this[i].setAttribute(attr, value);
                    }
                }
                return this;
            },
            /**
            * Removes an attribute on the elements
                ```
                $().removeAttr("foo");
                ```

            * @param {String} attributes that can be space delimited
            * @return {Object} appframework object
            * @title $().removeAttr(attribute)
            */
            removeAttr: function(attr) {
                var that = this;
                for (var i = 0; i < this.length; i++) {
                    attr.split(/\s+/g).forEach(function(param) {
                        that[i].removeAttribute(param);
                        if (that[i].afmCacheId && _attrCache[that[i].afmCacheId][attr])
                            delete _attrCache[that[i].afmCacheId][attr];
                    });
                }
                return this;
            },

            /**
            * Gets or sets a property on an element
            * If used as a getter, we return the first elements value.  If nothing is in the collection, we return undefined
                ```
                $().prop("foo"); //Gets the first elements 'foo' property
                $().prop("foo","bar");//Sets the elements 'foo' property to 'bar'
                $().prop("foo",{bar:'bar'}) //Adds the object to an internal cache
                ```

            * @param {String|Object} property to act upon.  If it's an object (hashmap), it will set the attributes based off the kvp.
            * @param {String|Array|Object|function} [value] to set
            * @return {String|Object|Array|Function} If used as a getter, return the property value.  If a setter, return an appframework object
            * @title $().prop(property,[value])
            */
            prop: function(prop, value) {
                if (this.length === 0)
                    return (value === nundefined) ? undefined : this;
                if (value === nundefined && !$.isObject(prop)) {
                    var res;
                    var val = (this[0].afmCacheId && _propCache[this[0].afmCacheId][prop]) ? (this[0].afmCacheId && _propCache[this[0].afmCacheId][prop]) : !(res = this[0][prop]) && prop in this[0] ? this[0][prop] : res;
                    return val;
                }
                for (var i = 0; i < this.length; i++) {
                    if ($.isObject(prop)) {
                        for (var key in prop) {
                            $(this[i]).prop(key, prop[key]);
                        }
                    } else if ($.isArray(value) || $.isObject(value) || $.isFunction(value)) {

                        if (!this[i].afmCacheId)
                            this[i].afmCacheId = $.uuid();

                        if (!_propCache[this[i].afmCacheId])
                            _propCache[this[i].afmCacheId] = {};
                        _propCache[this[i].afmCacheId][prop] = value;
                    } else if (value === null && value !== undefined) {
                        $(this[i]).removeProp(prop);
                    } else {
                        this[i][prop] = value;
                    }
                }
                return this;
            },
            /**
            * Removes a property on the elements
                ```
                $().removeProp("foo");
                ```

            * @param {String} properties that can be space delimited
            * @return {Object} appframework object
            * @title $().removeProp(attribute)
            */
            removeProp: function(prop) {
                var that = this;
                for (var i = 0; i < this.length; i++) {
                    prop.split(/\s+/g).forEach(function(param) {
                        if (that[i][param])
                            that[i][param] = undefined;
                        if (that[i].afmCacheId && _propCache[that[i].afmCacheId][prop]) {
                            delete _propCache[that[i].afmCacheId][prop];
                        }
                    });
                }
                return this;
            },

            /**
            * Removes elements based off a selector
                ```
                $().remove();  //Remove all
                $().remove(".foo");//Remove off a string selector
                var element=$("#foo").get(0);
                $().remove(element); //Remove by an element
                $().remove($(".foo"));  //Remove by a collection

                ```

            * @param {String|Object|Array} selector to filter against
            * @return {Object} appframework object
            * @title $().remove(selector)
            */
            remove: function(selector) {
                var elems = $(this).filter(selector);
                if (elems == nundefined)
                    return this;
                for (var i = 0; i < elems.length; i++) {
                    $.cleanUpContent(elems[i], true, true);
                    if (elems[i] && elems[i].parentNode) {
                        elems[i].parentNode.removeChild(elems[i]);
                    }
                }
                return this;
            },
            /**
            * Adds a css class to elements.
                ```
                $().addClass("selected");
                ```

            * @param {String} classes that are space delimited
            * @return {Object} appframework object
            * @title $().addClass(name)
            */
            addClass: function(name) {
                if (name == nundefined) return this;
                for (var i = 0; i < this.length; i++) {
                    var cls = this[i].className;
                    var classList = [];
                    var that = this;
                    name.split(/\s+/g).forEach(function(cname) {
                        if (!that.hasClass(cname, that[i]))
                            classList.push(cname);
                    });

                    this[i].className += (cls ? " " : "") + classList.join(" ");
                    this[i].className = this[i].className.trim();
                }
                return this;
            },
            /**
            * Removes a css class from elements.
                ```
                $().removeClass("foo"); //single class
                $().removeClass("foo selected");//remove multiple classess
                ```

            * @param {String} classes that are space delimited
            * @return {Object} appframework object
            * @title $().removeClass(name)
            */
            removeClass: function(name) {
                if (name == nundefined) return this;
                for (var i = 0; i < this.length; i++) {
                    if (name == nundefined) {
                        this[i].className = '';
                        return this;
                    }
                    var classList = this[i].className;
					//SGV LINK EVENT
					if (typeof this[i].className == "object") {
						classList = " ";
					}
                    name.split(/\s+/g).forEach(function(cname) {
                        classList = classList.replace(classRE(cname), " ");
                    });
                    if (classList.length > 0)
                        this[i].className = classList.trim();
                    else
                        this[i].className = "";
                }
                return this;
            },
            /**
            * Adds or removes a css class to elements.
                ```
                $().toggleClass("selected");
                ```

            * @param {String} classes that are space delimited
            * @param {Boolean} [state] force toggle to add or remove classes
            * @return {Object} appframework object
            * @title $().toggleClass(name)
            */
            toggleClass: function(name, state) {
                if (name == nundefined) return this;
                for (var i = 0; i < this.length; i++) {
                    if (typeof state != "boolean") {
                        state = this.hasClass(name, this[i]);
                    }
                    $(this[i])[state ? 'removeClass' : 'addClass'](name);
                }
                return this;
            },
            /**
            * Replaces a css class on elements.
                ```
                $().replaceClass("on", "off");
                ```

            * @param {String} classes that are space delimited
            * @param {String} classes that are space delimited
            * @return {Object} appframework object
            * @title $().replaceClass(old, new)
            */
            replaceClass: function(name, newName) {
                if (name == nundefined || newName == nundefined) return this;
                for (var i = 0; i < this.length; i++) {
                    if (name == nundefined) {
                        this[i].className = newName;
                        continue;
                    }
                    var classList = this[i].className;
                    name.split(/\s+/g).concat(newName.split(/\s+/g)).forEach(function(cname) {
                        classList = classList.replace(classRE(cname), " ");
                    });
                    classList = classList.trim();
                    if (classList.length > 0) {
                        this[i].className = (classList + " " + newName).trim();
                    } else
                        this[i].className = newName;
                }
                return this;
            },
            /**
            * Checks to see if an element has a class.
                ```
                $().hasClass('foo');
                $().hasClass('foo',element);
                ```

            * @param {String} class name to check against
            * @param {Object} [element] to check against
            * @return {Boolean}
            * @title $().hasClass(name,[element])
            */
            hasClass: function(name, element) {
                if (this.length === 0)
                    return false;
                if (!element)
                    element = this[0];
                return classRE(name).test(element.className);
            },
            /**
            * Appends to the elements
            * We boil everything down to an appframework object and then loop through that.
            * If it's HTML, we create a dom element so we do not break event bindings.
            * if it's a script tag, we evaluate it.
                ```
                $().append("<div></div>"); //Creates the object from the string and appends it
                $().append($("#foo")); //Append an object;
                ```

            * @param {String|Object} Element/string to add
            * @param {Boolean} [insert] insert or append
            * @return {Object} appframework object
            * @title $().append(element,[insert])
            */
            append: function(element, insert) {
                if (element && element.length != nundefined && element.length === 0)
                    return this;
                if ($.isArray(element) || $.isObject(element))
                    element = $(element);
                var i, node;


                for (i = 0; i < this.length; i++) {
                    if (element.length && typeof element != "string") {
                        element = $(element);
                        _insertFragments(element, this[i], insert);
                    } else {
                        var obj = fragmentRE.test(element) ? $(element) : undefined;                        
                        if (obj == nundefined || obj.length === 0) {
                            obj = document.createTextNode(element);
                        }
                        if (obj instanceof $afm) {
                            for (var k=0,lenk=obj.length; k<lenk; k++) {
                            	node = obj[k];
                            	if (node.nodeName != nundefined && node.nodeName.toLowerCase() == "script" && (!node.type || node.type.toLowerCase() === 'text/javascript')) {
                            	    window['eval'](node.innerHTML);	
                            	} else {
                            	    _insertFragments($(node), this[i], insert);
                            	}
                            }	
                        } else {
                            insert != nundefined ? this[i].insertBefore(obj, this[i].firstChild) : this[i].appendChild(obj);
                        }
                    }
                }
                return this;
            },
            /**
            * Appends the current collection to the selector
                ```
                $().appendTo("#foo"); //Append an object;
                ```

            * @param {String|Object} Selector to append to
            * @param {Boolean} [insert] insert or append
            * @title $().appendTo(element,[insert])
            */
            appendTo: function(selector, insert) {
                var tmp = $(selector);
                tmp.append(this);
                return this;
            },
            /**
            * Prepends the current collection to the selector
                ```
                $().prependTo("#foo"); //Prepend an object;
                ```

            * @param {String|Object} Selector to prepent to
            * @title $().prependTo(element)
            */
            prependTo: function(selector) {
                var tmp = $(selector);
                tmp.append(this, true);
                return this;
            },
            /**
            * Prepends to the elements
            * This simply calls append and sets insert to true
                ```
                $().prepend("<div></div>");//Creates the object from the string and appends it
                $().prepend($("#foo")); //Prepends an object
                ```

            * @param {String|Object} Element/string to add
            * @return {Object} appframework object
            * @title $().prepend(element)
            */
            prepend: function(element) {
                return this.append(element, 1);
            },
            /**
             * Inserts collection before the target (adjacent)
                ```
                $().insertBefore(af("#target"));
                ```

             * @param {String|Object} Target
             * @title $().insertBefore(target);
             */
            insertBefore: function(target, after) {
                if (this.length === 0)
                    return this;
                target = $(target).get(0);
                if (!target)
                    return this;
                for (var i = 0; i < this.length; i++) {
                    after ? target.parentNode.insertBefore(this[i], target.nextSibling) : target.parentNode.insertBefore(this[i], target);
                }
                return this;
            },
            /**
             * Inserts collection after the target (adjacent)
                ```
                $().insertAfter(af("#target"));
                ```
             * @param {String|Object} target
             * @title $().insertAfter(target);
             */
            insertAfter: function(target) {
                this.insertBefore(target, true);
            },
            /**
            * Returns the raw DOM element.
                ```
                $().get(0); //returns the first element
                $().get(2);// returns the third element
                ```

            * @param {Int} [index]
            * @return {Object} raw DOM element
            * @title $().get([index])
            */
            get: function(index) {
                index = index == nundefined ? 0 : index;
                if (index < 0)
                    index += this.length;
                return (this[index]) ? this[index] : undefined;
            },
            /**
            * Returns the offset of the element, including traversing up the tree
                ```
                $().offset();
                ```

            * @return {Object} with left, top, width and height properties
            * @title $().offset()
            */
            offset: function() {
                var obj;
                if (this.length === 0)
                    return this;
                if (this[0] == window)
                    return {
                        left: 0,
                        top: 0,
                        right: 0,
                        bottom: 0,
                        width: window.innerWidth,
                        height: window.innerHeight
                };
                else
                    obj = this[0].getBoundingClientRect();
                return {
                    left: obj.left + window.pageXOffset,
                    top: obj.top + window.pageYOffset,
                    right: obj.right + window.pageXOffset,
                    bottom: obj.bottom + window.pageYOffset,
                    width: obj.right - obj.left,
                    height: obj.bottom - obj.top
                };
            },
            /**
             * returns the height of the element, including padding on IE
               ```
               $().height();
               ```
             * @return {string} height
             * @title $().height()
             */
            height: function(val) {
                if (this.length === 0)
                    return this;
                if (val != nundefined)
                    return this.css("height", val);
                if (this[0] == this[0].window)
                    return window.innerHeight;
                if (this[0].nodeType == this[0].DOCUMENT_NODE)
                    return this[0].documentElement.offsetHeight;
                else {
                    var tmpVal = this.css("height").replace("px", "");
                    if (tmpVal)
                        return +tmpVal;
                    else
                        return this.offset().height;
                }
            },
            /**
             * returns the width of the element, including padding on IE
               ```
               $().width();
               ```
             * @return {string} width
             * @title $().width()
             */
            width: function(val) {
                if (this.length === 0)
                    return this;
                if (val != nundefined)
                    return this.css("width", val);
                if (this[0] == this[0].window)
                    return window.innerWidth;
                if (this[0].nodeType == this[0].DOCUMENT_NODE)
                    return this[0].documentElement.offsetWidth;
                else {
                    var tmpVal = this.css("width").replace("px", "");
                    if (tmpVal)
                        return +tmpVal;
                    else
                        return this.offset().width;
                }
            },
            /**
            * Returns the parent nodes of the elements based off the selector
                ```
                $("#foo").parent('.bar');
                $("#foo").parent($('.bar'));
                $("#foo").parent($('.bar').get(0));
                ```

            * @param {String|Array|Object} [selector]
            * @return {Object} appframework object with unique parents
            * @title $().parent(selector)
            */
            parent: function(selector, recursive) {
                if (this.length === 0)
                    return this;
                var elems = [];
                for (var i = 0; i < this.length; i++) {
                    var tmp = this[i];
                    while (tmp.parentNode && tmp.parentNode != document) {
                        elems.push(tmp.parentNode);
                        if (tmp.parentNode)
                            tmp = tmp.parentNode;
                        if (!recursive)
                            break;
                    }
                }
                return this.setupOld($(unique(elems)).filter(selector));
            },
            /**
            * Returns the parents of the elements based off the selector (traversing up until html document)
                ```
                $("#foo").parents('.bar');
                $("#foo").parents($('.bar'));
                $("#foo").parents($('.bar').get(0));
                ```

            * @param {String|Array|Object} [selector]
            * @return {Object} appframework object with unique parents
            * @title $().parents(selector)
            */
            parents: function(selector) {
                return this.parent(selector, true);
            },
            /**
            * Returns the child nodes of the elements based off the selector
                ```
                $("#foo").children('.bar'); //Selector
                $("#foo").children($('.bar')); //Objects
                $("#foo").children($('.bar').get(0)); //Single element
                ```

            * @param {String|Array|Object} [selector]
            * @return {Object} appframework object with unique children
            * @title $().children(selector)
            */
            children: function(selector) {

                if (this.length === 0)
                    return this;
                var elems = [];
                for (var i = 0; i < this.length; i++) {
                    elems = elems.concat(siblings(this[i].firstChild));
                }
                return this.setupOld($((elems)).filter(selector));

            },
            /**
            * Returns the siblings of the element based off the selector
                ```
                $("#foo").siblings('.bar'); //Selector
                $("#foo").siblings($('.bar')); //Objects
                $("#foo").siblings($('.bar').get(0)); //Single element
                ```

            * @param {String|Array|Object} [selector]
            * @return {Object} appframework object with unique siblings
            * @title $().siblings(selector)
            */
            siblings: function(selector) {
                if (this.length === 0)
                    return this;
                var elems = [];
                for (var i = 0; i < this.length; i++) {
                    if (this[i].parentNode)
                        elems = elems.concat(siblings(this[i].parentNode.firstChild, this[i]));
                }
                return this.setupOld($(elems).filter(selector));
            },
            /**
            * Returns the child nodes of the elements based off the selector and includes text nodes
                ```
                $("#foo").contents('.bar'); //Selector
                $("#foo").contents($('.bar')); //Objects
                $("#foo").contents($('.bar').get(0)); //Single element
                ```

            * @param {String|Array|Object} [selector]
            * @return {Object} appframework object with unique children
            * @title $().contents(selector)
            */
            contents:function(selector){
                if (this.length === 0)
                    return this;
                var elems = [];
                for (var i = 0; i < this.length; i++) {
                    if (this[i].parentNode)
                        //elems = elems.concat(this[i].childNodes);
                        _shimNodes(this[i].childNodes,elems);
                }
                return this.setupOld($(elems).filter(selector));
            },
            /**

            /**
            * Returns the closest element based off the selector and optional context
                ```
                $("#foo").closest('.bar'); //Selector
                $("#foo").closest($('.bar')); //Objects
                $("#foo").closest($('.bar').get(0)); //Single element
                ```

            * @param {String|Array|Object} selector
            * @param {Object} [context]
            * @return {Object} Returns an appframework object with the closest element based off the selector
            * @title $().closest(selector,[context]);
            */
            closest: function(selector, context) {
                if (this.length === 0)
                    return this;
                var elems = [],
                    cur = this[0];

                var start = $(selector, context);
                if (start.length === 0)
                    return $();
                while (cur && start.indexOf(cur) == -1) {
                    cur = cur !== context && cur !== document && cur.parentNode;
                }
                return $(cur);

            },
            /**
            * Filters elements based off the selector
                ```
                $("#foo").filter('.bar'); //Selector
                $("#foo").filter($('.bar')); //Objects
                $("#foo").filter($('.bar').get(0)); //Single element
                ```

            * @param {String|Array|Object} selector
            * @return {Object} Returns an appframework object after the filter was run
            * @title $().filter(selector);
            */
            filter: function(selector) {
                if (this.length === 0)
                    return this;

                if (selector == nundefined)
                    return this;
                var elems = [];
                for (var i = 0; i < this.length; i++) {
                    var val = this[i];
                    if (val.parentNode && $(selector, val.parentNode).indexOf(val) >= 0)
                        elems.push(val);
                }
                return this.setupOld($(unique(elems)));
            },
            /**
            * Basically the reverse of filter.  Return all elements that do NOT match the selector
                ```
                $("#foo").not('.bar'); //Selector
                $("#foo").not($('.bar')); //Objects
                $("#foo").not($('.bar').get(0)); //Single element
                ```

            * @param {String|Array|Object} selector
            * @return {Object} Returns an appframework object after the filter was run
            * @title $().not(selector);
            */
            not: function(selector) {
                if (this.length === 0)
                    return this;
                var elems = [];
                for (var i = 0; i < this.length; i++) {
                    var val = this[i];
                    if (val.parentNode && $(selector, val.parentNode).indexOf(val) == -1)
                        elems.push(val);
                }
                return this.setupOld($(unique(elems)));
            },
            /**
            * Gets or set data-* attribute parameters on elements (when a string)
            * When used as a getter, it's only the first element
                ```
                $().data("foo"); //Gets the data-foo attribute for the first element
                $().data("foo","bar"); //Sets the data-foo attribute for all elements
                $().data("foo",{bar:'bar'});//object as the data
                ```

            * @param {String} key
            * @param {String|Array|Object} value
            * @return {String|Object} returns the value or appframework object
            * @title $().data(key,[value]);
            */
            data: function(key, value) {
                var retData;
                // setter
                if (value) {
                    return this.attr('data-' + key, value);
                }
                // getter
                retData = this.attr('data-' + key);
                try {
                    retData = $.parseJSON(retData);
                } catch(ex) {}
                return retData;
            },
            /**
            * Rolls back the appframework elements when filters were applied
            * This can be used after .not(), .filter(), .children(), .parent()
                ```
                $().filter(".panel").end(); //This will return the collection BEFORE filter is applied
                ```

            * @return {Object} returns the previous appframework object before filter was applied
            * @title $().end();
            */
            end: function() {
                return this.oldElement != nundefined ? this.oldElement : $();
            },
            /**
            * Clones the nodes in the collection.
                ```
                $().clone();// Deep clone of all elements
                $().clone(false); //Shallow clone
                ```

            * @param {Boolean} [deep] - do a deep copy or not
            * @return {Object} appframework object of cloned nodes
            * @title $().clone();
            */
            clone: function(deep) {
                deep = deep === false ? false : true;
                if (this.length === 0)
                    return this;
                var elems = [];
                for (var i = 0; i < this.length; i++) {
                    elems.push(this[i].cloneNode(deep));
                }

                return $(elems);
            },
            /**
            * Returns the number of elements in the collection
                ```
                $().size();
                ```

            * @return {Int}
            * @title $().size();
            */
            size: function() {
                return this.length;
            },
            /**
             * Serailizes a form into a query string
               ```
               $().serialize();
               ```
             * @return {String}
             * @title $().serialize()
             */
            serialize: function() {
                if (this.length === 0)
                    return "";
                var params = [];
                for (var i = 0; i < this.length; i++) {
                    this.slice.call(this[i].elements).forEach(function(elem) {
                        var type = elem.getAttribute("type");
                        if (elem.nodeName.toLowerCase() != "fieldset" && !elem.disabled && type != "submit" && type != "reset" && type != "button" && ((type != "radio" && type != "checkbox") || elem.checked)) {

                            if (elem.getAttribute("name")) {
                                if (elem.type == "select-multiple") {
                                    for (var j = 0; j < elem.options.length; j++) {
                                        if (elem.options[j].selected)
                                            params.push(elem.getAttribute("name") + "=" + encodeURIComponent(elem.options[j].value));
                                    }
                                } else
                                    params.push(elem.getAttribute("name") + "=" + encodeURIComponent(elem.value));
                            }
                        }
                    });
                }
                return params.join("&");
            },

            /* added in 1.2 */
            /**
             * Reduce the set of elements based off index
                ```
               $().eq(index)
               ```
             * @param {Int} index - Index to filter by. If negative, it will go back from the end
             * @return {Object} appframework object
             * @title $().eq(index)
             */
            eq: function(ind) {
                return $(this.get(ind));
            },
            /**
             * Returns the index of the selected element in the collection
               ```
               $().index(elem)
               ```
             * @param {String|Object} element to look for.  Can be a selector or object
             * @return integer - index of selected element
             * @title $().index(elem)
             */
            index: function(elem) {
                return elem ? this.indexOf($(elem)[0]) : this.parent().children().indexOf(this[0]);
            },
            /**
              * Returns boolean if the object is a type of the selector
              ```
              $().is(selector)
              ```
             * param {String|Object} selector to act upon
             * @return boolean
             * @title $().is(selector)
             */
            is: function(selector) {
                return !!selector && this.filter(selector).length > 0;
            }

        };


        /* AJAX functions */

        function empty() {}
        $.ajaxSettings = {
            type: 'GET',
            beforeSend: empty,
            success: empty,
            error: empty,
            complete: empty,
            context: undefined,
            timeout: 0,
            crossDomain: null
        };
        /**
        * Execute a jsonP call, allowing cross domain scripting
        * options.url - URL to call
        * options.success - Success function to call
        * options.error - Error function to call
            ```
            $.jsonP({url:'mysite.php?callback=?&foo=bar',success:function(){},error:function(){}});
            ```

        * @param {Object} options
        * @title $.jsonP(options)
        */
        $.jsonP = function(options) {
            if (isWin8) {
                options.type = "get";
                options.dataType = null;
                return $.get(options);
            }
            var callbackName = 'jsonp_callback' + (++_jsonPID);
            var abortTimeout = "",
                context, callback;
            var script = document.createElement("script");
            var abort = function() {
                $(script).remove();
                if (window[callbackName])
                    window[callbackName] = empty;
            };
            window[callbackName] = function(data) {
                clearTimeout(abortTimeout);
                $(script).remove();
                delete window[callbackName];
                options.success.call(context, data);
            };
            if (options.url.indexOf('callback=?') !== -1) {
                script.src = options.url.replace(/=\?/, '=' + callbackName);
            } else {
                callback = options.jsonp ? options.jsonp : 'callback';
                if (options.url.indexOf("?") === -1) {
                    options.url += ("?" + callback + '=' + callbackName);
                }
                else {
                    options.url += ("&" + callback + '=' + callbackName);
                }
                script.src = options.url;
            }
            if (options.error) {
                script.onerror = function() {
                    clearTimeout(abortTimeout);
                    options.error.call(context, "", 'error');
                };
            }
            $('head').append(script);
            if (options.timeout > 0)
                abortTimeout = setTimeout(function() {
                    options.error.call(context, "", 'timeout');
                }, options.timeout);
            return {};
        };

        /**
        * Execute an Ajax call with the given options
        * options.type - Type of request
        * options.beforeSend - function to execute before sending the request
        * options.success - success callback
        * options.error - error callback
        * options.complete - complete callback - callled with a success or error
        * options.timeout - timeout to wait for the request
        * options.url - URL to make request against
        * options.contentType - HTTP Request Content Type
        * options.headers - Object of headers to set
        * options.dataType - Data type of request
        * options.data - data to pass into request.  $.param is called on objects
            ```
            var opts={
            type:"GET",
            success:function(data){},
            url:"mypage.php",
            data:{bar:'bar'},
            }
            $.ajax(opts);
            ```

        * @param {Object} options
        * @title $.ajax(options)
        */
        $.ajax = function(opts) {
            var xhr;
            try {

                var settings = opts || {};
                for (var key in $.ajaxSettings) {
                    if (typeof(settings[key]) == 'undefined')
                        settings[key] = $.ajaxSettings[key];
                }

                if (!settings.url)
                    settings.url = window.location;
                if (!settings.contentType)
                    settings.contentType = "application/x-www-form-urlencoded";
                if (!settings.headers)
                    settings.headers = {};

                if (!('async' in settings) || settings.async !== false)
                    settings.async = true;
                    
                if ($.isObject(settings.data))
                    settings.data = $.param(settings.data);
                if (settings.type.toLowerCase() === "get" && settings.data) {
                    if (settings.url.indexOf("?") === -1)
                        settings.url += "?" + settings.data;
                    else
                        settings.url += "&" + settings.data;
                }

		if (!settings.dataType)
                    settings.dataType = "text/html";
                else {
                    switch (settings.dataType) {
                        case "script":
                            settings.dataType = 'text/javascript, application/javascript';
                            break;
                        case "json":
                            settings.dataType = 'application/json';
                            break;
                        case "xml":
                            settings.dataType = 'application/xml, text/xml';
                            break;
                        case "html":
                            settings.dataType = 'text/html';
                            break;
                        case "text":
                            settings.dataType = 'text/plain';
                            break;
                        case "jsonp":
                            return $.jsonP(settings);
                            break;
                        default:
                            settings.dataType = "text/html";
                            break;
                    }
                }
                
                if (/=\?/.test(settings.url)) {
                    return $.jsonP(settings);
                }
                if (settings.crossDomain === null) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) &&
                        RegExp.$2 != window.location.host;

                if (!settings.crossDomain)
                    settings.headers = $.extend({
                        'X-Requested-With': 'XMLHttpRequest'
                    }, settings.headers);
                var abortTimeout;
                var context = settings.context;
                var protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol;

                //ok, we are really using xhr
                xhr = new window.XMLHttpRequest();


                xhr.onreadystatechange = function() {
                    var mime = settings.dataType;
                    if (xhr.readyState === 4) {
                        clearTimeout(abortTimeout);
                        var result, error = false;
                        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0 && protocol == 'file:') {
                            if (mime === 'application/json' && !(/^\s*$/.test(xhr.responseText))) {
                                try {
                                    result = JSON.parse(xhr.responseText);
                                } catch (e) {
                                    error = e;
                                }
                            } else if (mime === 'application/xml, text/xml') {
                                result = xhr.responseXML;
                            } else if (mime == "text/html") {
                                result = xhr.responseText;
                                $.parseJS(result);
                            } else
                                result = xhr.responseText;
                            //If we're looking at a local file, we assume that no response sent back means there was an error
                            if (xhr.status === 0 && result.length === 0)
                                error = true;
                            if (error)
                                settings.error.call(context, xhr, 'parsererror', error);
                            else {
                                settings.success.call(context, result, 'success', xhr);
                            }
                        } else {
                            error = true;
                            settings.error.call(context, xhr, 'error');
                        }
                        settings.complete.call(context, xhr, error ? 'error' : 'success');
                    }
                };
                xhr.open(settings.type, settings.url, settings.async);
                if (settings.withCredentials) xhr.withCredentials = true;

                if (settings.contentType)
                    settings.headers['Content-Type'] = settings.contentType;
                for (var name in settings.headers)
                    if (typeof settings.headers[name] === 'string')
                        xhr.setRequestHeader(name, settings.headers[name]);
                if (settings.beforeSend.call(context, xhr, settings) === false) {
                    xhr.abort();
                    return false;
                }

                if (settings.timeout > 0)
                    abortTimeout = setTimeout(function() {
                        xhr.onreadystatechange = empty;
                        xhr.abort();
                        settings.error.call(context, xhr, 'timeout');
                    }, settings.timeout);
                xhr.send(settings.data);
            } catch (e) {
                // General errors (e.g. access denied) should also be sent to the error callback
                console.log(e);
                settings.error.call(context, xhr, 'error', e);
            }
            return xhr;
        };


        /**
        * Shorthand call to an Ajax GET request
            ```
            $.get("mypage.php?foo=bar",function(data){});
            ```

        * @param {String} url to hit
        * @param {Function} success
        * @title $.get(url,success)
        */
        $.get = function(url, success) {
            return this.ajax({
                url: url,
                success: success
            });
        };
        /**
        * Shorthand call to an Ajax POST request
            ```
            $.post("mypage.php",{bar:'bar'},function(data){});
            ```

        * @param {String} url to hit
        * @param {Object} [data] to pass in
        * @param {Function} success
        * @param {String} [dataType]
        * @title $.post(url,[data],success,[dataType])
        */
        $.post = function(url, data, success, dataType) {
            if (typeof(data) === "function") {
                success = data;
                data = {};
            }
            if (dataType === nundefined)
                dataType = "html";
            return this.ajax({
                url: url,
                type: "POST",
                data: data,
                dataType: dataType,
                success: success
            });
        };
        /**
        * Shorthand call to an Ajax request that expects a JSON response
            ```
            $.getJSON("mypage.php",{bar:'bar'},function(data){});
            ```

        * @param {String} url to hit
        * @param {Object} [data]
        * @param {Function} [success]
        * @title $.getJSON(url,data,success)
        */
        $.getJSON = function(url, data, success) {
            if (typeof(data) === "function") {
                success = data;
                data = {};
            }
            return this.ajax({
                url: url,
                data: data,
                success: success,
                dataType: "json"
            });
        };

        /**
        * Converts an object into a key/value par with an optional prefix.  Used for converting objects to a query string
            ```
            var obj={
            foo:'foo',
            bar:'bar'
            }
            var kvp=$.param(obj,'data');
            ```

        * @param {Object} object
        * @param {String} [prefix]
        * @return {String} Key/value pair representation
        * @title $.param(object,[prefix];
        */
        $.param = function(obj, prefix) {
            var str = [];
            if (obj instanceof $afm) {
                obj.each(function() {
                    var k = prefix ? prefix + "[" + this.id + "]" : this.id,
                        v = this.value;
                    str.push((k) + "=" + encodeURIComponent(v));
                });
            } else {
                for (var p in obj) {

                    if ($.isFunction(obj[p]))
                        continue;
                    var k = prefix ? prefix + "[" + p + "]" : p,
                        v = obj[p];
                    str.push($.isObject(v) ? $.param(v, k) : (k) + "=" + encodeURIComponent(v));
                }
            }
            return str.join("&");
        };
        /**
        * Used for backwards compatibility.  Uses native JSON.parse function
            ```
            var obj=$.parseJSON("{\"bar\":\"bar\"}");
            ```

        * @params {String} string
        * @return {Object}
        * @title $.parseJSON(string)
        */
        $.parseJSON = function(string) {
            return JSON.parse(string);
        };
        /**
        * Helper function to convert XML into  the DOM node representation
            ```
            var xmlDoc=$.parseXML("<xml><foo>bar</foo></xml>");
            ```

        * @param {String} string
        * @return {Object} DOM nodes
        * @title $.parseXML(string)
        */
        $.parseXML = function(string) {
            if (isWin8) {
                MSApp.execUnsafeLocalFunction(function() {
                    return (new DOMParser()).parseFromString(string, "text/xml");
                });
            } else
                return (new DOMParser()).parseFromString(string, "text/xml");
        };
        /**
         * Helper function to parse the user agent.  Sets the following
         * .os.webkit
         * .os.android
         * .os.ipad
         * .os.iphone
         * .os.webos
         * .os.touchpad
         * .os.blackberry
         * .os.opera
         * .os.fennec
         * .os.ie
         * .os.ieTouch
         * .os.supportsTouch
         * .os.playbook
         $.os.tizen
         * .feat.nativetouchScroll
         * @api private
         */

        function detectUA($, userAgent) {
            $.os = {};
            $.os.webkit = userAgent.match(/WebKit\/([\d.]+)/) ? true : false;
            $.os.android = userAgent.match(/(Android)\s+([\d.]+)/) || userAgent.match(/Silk-Accelerated/) ? true : false;
            $.os.androidICS = $.os.android && userAgent.match(/(Android)\s4/) ? true : false;
            $.os.ipad = userAgent.match(/(iPad).*OS\s([\d_]+)/) ? true : false;
            $.os.iphone = !$.os.ipad && userAgent.match(/(iPhone\sOS)\s([\d_]+)/) ? true : false;
            $.os.ios7 = ($.os.ipad||$.os.iphone)&&userAgent.match(/7_/) ? true : false;
            $.os.webos = userAgent.match(/(webOS|hpwOS)[\s\/]([\d.]+)/) ? true : false;
            $.os.touchpad = $.os.webos && userAgent.match(/TouchPad/) ? true : false;
            $.os.ios = $.os.ipad || $.os.iphone;
            $.os.playbook = userAgent.match(/PlayBook/) ? true : false;
            $.os.blackberry10 = userAgent.match(/BB10/) ? true : false;
            $.os.blackberry = $.os.playbook || $.os.blackberry10|| userAgent.match(/BlackBerry/) ? true : false;
            $.os.chrome = userAgent.match(/Chrome/) ? true : false;
            $.os.opera = userAgent.match(/Opera/) ? true : false;
            $.os.fennec = userAgent.match(/fennec/i) ? true : userAgent.match(/Firefox/) ? true : false;
            $.os.ie = userAgent.match(/MSIE 10.0/i)||userAgent.match(/Trident\/7/i) ? true : false;
            $.os.ieTouch = $.os.ie && userAgent.toLowerCase().match(/touch/i) ? true : false;
            $.os.tizen = userAgent.match(/Tizen/i)?true:false;
            $.os.supportsTouch = ((window.DocumentTouch && document instanceof window.DocumentTouch) || 'ontouchstart' in window);
            //features
            $.feat = {};
            var head = document.documentElement.getElementsByTagName("head")[0];
            $.feat.nativeTouchScroll = typeof(head.style["-webkit-overflow-scrolling"]) !== "undefined" && ($.os.ios||$.os.blackberry10);
            $.feat.cssPrefix = $.os.webkit ? "Webkit" : $.os.fennec ? "Moz" : $.os.ie ? "ms" : $.os.opera ? "O" : "";
            $.feat.cssTransformStart = !$.os.opera ? "3d(" : "(";
            $.feat.cssTransformEnd = !$.os.opera ? ",0)" : ")";
            if ($.os.android && !$.os.webkit)
                $.os.android = false;

        }

        detectUA($, navigator.userAgent);
        $.__detectUA = detectUA; //needed for unit tests

        /**
         * Utility function to create a psuedo GUID
           ```
           var id= $.uuid();
           ```
         * @title $.uuid
         */
        $.uuid = function() {
            var S4 = function() {
                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
            };
            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
        };

        /**
         * Gets the css matrix, or creates a fake one
           ```
           $.getCssMatrix(domElement)
           ```
           @returns matrix with postion
           */
        $.getCssMatrix = function(ele) {
            if ($.is$(ele)) ele = ele.get(0);

            var matrixFn = window.WebKitCSSMatrix || window.MSCSSMatrix;

            if (ele === nundefined) {
                if (matrixFn) {
                    return new matrixFn();
                }
                else {
                    return {
                        a: 0,
                        b: 0,
                        c: 0,
                        d: 0,
                        e: 0,
                        f: 0
                    };
                }
            }

            var computedStyle = window.getComputedStyle(ele);

            var transform = computedStyle.webkitTransform ||
                            computedStyle.transform ||
                            computedStyle[$.feat.cssPrefix + 'Transform'];

            if (matrixFn)
                return new matrixFn(transform);
            else if (transform) {
                //fake css matrix
                var mat = transform.replace(/[^0-9\-.,]/g, '').split(',');
                return {
                    a: +mat[0],
                    b: +mat[1],
                    c: +mat[2],
                    d: +mat[3],
                    e: +mat[4],
                    f: +mat[5]
                };
            }
            else {
                return {
                    a: 0,
                    b: 0,
                    c: 0,
                    d: 0,
                    e: 0,
                    f: 0
                };
            }
        };

        /**
         * $.create - a faster alertnative to $("<div id='main'>this is some text</div>");
          ```
          $.create("div",{id:'main',innerHTML:'this is some text'});
          $.create("<div id='main'>this is some text</div>");
          ```
          * @param {String} DOM Element type or html
          * @param [{Object}] properties to apply to the element
          * @return {Object} Returns an appframework object
          * @title $.create(type,[params])
          */
        $.create = function(type, props) {
            var elem;
            var f = new $afm();
            if (props || type[0] !== "<") {
                if (props.html)
                    props.innerHTML = props.html, delete props.html;

                elem = document.createElement(type);
                for (var j in props) {
                    elem[j] = props[j];
                }
                f[f.length++] = elem;
            } else {
                elem = document.createElement("div");
                if (isWin8) {
                    MSApp.execUnsafeLocalFunction(function() {
                        elem.innerHTML = selector.trim();
                    });
                } else
                    elem.innerHTML = type;
                _shimNodes(elem.childNodes, f);
            }
            return f;
        };
        /**
         * $.query  - a faster alertnative to $("div");
          ```
          $.query(".panel");
          ```
          * @param {String} selector
          * @param {Object} [context]
          * @return {Object} Returns an appframework object
          * @title $.query(selector,[context])
          */
        $.query = function(sel, what) {
            if (!sel)
                return new $afm();
            what = what || document;
            var f = new $afm();
            return f.selector(sel, what);
        };
        /**
         Zepto.js events
         @api private
         */

        //The following is modified from Zepto.js / events.js
        //We've removed depricated  events like .live and allow anonymous functions to be removed
        var handlers = {},
            _afmid = 1;
        /**
         * Gets or sets the expando property on a javascript element
         * Also increments the internal counter for elements;
         * @param {Object} element
         * @return {Int} afmid
         * @api private
         */

        function afmid(element) {
            return element._afmid || (element._afmid = _afmid++);
        }
        /**
         * Searches through a local array that keeps track of event handlers for proxying.
         * Since we listen for multiple events, we match up the event, function and selector.
         * This is used to find, execute, remove proxied event functions
         * @param {Object} element
         * @param {String} [event]
         * @param {Function} [function]
         * @param {String|Object|Array} [selector]
         * @return {Function|null} handler function or false if not found
         * @api private
         */

        function findHandlers(element, event, fn, selector) {
            event = parse(event);
            if (event.ns)
                var matcher = matcherFor(event.ns);
            return (handlers[afmid(element)] || []).filter(function(handler) {
                return handler && (!event.e || handler.e == event.e) && (!event.ns || matcher.test(handler.ns)) && (!fn || handler.fn == fn || (typeof handler.fn === 'function' && typeof fn === 'function' && handler.fn === fn)) && (!selector || handler.sel == selector);
            });
        }
        /**
         * Splits an event name by "." to look for namespaces (e.g touch.click)
         * @param {String} event
         * @return {Object} an object with the event name and namespace
         * @api private
         */

        function parse(event) {
            var parts = ('' + event).split('.');
            return {
                e: parts[0],
                ns: parts.slice(1).sort().join(' ')
            };
        }
        /**
         * Regular expression checker for event namespace checking
         * @param {String} namespace
         * @return {Regex} regular expression
         * @api private
         */

        function matcherFor(ns) {
            return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)');
        }

        /**
         * Utility function that will loop through events that can be a hash or space delimited and executes the function
         * @param {String|Object} events
         * @param {Function} fn
         * @param {Iterator} [iterator]
         * @api private
         */

        function eachEvent(events, fn, iterator) {
            if ($.isObject(events))
                $.each(events, iterator);
            else
                events.split(/\s/).forEach(function(type) {
                    iterator(type, fn);
                });
        }

        /**
         * Helper function for adding an event and creating the proxy handler function.
         * All event handlers call this to wire event listeners up.  We create proxy handlers so they can be removed then.
         * This is needed for delegate/on
         * @param {Object} element
         * @param {String|Object} events
         * @param {Function} function that will be executed when event triggers
         * @param {String|Array|Object} [selector]
         * @param {Function} [getDelegate]
         * @api private
         */

        function add(element, events, fn, selector, getDelegate) {

            var id = afmid(element),
                set = (handlers[id] || (handlers[id] = []));
            eachEvent(events, fn, function(event, fn) {
                var delegate = getDelegate && getDelegate(fn, event),
                    callback = delegate || fn;
                var proxyfn = function(event) {
                    var result = callback.apply(element, [event].concat(event.data));
                    if (result === false)
                        event.preventDefault();
                    return result;
                };
                var handler = $.extend(parse(event), {
                    fn: fn,
                    proxy: proxyfn,
                    sel: selector,
                    del: delegate,
                    i: set.length
                });
                set.push(handler);
                element.addEventListener(handler.e, proxyfn, false);
            });
        }

        /**
         * Helper function to remove event listeners.  We look through each event and then the proxy handler array to see if it exists
         * If found, we remove the listener and the entry from the proxy array.  If no function is specified, we remove all listeners that match
         * @param {Object} element
         * @param {String|Object} events
         * @param {Function} [fn]
         * @param {String|Array|Object} [selector]
         * @api private
         */

        function remove(element, events, fn, selector) {

            var id = afmid(element);
            eachEvent(events || '', fn, function(event, fn) {
                findHandlers(element, event, fn, selector).forEach(function(handler) {
                    delete handlers[id][handler.i];
                    element.removeEventListener(handler.e, handler.proxy, false);
                });
            });
        }

        $.event = {
            add: add,
            remove: remove
        };

        /**
        * Binds an event to each element in the collection and executes the callback
            ```
            $().bind('click',function(){console.log('I clicked '+this.id);});
            ```

        * @param {String|Object} event
        * @param {Function} callback
        * @return {Object} appframework object
        * @title $().bind(event,callback)
        */
        $.fn.bind = function(event, callback) {
            for (var i = 0, len = this.length; i < len; i++) {
                add(this[i], event, callback);
            }
            return this;
        };
        /**
        * Unbinds an event to each element in the collection.  If a callback is passed in, we remove just that one, otherwise we remove all callbacks for those events
            ```
            $().unbind('click'); //Unbinds all click events
            $().unbind('click',myFunc); //Unbinds myFunc
            ```

        * @param {String|Object} event
        * @param {Function} [callback]
        * @return {Object} appframework object
        * @title $().unbind(event,[callback]);
        */
        $.fn.unbind = function(event, callback) {
            for (var i = 0, len = this.length; i < len; i++) {
                remove(this[i], event, callback);
            }
            return this;
        };

        /**
        * Binds an event to each element in the collection that will only execute once.  When it executes, we remove the event listener then right away so it no longer happens
            ```
            $().one('click',function(){console.log('I was clicked once');});
            ```

        * @param {String|Object} event
        * @param {Function} [callback]
        * @return appframework object
        * @title $().one(event,callback);
        */
        $.fn.one = function(event, callback) {
            return this.each(function(i, element) {
                add(this, event, callback, null, function(fn, type) {
                    return function() {
                        remove(element, type, fn);
                        var result = fn.apply(element, arguments);
                        return result;
                    };
                });
            });
        };

        /**
         * internal variables
         * @api private
         */

        var returnTrue = function() {
            return true;
        };
        var returnFalse = function() {
            return false;
        };
        var eventMethods = {
            preventDefault: 'isDefaultPrevented',
            stopImmediatePropagation: 'isImmediatePropagationStopped',
            stopPropagation: 'isPropagationStopped'
        };
        /**
         * Creates a proxy function for event handlers.
         * As "some" browsers dont support event.stopPropagation this call is bypassed if it cant be found on the event object.
         * @param {String} event
         * @return {Function} proxy
         * @api private
         */

        function createProxy(event) {
            var proxy = $.extend({
                originalEvent: event
            }, event);
            $.each(eventMethods, function(name, predicate) {
                proxy[name] = function() {
                    this[predicate] = returnTrue;
                    if (name == "stopImmediatePropagation" || name == "stopPropagation") {
                        event.cancelBubble = true;
                        if (!event[name])
                            return;
                    }
                    return event[name].apply(event, arguments);
                };
                proxy[predicate] = returnFalse;
            });
            return proxy;
        }

        /**
        * Delegate an event based off the selector.  The event will be registered at the parent level, but executes on the selector.
            ```
            $("#div").delegate("p",'click',callback);
            ```

        * @param {String|Array|Object} selector
        * @param {String|Object} event
        * @param {Object} data
        * @param {Function} callback
        * @return {Object} appframework object
        * @title $().delegate(selector,event,[data],callback)
        */
        function addDelegate(element,event,callback,selector,data){
            add(element, event, callback, selector, function(fn) {
                    return function(e) {
                        var evt, match = $(e.target).closest(selector, element).get(0);
                        if (match) {
                            evt = $.extend(createProxy(e), {
                                currentTarget: match,
                                liveFired: element,
                                delegateTarget:element,
                                data:data
                            });
                            return fn.apply(match, [evt].concat([].slice.call(arguments, 1)));
                        }
                    };
                });
        }
        $.fn.delegate = function(selector, event, data, callback) {
            if ($.isFunction(data)) {
                callback = data;
                data = null;
            }
            for (var i = 0, len = this.length; i < len; i++) {
                addDelegate(this[i],event,callback,selector,data);
            }
            return this;
        };

        /**
        * Unbinds events that were registered through delegate.  It acts upon the selector and event.  If a callback is specified, it will remove that one, otherwise it removes all of them.
            ```
            $("#div").undelegate("p",'click',callback);//Undelegates callback for the click event
            $("#div").undelegate("p",'click');//Undelegates all click events
            ```

        * @param {String|Array|Object} selector
        * @param {String|Object} event
        * @param {Function} callback
        * @return {Object} appframework object
        * @title $().undelegate(selector,event,[callback]);
        */
        $.fn.undelegate = function(selector, event, callback) {
            for (var i = 0, len = this.length; i < len; i++) {
                remove(this[i], event, callback, selector);
            }
            return this;
        };

        /**
        * Similar to delegate, but the function parameter order is easier to understand.
        * If selector is undefined or a function, we just call .bind, otherwise we use .delegate
            ```
            $("#div").on("click","p",callback);
            ```

        * @param {String|Array|Object} selector
        * @param {String|Object} event
        * @param {Object} data
        * @param {Function} callback
        * @return {Object} appframework object
        * @title $().on(event,selector,[data],callback);
        */
        $.fn.on = function(event, selector, data, callback) {
            if ($.isFunction(data)) {
                callback = data;
                data = null;
            }

            return selector === nundefined || $.isFunction(selector) ? this.bind(event, selector) : this.delegate(selector, event, data,callback);
        };
        /**
        * Removes event listeners for .on()
        * If selector is undefined or a function, we call unbind, otherwise it's undelegate
            ```
            $().off("click","p",callback); //Remove callback function for click events
            $().off("click","p") //Remove all click events
            ```

        * @param {String|Object} event
        * @param {String|Array|Object} selector
        * @param {Sunction} callback
        * @return {Object} appframework object
        * @title $().off(event,selector,[callback])
        */
        $.fn.off = function(event, selector, callback) {
            return selector === nundefined || $.isFunction(selector) ? this.unbind(event, selector) : this.undelegate(selector, event, callback);
        };

        /**
        This triggers an event to be dispatched.  Usefull for emulating events, etc.
        ```
        $().trigger("click",{foo:'bar'});//Trigger the click event and pass in data
        ```

        * @param {String|Object} event
        * @param {Object} [data]
        * @return {Object} appframework object
        * @title $().trigger(event,data);
        */
        $.fn.trigger = function(event, data, props) {
            if (typeof event == 'string')
                event = $.Event(event, props);
            event.data = data;
            for (var i = 0, len = this.length; i < len; i++) {
                this[i].dispatchEvent(event);
            }
            return this;
        };

        /**
         * Creates a custom event to be used internally.
         * @param {String} type
         * @param {Object} [properties]
         * @return {event} a custom event that can then be dispatched
         * @title $.Event(type,props);
         */

        $.Event = function(type, props) {
            var event = document.createEvent('Events'),
                bubbles = true;
            if (props)
                for (var name in props)
                    (name == 'bubbles') ? (bubbles = !! props[name]) : (event[name] = props[name]);
            event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null);
            return event;
        };

        /* The following are for events on objects */
        /**
         * Bind an event to an object instead of a DOM Node
           ```
           $.bind(this,'event',function(){});
           ```
         * @param {Object} object
         * @param {String} event name
         * @param {Function} function to execute
         * @title $.bind(object,event,function);
         */
        $.bind = function(obj, ev, f) {
            if (!obj) return;
            if (!obj.__events) obj.__events = {};
            if (!$.isArray(ev)) ev = [ev];
            for (var i = 0; i < ev.length; i++) {
                if (!obj.__events[ev[i]]) obj.__events[ev[i]] = [];
                obj.__events[ev[i]].push(f);
            }
        };

        /**
         * Trigger an event to an object instead of a DOM Node
           ```
           $.trigger(this,'event',arguments);
           ```
         * @param {Object} object
         * @param {String} event name
         * @param {Array} arguments
         * @title $.trigger(object,event,argments);
         */
        $.trigger = function(obj, ev, args) {
            if (!obj) return;
            var ret = true;
            if (!obj.__events) return ret;
            if (!$.isArray(ev)) ev = [ev];
            if (!$.isArray(args)) args = [];
            for (var i = 0; i < ev.length; i++) {
                if (obj.__events[ev[i]]) {
                    var evts = obj.__events[ev[i]].slice(0);
                    for (var j = 0; j < evts.length; j++)
                        if ($.isFunction(evts[j]) && evts[j].apply(obj, args) === false)
                            ret = false;
                }
            }
            return ret;
        };
        /**
         * Unbind an event to an object instead of a DOM Node
           ```
           $.unbind(this,'event',function(){});
           ```
         * @param {Object} object
         * @param {String} event name
         * @param {Function} function to execute
         * @title $.unbind(object,event,function);
         */
        $.unbind = function(obj, ev, f) {
            if (!obj.__events) return;
            if (!$.isArray(ev)) ev = [ev];
            for (var i = 0; i < ev.length; i++) {
                if (obj.__events[ev[i]]) {
                    var evts = obj.__events[ev[i]];
                    for (var j = 0; j < evts.length; j++) {
                        if (f == nundefined)
                            delete evts[j];
                        if (evts[j] == f) {
                            evts.splice(j, 1);
                            break;
                        }
                    }
                }
            }
        };


        /**
         * Creates a proxy function so you can change the 'this' context in the function
         * Update: now also allows multiple argument call or for you to pass your own arguments
           ```
            var newObj={foo:bar}
            $("#main").bind("click",$.proxy(function(evt){console.log(this)},newObj);

            or

            ( $.proxy(function(foo, bar){console.log(this+foo+bar)}, newObj) )('foo', 'bar');

            or

            ( $.proxy(function(foo, bar){console.log(this+foo+bar)}, newObj, ['foo', 'bar']) )();
           ```
         * @param {Function} Callback
         * @param {Object} Context
         * @title $.proxy(callback,context);
         */
        $.proxy = function(f, c, args) {
            return function() {
                if (args) return f.apply(c, args); //use provided arguments
                return f.apply(c, arguments); //use scope function call arguments
            };
        };


        /**
         * Removes listeners on a div and its children recursively
            ```
             cleanUpNode(node,kill)
            ```
         * @param {HTMLDivElement} the element to clean up recursively
         * @api private
         */

        function cleanUpNode(node, kill) {
            //kill it before it lays eggs!
            if (kill && node.dispatchEvent) {
                var e = $.Event('destroy', {
                    bubbles: false
                });
                node.dispatchEvent(e);
            }
            //cleanup itself
            var id = afmid(node);
            if (id && handlers[id]) {
                for (var key in handlers[id])
                    node.removeEventListener(handlers[id][key].e, handlers[id][key].proxy, false);
                delete handlers[id];
            }
        }

        function cleanUpContent(node, kill) {
            if (!node) return;
            //cleanup children
            var children = node.childNodes;
            if (children && children.length > 0) {
                for (var i; i < children.length; i++) {
                    cleanUpContent(children[i], kill);
                }
            }

            cleanUpNode(node, kill);
        }
        var cleanUpAsap = function(els, kill) {
            for (var i = 0; i < els.length; i++) {
                cleanUpContent(els[i], kill);
            }
        };

        /**
         * Function to clean up node content to prevent memory leaks
           ```
           $.cleanUpContent(node,itself,kill)
           ```
         * @param {HTMLNode} node
         * @param {Bool} kill itself
         * @param {bool} Kill nodes
         * @title $.cleanUpContent(node,itself,kill)
         */
        $.cleanUpContent = function(node, itself, kill) {
            if (!node) return;
            //cleanup children
            var cn = node.childNodes;
            if (cn && cn.length > 0) {
                //destroy everything in a few ms to avoid memory leaks
                //remove them all and copy objs into new array
                $.asap(cleanUpAsap, {}, [slice.apply(cn, [0]), kill]);
            }
            //cleanUp this node
            if (itself) cleanUpNode(node, kill);
        };

        // Like setTimeout(fn, 0); but much faster
        var timeouts = [];
        var contexts = [];
        var params = [];
        /**
         * This adds a command to execute in the JS stack, but is faster then setTimeout
           ```
           $.asap(function,context,args)
           ```
         * @param {Function} function
         * @param {Object} context
         * @param {Array} arguments
         */
        $.asap = function(fn, context, args) {
            if (!$.isFunction(fn)) throw "$.asap - argument is not a valid function";
            timeouts.push(fn);
            contexts.push(context ? context : {});
            params.push(args ? args : []);
            //post a message to ourselves so we know we have to execute a function from the stack
            window.postMessage("afm-asap", "*");
        };
        window.addEventListener("message", function(event) {
            if (event.source == window && event.data == "afm-asap") {
                event.stopPropagation();
                if (timeouts.length > 0) { //just in case...
                    (timeouts.shift()).apply(contexts.shift(), params.shift());
                }
            }
        }, true);

        /**
         * this function executes javascript in HTML.
           ```
           $.parseJS(content)
           ```
        * @param {String|DOM} content
        * @title $.parseJS(content);
        */
        var remoteJSPages = {};
        $.parseJS = function(div) {
            if (!div)
                return;
            if (typeof(div) == "string") {
                var elem = document.createElement("div");
                if (isWin8) {
                    MSApp.execUnsafeLocalFunction(function() {
                        elem.innerHTML = div;
                    });
                } else
                    elem.innerHTML = div;

                div = elem;
            }
            var scripts = div.getElementsByTagName("script");
            div = null;
            for (var i = 0; i < scripts.length; i++) {
                if (scripts[i].src.length > 0 && !remoteJSPages[scripts[i].src] && !isWin8) {
                    var doc = document.createElement("script");
                    doc.type = scripts[i].type;
                    doc.src = scripts[i].src;
                    document.getElementsByTagName('head')[0].appendChild(doc);
                    remoteJSPages[scripts[i].src] = 1;
                    doc = null;
                } else {
                    window['eval'](scripts[i].innerHTML);
                }
            }
        };


        /**
        //custom events since people want to do $().click instead of $().bind("click")
        */

        ["click", "keydown", "keyup", "keypress", "submit", "load", "resize", "change", "select", "error"].forEach(function(event) {
            $.fn[event] = function(cb) {
                return cb ? this.bind(event, cb) : this.trigger(event);
            };
        });


        ['focus', 'blur'].forEach(function(name) {
            $.fn[name] = function(callback) {
                if (this.length === 0) return;
                if (callback)
                    this.bind(name, callback);
                else
                    for (var i = 0; i < this.length; i++) {
                        try {
                            this[i][name]();
                        } catch (e) {}
                }
                return this;
            };
        });

        /**
         * End of APIS
         * @api private
         */
        return $;

    })(window);
    window.jq = af; //backwards compat
    '$' in window || (window.$ = af);
    if (typeof define === "function" && define.amd) {
        define("appframework", [], function() {
            return af;
        });
    } else if (typeof module !== 'undefined' && module.exports) {
        module.exports.af = af;
        module.exports.$ = af;
    }
    //Helper function used in af.mobi.plugins.
    if (!window.numOnly) {
        window.numOnly = function numOnly(val) {
            if (val === undefined || val === '') return 0;
            if (isNaN(parseFloat(val))) {
                if (val.replace) {
                    val = val.replace(/[^0-9.-]/g, "");
                } else return 0;
            }
            return parseFloat(val);
        };
    }
}
