[
  {
    "path": ".jshintignore",
    "content": "test/zepto-0.4.js\ntest/underscore.js\ntest/jquery-1.4.4.min.js\ntest/qunit\n"
  },
  {
    "path": ".jshintrc",
    "content": "{\n    \"asi\": false,\n    \"expr\": true,\n    \"loopfunc\": true,\n    \"curly\": false,\n    \"evil\": true,\n    \"white\": true,\n    \"undef\": true,\n    \"browser\": true,\n    \"trailing\": true,\n    \"node\": true\n}\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "Copyright (c) 2011 Henrik Joreteg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "# Happy.js – are your forms happy? Just ask 'em!\n\n[http://projects.joreteg.com/Happy.js/](http://projects.joreteg.com/Happy.js/) | [Demo](http://projects.joreteg.com/Happy.js/demo.html)\n"
  },
  {
    "path": "demo.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n    <meta name=\"viewport\" content=\"user-scalable=yes, width=device-width, initial-scale=1\" />\n    <title>Happy.js | Demo</title>\n    <style>\n        *, *:before, *:after {\n            box-sizing: inherit;\n        }\n        html {\n            font-size: 16px;\n        }\n        body {\n            box-sizing: border-box;\n            font-family: Helvetica;\n            background: #eee;\n            padding: 0 1rem;\n        }\n        h1 {\n            font-size: 1.5rem;\n            color: #2196F3;\n            margin: 0 0 1rem;\n        }\n        form {\n            margin: 0;\n        }\n        input {\n            display: block;\n        }\n        .unhappyMessage {\n            color: #F44336;\n            display: block;\n        }\n\n        .card {\n            background: #fff;\n            padding: 1rem;\n            margin: 1rem auto;\n            max-width: 360px;\n            box-shadow: 0 1px 1px rgba(0,0,0,0.15) ,\n            0 1px 2px rgba(0,0,0,0.1);\n        }\n\n        input,\n        button,\n        .unhappyMessage {\n            display: block;\n            width: 100%;\n            border: 0;\n            padding: 10px 15px;\n        }\n\n        input {\n            background: #eee;\n            margin-bottom: 1rem;\n            transition: box-shadow .05s;\n        }\n\n        input:focus {\n            outline: 0;\n            box-shadow: inset 0 1px 2px rgba(0,0,0,.15);\n        }\n\n        .unhappyMessage {\n            margin-top: -1em;\n            margin-bottom: 1rem;\n            padding-left: 0;\n            padding-right: 0;\n        }\n\n        button {\n            appearance: none;\n            background: #4CAF50;\n            color: #fff;\n            text-align: center;\n            transition: background .2s;\n        }\n\n        button:hover, button:focus {\n            outline: 0;\n            background: #8BC34A;\n        }\n    </style>\n    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js\"></script>\n    <script src=\"happy.js\"></script>\n    <script src=\"happy.methods.js\"></script>\n    <script>\n        function minLength(val, min) {\n            return val.length < min ? new Error('Your name must be longer than ' + min + ' character' + (min !== 0 ? 's' : '') + '.') : true;\n        }\n\n        function maxLength(val, max) {\n            return val.length > max ? new Error('Your name must be shorter than ' + max + ' character' + (max !== 0 ? 's' : '') + '.') : true;\n        }\n\n        $(document).ready(function () {\n            $('#awesomeForm').isHappy({\n                fields: {\n                    // reference the field you're talking about, probably by `id`\n                    // but you could certainly do $('[name=name]') as well.\n                    '#yourName': {\n                        required: true,\n                        message: 'Might we inquire your name',\n                        test: [minLength, maxLength],\n                        arg: [3, 64]\n                    },\n                    '#email': {\n                        required: true,\n                        message: 'How are we to reach you sans email??',\n                        test: happy.email // this can be *any* function that returns true or false\n                    },\n                    '#birthday': {\n                        required: true,\n                        message: 'Please provide a valid birth date.',\n                        test: function(value) {\n                            var birthday = new Date(value);\n                            var birthdayInt = birthday.getTime();\n\n                            if (isNaN(birthdayInt)) {\n                                // uses the default message.\n                                return false;\n                            }\n                            if(birthdayInt > new Date()) {\n                                return new Error('Your birthday must have already happened.');\n                            }\n                            if (birthday.getDay() === 3) {\n                                return new Error('Your birthday cannot have happened on a Wednesday.');\n                            }\n                            return true;\n                        }\n                    }\n                }\n            });\n            $('#awesomeFormSubmitButton').isHappy({\n                submitButton: '#submitTheForm',\n                fields: {\n                    // reference the field you're talking about, probably by `id`\n                    // but you could certainly do $('[name=name]') as well.\n                    '#yourName-2': {\n                        required: true,\n                        message: 'Might we inquire your name'\n                    },\n                    '#email-2': {\n                        required: true,\n                        message: 'How are we to reach you sans email??',\n                        test: happy.email // this can be *any* function that returns true or false\n                    }\n                }\n            });\n        });\n    </script>\n</head>\n<body>\n    <div class=\"card\">\n        <h1>Simple Form</h1>\n        <form id=\"awesomeForm\" action=\"/lights/camera\" method=\"post\">\n            <label for=\"yourName\">Name</label>\n            <input id=\"yourName\" type=\"text\" name=\"name\" />\n            <label for=\"email\">Email</label>\n            <input id=\"email\" type=\"email\" name=\"email\" />\n            <label for=\"birthday\">Birthday</label>\n            <input id=\"birthday\" type=\"text\" name=\"birthday\" />\n            <button type=\"submit\">go</button>\n        </form>\n    </div>\n\n    <div class=\"card\">\n        <h1>With config.submitButton</h1>\n        <form id=\"awesomeFormSubmitButton\" action=\"/lights/camera\" method=\"post\">\n            <label for=\"yourName-2\">Name</label>\n            <input id=\"yourName-2\" type=\"text\" name=\"name\" />\n            <label for=\"email-2\">Email</label>\n            <input id=\"email-2\" type=\"email\" name=\"email\" />\n        </form>\n    </div>\n\n    <div class=\"card\">\n        <button id=\"submitTheForm\">Submit the form</button>\n    </div>\n</body>\n</html>"
  },
  {
    "path": "happy.js",
    "content": "/*global $*/\n(function happyJS($) {\n    $.fn.isHappy = function isHappy(config) {\n        var fields = [], item;\n        var pauseMessages = false;\n\n        function isFunction(obj) {\n            return typeof obj === 'function';\n        }\n        function defaultError(error) { //Default error template\n            var msgErrorClass = config.classes && config.classes.message || 'unhappyMessage';\n            return $('<span id=\"' + error.id + '\" class=\"' + msgErrorClass + '\" role=\"alert\">' + error.message + '</span>');\n        }\n        function getError(error) { //Generate error html from either config or default\n            if (isFunction(config.errorTemplate)) {\n                return config.errorTemplate(error);\n            }\n            return defaultError(error);\n        }\n        function handleSubmit(e) {\n            var  i, l;\n            var errors = false;\n            if (config.testMode) {\n                e.preventDefault();\n            }\n            for (i = 0, l = fields.length; i < l; i += 1) {\n                if (!fields[i].testValid(true)) {\n                    errors = true;\n                }\n            }\n            if (errors) {\n                if (isFunction(config.unHappy)) config.unHappy(e);\n                return false;\n            } else if (config.testMode) {\n                if (window.console) console.warn('would have submitted');\n                if (isFunction(config.happy)) return config.happy(e);\n            }\n            if (isFunction(config.happy)) return config.happy(e);\n        }\n        function handleMouseUp() {\n            pauseMessages = false;\n        }\n        function handleMouseDown() {\n            pauseMessages = true;\n        }\n        function processField(opts, selector) {\n            var field = $(selector);\n            if (!field.length) return;\n\n            selector = field.prop('id') || field.prop('name').replace(['[',']'], '');\n            var error = {\n                message: opts.message || '',\n                id: selector + '_unhappy'\n            };\n            var errorEl = $(error.id).length > 0 ? $(error.id) : getError(error);\n            var handleBlur = function handleBlur() {\n                if (!pauseMessages) {\n                    field.testValid();\n                } else {\n                    $(window).one('mouseup', field.testValid);\n                }\n            };\n\n            fields.push(field);\n            field.testValid = function testValid(submit) {\n                var val, temp;\n                var required = field.prop('required') || opts.required;\n                var password = field.attr('type') === 'password';\n                var arg = isFunction(opts.arg) ? opts.arg() : opts.arg;\n                var errorTarget = (opts.errorTarget && $(opts.errorTarget)) || field;\n                var fieldErrorClass = config.classes && config.classes.field || 'unhappy';\n                var testResult = errorTarget.hasClass(fieldErrorClass);\n                var oldMessage = error.message;\n\n                // handle control groups (checkboxes, radio)\n                if (field.length > 1) {\n                    val = [];\n                    field.each(function(i,obj) {\n                        val.push($(obj).val());\n                    });\n                    val = val.join(',');\n                } else {\n                    // clean it or trim it\n                    if (isFunction(opts.clean)) {\n                        val = opts.clean(field.val());\n                    } else if (!password && typeof opts.trim === 'undefined' || opts.trim) {\n                        val = $.trim(field.val());\n                    } else {\n                        val = field.val();\n                    }\n\n                    // write it back to the field\n                    field.val(val);\n                }\n\n                // check if we've got an error on our hands\n                if (submit === true && required === true) {\n                    testResult = !val.length;\n                }\n                if ((val.length > 0 || required === 'sometimes') && opts.test) {\n                    if (isFunction(opts.test)) {\n                        testResult = opts.test(val, arg);\n                    }\n                    else if (typeof opts.test === 'object') {\n                        $.each(opts.test, function (i, test) {\n                            if (isFunction(test)) {\n                                testResult = test(val, arg);\n                                if (testResult !== true) {\n                                    return false;\n                                }\n                            }\n                        });\n                    }\n\n                    if (testResult instanceof Error) {\n                        error.message = testResult.message;\n                    }\n                    else {\n                        testResult = !testResult;\n                        error.message = opts.message || '';\n                    }\n                }\n\n                // only rebuild the error if necessary\n                if (!oldMessage !== error.message) {\n                    temp = getError(error);\n                    errorEl.replaceWith(temp);\n                    errorEl = temp;\n                }\n\n                if (testResult) {\n                    errorTarget.addClass(fieldErrorClass).after(errorEl);\n                    return false;\n                } else {\n                    errorEl.remove();\n                    errorTarget.removeClass(fieldErrorClass);\n                    return true;\n                }\n            };\n            field.on(opts.when || config.when || 'blur', handleBlur);\n        }\n\n        for (item in config.fields) {\n            if (config.fields.hasOwnProperty(item)) {\n                processField(config.fields[item], item);\n            }\n        }\n\n        $(config.submitButton || this).on('mousedown', handleMouseDown);\n        $(window).on('mouseup', handleMouseUp);\n\n        if (config.submitButton) {\n            $(config.submitButton).click(handleSubmit);\n        } else {\n            this.on('submit', handleSubmit);\n        }\n        return this;\n    };\n})(this.jQuery || this.Zepto);\n"
  },
  {
    "path": "happy.methods.js",
    "content": "var happy = {\n    USPhone: function (val) {\n        return /^\\(?(\\d{3})\\)?[\\- ]?\\d{3}[\\- ]?\\d{4}$/.test(val);\n    },\n\n    // matches mm/dd/yyyy (requires leading 0's (which may be a bit silly, what do you think?)\n    date: function (val) {\n        return /^(?:0[1-9]|1[0-2])\\/(?:0[1-9]|[12][0-9]|3[01])\\/(?:\\d{4})/.test(val);\n    },\n\n    email: function (val) {\n        return /^(?:\\w+\\.?\\+?)*\\w+@(?:\\w+\\.)+\\w+$/.test(val);\n    },\n\n    minLength: function (val, length) {\n        return val.length >= length;\n    },\n\n    maxLength: function (val, length) {\n        return val.length <= length;\n    },\n\n    equal: function (val1, val2) {\n        return (val1 == val2);\n    }\n};\n"
  },
  {
    "path": "test/qunit/qunit.css",
    "content": "/** Font Family and Sizes */\n\n#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {\n\tfont-family: \"Helvetica Neue Light\", \"HelveticaNeue-Light\", \"Helvetica Neue\", Calibri, Helvetica, Arial;\n}\n\n#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }\n#qunit-tests { font-size: smaller; }\n\n\n/** Resets */\n\n#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {\n\tmargin: 0;\n\tpadding: 0;\n}\n\n\n/** Header */\n\n#qunit-header {\n\tpadding: 0.5em 0 0.5em 1em;\n\t\n\tcolor: #fff;\n\ttext-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px;\n\tbackground-color: #0d3349;\n\t\n\tborder-radius: 15px 15px 0 0;\n\t-moz-border-radius: 15px 15px 0 0;\n\t-webkit-border-top-right-radius: 15px;\n\t-webkit-border-top-left-radius: 15px;\n}\n\n#qunit-header a {\n\ttext-decoration: none;\n\tcolor: white;\n}\n\n#qunit-banner {\n\theight: 5px;\n}\n\n#qunit-testrunner-toolbar {\n\tpadding: 0em 0 0.5em 2em;\n}\n\n#qunit-userAgent {\n\tpadding: 0.5em 0 0.5em 2.5em;\n\tbackground-color: #2b81af;\n\tcolor: #fff;\n\ttext-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;\n}\n\n\n/** Tests: Pass/Fail */\n\n#qunit-tests {\n\tlist-style-position: inside;\n}\n\n#qunit-tests li {\n\tpadding: 0.4em 0.5em 0.4em 2.5em;\n\tborder-bottom: 1px solid #fff;\n\tlist-style-position: inside;\n}\n\n#qunit-tests li strong {\n\tcursor: pointer;\n}\n\n#qunit-tests ol {\n\tmargin-top: 0.5em;\n\tpadding: 0.5em;\n\t\n\tbackground-color: #fff;\n\t\n\tborder-radius: 15px;\n\t-moz-border-radius: 15px;\n\t-webkit-border-radius: 15px;\n\t\n\tbox-shadow: inset 0px 2px 13px #999;\n\t-moz-box-shadow: inset 0px 2px 13px #999;\n\t-webkit-box-shadow: inset 0px 2px 13px #999;\n}\n\n/*** Test Counts */\n\n#qunit-tests b.counts                       { color: black; }\n#qunit-tests b.passed                       { color: #5E740B; }\n#qunit-tests b.failed                       { color: #710909; }\n\n#qunit-tests li li {\n\tmargin: 0.5em;\n\tpadding: 0.4em 0.5em 0.4em 0.5em;\n\tbackground-color: #fff;\n\tborder-bottom: none;\n\tlist-style-position: inside;\n}\n\n/*** Passing Styles */\n\n#qunit-tests li li.pass {\n\tcolor: #5E740B;\n\tbackground-color: #fff;\n\tborder-left: 26px solid #C6E746;\n}\n\n#qunit-tests .pass                          { color: #528CE0; background-color: #D2E0E6; }\n#qunit-tests .pass .test-name               { color: #366097; }\n \n#qunit-tests .pass .test-actual,\n#qunit-tests .pass .test-expected           { color: #999999; }\n\n#qunit-banner.qunit-pass                    { background-color: #C6E746; }\n\n/*** Failing Styles */\n\n#qunit-tests li li.fail {\n\tcolor: #710909;\n\tbackground-color: #fff;\n\tborder-left: 26px solid #EE5757;\n}\n\n#qunit-tests .fail                          { color: #000000; background-color: #EE5757; }\n#qunit-tests .fail .test-name,\n#qunit-tests .fail .module-name             { color: #000000; }\n\n#qunit-tests .fail .test-actual             { color: #EE5757; }\n#qunit-tests .fail .test-expected           { color: green;   }\n\n#qunit-banner.qunit-fail, \n#qunit-testrunner-toolbar                   { background-color: #EE5757; }\n\n\n/** Footer */\n\n#qunit-testresult {\n\tpadding: 0.5em 0.5em 0.5em 2.5em;\n\n\tcolor: #2b81af;\n\tbackground-color: #D2E0E6;\n\n\tborder-radius: 0 0 15px 15px;\n\t-moz-border-radius: 0 0 15px 15px;\n\t-webkit-border-bottom-right-radius: 15px;\n\t-webkit-border-bottom-left-radius: 15px;\n}\n\n/** Fixture */\n\n#qunit-fixture {\n\tposition: absolute;\n\ttop: -10000px;\n\tleft: -10000px;\n}\n"
  },
  {
    "path": "test/qunit/qunit.js",
    "content": "/*\n * QUnit - A JavaScript Unit Testing Framework\n * \n * http://docs.jquery.com/QUnit\n *\n * Copyright (c) 2009 John Resig, Jörn Zaefferer\n * Dual licensed under the MIT (MIT-LICENSE.txt)\n * and GPL (GPL-LICENSE.txt) licenses.\n */\n\n(function(window) {\n\nvar QUnit = {\n\n\t// call on start of module test to prepend name to all tests\n\tmodule: function(name, testEnvironment) {\n\t\tconfig.currentModule = name;\n\n\t\tsynchronize(function() {\n\t\t\tif ( config.currentModule ) {\n\t\t\t\tQUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );\n\t\t\t}\n\n\t\t\tconfig.currentModule = name;\n\t\t\tconfig.moduleTestEnvironment = testEnvironment;\n\t\t\tconfig.moduleStats = { all: 0, bad: 0 };\n\n\t\t\tQUnit.moduleStart( name, testEnvironment );\n\t\t});\n\t},\n\n\tasyncTest: function(testName, expected, callback) {\n\t\tif ( arguments.length === 2 ) {\n\t\t\tcallback = expected;\n\t\t\texpected = 0;\n\t\t}\n\n\t\tQUnit.test(testName, expected, callback, true);\n\t},\n\t\n\ttest: function(testName, expected, callback, async) {\n\t\tvar name = '<span class=\"test-name\">' + testName + '</span>', testEnvironment, testEnvironmentArg;\n\n\t\tif ( arguments.length === 2 ) {\n\t\t\tcallback = expected;\n\t\t\texpected = null;\n\t\t}\n\t\t// is 2nd argument a testEnvironment?\n\t\tif ( expected && typeof expected === 'object') {\n\t\t\ttestEnvironmentArg =  expected;\n\t\t\texpected = null;\n\t\t}\n\n\t\tif ( config.currentModule ) {\n\t\t\tname = '<span class=\"module-name\">' + config.currentModule + \"</span>: \" + name;\n\t\t}\n\n\t\tif ( !validTest(config.currentModule + \": \" + testName) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsynchronize(function() {\n\n\t\t\ttestEnvironment = extend({\n\t\t\t\tsetup: function() {},\n\t\t\t\tteardown: function() {}\n\t\t\t}, config.moduleTestEnvironment);\n\t\t\tif (testEnvironmentArg) {\n\t\t\t\textend(testEnvironment,testEnvironmentArg);\n\t\t\t}\n\n\t\t\tQUnit.testStart( testName, testEnvironment );\n\n\t\t\t// allow utility functions to access the current test environment\n\t\t\tQUnit.current_testEnvironment = testEnvironment;\n\t\t\t\n\t\t\tconfig.assertions = [];\n\t\t\tconfig.expected = expected;\n\t\t\t\n\t\t\tvar tests = id(\"qunit-tests\");\n\t\t\tif (tests) {\n\t\t\t\tvar b = document.createElement(\"strong\");\n\t\t\t\t\tb.innerHTML = \"Running \" + name;\n\t\t\t\tvar li = document.createElement(\"li\");\n\t\t\t\t\tli.appendChild( b );\n\t\t\t\t\tli.id = \"current-test-output\";\n\t\t\t\ttests.appendChild( li )\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tif ( !config.pollution ) {\n\t\t\t\t\tsaveGlobal();\n\t\t\t\t}\n\n\t\t\t\ttestEnvironment.setup.call(testEnvironment);\n\t\t\t} catch(e) {\n\t\t\t\tQUnit.ok( false, \"Setup failed on \" + name + \": \" + e.message );\n\t\t\t}\n\t    });\n\t\n\t    synchronize(function() {\n\t\t\tif ( async ) {\n\t\t\t\tQUnit.stop();\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcallback.call(testEnvironment);\n\t\t\t} catch(e) {\n\t\t\t\tfail(\"Test \" + name + \" died, exception and test follows\", e, callback);\n\t\t\t\tQUnit.ok( false, \"Died on test #\" + (config.assertions.length + 1) + \": \" + e.message );\n\t\t\t\t// else next test will carry the responsibility\n\t\t\t\tsaveGlobal();\n\n\t\t\t\t// Restart the tests if they're blocking\n\t\t\t\tif ( config.blocking ) {\n\t\t\t\t\tstart();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tsynchronize(function() {\n\t\t\ttry {\n\t\t\t\tcheckPollution();\n\t\t\t\ttestEnvironment.teardown.call(testEnvironment);\n\t\t\t} catch(e) {\n\t\t\t\tQUnit.ok( false, \"Teardown failed on \" + name + \": \" + e.message );\n\t\t\t}\n\t    });\n\t\n\t    synchronize(function() {\n\t\t\ttry {\n\t\t\t\tQUnit.reset();\n\t\t\t} catch(e) {\n\t\t\t\tfail(\"reset() failed, following Test \" + name + \", exception and reset fn follows\", e, QUnit.reset);\n\t\t\t}\n\n\t\t\tif ( config.expected && config.expected != config.assertions.length ) {\n\t\t\t\tQUnit.ok( false, \"Expected \" + config.expected + \" assertions, but \" + config.assertions.length + \" were run\" );\n\t\t\t}\n\n\t\t\tvar good = 0, bad = 0,\n\t\t\t\ttests = id(\"qunit-tests\");\n\n\t\t\tconfig.stats.all += config.assertions.length;\n\t\t\tconfig.moduleStats.all += config.assertions.length;\n\n\t\t\tif ( tests ) {\n\t\t\t\tvar ol  = document.createElement(\"ol\");\n\n\t\t\t\tfor ( var i = 0; i < config.assertions.length; i++ ) {\n\t\t\t\t\tvar assertion = config.assertions[i];\n\n\t\t\t\t\tvar li = document.createElement(\"li\");\n\t\t\t\t\tli.className = assertion.result ? \"pass\" : \"fail\";\n\t\t\t\t\tli.innerHTML = assertion.message || \"(no message)\";\n\t\t\t\t\tol.appendChild( li );\n\n\t\t\t\t\tif ( assertion.result ) {\n\t\t\t\t\t\tgood++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbad++;\n\t\t\t\t\t\tconfig.stats.bad++;\n\t\t\t\t\t\tconfig.moduleStats.bad++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (bad == 0) {\n\t\t\t\t\tol.style.display = \"none\";\n\t\t\t\t}\n\n\t\t\t\tvar b = document.createElement(\"strong\");\n\t\t\t\tb.innerHTML = name + \" <b class='counts'>(<b class='failed'>\" + bad + \"</b>, <b class='passed'>\" + good + \"</b>, \" + config.assertions.length + \")</b>\";\n\t\t\t\t\n\t\t\t\taddEvent(b, \"click\", function() {\n\t\t\t\t\tvar next = b.nextSibling, display = next.style.display;\n\t\t\t\t\tnext.style.display = display === \"none\" ? \"block\" : \"none\";\n\t\t\t\t});\n\t\t\t\t\n\t\t\t\taddEvent(b, \"dblclick\", function(e) {\n\t\t\t\t\tvar target = e && e.target ? e.target : window.event.srcElement;\n\t\t\t\t\tif ( target.nodeName.toLowerCase() == \"span\" || target.nodeName.toLowerCase() == \"b\" ) {\n\t\t\t\t\t\ttarget = target.parentNode;\n\t\t\t\t\t}\n\t\t\t\t\tif ( window.location && target.nodeName.toLowerCase() === \"strong\" ) {\n\t\t\t\t\t\twindow.location.search = \"?\" + encodeURIComponent(getText([target]).replace(/\\(.+\\)$/, \"\").replace(/(^\\s*|\\s*$)/g, \"\"));\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tvar li = id(\"current-test-output\");\n\t\t\t\tli.id = \"\";\n\t\t\t\tli.className = bad ? \"fail\" : \"pass\";\n\t\t\t\tli.removeChild( li.firstChild );\n\t\t\t\tli.appendChild( b );\n\t\t\t\tli.appendChild( ol );\n\n\t\t\t\tif ( bad ) {\n\t\t\t\t\tvar toolbar = id(\"qunit-testrunner-toolbar\");\n\t\t\t\t\tif ( toolbar ) {\n\t\t\t\t\t\ttoolbar.style.display = \"block\";\n\t\t\t\t\t\tid(\"qunit-filter-pass\").disabled = null;\n\t\t\t\t\t\tid(\"qunit-filter-missing\").disabled = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tfor ( var i = 0; i < config.assertions.length; i++ ) {\n\t\t\t\t\tif ( !config.assertions[i].result ) {\n\t\t\t\t\t\tbad++;\n\t\t\t\t\t\tconfig.stats.bad++;\n\t\t\t\t\t\tconfig.moduleStats.bad++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tQUnit.testDone( testName, bad, config.assertions.length );\n\n\t\t\tif ( !window.setTimeout && !config.queue.length ) {\n\t\t\t\tdone();\n\t\t\t}\n\t\t});\n\n\t\tsynchronize( done );\n\t},\n\t\n\t/**\n\t * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.\n\t */\n\texpect: function(asserts) {\n\t\tconfig.expected = asserts;\n\t},\n\n\t/**\n\t * Asserts true.\n\t * @example ok( \"asdfasdf\".length > 5, \"There must be at least 5 chars\" );\n\t */\n\tok: function(a, msg) {\n\t\tmsg = escapeHtml(msg);\n\t\tQUnit.log(a, msg);\n\n\t\tconfig.assertions.push({\n\t\t\tresult: !!a,\n\t\t\tmessage: msg\n\t\t});\n\t},\n\n\t/**\n\t * Checks that the first two arguments are equal, with an optional message.\n\t * Prints out both actual and expected values.\n\t *\n\t * Prefered to ok( actual == expected, message )\n\t *\n\t * @example equal( format(\"Received {0} bytes.\", 2), \"Received 2 bytes.\" );\n\t *\n\t * @param Object actual\n\t * @param Object expected\n\t * @param String message (optional)\n\t */\n\tequal: function(actual, expected, message) {\n\t\tpush(expected == actual, actual, expected, message);\n\t},\n\n\tnotEqual: function(actual, expected, message) {\n\t\tpush(expected != actual, actual, expected, message);\n\t},\n\t\n\tdeepEqual: function(actual, expected, message) {\n\t\tpush(QUnit.equiv(actual, expected), actual, expected, message);\n\t},\n\n\tnotDeepEqual: function(actual, expected, message) {\n\t\tpush(!QUnit.equiv(actual, expected), actual, expected, message);\n\t},\n\n\tstrictEqual: function(actual, expected, message) {\n\t\tpush(expected === actual, actual, expected, message);\n\t},\n\n\tnotStrictEqual: function(actual, expected, message) {\n\t\tpush(expected !== actual, actual, expected, message);\n\t},\n\n\traises: function(fn,  message) {\n\t\ttry {\n\t\t\tfn();\n\t\t\tok( false, message );\n\t\t}\n\t\tcatch (e) {\n\t\t\tok( true, message );\n\t\t}\n\t},\n\n\tstart: function() {\n\t\t// A slight delay, to avoid any current callbacks\n\t\tif ( window.setTimeout ) {\n\t\t\twindow.setTimeout(function() {\n\t\t\t\tif ( config.timeout ) {\n\t\t\t\t\tclearTimeout(config.timeout);\n\t\t\t\t}\n\n\t\t\t\tconfig.blocking = false;\n\t\t\t\tprocess();\n\t\t\t}, 13);\n\t\t} else {\n\t\t\tconfig.blocking = false;\n\t\t\tprocess();\n\t\t}\n\t},\n\t\n\tstop: function(timeout) {\n\t\tconfig.blocking = true;\n\n\t\tif ( timeout && window.setTimeout ) {\n\t\t\tconfig.timeout = window.setTimeout(function() {\n\t\t\t\tQUnit.ok( false, \"Test timed out\" );\n\t\t\t\tQUnit.start();\n\t\t\t}, timeout);\n\t\t}\n\t}\n\n};\n\n// Backwards compatibility, deprecated\nQUnit.equals = QUnit.equal;\nQUnit.same = QUnit.deepEqual;\n\n// Maintain internal state\nvar config = {\n\t// The queue of tests to run\n\tqueue: [],\n\n\t// block until document ready\n\tblocking: true\n};\n\n// Load paramaters\n(function() {\n\tvar location = window.location || { search: \"\", protocol: \"file:\" },\n\t\tGETParams = location.search.slice(1).split('&');\n\n\tfor ( var i = 0; i < GETParams.length; i++ ) {\n\t\tGETParams[i] = decodeURIComponent( GETParams[i] );\n\t\tif ( GETParams[i] === \"noglobals\" ) {\n\t\t\tGETParams.splice( i, 1 );\n\t\t\ti--;\n\t\t\tconfig.noglobals = true;\n\t\t} else if ( GETParams[i].search('=') > -1 ) {\n\t\t\tGETParams.splice( i, 1 );\n\t\t\ti--;\n\t\t}\n\t}\n\t\n\t// restrict modules/tests by get parameters\n\tconfig.filters = GETParams;\n\t\n\t// Figure out if we're running the tests from a server or not\n\tQUnit.isLocal = !!(location.protocol === 'file:');\n})();\n\n// Expose the API as global variables, unless an 'exports'\n// object exists, in that case we assume we're in CommonJS\nif ( typeof exports === \"undefined\" || typeof require === \"undefined\" ) {\n\textend(window, QUnit);\n\twindow.QUnit = QUnit;\n} else {\n\textend(exports, QUnit);\n\texports.QUnit = QUnit;\n}\n\n// define these after exposing globals to keep them in these QUnit namespace only\nextend(QUnit, {\n\tconfig: config,\n\n\t// Initialize the configuration options\n\tinit: function() {\n\t\textend(config, {\n\t\t\tstats: { all: 0, bad: 0 },\n\t\t\tmoduleStats: { all: 0, bad: 0 },\n\t\t\tstarted: +new Date,\n\t\t\tupdateRate: 1000,\n\t\t\tblocking: false,\n\t\t\tautostart: true,\n\t\t\tautorun: false,\n\t\t\tassertions: [],\n\t\t\tfilters: [],\n\t\t\tqueue: []\n\t\t});\n\n\t\tvar tests = id(\"qunit-tests\"),\n\t\t\tbanner = id(\"qunit-banner\"),\n\t\t\tresult = id(\"qunit-testresult\");\n\n\t\tif ( tests ) {\n\t\t\ttests.innerHTML = \"\";\n\t\t}\n\n\t\tif ( banner ) {\n\t\t\tbanner.className = \"\";\n\t\t}\n\n\t\tif ( result ) {\n\t\t\tresult.parentNode.removeChild( result );\n\t\t}\n\t},\n\t\n\t/**\n\t * Resets the test setup. Useful for tests that modify the DOM.\n\t */\n\treset: function() {\n\t\tif ( window.jQuery ) {\n\t\t\tjQuery(\"#main, #qunit-fixture\").html( config.fixture );\n\t\t}\n\t},\n\t\n\t/**\n\t * Trigger an event on an element.\n\t *\n\t * @example triggerEvent( document.body, \"click\" );\n\t *\n\t * @param DOMElement elem\n\t * @param String type\n\t */\n\ttriggerEvent: function( elem, type, event ) {\n\t\tif ( document.createEvent ) {\n\t\t\tevent = document.createEvent(\"MouseEvents\");\n\t\t\tevent.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,\n\t\t\t\t0, 0, 0, 0, 0, false, false, false, false, 0, null);\n\t\t\telem.dispatchEvent( event );\n\n\t\t} else if ( elem.fireEvent ) {\n\t\t\telem.fireEvent(\"on\"+type);\n\t\t}\n\t},\n\t\n\t// Safe object type checking\n\tis: function( type, obj ) {\n\t\treturn QUnit.objectType( obj ) == type;\n\t},\n\t\n\tobjectType: function( obj ) {\n\t\tif (typeof obj === \"undefined\") {\n\t\t\t\treturn \"undefined\";\n\n\t\t// consider: typeof null === object\n\t\t}\n\t\tif (obj === null) {\n\t\t\t\treturn \"null\";\n\t\t}\n\n\t\tvar type = Object.prototype.toString.call( obj )\n\t\t\t.match(/^\\[object\\s(.*)\\]$/)[1] || '';\n\n\t\tswitch (type) {\n\t\t\t\tcase 'Number':\n\t\t\t\t\t\tif (isNaN(obj)) {\n\t\t\t\t\t\t\t\treturn \"nan\";\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn \"number\";\n\t\t\t\t\t\t}\n\t\t\t\tcase 'String':\n\t\t\t\tcase 'Boolean':\n\t\t\t\tcase 'Array':\n\t\t\t\tcase 'Date':\n\t\t\t\tcase 'RegExp':\n\t\t\t\tcase 'Function':\n\t\t\t\t\t\treturn type.toLowerCase();\n\t\t}\n\t\tif (typeof obj === \"object\") {\n\t\t\t\treturn \"object\";\n\t\t}\n\t\treturn undefined;\n\t},\n\t\n\t// Logging callbacks\n\tbegin: function() {},\n\tdone: function(failures, total) {},\n\tlog: function(result, message) {},\n\ttestStart: function(name, testEnvironment) {},\n\ttestDone: function(name, failures, total) {},\n\tmoduleStart: function(name, testEnvironment) {},\n\tmoduleDone: function(name, failures, total) {}\n});\n\nif ( typeof document === \"undefined\" || document.readyState === \"complete\" ) {\n\tconfig.autorun = true;\n}\n\naddEvent(window, \"load\", function() {\n\tQUnit.begin();\n\t\n\t// Initialize the config, saving the execution queue\n\tvar oldconfig = extend({}, config);\n\tQUnit.init();\n\textend(config, oldconfig);\n\n\tconfig.blocking = false;\n\n\tvar userAgent = id(\"qunit-userAgent\");\n\tif ( userAgent ) {\n\t\tuserAgent.innerHTML = navigator.userAgent;\n\t}\n\tvar banner = id(\"qunit-header\");\n\tif ( banner ) {\n\t\tbanner.innerHTML = '<a href=\"' + location.href + '\">' + banner.innerHTML + '</a>'; \n\t}\n\t\n\tvar toolbar = id(\"qunit-testrunner-toolbar\");\n\tif ( toolbar ) {\n\t\ttoolbar.style.display = \"none\";\n\t\t\n\t\tvar filter = document.createElement(\"input\");\n\t\tfilter.type = \"checkbox\";\n\t\tfilter.id = \"qunit-filter-pass\";\n\t\tfilter.disabled = true;\n\t\taddEvent( filter, \"click\", function() {\n\t\t\tvar li = document.getElementsByTagName(\"li\");\n\t\t\tfor ( var i = 0; i < li.length; i++ ) {\n\t\t\t\tif ( li[i].className.indexOf(\"pass\") > -1 ) {\n\t\t\t\t\tli[i].style.display = filter.checked ? \"none\" : \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttoolbar.appendChild( filter );\n\n\t\tvar label = document.createElement(\"label\");\n\t\tlabel.setAttribute(\"for\", \"qunit-filter-pass\");\n\t\tlabel.innerHTML = \"Hide passed tests\";\n\t\ttoolbar.appendChild( label );\n\n\t\tvar missing = document.createElement(\"input\");\n\t\tmissing.type = \"checkbox\";\n\t\tmissing.id = \"qunit-filter-missing\";\n\t\tmissing.disabled = true;\n\t\taddEvent( missing, \"click\", function() {\n\t\t\tvar li = document.getElementsByTagName(\"li\");\n\t\t\tfor ( var i = 0; i < li.length; i++ ) {\n\t\t\t\tif ( li[i].className.indexOf(\"fail\") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {\n\t\t\t\t\tli[i].parentNode.parentNode.style.display = missing.checked ? \"none\" : \"block\";\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\ttoolbar.appendChild( missing );\n\n\t\tlabel = document.createElement(\"label\");\n\t\tlabel.setAttribute(\"for\", \"qunit-filter-missing\");\n\t\tlabel.innerHTML = \"Hide missing tests (untested code is broken code)\";\n\t\ttoolbar.appendChild( label );\n\t}\n\n\tvar main = id('main') || id('qunit-fixture');\n\tif ( main ) {\n\t\tconfig.fixture = main.innerHTML;\n\t}\n\n\tif (config.autostart) {\n\t\tQUnit.start();\n\t}\n});\n\nfunction done() {\n\tif ( config.doneTimer && window.clearTimeout ) {\n\t\twindow.clearTimeout( config.doneTimer );\n\t\tconfig.doneTimer = null;\n\t}\n\n\tif ( config.queue.length ) {\n\t\tconfig.doneTimer = window.setTimeout(function(){\n\t\t\tif ( !config.queue.length ) {\n\t\t\t\tdone();\n\t\t\t} else {\n\t\t\t\tsynchronize( done );\n\t\t\t}\n\t\t}, 13);\n\n\t\treturn;\n\t}\n\n\tconfig.autorun = true;\n\n\t// Log the last module results\n\tif ( config.currentModule ) {\n\t\tQUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );\n\t}\n\n\tvar banner = id(\"qunit-banner\"),\n\t\ttests = id(\"qunit-tests\"),\n\t\thtml = ['Tests completed in ',\n\t\t+new Date - config.started, ' milliseconds.<br/>',\n\t\t'<span class=\"passed\">', config.stats.all - config.stats.bad, '</span> tests of <span class=\"total\">', config.stats.all, '</span> passed, <span class=\"failed\">', config.stats.bad,'</span> failed.'].join('');\n\n\tif ( banner ) {\n\t\tbanner.className = (config.stats.bad ? \"qunit-fail\" : \"qunit-pass\");\n\t}\n\n\tif ( tests ) {\t\n\t\tvar result = id(\"qunit-testresult\");\n\n\t\tif ( !result ) {\n\t\t\tresult = document.createElement(\"p\");\n\t\t\tresult.id = \"qunit-testresult\";\n\t\t\tresult.className = \"result\";\n\t\t\ttests.parentNode.insertBefore( result, tests.nextSibling );\n\t\t}\n\n\t\tresult.innerHTML = html;\n\t}\n\n\tQUnit.done( config.stats.bad, config.stats.all );\n}\n\nfunction validTest( name ) {\n\tvar i = config.filters.length,\n\t\trun = false;\n\n\tif ( !i ) {\n\t\treturn true;\n\t}\n\t\n\twhile ( i-- ) {\n\t\tvar filter = config.filters[i],\n\t\t\tnot = filter.charAt(0) == '!';\n\n\t\tif ( not ) {\n\t\t\tfilter = filter.slice(1);\n\t\t}\n\n\t\tif ( name.indexOf(filter) !== -1 ) {\n\t\t\treturn !not;\n\t\t}\n\n\t\tif ( not ) {\n\t\t\trun = true;\n\t\t}\n\t}\n\n\treturn run;\n}\n\nfunction escapeHtml(s) {\n\ts = s === null ? \"\" : s + \"\";\n\treturn s.replace(/[\\&\"<>\\\\]/g, function(s) {\n\t\tswitch(s) {\n\t\t\tcase \"&\": return \"&amp;\";\n\t\t\tcase \"\\\\\": return \"\\\\\\\\\";\n\t\t\tcase '\"': return '\\\"';\n\t\t\tcase \"<\": return \"&lt;\";\n\t\t\tcase \">\": return \"&gt;\";\n\t\t\tdefault: return s;\n\t\t}\n\t});\n}\n\nfunction push(result, actual, expected, message) {\n\tmessage = escapeHtml(message) || (result ? \"okay\" : \"failed\");\n\tmessage = '<span class=\"test-message\">' + message + \"</span>\";\n\texpected = escapeHtml(QUnit.jsDump.parse(expected));\n\tactual = escapeHtml(QUnit.jsDump.parse(actual));\n\tvar output = message + ', expected: <span class=\"test-expected\">' + expected + '</span>';\n\tif (actual != expected) {\n\t\toutput += ' result: <span class=\"test-actual\">' + actual + '</span>, diff: ' + QUnit.diff(expected, actual);\n\t}\n\t\n\t// can't use ok, as that would double-escape messages\n\tQUnit.log(result, output);\n\tconfig.assertions.push({\n\t\tresult: !!result,\n\t\tmessage: output\n\t});\n}\n\nfunction synchronize( callback ) {\n\tconfig.queue.push( callback );\n\n\tif ( config.autorun && !config.blocking ) {\n\t\tprocess();\n\t}\n}\n\nfunction process() {\n\tvar start = (new Date()).getTime();\n\n\twhile ( config.queue.length && !config.blocking ) {\n\t\tif ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {\n\t\t\tconfig.queue.shift()();\n\n\t\t} else {\n\t\t\tsetTimeout( process, 13 );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nfunction saveGlobal() {\n\tconfig.pollution = [];\n\t\n\tif ( config.noglobals ) {\n\t\tfor ( var key in window ) {\n\t\t\tconfig.pollution.push( key );\n\t\t}\n\t}\n}\n\nfunction checkPollution( name ) {\n\tvar old = config.pollution;\n\tsaveGlobal();\n\t\n\tvar newGlobals = diff( old, config.pollution );\n\tif ( newGlobals.length > 0 ) {\n\t\tok( false, \"Introduced global variable(s): \" + newGlobals.join(\", \") );\n\t\tconfig.expected++;\n\t}\n\n\tvar deletedGlobals = diff( config.pollution, old );\n\tif ( deletedGlobals.length > 0 ) {\n\t\tok( false, \"Deleted global variable(s): \" + deletedGlobals.join(\", \") );\n\t\tconfig.expected++;\n\t}\n}\n\n// returns a new Array with the elements that are in a but not in b\nfunction diff( a, b ) {\n\tvar result = a.slice();\n\tfor ( var i = 0; i < result.length; i++ ) {\n\t\tfor ( var j = 0; j < b.length; j++ ) {\n\t\t\tif ( result[i] === b[j] ) {\n\t\t\t\tresult.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction fail(message, exception, callback) {\n\tif ( typeof console !== \"undefined\" && console.error && console.warn ) {\n\t\tconsole.error(message);\n\t\tconsole.error(exception);\n\t\tconsole.warn(callback.toString());\n\n\t} else if ( window.opera && opera.postError ) {\n\t\topera.postError(message, exception, callback.toString);\n\t}\n}\n\nfunction extend(a, b) {\n\tfor ( var prop in b ) {\n\t\ta[prop] = b[prop];\n\t}\n\n\treturn a;\n}\n\nfunction addEvent(elem, type, fn) {\n\tif ( elem.addEventListener ) {\n\t\telem.addEventListener( type, fn, false );\n\t} else if ( elem.attachEvent ) {\n\t\telem.attachEvent( \"on\" + type, fn );\n\t} else {\n\t\tfn();\n\t}\n}\n\nfunction id(name) {\n\treturn !!(typeof document !== \"undefined\" && document && document.getElementById) &&\n\t\tdocument.getElementById( name );\n}\n\n// Test for equality any JavaScript type.\n// Discussions and reference: http://philrathe.com/articles/equiv\n// Test suites: http://philrathe.com/tests/equiv\n// Author: Philippe Rathé <prathe@gmail.com>\nQUnit.equiv = function () {\n\n    var innerEquiv; // the real equiv function\n    var callers = []; // stack to decide between skip/abort functions\n    var parents = []; // stack to avoiding loops from circular referencing\n\n    // Call the o related callback with the given arguments.\n    function bindCallbacks(o, callbacks, args) {\n        var prop = QUnit.objectType(o);\n        if (prop) {\n            if (QUnit.objectType(callbacks[prop]) === \"function\") {\n                return callbacks[prop].apply(callbacks, args);\n            } else {\n                return callbacks[prop]; // or undefined\n            }\n        }\n    }\n    \n    var callbacks = function () {\n\n        // for string, boolean, number and null\n        function useStrictEquality(b, a) {\n            if (b instanceof a.constructor || a instanceof b.constructor) {\n                // to catch short annotaion VS 'new' annotation of a declaration\n                // e.g. var i = 1;\n                //      var j = new Number(1);\n                return a == b;\n            } else {\n                return a === b;\n            }\n        }\n\n        return {\n            \"string\": useStrictEquality,\n            \"boolean\": useStrictEquality,\n            \"number\": useStrictEquality,\n            \"null\": useStrictEquality,\n            \"undefined\": useStrictEquality,\n\n            \"nan\": function (b) {\n                return isNaN(b);\n            },\n\n            \"date\": function (b, a) {\n                return QUnit.objectType(b) === \"date\" && a.valueOf() === b.valueOf();\n            },\n\n            \"regexp\": function (b, a) {\n                return QUnit.objectType(b) === \"regexp\" &&\n                    a.source === b.source && // the regex itself\n                    a.global === b.global && // and its modifers (gmi) ...\n                    a.ignoreCase === b.ignoreCase &&\n                    a.multiline === b.multiline;\n            },\n\n            // - skip when the property is a method of an instance (OOP)\n            // - abort otherwise,\n            //   initial === would have catch identical references anyway\n            \"function\": function () {\n                var caller = callers[callers.length - 1];\n                return caller !== Object &&\n                        typeof caller !== \"undefined\";\n            },\n\n            \"array\": function (b, a) {\n                var i, j, loop;\n                var len;\n\n                // b could be an object literal here\n                if ( ! (QUnit.objectType(b) === \"array\")) {\n                    return false;\n                }   \n                \n                len = a.length;\n                if (len !== b.length) { // safe and faster\n                    return false;\n                }\n                \n                //track reference to avoid circular references\n                parents.push(a);\n                for (i = 0; i < len; i++) {\n                    loop = false;\n                    for(j=0;j<parents.length;j++){\n                        if(parents[j] === a[i]){\n                            loop = true;//dont rewalk array\n                        }\n                    }\n                    if (!loop && ! innerEquiv(a[i], b[i])) {\n                        parents.pop();\n                        return false;\n                    }\n                }\n                parents.pop();\n                return true;\n            },\n\n            \"object\": function (b, a) {\n                var i, j, loop;\n                var eq = true; // unless we can proove it\n                var aProperties = [], bProperties = []; // collection of strings\n\n                // comparing constructors is more strict than using instanceof\n                if ( a.constructor !== b.constructor) {\n                    return false;\n                }\n\n                // stack constructor before traversing properties\n                callers.push(a.constructor);\n                //track reference to avoid circular references\n                parents.push(a);\n                \n                for (i in a) { // be strict: don't ensures hasOwnProperty and go deep\n                    loop = false;\n                    for(j=0;j<parents.length;j++){\n                        if(parents[j] === a[i])\n                            loop = true; //don't go down the same path twice\n                    }\n                    aProperties.push(i); // collect a's properties\n\n                    if (!loop && ! innerEquiv(a[i], b[i])) {\n                        eq = false;\n                        break;\n                    }\n                }\n\n                callers.pop(); // unstack, we are done\n                parents.pop();\n\n                for (i in b) {\n                    bProperties.push(i); // collect b's properties\n                }\n\n                // Ensures identical properties name\n                return eq && innerEquiv(aProperties.sort(), bProperties.sort());\n            }\n        };\n    }();\n\n    innerEquiv = function () { // can take multiple arguments\n        var args = Array.prototype.slice.apply(arguments);\n        if (args.length < 2) {\n            return true; // end transition\n        }\n\n        return (function (a, b) {\n            if (a === b) {\n                return true; // catch the most you can\n            } else if (a === null || b === null || typeof a === \"undefined\" || typeof b === \"undefined\" || QUnit.objectType(a) !== QUnit.objectType(b)) {\n                return false; // don't lose time with error prone cases\n            } else {\n                return bindCallbacks(a, callbacks, [b, a]);\n            }\n\n        // apply transition with (1..n) arguments\n        })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));\n    };\n\n    return innerEquiv;\n\n}();\n\n/**\n * jsDump\n * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com\n * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)\n * Date: 5/15/2008\n * @projectDescription Advanced and extensible data dumping for Javascript.\n * @version 1.0.0\n * @author Ariel Flesler\n * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}\n */\nQUnit.jsDump = (function() {\n\tfunction quote( str ) {\n\t\treturn '\"' + str.toString().replace(/\"/g, '\\\\\"') + '\"';\n\t};\n\tfunction literal( o ) {\n\t\treturn o + '';\t\n\t};\n\tfunction join( pre, arr, post ) {\n\t\tvar s = jsDump.separator(),\n\t\t\tbase = jsDump.indent(),\n\t\t\tinner = jsDump.indent(1);\n\t\tif ( arr.join )\n\t\t\tarr = arr.join( ',' + s + inner );\n\t\tif ( !arr )\n\t\t\treturn pre + post;\n\t\treturn [ pre, inner + arr, base + post ].join(s);\n\t};\n\tfunction array( arr ) {\n\t\tvar i = arr.length,\tret = Array(i);\t\t\t\t\t\n\t\tthis.up();\n\t\twhile ( i-- )\n\t\t\tret[i] = this.parse( arr[i] );\t\t\t\t\n\t\tthis.down();\n\t\treturn join( '[', ret, ']' );\n\t};\n\t\n\tvar reName = /^function (\\w+)/;\n\t\n\tvar jsDump = {\n\t\tparse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance\n\t\t\tvar\tparser = this.parsers[ type || this.typeOf(obj) ];\n\t\t\ttype = typeof parser;\t\t\t\n\t\t\t\n\t\t\treturn type == 'function' ? parser.call( this, obj ) :\n\t\t\t\t   type == 'string' ? parser :\n\t\t\t\t   this.parsers.error;\n\t\t},\n\t\ttypeOf:function( obj ) {\n\t\t\tvar type;\n\t\t\tif ( obj === null ) {\n\t\t\t\ttype = \"null\";\n\t\t\t} else if (typeof obj === \"undefined\") {\n\t\t\t\ttype = \"undefined\";\n\t\t\t} else if (QUnit.is(\"RegExp\", obj)) {\n\t\t\t\ttype = \"regexp\";\n\t\t\t} else if (QUnit.is(\"Date\", obj)) {\n\t\t\t\ttype = \"date\";\n\t\t\t} else if (QUnit.is(\"Function\", obj)) {\n\t\t\t\ttype = \"function\";\n\t\t\t} else if (obj.setInterval && obj.document && !obj.nodeType) {\n\t\t\t\ttype = \"window\";\n\t\t\t} else if (obj.nodeType === 9) {\n\t\t\t\ttype = \"document\";\n\t\t\t} else if (obj.nodeType) {\n\t\t\t\ttype = \"node\";\n\t\t\t} else if (typeof obj === \"object\" && typeof obj.length === \"number\" && obj.length >= 0) {\n\t\t\t\ttype = \"array\";\n\t\t\t} else {\n\t\t\t\ttype = typeof obj;\n\t\t\t}\n\t\t\treturn type;\n\t\t},\n\t\tseparator:function() {\n\t\t\treturn this.multiline ?\tthis.HTML ? '<br />' : '\\n' : this.HTML ? '&nbsp;' : ' ';\n\t\t},\n\t\tindent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing\n\t\t\tif ( !this.multiline )\n\t\t\t\treturn '';\n\t\t\tvar chr = this.indentChar;\n\t\t\tif ( this.HTML )\n\t\t\t\tchr = chr.replace(/\\t/g,'   ').replace(/ /g,'&nbsp;');\n\t\t\treturn Array( this._depth_ + (extra||0) ).join(chr);\n\t\t},\n\t\tup:function( a ) {\n\t\t\tthis._depth_ += a || 1;\n\t\t},\n\t\tdown:function( a ) {\n\t\t\tthis._depth_ -= a || 1;\n\t\t},\n\t\tsetParser:function( name, parser ) {\n\t\t\tthis.parsers[name] = parser;\n\t\t},\n\t\t// The next 3 are exposed so you can use them\n\t\tquote:quote, \n\t\tliteral:literal,\n\t\tjoin:join,\n\t\t//\n\t\t_depth_: 1,\n\t\t// This is the list of parsers, to modify them, use jsDump.setParser\n\t\tparsers:{\n\t\t\twindow: '[Window]',\n\t\t\tdocument: '[Document]',\n\t\t\terror:'[ERROR]', //when no parser is found, shouldn't happen\n\t\t\tunknown: '[Unknown]',\n\t\t\t'null':'null',\n\t\t\tundefined:'undefined',\n\t\t\t'function':function( fn ) {\n\t\t\t\tvar ret = 'function',\n\t\t\t\t\tname = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE\n\t\t\t\tif ( name )\n\t\t\t\t\tret += ' ' + name;\n\t\t\t\tret += '(';\n\t\t\t\t\n\t\t\t\tret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');\n\t\t\t\treturn join( ret, this.parse(fn,'functionCode'), '}' );\n\t\t\t},\n\t\t\tarray: array,\n\t\t\tnodelist: array,\n\t\t\targuments: array,\n\t\t\tobject:function( map ) {\n\t\t\t\tvar ret = [ ];\n\t\t\t\tthis.up();\n\t\t\t\tfor ( var key in map )\n\t\t\t\t\tret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );\n\t\t\t\tthis.down();\n\t\t\t\treturn join( '{', ret, '}' );\n\t\t\t},\n\t\t\tnode:function( node ) {\n\t\t\t\tvar open = this.HTML ? '&lt;' : '<',\n\t\t\t\t\tclose = this.HTML ? '&gt;' : '>';\n\t\t\t\t\t\n\t\t\t\tvar tag = node.nodeName.toLowerCase(),\n\t\t\t\t\tret = open + tag;\n\t\t\t\t\t\n\t\t\t\tfor ( var a in this.DOMAttrs ) {\n\t\t\t\t\tvar val = node[this.DOMAttrs[a]];\n\t\t\t\t\tif ( val )\n\t\t\t\t\t\tret += ' ' + a + '=' + this.parse( val, 'attribute' );\n\t\t\t\t}\n\t\t\t\treturn ret + close + open + '/' + tag + close;\n\t\t\t},\n\t\t\tfunctionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function\n\t\t\t\tvar l = fn.length;\n\t\t\t\tif ( !l ) return '';\t\t\t\t\n\t\t\t\t\n\t\t\t\tvar args = Array(l);\n\t\t\t\twhile ( l-- )\n\t\t\t\t\targs[l] = String.fromCharCode(97+l);//97 is 'a'\n\t\t\t\treturn ' ' + args.join(', ') + ' ';\n\t\t\t},\n\t\t\tkey:quote, //object calls it internally, the key part of an item in a map\n\t\t\tfunctionCode:'[code]', //function calls it internally, it's the content of the function\n\t\t\tattribute:quote, //node calls it internally, it's an html attribute value\n\t\t\tstring:quote,\n\t\t\tdate:quote,\n\t\t\tregexp:literal, //regex\n\t\t\tnumber:literal,\n\t\t\t'boolean':literal\n\t\t},\n\t\tDOMAttrs:{//attributes to dump from nodes, name=>realName\n\t\t\tid:'id',\n\t\t\tname:'name',\n\t\t\t'class':'className'\n\t\t},\n\t\tHTML:false,//if true, entities are escaped ( <, >, \\t, space and \\n )\n\t\tindentChar:'   ',//indentation unit\n\t\tmultiline:false //if true, items in a collection, are separated by a \\n, else just a space.\n\t};\n\n\treturn jsDump;\n})();\n\n// from Sizzle.js\nfunction getText( elems ) {\n\tvar ret = \"\", elem;\n\n\tfor ( var i = 0; elems[i]; i++ ) {\n\t\telem = elems[i];\n\n\t\t// Get the text from text nodes and CDATA nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 4 ) {\n\t\t\tret += elem.nodeValue;\n\n\t\t// Traverse everything else, except comment nodes\n\t\t} else if ( elem.nodeType !== 8 ) {\n\t\t\tret += getText( elem.childNodes );\n\t\t}\n\t}\n\n\treturn ret;\n};\n\n/*\n * Javascript Diff Algorithm\n *  By John Resig (http://ejohn.org/)\n *  Modified by Chu Alan \"sprite\"\n *\n * Released under the MIT license.\n *\n * More Info:\n *  http://ejohn.org/projects/javascript-diff-algorithm/\n *  \n * Usage: QUnit.diff(expected, actual)\n * \n * QUnit.diff(\"the quick brown fox jumped over\", \"the quick fox jumps over\") == \"the  quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over\"\n */\nQUnit.diff = (function() {\n\tfunction diff(o, n){\n\t\tvar ns = new Object();\n\t\tvar os = new Object();\n\t\t\n\t\tfor (var i = 0; i < n.length; i++) {\n\t\t\tif (ns[n[i]] == null) \n\t\t\t\tns[n[i]] = {\n\t\t\t\t\trows: new Array(),\n\t\t\t\t\to: null\n\t\t\t\t};\n\t\t\tns[n[i]].rows.push(i);\n\t\t}\n\t\t\n\t\tfor (var i = 0; i < o.length; i++) {\n\t\t\tif (os[o[i]] == null) \n\t\t\t\tos[o[i]] = {\n\t\t\t\t\trows: new Array(),\n\t\t\t\t\tn: null\n\t\t\t\t};\n\t\t\tos[o[i]].rows.push(i);\n\t\t}\n\t\t\n\t\tfor (var i in ns) {\n\t\t\tif (ns[i].rows.length == 1 && typeof(os[i]) != \"undefined\" && os[i].rows.length == 1) {\n\t\t\t\tn[ns[i].rows[0]] = {\n\t\t\t\t\ttext: n[ns[i].rows[0]],\n\t\t\t\t\trow: os[i].rows[0]\n\t\t\t\t};\n\t\t\t\to[os[i].rows[0]] = {\n\t\t\t\t\ttext: o[os[i].rows[0]],\n\t\t\t\t\trow: ns[i].rows[0]\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor (var i = 0; i < n.length - 1; i++) {\n\t\t\tif (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&\n\t\t\tn[i + 1] == o[n[i].row + 1]) {\n\t\t\t\tn[i + 1] = {\n\t\t\t\t\ttext: n[i + 1],\n\t\t\t\t\trow: n[i].row + 1\n\t\t\t\t};\n\t\t\t\to[n[i].row + 1] = {\n\t\t\t\t\ttext: o[n[i].row + 1],\n\t\t\t\t\trow: i + 1\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\tfor (var i = n.length - 1; i > 0; i--) {\n\t\t\tif (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&\n\t\t\tn[i - 1] == o[n[i].row - 1]) {\n\t\t\t\tn[i - 1] = {\n\t\t\t\t\ttext: n[i - 1],\n\t\t\t\t\trow: n[i].row - 1\n\t\t\t\t};\n\t\t\t\to[n[i].row - 1] = {\n\t\t\t\t\ttext: o[n[i].row - 1],\n\t\t\t\t\trow: i - 1\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn {\n\t\t\to: o,\n\t\t\tn: n\n\t\t};\n\t}\n\t\n\treturn function(o, n){\n\t\to = o.replace(/\\s+$/, '');\n\t\tn = n.replace(/\\s+$/, '');\n\t\tvar out = diff(o == \"\" ? [] : o.split(/\\s+/), n == \"\" ? [] : n.split(/\\s+/));\n\n\t\tvar str = \"\";\n\t\t\n\t\tvar oSpace = o.match(/\\s+/g);\n\t\tif (oSpace == null) {\n\t\t\toSpace = [\" \"];\n\t\t}\n\t\telse {\n\t\t\toSpace.push(\" \");\n\t\t}\n\t\tvar nSpace = n.match(/\\s+/g);\n\t\tif (nSpace == null) {\n\t\t\tnSpace = [\" \"];\n\t\t}\n\t\telse {\n\t\t\tnSpace.push(\" \");\n\t\t}\n\t\t\n\t\tif (out.n.length == 0) {\n\t\t\tfor (var i = 0; i < out.o.length; i++) {\n\t\t\t\tstr += '<del>' + out.o[i] + oSpace[i] + \"</del>\";\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (out.n[0].text == null) {\n\t\t\t\tfor (n = 0; n < out.o.length && out.o[n].text == null; n++) {\n\t\t\t\t\tstr += '<del>' + out.o[n] + oSpace[n] + \"</del>\";\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfor (var i = 0; i < out.n.length; i++) {\n\t\t\t\tif (out.n[i].text == null) {\n\t\t\t\t\tstr += '<ins>' + out.n[i] + nSpace[i] + \"</ins>\";\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar pre = \"\";\n\t\t\t\t\t\n\t\t\t\t\tfor (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {\n\t\t\t\t\t\tpre += '<del>' + out.o[n] + oSpace[n] + \"</del>\";\n\t\t\t\t\t}\n\t\t\t\t\tstr += \" \" + out.n[i].text + nSpace[i] + pre;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn str;\n\t}\n})();\n\n})(this);\n"
  },
  {
    "path": "test/test.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>Happy Tests</title>\n        <link rel=\"stylesheet\" href=\"qunit/qunit.css\" type=\"text/css\" media=\"screen\" />\n        <script src=\"jquery-1.11.3.min.js\"></script>\n        <script src=\"qunit/qunit.js\"></script>\n        <script src=\"../happy.js\"></script>\n        <script src=\"../happy.methods.js\"></script>\n        <script src=\"./tests.js\"></script>\n    </head>\n    <body>\n        <h1 id=\"qunit-header\">Happy Tests</h1>\n        <h2 id=\"qunit-banner\"></h2>\n        <h2 id=\"qunit-userAgent\"></h2>\n        <ol id=\"qunit-tests\"></ol>\n        <div id=\"qunit-fixture\"></div>\n    </body>\n</html>"
  },
  {
    "path": "test/tests.js",
    "content": "/*global $, test, equal, happy, ok, equals*/\nmodule('Tiny Validator');\n\nfunction fixture(html) {\n    return $('#qunit-fixture').html('<form>' + html + '</form>').find('form');\n}\n\nfunction submit() {\n    $('form').trigger('submit');\n}\n\nfunction fill() {\n    $('#textInput1').val('hjoreteg@gmail.com');\n    $('#textInput2').val('(909)555-5555');\n    $('#textarea1').val('something');\n    $('#password1').val('password');\n    $('#password2').val('password');\n}\n\ntest('check basic required', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true,\n                message: 'Please enter an email'\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n    equal($('.unhappyMessage').length, 1);\n\n    $('#textInput1').val('test');\n    form.trigger('submit');\n    equal($('.unhappy').length, 0);\n    equal($('.unhappyMessage').length, 0);\n});\n\ntest('check setting required with \"required\" attribute', function () {\n    var form = fixture('<input type=\"text\" required id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                message: 'Please enter an email'\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n    equal($('.unhappyMessage').length, 1);\n\n    $('#textInput1').val('test');\n    form.trigger('submit');\n    equal($('.unhappy').length, 0);\n    equal($('.unhappyMessage').length, 0);\n});\n\n\ntest('check email', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true,\n                message: 'Please enter an email',\n                test: happy.email\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n    equal($('.unhappyMessage').length, 1);\n\n    $('#textInput1').val('test');\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n    equal($('.unhappyMessage').length, 1);\n\n    $('#textInput1').val('hjoreteg@gmail.com');\n    form.trigger('submit');\n    equal($('.unhappy').length, 0);\n    equal($('.unhappyMessage').length, 0);\n});\n\n\ntest('test password match', function () {\n    var form = fixture('<input type=\"password1\" id=\"p1\" /><input type=\"password2\" id=\"p2\" />');\n\n    form.isHappy({\n        fields: {\n            '#p1': {\n                required: true,\n                message: 'Please enter a new password',\n                test: function (val1, val2) {\n                    return (val1 === val2);\n                },\n                arg: function () {\n                    return $('#p2').val();\n                }\n            },\n            '#p2': {\n                required: true,\n                message: 'Please enter your new password again'\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('.unhappy').length, 2);\n    equal($('.unhappyMessage').length, 2);\n\n    $('#p1').val('test');\n    form.trigger('submit');\n    equal($('.unhappy').length, 2);\n    equal($('.unhappyMessage').length, 2);\n\n    $('#p2').val('test2');\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n    equal($('.unhappyMessage').length, 1);\n\n    $('#p2').val('test');\n    form.trigger('submit');\n    equal($('.unhappy').length, 0);\n    equal($('.unhappyMessage').length, 0);\n});\n\ntest('test trimming fields', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />' +\n                        '<input type=\"text\" id=\"textInput2\" />' +\n                        '<input type=\"text\" id=\"textInput3\" />' +\n                        '<input type=\"password\" id=\"passwordInput\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                trim: false\n            },\n            '#textInput2': {\n                trim: true\n            },\n            '#textInput3': {\n                message: 'Please enter an email'\n            },\n            '#passwordInput': {\n                message: 'Please enter a password'\n            }\n        },\n        testMode: true\n    });\n\n    $('#textInput1').val('  a  ');\n    $('#textInput2').val('  b  ');\n    $('#textInput3').val('  c  ');\n    $('#passwordInput').val('  password  ');\n    form.trigger('submit');\n    equal($('#textInput1').val(), '  a  ');\n    equal($('#textInput2').val(), 'b');\n    equal($('#textInput3').val(), 'c');\n    equal($('#passwordInput').val(), '  password  ');\n});\n\ntest('test passed in \"clean\" method', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                message: 'Please enter an email',\n                clean: function (val) {\n                    return val.replace(\"a\", \"b\");\n                }\n            }\n        },\n        testMode: true\n    });\n\n\n    $('#textInput1').val('  a  ');\n    form.trigger('submit');\n    equal($('#textInput1').val(), '  b  ');\n});\n\ntest('test passing \"sometimes\" to required', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />'),\n    testFlag = false;\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                message: 'Please enter an email',\n                required: 'sometimes',\n                test: function (val) {\n                    return testFlag;\n                }\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n    testFlag = true;\n    form.trigger('submit');\n    equal($('.unhappy').length, 0);\n});\n\ntest('test required fields should only be tested on submit', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                message: 'test',\n                required: true\n            }\n        },\n        testMode: true\n    });\n\n    $('#textInput1').trigger('blur');\n    equal($('.unhappy').length, 0);\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n});\n\ntest('test non-required fields still tested on blur', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                message: 'test',\n                test: happy.email\n            }\n        },\n        testMode: true\n    });\n\n    $('#textInput1').val('h@h').trigger('blur');\n    equal($('.unhappy').length, 1);\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n});\n\ntest('test unHappy callback', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" required />'),\n    myFlag = false;\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                message: 'not happy dude'\n            }\n        },\n        testMode: true,\n        unHappy: function () {\n            myFlag = true;\n        }\n    });\n\n    form.trigger('submit');\n    ok(myFlag);\n    myFlag = false;\n    $('#textInput1').val('test');\n    form.trigger('submit');\n    equals(myFlag, false);\n});\n\ntest('test happy callback', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" required />'),\n    myFlag = false;\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                message: 'not happy dude'\n            }\n        },\n        testMode: true,\n        happy: function () {\n            myFlag = true;\n        }\n    });\n\n    form.trigger('submit');\n    equals(myFlag, false);\n    $('#textInput1').val('test');\n    form.trigger('submit');\n    ok(myFlag);\n});\n\ntest('test included email validator', function () {\n    var happyEmails = [\n        'henrik@andyet.net',\n        'h.joreteg@gmail.com',\n        '23423.24.2.2342@test.test',\n        '2.3.2.4.a.a.a.ffasaf.a@aol.com'\n    ],\n    sadEmails = [\n        '.henrik@andyet.net',\n        'henrik.@andyet.net',\n        'test@test.afcom.com.',\n        'h@.h',\n        'a@a'\n    ],\n    i;\n\n    for (i = 0; i < happyEmails.length; i++) {\n        ok(happy.email(happyEmails[i]));\n    }\n\n    for (i = 0; i < sadEmails.length; i++) {\n        ok(!happy.email(sadEmails[i]));\n    }\n});\n\ntest('test included date validator', function () {\n    var happyDates = [\n        '12/29/1982',\n        '11/02/2099'\n    ],\n    sadDates = [\n        '123/24/1999',\n        '13/31/2099',\n        '12/32/2099',\n        '1/31/2999'\n    ],\n    i;\n\n    for (i = 0; i < happyDates.length; i++) {\n        ok(happy.date(happyDates[i]));\n    }\n\n    for (i = 0; i < sadDates.length; i++) {\n        ok(!happy.date(sadDates[i]));\n    }\n});\n\ntest('test included phone validator', function () {\n    var happyPhones = [\n        '909-765-3941',\n        '(909) 234-2343',\n        '9999999999',\n        '(909)234-2343',\n    ],\n    sadPhones = [\n        '12-123-22311',\n        'asdfasdf',\n        '123-123-12344'\n    ],\n    i;\n\n    for (i = 0; i < happyPhones.length; i++) {\n        ok(happy.USPhone(happyPhones[i]));\n    }\n\n    for (i = 0; i < sadPhones.length; i++) {\n        ok(!happy.USPhone(sadPhones[i]));\n    }\n});\n\ntest('check return value', function () {\n    var form = fixture('');\n    equal(form.isHappy({fields: {}}), form);\n});\n\ntest('test message is empty string when not explicitly set', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true,\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('.unhappyMessage').first().text(), '');\n});\n\ntest('custom error template', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    var myTemplate = function (error) {\n        return $('<span id=\"' + error.id + '\" class=\"customUnhappy\">custom ' + error.message + '</span>');\n    };\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true,\n            }\n        },\n        testMode: true,\n        errorTemplate: myTemplate\n    });\n\n    form.trigger('submit');\n    equal($('.customUnhappy').length, 1);\n\n});\n\ntest ('error target', function () {\n\n    var form = fixture('<p id=\"customError\"><input type=\"text\" id=\"textInput\" /></p>');\n\n    form.isHappy({\n        fields: {\n            '#textInput': {\n                required: true,\n                message: 'nope',\n                errorTarget: '#customError'\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('#customError').length, 1); //Didn't insert after input\n    equal($($('form').children()[1]).text(), 'nope'); //Inserted after <p>\n\n});\n\ntest('test config item when to be set on all fields', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n    var test1ran = false;\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                test: function () {\n                    test1ran = true;\n                    return true;\n                }\n            }\n        },\n        when: 'keyup',\n        testMode: true\n    });\n\n    $('#textInput1').val('asdf').trigger('blur');\n    equal(test1ran, false);\n    $('#textInput1').val('asdf').trigger('keyup');\n    equal(test1ran, true);\n});\n\ntest('test config item when to be set on a unique field', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" /><input type=\"text\" id=\"textInput2\" />');\n    var test1ran = false;\n    var test2ran = false;\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                test: function () {\n                    test1ran = true;\n                    return true;\n                }\n            },\n            '#textInput2': {\n                test: function () {\n                    test2ran = true;\n                    return true;\n                },\n                when: 'keyup'\n            }\n        },\n        testMode: true\n    });\n\n    $('#textInput1').val('asdf').trigger('keyup');\n    equal(test1ran, false);\n    $('#textInput1').val('asdf').trigger('blur');\n    equal(test1ran, true);\n    $('#textInput2').val('asdf').trigger('keyup');\n    equal(test2ran, true);\n\n});\n\ntest('test custom classes', function () {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true\n            },\n        },\n        classes: {\n            field: 'error',\n            message: 'errorMsg'\n        },\n        testMode: true\n    });\n\n    form.submit();\n    equal($('#textInput1').attr('class'), 'error');\n    equal($('#textInput1_unhappy').attr('class'), 'errorMsg');\n\n    $('#textInput1').val('asdf');\n    form.submit();\n    equal($('#textInput1').attr('class'), '');\n});\n\ntest('checkbox values aren\\'t clobbered', function () {\n    var form = fixture('<input class=\"answer\" id=\"valueA\" type=\"checkbox\" name=\"answer\" value=\"a\"/><input class=\"answer\" id=\"valueB\" type=\"checkbox\" name=\"answer\" value=\"b\"/>');\n\n    form.isHappy({\n        fields: {\n            '.answer': {\n                required: true\n            }\n        },\n        testMode: true\n    });\n\n    form.submit();\n    equal($('#valueA').attr('value'), 'a');\n    equal($('#valueB').attr('value'), 'b');\n});\n\ntest('check name attribute selector', function () {\n    var form = fixture('<input type=\"text\" name=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '[name=\"textInput1\"]': {\n                required: true,\n                message: 'Please enter an email'\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('.unhappy').length, 1);\n    equal($('.unhappyMessage').length, 1);\n\n    $('[name=\"textInput1\"]').val('test');\n    form.trigger('submit');\n    equal($('.unhappy').length, 0);\n    equal($('.unhappyMessage').length, 0);\n});\n\ntest('error message persists until valid', function() {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true,\n                message: 'Please enter an email'\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').text(), 'Please enter an email', 'Error message present after submit.');\n    $('#textInput1').trigger('blur');\n    equal($('#textInput1_unhappy').text(), 'Please enter an email', 'Error message persists after blur.');\n    $('#textInput1').val('name@example.com');\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').length, 0, 'Error message removed with valid value.');\n});\n\ntest('custom error messages', function() {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true,\n                test: function(value) {\n\n                    var birthday = new Date(value);\n                    var birthdayInt = birthday.getTime();\n\n                    if (isNaN(birthdayInt)) {\n                        return false;\n                    }\n                    if(birthdayInt > new Date()) {\n                        return new Error('Your birthday must have already happened.');\n                    }\n                    if (birthday.getDay() === 3) {\n                        return new Error('Your birthday cannot have happened on a Wednesday.');\n                    }\n                    return true;\n                },\n                message: 'Please provide a valid birth date.'\n            }\n        },\n        testMode: true\n    });\n\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').text(), 'Please provide a valid birth date.', 'Default error message is shown.');\n\n    // tomorrow\n    var dateVal = new Date(new Date().getTime() + (1000 * 60 * 60 * 24)).toString();\n    $('#textInput1').val(dateVal);\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').text(), 'Your birthday must have already happened.', 'Future dates are invalid.');\n\n    $('#textInput1').val('foo');\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').text(), 'Please provide a valid birth date.', 'Default error message is shown for poorly formatted dates.');\n\n    $('#textInput1').val('11/04/2015');\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').text(), 'Your birthday cannot have happened on a Wednesday.', 'Testing for another custom message.');\n\n    $('#textInput1').val('01/01/1989');\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').length, 0, 'Error message removed with valid value.');\n});\n\ntest('test support for multiple tests', function() {\n    var form = fixture('<input type=\"text\" id=\"textInput1\" />');\n\n    function minLength(val, arg) {\n        return val.length < arg[0] ? new Error('Your name must be longer.') : true;\n    }\n\n    function maxLength(val, arg) {\n        return val.length > arg[1] ? new Error('Your name must be shorter.') : true;\n    }\n\n    form.isHappy({\n        fields: {\n            '#textInput1': {\n                required: true,\n                message: 'Might we inquire your name',\n                test: [minLength, maxLength],\n                arg: [3, 32]\n            }\n        },\n        testMode: true\n    });\n\n    $('#textInput1').val('xx');\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').text(), 'Your name must be longer.', 'Stop after first test fails.');\n\n    $('#textInput1').val((new Array(42)).join('x'));\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').text(), 'Your name must be shorter.', 'Second test fails.');\n\n    $('#textInput1').val('John Smith');\n    form.trigger('submit');\n    equal($('#textInput1_unhappy').length, 0, 'All tests pass.');\n});\n"
  },
  {
    "path": "test/underscore.js",
    "content": "//     Underscore.js 1.1.4\n//     (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.\n//     Underscore is freely distributable under the MIT license.\n//     Portions of Underscore are inspired or borrowed from Prototype,\n//     Oliver Steele's Functional, and John Resig's Micro-Templating.\n//     For all details and documentation:\n//     http://documentcloud.github.com/underscore\n\n(function() {\n\n  // Baseline setup\n  // --------------\n\n  // Establish the root object, `window` in the browser, or `global` on the server.\n  var root = this;\n\n  // Save the previous value of the `_` variable.\n  var previousUnderscore = root._;\n\n  // Establish the object that gets returned to break out of a loop iteration.\n  var breaker = {};\n\n  // Save bytes in the minified (but not gzipped) version:\n  var ArrayProto = Array.prototype, ObjProto = Object.prototype;\n\n  // Create quick reference variables for speed access to core prototypes.\n  var slice            = ArrayProto.slice,\n      unshift          = ArrayProto.unshift,\n      toString         = ObjProto.toString,\n      hasOwnProperty   = ObjProto.hasOwnProperty;\n\n  // All **ECMAScript 5** native function implementations that we hope to use\n  // are declared here.\n  var\n    nativeForEach      = ArrayProto.forEach,\n    nativeMap          = ArrayProto.map,\n    nativeReduce       = ArrayProto.reduce,\n    nativeReduceRight  = ArrayProto.reduceRight,\n    nativeFilter       = ArrayProto.filter,\n    nativeEvery        = ArrayProto.every,\n    nativeSome         = ArrayProto.some,\n    nativeIndexOf      = ArrayProto.indexOf,\n    nativeLastIndexOf  = ArrayProto.lastIndexOf,\n    nativeIsArray      = Array.isArray,\n    nativeKeys         = Object.keys;\n\n  // Create a safe reference to the Underscore object for use below.\n  var _ = function(obj) { return new wrapper(obj); };\n\n  // Export the Underscore object for **CommonJS**, with backwards-compatibility\n  // for the old `require()` API. If we're not in CommonJS, add `_` to the\n  // global object.\n  if (typeof module !== 'undefined' && module.exports) {\n    module.exports = _;\n    _._ = _;\n  } else {\n    root._ = _;\n  }\n\n  // Current version.\n  _.VERSION = '1.1.4';\n\n  // Collection Functions\n  // --------------------\n\n  // The cornerstone, an `each` implementation, aka `forEach`.\n  // Handles objects implementing `forEach`, arrays, and raw objects.\n  // Delegates to **ECMAScript 5**'s native `forEach` if available.\n  var each = _.each = _.forEach = function(obj, iterator, context) {\n    var value;\n    if (obj == null) return;\n    if (nativeForEach && obj.forEach === nativeForEach) {\n      obj.forEach(iterator, context);\n    } else if (_.isNumber(obj.length)) {\n      for (var i = 0, l = obj.length; i < l; i++) {\n        if (iterator.call(context, obj[i], i, obj) === breaker) return;\n      }\n    } else {\n      for (var key in obj) {\n        if (hasOwnProperty.call(obj, key)) {\n          if (iterator.call(context, obj[key], key, obj) === breaker) return;\n        }\n      }\n    }\n  };\n\n  // Return the results of applying the iterator to each element.\n  // Delegates to **ECMAScript 5**'s native `map` if available.\n  _.map = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n    each(obj, function(value, index, list) {\n      results[results.length] = iterator.call(context, value, index, list);\n    });\n    return results;\n  };\n\n  // **Reduce** builds up a single result from a list of values, aka `inject`,\n  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.\n  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {\n    var initial = memo !== void 0;\n    if (obj == null) obj = [];\n    if (nativeReduce && obj.reduce === nativeReduce) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n    }\n    each(obj, function(value, index, list) {\n      if (!initial && index === 0) {\n        memo = value;\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, value, index, list);\n      }\n    });\n    if (!initial) throw new TypeError(\"Reduce of empty array with no initial value\");\n    return memo;\n  };\n\n  // The right-associative version of reduce, also known as `foldr`.\n  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n    if (obj == null) obj = [];\n    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n      if (context) iterator = _.bind(iterator, context);\n      return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n    }\n    var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();\n    return _.reduce(reversed, iterator, memo, context);\n  };\n\n  // Return the first value which passes a truth test. Aliased as `detect`.\n  _.find = _.detect = function(obj, iterator, context) {\n    var result;\n    any(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) {\n        result = value;\n        return true;\n      }\n    });\n    return result;\n  };\n\n  // Return all the elements that pass a truth test.\n  // Delegates to **ECMAScript 5**'s native `filter` if available.\n  // Aliased as `select`.\n  _.filter = _.select = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n    each(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) results[results.length] = value;\n    });\n    return results;\n  };\n\n  // Return all the elements for which a truth test fails.\n  _.reject = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    each(obj, function(value, index, list) {\n      if (!iterator.call(context, value, index, list)) results[results.length] = value;\n    });\n    return results;\n  };\n\n  // Determine whether all of the elements match a truth test.\n  // Delegates to **ECMAScript 5**'s native `every` if available.\n  // Aliased as `all`.\n  _.every = _.all = function(obj, iterator, context) {\n    iterator = iterator || _.identity;\n    var result = true;\n    if (obj == null) return result;\n    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n    each(obj, function(value, index, list) {\n      if (!(result = result && iterator.call(context, value, index, list))) return breaker;\n    });\n    return result;\n  };\n\n  // Determine if at least one element in the object matches a truth test.\n  // Delegates to **ECMAScript 5**'s native `some` if available.\n  // Aliased as `any`.\n  var any = _.some = _.any = function(obj, iterator, context) {\n    iterator = iterator || _.identity;\n    var result = false;\n    if (obj == null) return result;\n    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n    each(obj, function(value, index, list) {\n      if (result = iterator.call(context, value, index, list)) return breaker;\n    });\n    return result;\n  };\n\n  // Determine if a given value is included in the array or object using `===`.\n  // Aliased as `contains`.\n  _.include = _.contains = function(obj, target) {\n    var found = false;\n    if (obj == null) return found;\n    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n    any(obj, function(value) {\n      if (found = value === target) return true;\n    });\n    return found;\n  };\n\n  // Invoke a method (with arguments) on every item in a collection.\n  _.invoke = function(obj, method) {\n    var args = slice.call(arguments, 2);\n    return _.map(obj, function(value) {\n      return (method ? value[method] : value).apply(value, args);\n    });\n  };\n\n  // Convenience version of a common use case of `map`: fetching a property.\n  _.pluck = function(obj, key) {\n    return _.map(obj, function(value){ return value[key]; });\n  };\n\n  // Return the maximum element or (element-based computation).\n  _.max = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);\n    var result = {computed : -Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed >= result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Return the minimum element (or element-based computation).\n  _.min = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);\n    var result = {computed : Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed < result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Sort the object's values by a criterion produced by an iterator.\n  _.sortBy = function(obj, iterator, context) {\n    return _.pluck(_.map(obj, function(value, index, list) {\n      return {\n        value : value,\n        criteria : iterator.call(context, value, index, list)\n      };\n    }).sort(function(left, right) {\n      var a = left.criteria, b = right.criteria;\n      return a < b ? -1 : a > b ? 1 : 0;\n    }), 'value');\n  };\n\n  // Use a comparator function to figure out at what index an object should\n  // be inserted so as to maintain order. Uses binary search.\n  _.sortedIndex = function(array, obj, iterator) {\n    iterator = iterator || _.identity;\n    var low = 0, high = array.length;\n    while (low < high) {\n      var mid = (low + high) >> 1;\n      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;\n    }\n    return low;\n  };\n\n  // Safely convert anything iterable into a real, live array.\n  _.toArray = function(iterable) {\n    if (!iterable)                return [];\n    if (iterable.toArray)         return iterable.toArray();\n    if (_.isArray(iterable))      return iterable;\n    if (_.isArguments(iterable))  return slice.call(iterable);\n    return _.values(iterable);\n  };\n\n  // Return the number of elements in an object.\n  _.size = function(obj) {\n    return _.toArray(obj).length;\n  };\n\n  // Array Functions\n  // ---------------\n\n  // Get the first element of an array. Passing **n** will return the first N\n  // values in the array. Aliased as `head`. The **guard** check allows it to work\n  // with `_.map`.\n  _.first = _.head = function(array, n, guard) {\n    return n && !guard ? slice.call(array, 0, n) : array[0];\n  };\n\n  // Returns everything but the first entry of the array. Aliased as `tail`.\n  // Especially useful on the arguments object. Passing an **index** will return\n  // the rest of the values in the array from that index onward. The **guard**\n  // check allows it to work with `_.map`.\n  _.rest = _.tail = function(array, index, guard) {\n    return slice.call(array, _.isUndefined(index) || guard ? 1 : index);\n  };\n\n  // Get the last element of an array.\n  _.last = function(array) {\n    return array[array.length - 1];\n  };\n\n  // Trim out all falsy values from an array.\n  _.compact = function(array) {\n    return _.filter(array, function(value){ return !!value; });\n  };\n\n  // Return a completely flattened version of an array.\n  _.flatten = function(array) {\n    return _.reduce(array, function(memo, value) {\n      if (_.isArray(value)) return memo.concat(_.flatten(value));\n      memo[memo.length] = value;\n      return memo;\n    }, []);\n  };\n\n  // Return a version of the array that does not contain the specified value(s).\n  _.without = function(array) {\n    var values = slice.call(arguments, 1);\n    return _.filter(array, function(value){ return !_.include(values, value); });\n  };\n\n  // Produce a duplicate-free version of the array. If the array has already\n  // been sorted, you have the option of using a faster algorithm.\n  // Aliased as `unique`.\n  _.uniq = _.unique = function(array, isSorted) {\n    return _.reduce(array, function(memo, el, i) {\n      if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;\n      return memo;\n    }, []);\n  };\n\n  // Produce an array that contains every item shared between all the\n  // passed-in arrays.\n  _.intersect = function(array) {\n    var rest = slice.call(arguments, 1);\n    return _.filter(_.uniq(array), function(item) {\n      return _.every(rest, function(other) {\n        return _.indexOf(other, item) >= 0;\n      });\n    });\n  };\n\n  // Zip together multiple lists into a single array -- elements that share\n  // an index go together.\n  _.zip = function() {\n    var args = slice.call(arguments);\n    var length = _.max(_.pluck(args, 'length'));\n    var results = new Array(length);\n    for (var i = 0; i < length; i++) results[i] = _.pluck(args, \"\" + i);\n    return results;\n  };\n\n  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n  // we need this function. Return the position of the first occurrence of an\n  // item in an array, or -1 if the item is not included in the array.\n  // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n  // If the array is large and already in sort order, pass `true`\n  // for **isSorted** to use binary search.\n  _.indexOf = function(array, item, isSorted) {\n    if (array == null) return -1;\n    if (isSorted) {\n      var i = _.sortedIndex(array, item);\n      return array[i] === item ? i : -1;\n    }\n    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);\n    for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;\n    return -1;\n  };\n\n\n  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n  _.lastIndexOf = function(array, item) {\n    if (array == null) return -1;\n    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);\n    var i = array.length;\n    while (i--) if (array[i] === item) return i;\n    return -1;\n  };\n\n  // Generate an integer Array containing an arithmetic progression. A port of\n  // the native Python `range()` function. See\n  // [the Python documentation](http://docs.python.org/library/functions.html#range).\n  _.range = function(start, stop, step) {\n    var args  = slice.call(arguments),\n        solo  = args.length <= 1,\n        start = solo ? 0 : args[0],\n        stop  = solo ? args[0] : args[1],\n        step  = args[2] || 1,\n        len   = Math.max(Math.ceil((stop - start) / step), 0),\n        idx   = 0,\n        range = new Array(len);\n    while (idx < len) {\n      range[idx++] = start;\n      start += step;\n    }\n    return range;\n  };\n\n  // Function (ahem) Functions\n  // ------------------\n\n  // Create a function bound to a given object (assigning `this`, and arguments,\n  // optionally). Binding with arguments is also known as `curry`.\n  _.bind = function(func, obj) {\n    var args = slice.call(arguments, 2);\n    return function() {\n      return func.apply(obj || {}, args.concat(slice.call(arguments)));\n    };\n  };\n\n  // Bind all of an object's methods to that object. Useful for ensuring that\n  // all callbacks defined on an object belong to it.\n  _.bindAll = function(obj) {\n    var funcs = slice.call(arguments, 1);\n    if (funcs.length == 0) funcs = _.functions(obj);\n    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n    return obj;\n  };\n\n  // Memoize an expensive function by storing its results.\n  _.memoize = function(func, hasher) {\n    var memo = {};\n    hasher = hasher || _.identity;\n    return function() {\n      var key = hasher.apply(this, arguments);\n      return key in memo ? memo[key] : (memo[key] = func.apply(this, arguments));\n    };\n  };\n\n  // Delays a function for the given number of milliseconds, and then calls\n  // it with the arguments supplied.\n  _.delay = function(func, wait) {\n    var args = slice.call(arguments, 2);\n    return setTimeout(function(){ return func.apply(func, args); }, wait);\n  };\n\n  // Defers a function, scheduling it to run after the current call stack has\n  // cleared.\n  _.defer = function(func) {\n    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n  };\n\n  // Internal function used to implement `_.throttle` and `_.debounce`.\n  var limit = function(func, wait, debounce) {\n    var timeout;\n    return function() {\n      var context = this, args = arguments;\n      var throttler = function() {\n        timeout = null;\n        func.apply(context, args);\n      };\n      if (debounce) clearTimeout(timeout);\n      if (debounce || !timeout) timeout = setTimeout(throttler, wait);\n    };\n  };\n\n  // Returns a function, that, when invoked, will only be triggered at most once\n  // during a given window of time.\n  _.throttle = function(func, wait) {\n    return limit(func, wait, false);\n  };\n\n  // Returns a function, that, as long as it continues to be invoked, will not\n  // be triggered. The function will be called after it stops being called for\n  // N milliseconds.\n  _.debounce = function(func, wait) {\n    return limit(func, wait, true);\n  };\n\n  // Returns the first function passed as an argument to the second,\n  // allowing you to adjust arguments, run code before and after, and\n  // conditionally execute the original function.\n  _.wrap = function(func, wrapper) {\n    return function() {\n      var args = [func].concat(slice.call(arguments));\n      return wrapper.apply(this, args);\n    };\n  };\n\n  // Returns a function that is the composition of a list of functions, each\n  // consuming the return value of the function that follows.\n  _.compose = function() {\n    var funcs = slice.call(arguments);\n    return function() {\n      var args = slice.call(arguments);\n      for (var i=funcs.length-1; i >= 0; i--) {\n        args = [funcs[i].apply(this, args)];\n      }\n      return args[0];\n    };\n  };\n\n  // Object Functions\n  // ----------------\n\n  // Retrieve the names of an object's properties.\n  // Delegates to **ECMAScript 5**'s native `Object.keys`\n  _.keys = nativeKeys || function(obj) {\n    if (_.isArray(obj)) return _.range(0, obj.length);\n    var keys = [];\n    for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;\n    return keys;\n  };\n\n  // Retrieve the values of an object's properties.\n  _.values = function(obj) {\n    return _.map(obj, _.identity);\n  };\n\n  // Return a sorted list of the function names available on the object.\n  // Aliased as `methods`\n  _.functions = _.methods = function(obj) {\n    return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();\n  };\n\n  // Extend a given object with all the properties in passed-in object(s).\n  _.extend = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      for (var prop in source) obj[prop] = source[prop];\n    });\n    return obj;\n  };\n\n  // Create a (shallow-cloned) duplicate of an object.\n  _.clone = function(obj) {\n    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n  };\n\n  // Invokes interceptor with the obj, and then returns obj.\n  // The primary purpose of this method is to \"tap into\" a method chain, in\n  // order to perform operations on intermediate results within the chain.\n  _.tap = function(obj, interceptor) {\n    interceptor(obj);\n    return obj;\n  };\n\n  // Perform a deep comparison to check if two objects are equal.\n  _.isEqual = function(a, b) {\n    // Check object identity.\n    if (a === b) return true;\n    // Different types?\n    var atype = typeof(a), btype = typeof(b);\n    if (atype != btype) return false;\n    // Basic equality test (watch out for coercions).\n    if (a == b) return true;\n    // One is falsy and the other truthy.\n    if ((!a && b) || (a && !b)) return false;\n    // Unwrap any wrapped objects.\n    if (a._chain) a = a._wrapped;\n    if (b._chain) b = b._wrapped;\n    // One of them implements an isEqual()?\n    if (a.isEqual) return a.isEqual(b);\n    // Check dates' integer values.\n    if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();\n    // Both are NaN?\n    if (_.isNaN(a) && _.isNaN(b)) return false;\n    // Compare regular expressions.\n    if (_.isRegExp(a) && _.isRegExp(b))\n      return a.source     === b.source &&\n             a.global     === b.global &&\n             a.ignoreCase === b.ignoreCase &&\n             a.multiline  === b.multiline;\n    // If a is not an object by this point, we can't handle it.\n    if (atype !== 'object') return false;\n    // Check for different array lengths before comparing contents.\n    if (a.length && (a.length !== b.length)) return false;\n    // Nothing else worked, deep compare the contents.\n    var aKeys = _.keys(a), bKeys = _.keys(b);\n    // Different object sizes?\n    if (aKeys.length != bKeys.length) return false;\n    // Recursive comparison of contents.\n    for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;\n    return true;\n  };\n\n  // Is a given array or object empty?\n  _.isEmpty = function(obj) {\n    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n    for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;\n    return true;\n  };\n\n  // Is a given value a DOM element?\n  _.isElement = function(obj) {\n    return !!(obj && obj.nodeType == 1);\n  };\n\n  // Is a given value an array?\n  // Delegates to ECMA5's native Array.isArray\n  _.isArray = nativeIsArray || function(obj) {\n    return toString.call(obj) === '[object Array]';\n  };\n\n  // Is a given variable an arguments object?\n  _.isArguments = function(obj) {\n    return !!(obj && hasOwnProperty.call(obj, 'callee'));\n  };\n\n  // Is a given value a function?\n  _.isFunction = function(obj) {\n    return !!(obj && obj.constructor && obj.call && obj.apply);\n  };\n\n  // Is a given value a string?\n  _.isString = function(obj) {\n    return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));\n  };\n\n  // Is a given value a number?\n  _.isNumber = function(obj) {\n    return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));\n  };\n\n  // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript\n  // that does not equal itself.\n  _.isNaN = function(obj) {\n    return obj !== obj;\n  };\n\n  // Is a given value a boolean?\n  _.isBoolean = function(obj) {\n    return obj === true || obj === false;\n  };\n\n  // Is a given value a date?\n  _.isDate = function(obj) {\n    return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);\n  };\n\n  // Is the given value a regular expression?\n  _.isRegExp = function(obj) {\n    return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));\n  };\n\n  // Is a given value equal to null?\n  _.isNull = function(obj) {\n    return obj === null;\n  };\n\n  // Is a given variable undefined?\n  _.isUndefined = function(obj) {\n    return obj === void 0;\n  };\n\n  // Utility Functions\n  // -----------------\n\n  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n  // previous owner. Returns a reference to the Underscore object.\n  _.noConflict = function() {\n    root._ = previousUnderscore;\n    return this;\n  };\n\n  // Keep the identity function around for default iterators.\n  _.identity = function(value) {\n    return value;\n  };\n\n  // Run a function **n** times.\n  _.times = function (n, iterator, context) {\n    for (var i = 0; i < n; i++) iterator.call(context, i);\n  };\n\n  // Add your own custom functions to the Underscore object, ensuring that\n  // they're correctly added to the OOP wrapper as well.\n  _.mixin = function(obj) {\n    each(_.functions(obj), function(name){\n      addToWrapper(name, _[name] = obj[name]);\n    });\n  };\n\n  // Generate a unique integer id (unique within the entire client session).\n  // Useful for temporary DOM ids.\n  var idCounter = 0;\n  _.uniqueId = function(prefix) {\n    var id = idCounter++;\n    return prefix ? prefix + id : id;\n  };\n\n  // By default, Underscore uses ERB-style template delimiters, change the\n  // following template settings to use alternative delimiters.\n  _.templateSettings = {\n    evaluate    : /<%([\\s\\S]+?)%>/g,\n    interpolate : /<%=([\\s\\S]+?)%>/g\n  };\n\n  // JavaScript micro-templating, similar to John Resig's implementation.\n  // Underscore templating handles arbitrary delimiters, preserves whitespace,\n  // and correctly escapes quotes within interpolated code.\n  _.template = function(str, data) {\n    var c  = _.templateSettings;\n    var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +\n      'with(obj||{}){__p.push(\\'' +\n      str.replace(/\\\\/g, '\\\\\\\\')\n         .replace(/'/g, \"\\\\'\")\n         .replace(c.interpolate, function(match, code) {\n           return \"',\" + code.replace(/\\\\'/g, \"'\") + \",'\";\n         })\n         .replace(c.evaluate || null, function(match, code) {\n           return \"');\" + code.replace(/\\\\'/g, \"'\")\n                              .replace(/[\\r\\n\\t]/g, ' ') + \"__p.push('\";\n         })\n         .replace(/\\r/g, '\\\\r')\n         .replace(/\\n/g, '\\\\n')\n         .replace(/\\t/g, '\\\\t')\n         + \"');}return __p.join('');\";\n    var func = new Function('obj', tmpl);\n    return data ? func(data) : func;\n  };\n\n  // The OOP Wrapper\n  // ---------------\n\n  // If Underscore is called as a function, it returns a wrapped object that\n  // can be used OO-style. This wrapper holds altered versions of all the\n  // underscore functions. Wrapped objects may be chained.\n  var wrapper = function(obj) { this._wrapped = obj; };\n\n  // Expose `wrapper.prototype` as `_.prototype`\n  _.prototype = wrapper.prototype;\n\n  // Helper function to continue chaining intermediate results.\n  var result = function(obj, chain) {\n    return chain ? _(obj).chain() : obj;\n  };\n\n  // A method to easily add functions to the OOP wrapper.\n  var addToWrapper = function(name, func) {\n    wrapper.prototype[name] = function() {\n      var args = slice.call(arguments);\n      unshift.call(args, this._wrapped);\n      return result(func.apply(_, args), this._chain);\n    };\n  };\n\n  // Add all of the Underscore functions to the wrapper object.\n  _.mixin(_);\n\n  // Add all mutator Array functions to the wrapper.\n  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n    var method = ArrayProto[name];\n    wrapper.prototype[name] = function() {\n      method.apply(this._wrapped, arguments);\n      return result(this._wrapped, this._chain);\n    };\n  });\n\n  // Add all accessor Array functions to the wrapper.\n  each(['concat', 'join', 'slice'], function(name) {\n    var method = ArrayProto[name];\n    wrapper.prototype[name] = function() {\n      return result(method.apply(this._wrapped, arguments), this._chain);\n    };\n  });\n\n  // Start chaining a wrapped Underscore object.\n  wrapper.prototype.chain = function() {\n    this._chain = true;\n    return this;\n  };\n\n  // Extracts the result from a wrapped and chained object.\n  wrapper.prototype.value = function() {\n    return this._wrapped;\n  };\n\n})();"
  },
  {
    "path": "test/zepto.html",
    "content": "<!DOCTYPE html>\n<html>\n    <head>\n        <title>Happy Zepto Tests</title>\n        <link rel=\"stylesheet\" href=\"qunit/qunit.css\" type=\"text/css\" media=\"screen\" />\n        <script src=\"zepto-1.1.6.min.js\"></script>\n        <script src=\"qunit/qunit.js\"></script>\n        <script src=\"../happy.js\"></script>\n        <script src=\"../happy.methods.js\"></script>\n        <script src=\"./tests.js\"></script>\n    </head>\n    <body>\n        <h1 id=\"qunit-header\">Happy Zepto Tests</h1>\n        <h2 id=\"qunit-banner\"></h2>\n        <h2 id=\"qunit-userAgent\"></h2>\n        <ol id=\"qunit-tests\"></ol>\n        <div id=\"qunit-fixture\"></div>\n    </body>\n</html>"
  }
]