Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 3 commits
  • 8 files changed
  • 0 comments
  • 1 contributor
110  index.html
... ...
@@ -1,39 +1,89 @@
1  
-<!DOCTYPE HTML>
2  
-<html>
3  
-<head>
4  
-    <title>CSS Regions Browserscope test</title>
5  
-</head>
6  
-<body> 
7  
-    
8  
-    <h1>BrowserScope + CSS Regions</h1>
9  
-    <p>This page automatically runs the CSS Regions tests on your browser then sends the results to browserscope.org</p>
10  
-    <p>Feelin' used?</p>
  1
+<!--
  2
+Copyright (C) 2012 Adobe Systems, Incorporated. All rights reserved.
  3
+
  4
+Permission is hereby granted, free of charge, to any person obtaining
  5
+a copy of this software and associated documentation files (the
  6
+"Software"), to deal in the Software without restriction, including
  7
+without limitation the rights to use, copy, modify, merge, publish,
  8
+distribute, sublicense, and/or sell copies of the Software, and to
  9
+permit persons to whom the Software is furnished to do so, subject to
  10
+the following conditions:
11 11
 
  12
+The above copyright notice and this permission notice shall be
  13
+included in all copies or substantial portions of the Software.
12 14
 
13  
-<script>
14  
-    // To save data in Browserscope do something like the following.
  15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22
+-->
  23
+<!DOCTYPE html>
  24
+<html>
  25
+<head> 
  26
+    <style type="text/css">
  27
+    
  28
+    .results{
  29
+        font-size:1.2em;
  30
+        color: white; 
  31
+        position: absolute;
  32
+        top: 20px;
  33
+        right: 20px;
  34
+    }
  35
+    
  36
+    </style>
  37
+	<meta charset="UTF-8" />
  38
+	<title>CSS Regions Test Suite</title>
  39
+	<script type="text/javascript" src="qunit/jquery-1.7.1.js"></script>
  40
+	<link rel="stylesheet" href="qunit/qunit.css" type="text/css" media="screen">
  41
+	<script type="text/javascript" src="qunit/qunit.js"></script> 
  42
+	<script type="text/javascript"> 
  43
+	
  44
+	// To save data in Browserscope do something like the following.
15 45
     // The syntax is 'test_key': 'value' where test_key is some unique
16 46
     // identifier for a piece of data you want to store (no = or , allowed)
17 47
     // and value is a numeric value from 0 through 1000000000000.
18 48
     // Note: You can only send a maximum of 200 results in a beacon.
19  
-    var _bTestResults = {}
  49
+    var _bTestResults = {}  
  50
+     
  51
+    // Add option in Qunit to toggle publishing results to BrowserScope.org
  52
+    QUnit.config.urlConfig.push("publishresults")
  53
+    QUnit.config.testTimeout = 3000
  54
+    
  55
+    // Build-up the test results beacon for BrowserScope.org
  56
+    QUnit.testDone = function(obj){   
  57
+        var testName = obj.module + " : " + obj.name;
  58
+        if (!obj.failed && obj.total === obj.passed){
  59
+            _bTestResults[testName] = 1
  60
+        } 
  61
+        else{
  62
+            _bTestResults[testName] = 0
  63
+        }
  64
+    }  
  65
+    
  66
+    // If the user agreed to publish results to BrowserScope.org, go for it!
  67
+    QUnit.done = function(obj){   
  68
+        if (QUnit.config.publishresults){
  69
+            
  70
+            var testKey = 'agt1YS1wcm9maWxlcnINCxIEVGVzdBia9NEQDA';
  71
+            var newScript = document.createElement('script'),
  72
+                firstScript = document.getElementsByTagName('script')[0];
  73
+            newScript.src = 'http://www.browserscope.org/user/beacon/' + testKey;
  74
+            firstScript.parentNode.insertBefore(newScript, firstScript);    
  75
+        }    
  76
+    }   
20 77
     
21  
-     var el = document.body,
22  
-         style
  78
+    </script>
  79
+	<script type="text/javascript" src="prefix-free/prefixfree.min.js"></script>
  80
+	<script type="text/javascript" src="prefix-free/prefixfree.jquery.js"></script>
  81
+	<script type="text/javascript" src="testregions.js"></script>  
23 82
 
24  
-     style = window.getComputedStyle(el, null)    
25  
-     
26  
-     _bTestResults["webkitFlowInto"] = (style['webkitFlowInto'] != undefined) ? 1 : 0
27  
-     _bTestResults["webkitFlowFrom"] = (style['webkitFlowFrom'] != undefined) ? 1 : 0
28  
-     
29  
-    // Beacon the results to Browserscope.
30  
-    !function(){
31  
-    var testKey = 'agt1YS1wcm9maWxlcnINCxIEVGVzdBia9NEQDA';
32  
-    var newScript = document.createElement('script'),
33  
-        firstScript = document.getElementsByTagName('script')[0];
34  
-    newScript.src = 'http://www.browserscope.org/user/beacon/' + testKey;
35  
-    firstScript.parentNode.insertBefore(newScript, firstScript);
36  
-    }();  
37  
-</script>    
  83
+</head>
  84
+<body>
  85
+    <a href="results.html" target="_blank" class="results">Browser test results</a>
  86
+	<div id="qunit"></div>
  87
+	<div id="qunit-fixture">test markup</div>
38 88
 </body>
39  
-</html>
  89
+</html>
15  prefix-free/prefixfree.jquery.js
... ...
@@ -0,0 +1,15 @@
  1
+(function($, self){
  2
+
  3
+if(!$ || !self) {
  4
+	return;
  5
+}
  6
+
  7
+for(var i=0; i<self.properties.length; i++) {
  8
+	var property = self.properties[i],
  9
+		camelCased = StyleFix.camelCase(property),
  10
+		PrefixCamelCased = self.prefixProperty(property, true);
  11
+	
  12
+	$.cssProps[camelCased] = PrefixCamelCased;
  13
+}
  14
+
  15
+})(window.jQuery, window.PrefixFree);
12  prefix-free/prefixfree.min.js
... ...
@@ -0,0 +1,12 @@
  1
+// StyleFix 1.0.2 + PrefixFree 1.0.6 / Lea Verou / MIT license
  2
+(function(){function h(a,b){return[].slice.call((b||document).querySelectorAll(a))}if(window.addEventListener){var e=window.StyleFix={link:function(a){try{if("stylesheet"!==a.rel||a.hasAttribute("data-noprefix"))return}catch(b){return}var c=a.href||a.getAttribute("data-href"),f=c.replace(/[^\/]+$/,""),i=a.parentNode,d=new XMLHttpRequest,g;d.onreadystatechange=function(){4===d.readyState&&g()};g=function(){var b=d.responseText;if(b&&a.parentNode&&(!d.status||400>d.status||600<d.status)){b=e.fix(b,
  3
+!0,a);f&&(b=b.replace(/url\(\s*?((?:"|')?)(.+?)\1\s*?\)/gi,function(b,a,c){return!/^([a-z]{3,10}:|\/|#)/i.test(c)?'url("'+f+c+'")':b}),b=b.replace(RegExp("\\b(behavior:\\s*?url\\('?\"?)"+f,"gi"),"$1"));var c=document.createElement("style");c.textContent=b;c.media=a.media;c.disabled=a.disabled;c.setAttribute("data-href",a.getAttribute("href"));i.insertBefore(c,a);i.removeChild(a)}};try{d.open("GET",c),d.send(null)}catch(k){"undefined"!=typeof XDomainRequest&&(d=new XDomainRequest,d.onerror=d.onprogress=
  4
+function(){},d.onload=g,d.open("GET",c),d.send(null))}a.setAttribute("data-inprogress","")},styleElement:function(a){var b=a.disabled;a.textContent=e.fix(a.textContent,!0,a);a.disabled=b},styleAttribute:function(a){var b=a.getAttribute("style"),b=e.fix(b,!1,a);a.setAttribute("style",b)},process:function(){h('link[rel="stylesheet"]:not([data-inprogress])').forEach(StyleFix.link);h("style").forEach(StyleFix.styleElement);h("[style]").forEach(StyleFix.styleAttribute)},register:function(a,b){(e.fixers=
  5
+e.fixers||[]).splice(void 0===b?e.fixers.length:b,0,a)},fix:function(a,b){for(var c=0;c<e.fixers.length;c++)a=e.fixers[c](a,b)||a;return a},camelCase:function(a){return a.replace(/-([a-z])/g,function(b,a){return a.toUpperCase()}).replace("-","")},deCamelCase:function(a){return a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()})}};(function(){setTimeout(function(){h('link[rel="stylesheet"]').forEach(StyleFix.link)},10);document.addEventListener("DOMContentLoaded",StyleFix.process,!1)})()}})();
  6
+(function(h){function e(b,c,f,i,d){b=a[b];b.length&&(b=RegExp(c+"("+b.join("|")+")"+f,"gi"),d=d.replace(b,i));return d}if(window.StyleFix&&window.getComputedStyle){var a=window.PrefixFree={prefixCSS:function(b,c){var f=a.prefix,b=e("functions","(\\s|:|,)","\\s*\\(","$1"+f+"$2(",b),b=e("keywords","(\\s|:)","(\\s|;|\\}|$)","$1"+f+"$2$3",b),b=e("properties","(^|\\{|\\s|;)","\\s*:","$1"+f+"$2:",b);if(a.properties.length)var i=RegExp("\\b("+a.properties.join("|")+")(?!:)","gi"),b=e("valueProperties","\\b",
  7
+":(.+?);",function(a){return a.replace(i,f+"$1")},b);c&&(b=e("selectors","","\\b",a.prefixSelector,b),b=e("atrules","@","\\b","@"+f+"$1",b));return b=b.replace(RegExp("-"+f,"g"),"-")},property:function(b){return(a.properties.indexOf(b)?a.prefix:"")+b},value:function(b){b=e("functions","(^|\\s|,)","\\s*\\(","$1"+a.prefix+"$2(",b);return b=e("keywords","(^|\\s)","(\\s|$)","$1"+a.prefix+"$2$3",b)},prefixSelector:function(b){return b.replace(/^:{1,2}/,function(b){return b+a.prefix})},prefixProperty:function(b,
  8
+c){var f=a.prefix+b;return c?StyleFix.camelCase(f):f}};(function(){var b={},c=[],f=getComputedStyle(document.documentElement,null),i=document.createElement("div").style,d=function(a){if("-"===a.charAt(0)){c.push(a);var a=a.split("-"),d=a[1];for(b[d]=++b[d]||1;3<a.length;)a.pop(),d=a.join("-"),StyleFix.camelCase(d)in i&&-1===c.indexOf(d)&&c.push(d)}};if(0<f.length)for(var g=0;g<f.length;g++)d(f[g]);else for(var e in f)d(StyleFix.deCamelCase(e));var g=0,j,h;for(h in b)f=b[h],g<f&&(j=h,g=f);a.prefix=
  9
+"-"+j+"-";a.Prefix=StyleFix.camelCase(a.prefix);a.properties=[];for(g=0;g<c.length;g++)e=c[g],0===e.indexOf(a.prefix)&&(j=e.slice(a.prefix.length),StyleFix.camelCase(j)in i||a.properties.push(j));"Ms"==a.Prefix&&!("transform"in i)&&!("MsTransform"in i)&&"msTransform"in i&&a.properties.push("transform","transform-origin");a.properties.sort()})();(function(){function b(a,b){e[b]="";e[b]=a;return!!e[b]}var c={"linear-gradient":{property:"backgroundImage",params:"red, teal"},calc:{property:"width",params:"1px + 5%"},
  10
+element:{property:"backgroundImage",params:"#foo"},"cross-fade":{property:"backgroundImage",params:"url(a.png), url(b.png), 50%"}};c["repeating-linear-gradient"]=c["repeating-radial-gradient"]=c["radial-gradient"]=c["linear-gradient"];var f={initial:"color","zoom-in":"cursor","zoom-out":"cursor",box:"display",flexbox:"display","inline-flexbox":"display"};a.functions=[];a.keywords=[];var e=document.createElement("div").style,d;for(d in c){var g=c[d],h=g.property,g=d+"("+g.params+")";!b(g,h)&&b(a.prefix+
  11
+g,h)&&a.functions.push(d)}for(var j in f)h=f[j],!b(j,h)&&b(a.prefix+j,h)&&a.keywords.push(j)})();(function(){function b(a){e.textContent=a+"{}";return!!e.sheet.cssRules.length}var c={":read-only":null,":read-write":null,":any-link":null,"::selection":null},f={keyframes:"name",viewport:null,document:'regexp(".")'};a.selectors=[];a.atrules=[];var e=h.appendChild(document.createElement("style")),d;for(d in c){var g=d+(c[d]?"("+c[d]+")":"");!b(g)&&b(a.prefixSelector(g))&&a.selectors.push(d)}for(var k in f)g=
  12
+k+" "+(f[k]||""),!b("@"+g)&&b("@"+a.prefix+g)&&a.atrules.push(k);h.removeChild(e)})();a.valueProperties=["transition","transition-property"];h.className+=" "+a.prefix;StyleFix.register(a.prefixCSS)}})(document.documentElement);
9,266  qunit/jquery-1.7.1.js
9266 additions, 0 deletions not shown
232  qunit/qunit.css
... ...
@@ -0,0 +1,232 @@
  1
+/**
  2
+ * QUnit v1.3.0pre - A JavaScript Unit Testing Framework
  3
+ *
  4
+ * http://docs.jquery.com/QUnit
  5
+ *
  6
+ * Copyright (c) 2012 John Resig, Jörn Zaefferer
  7
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
  8
+ * or GPL (GPL-LICENSE.txt) licenses.
  9
+ */
  10
+
  11
+/** Font Family and Sizes */
  12
+
  13
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
  14
+	font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
  15
+}
  16
+
  17
+#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
  18
+#qunit-tests { font-size: smaller; }
  19
+
  20
+
  21
+/** Resets */
  22
+
  23
+#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
  24
+	margin: 0;
  25
+	padding: 0;
  26
+}
  27
+
  28
+
  29
+/** Header */
  30
+
  31
+#qunit-header {
  32
+	padding: 0.5em 0 0.5em 1em;
  33
+
  34
+	color: #8699a4;
  35
+	background-color: #0d3349;
  36
+
  37
+	font-size: 1.5em;
  38
+	line-height: 1em;
  39
+	font-weight: normal;
  40
+
  41
+	border-radius: 15px 15px 0 0;
  42
+	-moz-border-radius: 15px 15px 0 0;
  43
+	-webkit-border-top-right-radius: 15px;
  44
+	-webkit-border-top-left-radius: 15px;
  45
+}
  46
+
  47
+#qunit-header a {
  48
+	text-decoration: none;
  49
+	color: #c2ccd1;
  50
+}
  51
+
  52
+#qunit-header a:hover,
  53
+#qunit-header a:focus {
  54
+	color: #fff;
  55
+}
  56
+
  57
+#qunit-header label {
  58
+	display: inline-block;
  59
+}
  60
+
  61
+#qunit-banner {
  62
+	height: 5px;
  63
+}
  64
+
  65
+#qunit-testrunner-toolbar {
  66
+	padding: 0.5em 0 0.5em 2em;
  67
+	color: #5E740B;
  68
+	background-color: #eee;
  69
+}
  70
+
  71
+#qunit-userAgent {
  72
+	padding: 0.5em 0 0.5em 2.5em;
  73
+	background-color: #2b81af;
  74
+	color: #fff;
  75
+	text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
  76
+}
  77
+
  78
+
  79
+/** Tests: Pass/Fail */
  80
+
  81
+#qunit-tests {
  82
+	list-style-position: inside;
  83
+}
  84
+
  85
+#qunit-tests li {
  86
+	padding: 0.4em 0.5em 0.4em 2.5em;
  87
+	border-bottom: 1px solid #fff;
  88
+	list-style-position: inside;
  89
+}
  90
+
  91
+#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running  {
  92
+	display: none;
  93
+}
  94
+
  95
+#qunit-tests li strong {
  96
+	cursor: pointer;
  97
+}
  98
+
  99
+#qunit-tests li a {
  100
+	padding: 0.5em;
  101
+	color: #c2ccd1;
  102
+	text-decoration: none;
  103
+}
  104
+#qunit-tests li a:hover,
  105
+#qunit-tests li a:focus {
  106
+	color: #000;
  107
+}
  108
+
  109
+#qunit-tests ol {
  110
+	margin-top: 0.5em;
  111
+	padding: 0.5em;
  112
+
  113
+	background-color: #fff;
  114
+
  115
+	border-radius: 15px;
  116
+	-moz-border-radius: 15px;
  117
+	-webkit-border-radius: 15px;
  118
+
  119
+	box-shadow: inset 0px 2px 13px #999;
  120
+	-moz-box-shadow: inset 0px 2px 13px #999;
  121
+	-webkit-box-shadow: inset 0px 2px 13px #999;
  122
+}
  123
+
  124
+#qunit-tests table {
  125
+	border-collapse: collapse;
  126
+	margin-top: .2em;
  127
+}
  128
+
  129
+#qunit-tests th {
  130
+	text-align: right;
  131
+	vertical-align: top;
  132
+	padding: 0 .5em 0 0;
  133
+}
  134
+
  135
+#qunit-tests td {
  136
+	vertical-align: top;
  137
+}
  138
+
  139
+#qunit-tests pre {
  140
+	margin: 0;
  141
+	white-space: pre-wrap;
  142
+	word-wrap: break-word;
  143
+}
  144
+
  145
+#qunit-tests del {
  146
+	background-color: #e0f2be;
  147
+	color: #374e0c;
  148
+	text-decoration: none;
  149
+}
  150
+
  151
+#qunit-tests ins {
  152
+	background-color: #ffcaca;
  153
+	color: #500;
  154
+	text-decoration: none;
  155
+}
  156
+
  157
+/*** Test Counts */
  158
+
  159
+#qunit-tests b.counts                       { color: black; }
  160
+#qunit-tests b.passed                       { color: #5E740B; }
  161
+#qunit-tests b.failed                       { color: #710909; }
  162
+
  163
+#qunit-tests li li {
  164
+	margin: 0.5em;
  165
+	padding: 0.4em 0.5em 0.4em 0.5em;
  166
+	background-color: #fff;
  167
+	border-bottom: none;
  168
+	list-style-position: inside;
  169
+}
  170
+
  171
+/*** Passing Styles */
  172
+
  173
+#qunit-tests li li.pass {
  174
+	color: #5E740B;
  175
+	background-color: #fff;
  176
+	border-left: 26px solid #C6E746;
  177
+}
  178
+
  179
+#qunit-tests .pass                          { color: #528CE0; background-color: #D2E0E6; }
  180
+#qunit-tests .pass .test-name               { color: #366097; }
  181
+
  182
+#qunit-tests .pass .test-actual,
  183
+#qunit-tests .pass .test-expected           { color: #999999; }
  184
+
  185
+#qunit-banner.qunit-pass                    { background-color: #C6E746; }
  186
+
  187
+/*** Failing Styles */
  188
+
  189
+#qunit-tests li li.fail {
  190
+	color: #710909;
  191
+	background-color: #fff;
  192
+	border-left: 26px solid #EE5757;
  193
+	white-space: pre;
  194
+}
  195
+
  196
+#qunit-tests > li:last-child {
  197
+	border-radius: 0 0 15px 15px;
  198
+	-moz-border-radius: 0 0 15px 15px;
  199
+	-webkit-border-bottom-right-radius: 15px;
  200
+	-webkit-border-bottom-left-radius: 15px;
  201
+}
  202
+
  203
+#qunit-tests .fail                          { color: #000000; background-color: #EE5757; }
  204
+#qunit-tests .fail .test-name,
  205
+#qunit-tests .fail .module-name             { color: #000000; }
  206
+
  207
+#qunit-tests .fail .test-actual             { color: #EE5757; }
  208
+#qunit-tests .fail .test-expected           { color: green;   }
  209
+
  210
+#qunit-banner.qunit-fail                    { background-color: #EE5757; }
  211
+
  212
+
  213
+/** Result */
  214
+
  215
+#qunit-testresult {
  216
+	padding: 0.5em 0.5em 0.5em 2.5em;
  217
+
  218
+	color: #2b81af;
  219
+	background-color: #D2E0E6;
  220
+
  221
+	border-bottom: 1px solid white;
  222
+}
  223
+
  224
+/** Fixture */
  225
+
  226
+#qunit-fixture {
  227
+	position: absolute;
  228
+	top: -10000px;
  229
+	left: -10000px;
  230
+	width: 1000px;
  231
+	height: 1000px;
  232
+}
1,633  qunit/qunit.js
... ...
@@ -0,0 +1,1633 @@
  1
+/**
  2
+ * QUnit v1.3.0pre - A JavaScript Unit Testing Framework
  3
+ *
  4
+ * http://docs.jquery.com/QUnit
  5
+ *
  6
+ * Copyright (c) 2012 John Resig, Jörn Zaefferer
  7
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
  8
+ * or GPL (GPL-LICENSE.txt) licenses.
  9
+ */
  10
+
  11
+(function(window) {
  12
+
  13
+var defined = {
  14
+	setTimeout: typeof window.setTimeout !== "undefined",
  15
+	sessionStorage: (function() {
  16
+		var x = "qunit-test-string";
  17
+		try {
  18
+			sessionStorage.setItem(x, x);
  19
+			sessionStorage.removeItem(x);
  20
+			return true;
  21
+		} catch(e) {
  22
+			return false;
  23
+		}
  24
+	})()
  25
+};
  26
+
  27
+var	testId = 0,
  28
+	toString = Object.prototype.toString,
  29
+	hasOwn = Object.prototype.hasOwnProperty;
  30
+
  31
+var Test = function(name, testName, expected, async, callback) {
  32
+	this.name = name;
  33
+	this.testName = testName;
  34
+	this.expected = expected;
  35
+	this.async = async;
  36
+	this.callback = callback;
  37
+	this.assertions = [];
  38
+};
  39
+Test.prototype = {
  40
+	init: function() {
  41
+		var tests = id("qunit-tests");
  42
+		if (tests) {
  43
+			var b = document.createElement("strong");
  44
+				b.innerHTML = "Running " + this.name;
  45
+			var li = document.createElement("li");
  46
+				li.appendChild( b );
  47
+				li.className = "running";
  48
+				li.id = this.id = "test-output" + testId++;
  49
+			tests.appendChild( li );
  50
+		}
  51
+	},
  52
+	setup: function() {
  53
+		if (this.module != config.previousModule) {
  54
+			if ( config.previousModule ) {
  55
+				runLoggingCallbacks('moduleDone', QUnit, {
  56
+					name: config.previousModule,
  57
+					failed: config.moduleStats.bad,
  58
+					passed: config.moduleStats.all - config.moduleStats.bad,
  59
+					total: config.moduleStats.all
  60
+				} );
  61
+			}
  62
+			config.previousModule = this.module;
  63
+			config.moduleStats = { all: 0, bad: 0 };
  64
+			runLoggingCallbacks( 'moduleStart', QUnit, {
  65
+				name: this.module
  66
+			} );
  67
+		} else if (config.autorun) {
  68
+			runLoggingCallbacks( 'moduleStart', QUnit, {
  69
+				name: this.module
  70
+			} );
  71
+		}
  72
+
  73
+		config.current = this;
  74
+		this.testEnvironment = extend({
  75
+			setup: function() {},
  76
+			teardown: function() {}
  77
+		}, this.moduleTestEnvironment);
  78
+
  79
+		runLoggingCallbacks( 'testStart', QUnit, {
  80
+			name: this.testName,
  81
+			module: this.module
  82
+		});
  83
+
  84
+		// allow utility functions to access the current test environment
  85
+		// TODO why??
  86
+		QUnit.current_testEnvironment = this.testEnvironment;
  87
+
  88
+		try {
  89
+			if ( !config.pollution ) {
  90
+				saveGlobal();
  91
+			}
  92
+
  93
+			this.testEnvironment.setup.call(this.testEnvironment);
  94
+		} catch(e) {
  95
+			QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
  96
+		}
  97
+	},
  98
+	run: function() {
  99
+		config.current = this;
  100
+		if ( this.async ) {
  101
+			QUnit.stop();
  102
+		}
  103
+
  104
+		if ( config.notrycatch ) {
  105
+			this.callback.call(this.testEnvironment);
  106
+			return;
  107
+		}
  108
+		try {
  109
+			this.callback.call(this.testEnvironment);
  110
+		} catch(e) {
  111
+			fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
  112
+			QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
  113
+			// else next test will carry the responsibility
  114
+			saveGlobal();
  115
+
  116
+			// Restart the tests if they're blocking
  117
+			if ( config.blocking ) {
  118
+				QUnit.start();
  119
+			}
  120
+		}
  121
+	},
  122
+	teardown: function() {
  123
+		config.current = this;
  124
+		try {
  125
+			this.testEnvironment.teardown.call(this.testEnvironment);
  126
+			checkPollution();
  127
+		} catch(e) {
  128
+			QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
  129
+		}
  130
+	},
  131
+	finish: function() {
  132
+		config.current = this;
  133
+		if ( this.expected != null && this.expected != this.assertions.length ) {
  134
+			QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
  135
+		}
  136
+
  137
+		var good = 0, bad = 0,
  138
+			tests = id("qunit-tests");
  139
+
  140
+		config.stats.all += this.assertions.length;
  141
+		config.moduleStats.all += this.assertions.length;
  142
+
  143
+		if ( tests ) {
  144
+			var ol = document.createElement("ol");
  145
+
  146
+			for ( var i = 0; i < this.assertions.length; i++ ) {
  147
+				var assertion = this.assertions[i];
  148
+
  149
+				var li = document.createElement("li");
  150
+				li.className = assertion.result ? "pass" : "fail";
  151
+				li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
  152
+				ol.appendChild( li );
  153
+
  154
+				if ( assertion.result ) {
  155
+					good++;
  156
+				} else {
  157
+					bad++;
  158
+					config.stats.bad++;
  159
+					config.moduleStats.bad++;
  160
+				}
  161
+			}
  162
+
  163
+			// store result when possible
  164
+			if ( QUnit.config.reorder && defined.sessionStorage ) {
  165
+				if (bad) {
  166
+					sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
  167
+				} else {
  168
+					sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
  169
+				}
  170
+			}
  171
+
  172
+			if (bad == 0) {
  173
+				ol.style.display = "none";
  174
+			}
  175
+
  176
+			var b = document.createElement("strong");
  177
+			b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
  178
+
  179
+			var a = document.createElement("a");
  180
+			a.innerHTML = "Rerun";
  181
+			a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
  182
+
  183
+			addEvent(b, "click", function() {
  184
+				var next = b.nextSibling.nextSibling,
  185
+					display = next.style.display;
  186
+				next.style.display = display === "none" ? "block" : "none";
  187
+			});
  188
+
  189
+			addEvent(b, "dblclick", function(e) {
  190
+				var target = e && e.target ? e.target : window.event.srcElement;
  191
+				if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
  192
+					target = target.parentNode;
  193
+				}
  194
+				if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
  195
+					window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
  196
+				}
  197
+			});
  198
+
  199
+			var li = id(this.id);
  200
+			li.className = bad ? "fail" : "pass";
  201
+			li.removeChild( li.firstChild );
  202
+			li.appendChild( b );
  203
+			li.appendChild( a );
  204
+			li.appendChild( ol );
  205
+
  206
+		} else {
  207
+			for ( var i = 0; i < this.assertions.length; i++ ) {
  208
+				if ( !this.assertions[i].result ) {
  209
+					bad++;
  210
+					config.stats.bad++;
  211
+					config.moduleStats.bad++;
  212
+				}
  213
+			}
  214
+		}
  215
+
  216
+		try {
  217
+			QUnit.reset();
  218
+		} catch(e) {
  219
+			fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
  220
+		}
  221
+		
  222
+
  223
+		runLoggingCallbacks( 'testDone', QUnit, {
  224
+			name: this.testName,
  225
+			module: this.module,
  226
+			failed: bad,
  227
+			passed: this.assertions.length - bad,
  228
+			total: this.assertions.length
  229
+		} );
  230
+	},
  231
+
  232
+	queue: function() {
  233
+		var test = this;
  234
+		synchronize(function() {
  235
+			test.init();
  236
+		});
  237
+		function run() {
  238
+			// each of these can by async
  239
+			synchronize(function() {
  240
+				test.setup();
  241
+			});
  242
+			synchronize(function() {
  243
+				test.run();
  244
+			});
  245
+			synchronize(function() {
  246
+				test.teardown();
  247
+			});
  248
+			synchronize(function() {
  249
+				test.finish();
  250
+			});
  251
+		}
  252
+		// defer when previous test run passed, if storage is available
  253
+		var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
  254
+		if (bad) {
  255
+			run();
  256
+		} else {
  257
+			synchronize(run, true);
  258
+		};
  259
+	}
  260
+
  261
+};
  262
+
  263
+var QUnit = {
  264
+
  265
+	// call on start of module test to prepend name to all tests
  266
+	module: function(name, testEnvironment) {
  267
+		config.currentModule = name;
  268
+		config.currentModuleTestEnviroment = testEnvironment;
  269
+	},
  270
+
  271
+	asyncTest: function(testName, expected, callback) {
  272
+		if ( arguments.length === 2 ) {
  273
+			callback = expected;
  274
+			expected = null;
  275
+		}
  276
+
  277
+		QUnit.test(testName, expected, callback, true);
  278
+	},
  279
+
  280
+	test: function(testName, expected, callback, async) {
  281
+		var name = '<span class="test-name">' + escapeInnerText(testName) + '</span>';
  282
+
  283
+		if ( arguments.length === 2 ) {
  284
+			callback = expected;
  285
+			expected = null;
  286
+		}
  287
+
  288
+		if ( config.currentModule ) {
  289
+			name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
  290
+		}
  291
+
  292
+		if ( !validTest(config.currentModule + ": " + testName) ) {
  293
+			return;
  294
+		}
  295
+
  296
+		var test = new Test(name, testName, expected, async, callback);
  297
+		test.module = config.currentModule;
  298
+		test.moduleTestEnvironment = config.currentModuleTestEnviroment;
  299
+		test.queue();
  300
+	},
  301
+
  302
+	/**
  303
+	 * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
  304
+	 */
  305
+	expect: function(asserts) {
  306
+		config.current.expected = asserts;
  307
+	},
  308
+
  309
+	/**
  310
+	 * Asserts true.
  311
+	 * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
  312
+	 */
  313
+	ok: function(a, msg) {
  314
+		if (!config.current) {
  315
+			throw new Error("ok() assertion outside test context, was " + sourceFromStacktrace(2));
  316
+		}
  317
+		a = !!a;
  318
+		var details = {
  319
+			result: a,
  320
+			message: msg
  321
+		};
  322
+		msg = escapeInnerText(msg);
  323
+		runLoggingCallbacks( 'log', QUnit, details );
  324
+		config.current.assertions.push({
  325
+			result: a,
  326
+			message: msg
  327
+		});
  328
+	},
  329
+
  330
+	/**
  331
+	 * Checks that the first two arguments are equal, with an optional message.
  332
+	 * Prints out both actual and expected values.
  333
+	 *
  334
+	 * Prefered to ok( actual == expected, message )
  335
+	 *
  336
+	 * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
  337
+	 *
  338
+	 * @param Object actual
  339
+	 * @param Object expected
  340
+	 * @param String message (optional)
  341
+	 */
  342
+	equal: function(actual, expected, message) {
  343
+		QUnit.push(expected == actual, actual, expected, message);
  344
+	},
  345
+
  346
+	notEqual: function(actual, expected, message) {
  347
+		QUnit.push(expected != actual, actual, expected, message);
  348
+	},
  349
+
  350
+	deepEqual: function(actual, expected, message) {
  351
+		QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
  352
+	},
  353
+
  354
+	notDeepEqual: function(actual, expected, message) {
  355
+		QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
  356
+	},
  357
+
  358
+	strictEqual: function(actual, expected, message) {
  359
+		QUnit.push(expected === actual, actual, expected, message);
  360
+	},
  361
+
  362
+	notStrictEqual: function(actual, expected, message) {
  363
+		QUnit.push(expected !== actual, actual, expected, message);
  364
+	},
  365
+
  366
+	raises: function(block, expected, message) {
  367
+		var actual, ok = false;
  368
+
  369
+		if (typeof expected === 'string') {
  370
+			message = expected;
  371
+			expected = null;
  372
+		}
  373
+
  374
+		try {
  375
+			block();
  376
+		} catch (e) {
  377
+			actual = e;
  378
+		}
  379
+
  380
+		if (actual) {
  381
+			// we don't want to validate thrown error
  382
+			if (!expected) {
  383
+				ok = true;
  384
+			// expected is a regexp
  385
+			} else if (QUnit.objectType(expected) === "regexp") {
  386
+				ok = expected.test(actual);
  387
+			// expected is a constructor
  388
+			} else if (actual instanceof expected) {
  389
+				ok = true;
  390
+			// expected is a validation function which returns true is validation passed
  391
+			} else if (expected.call({}, actual) === true) {
  392
+				ok = true;
  393
+			}
  394
+		}
  395
+
  396
+		QUnit.ok(ok, message);
  397
+	},
  398
+
  399
+	start: function(count) {
  400
+		config.semaphore -= count || 1;
  401
+		if (config.semaphore > 0) {
  402
+			// don't start until equal number of stop-calls
  403
+			return;
  404
+		}
  405
+		if (config.semaphore < 0) {
  406
+			// ignore if start is called more often then stop
  407
+			config.semaphore = 0;
  408
+		}
  409
+		// A slight delay, to avoid any current callbacks
  410
+		if ( defined.setTimeout ) {
  411
+			window.setTimeout(function() {
  412
+				if (config.semaphore > 0) {
  413
+					return;
  414
+				}
  415
+				if ( config.timeout ) {
  416
+					clearTimeout(config.timeout);
  417
+				}
  418
+
  419
+				config.blocking = false;
  420
+				process(true);
  421
+			}, 13);
  422
+		} else {
  423
+			config.blocking = false;
  424
+			process(true);
  425
+		}
  426
+	},
  427
+
  428
+	stop: function(count) {
  429
+		config.semaphore += count || 1;
  430
+		config.blocking = true;
  431
+
  432
+		if ( config.testTimeout && defined.setTimeout ) {
  433
+			clearTimeout(config.timeout);
  434
+			config.timeout = window.setTimeout(function() {
  435
+				QUnit.ok( false, "Test timed out" );
  436
+				config.semaphore = 1;
  437
+				QUnit.start();
  438
+			}, config.testTimeout);
  439
+		}
  440
+	}
  441
+};
  442
+
  443
+//We want access to the constructor's prototype
  444
+(function() {
  445
+	function F(){};
  446
+	F.prototype = QUnit;
  447
+	QUnit = new F();
  448
+	//Make F QUnit's constructor so that we can add to the prototype later
  449
+	QUnit.constructor = F;
  450
+})();
  451
+
  452
+// deprecated; still export them to window to provide clear error messages
  453
+// next step: remove entirely
  454
+QUnit.equals = function() {
  455
+	throw new Error("QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead");
  456
+};
  457
+QUnit.same = function() {
  458
+	throw new Error("QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead");
  459
+};
  460
+
  461
+// Maintain internal state
  462
+var config = {
  463
+	// The queue of tests to run
  464
+	queue: [],
  465
+
  466
+	// block until document ready
  467
+	blocking: true,
  468
+
  469
+	// when enabled, show only failing tests
  470
+	// gets persisted through sessionStorage and can be changed in UI via checkbox
  471
+	hidepassed: false,
  472
+
  473
+	// by default, run previously failed tests first
  474
+	// very useful in combination with "Hide passed tests" checked
  475
+	reorder: true,
  476
+
  477
+	// by default, modify document.title when suite is done
  478
+	altertitle: true,
  479
+
  480
+	urlConfig: ['noglobals', 'notrycatch'],
  481
+
  482
+	//logging callback queues
  483
+	begin: [],
  484
+	done: [],
  485
+	log: [],
  486
+	testStart: [],
  487
+	testDone: [],
  488
+	moduleStart: [],
  489
+	moduleDone: []
  490
+};
  491
+
  492
+// Load paramaters
  493
+(function() {
  494
+	var location = window.location || { search: "", protocol: "file:" },
  495
+		params = location.search.slice( 1 ).split( "&" ),
  496
+		length = params.length,
  497
+		urlParams = {},
  498
+		current;
  499
+
  500
+	if ( params[ 0 ] ) {
  501
+		for ( var i = 0; i < length; i++ ) {
  502
+			current = params[ i ].split( "=" );
  503
+			current[ 0 ] = decodeURIComponent( current[ 0 ] );
  504
+			// allow just a key to turn on a flag, e.g., test.html?noglobals
  505
+			current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
  506
+			urlParams[ current[ 0 ] ] = current[ 1 ];
  507
+		}
  508
+	}
  509
+
  510
+	QUnit.urlParams = urlParams;
  511
+	config.filter = urlParams.filter;
  512
+
  513
+	// Figure out if we're running the tests from a server or not
  514
+	QUnit.isLocal = !!(location.protocol === 'file:');
  515
+})();
  516
+
  517
+// Expose the API as global variables, unless an 'exports'
  518
+// object exists, in that case we assume we're in CommonJS
  519
+if ( typeof exports === "undefined" || typeof require === "undefined" ) {
  520
+	extend(window, QUnit);
  521
+	window.QUnit = QUnit;
  522
+} else {
  523
+	module.exports = QUnit;
  524
+}
  525
+
  526
+// define these after exposing globals to keep them in these QUnit namespace only
  527
+extend(QUnit, {
  528
+	config: config,
  529
+
  530
+	// Initialize the configuration options
  531
+	init: function() {
  532
+		extend(config, {
  533
+			stats: { all: 0, bad: 0 },
  534
+			moduleStats: { all: 0, bad: 0 },
  535
+			started: +new Date,
  536
+			updateRate: 1000,
  537
+			blocking: false,
  538
+			autostart: true,
  539
+			autorun: false,
  540
+			filter: "",
  541
+			queue: [],
  542
+			semaphore: 0
  543
+		});
  544
+
  545
+		var qunit = id( "qunit" );
  546
+		if ( qunit ) {
  547
+			qunit.innerHTML =
  548
+				'<h1 id="qunit-header">' + escapeInnerText( document.title ) + '</h1>' +
  549
+				'<h2 id="qunit-banner"></h2>' +
  550
+				'<div id="qunit-testrunner-toolbar"></div>' +
  551
+				'<h2 id="qunit-userAgent"></h2>' +
  552
+				'<ol id="qunit-tests"></ol>';
  553
+		}
  554
+
  555
+		var tests = id( "qunit-tests" ),
  556
+			banner = id( "qunit-banner" ),
  557
+			result = id( "qunit-testresult" );
  558
+
  559
+		if ( tests ) {
  560
+			tests.innerHTML = "";
  561
+		}
  562
+
  563
+		if ( banner ) {
  564
+			banner.className = "";
  565
+		}
  566
+
  567
+		if ( result ) {
  568
+			result.parentNode.removeChild( result );
  569
+		}
  570
+
  571
+		if ( tests ) {
  572
+			result = document.createElement( "p" );
  573
+			result.id = "qunit-testresult";
  574
+			result.className = "result";
  575
+			tests.parentNode.insertBefore( result, tests );
  576
+			result.innerHTML = 'Running...<br/>&nbsp;';
  577
+		}
  578
+	},
  579
+
  580
+	/**
  581
+	 * Resets the test setup. Useful for tests that modify the DOM.
  582
+	 *
  583
+	 * If jQuery is available, uses jQuery's replaceWith(), otherwise use replaceChild
  584
+	 */
  585
+	reset: function() {
  586
+		var main = id( 'qunit-fixture' );
  587
+		if ( main ) {
  588
+			if ( window.jQuery ) {
  589
+				jQuery( main ).replaceWith( config.fixture.cloneNode(true) );
  590
+			} else {
  591
+				main.parentNode.replaceChild(config.fixture.cloneNode(true), main);
  592
+			}
  593
+		}
  594
+	},
  595
+
  596
+	/**
  597
+	 * Trigger an event on an element.
  598
+	 *
  599
+	 * @example triggerEvent( document.body, "click" );
  600
+	 *
  601
+	 * @param DOMElement elem
  602
+	 * @param String type
  603
+	 */
  604
+	triggerEvent: function( elem, type, event ) {
  605
+		if ( document.createEvent ) {
  606
+			event = document.createEvent("MouseEvents");
  607
+			event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
  608
+				0, 0, 0, 0, 0, false, false, false, false, 0, null);
  609
+			elem.dispatchEvent( event );
  610
+
  611
+		} else if ( elem.fireEvent ) {
  612
+			elem.fireEvent("on"+type);
  613
+		}
  614
+	},
  615
+
  616
+	// Safe object type checking
  617
+	is: function( type, obj ) {
  618
+		return QUnit.objectType( obj ) == type;
  619
+	},
  620
+
  621
+	objectType: function( obj ) {
  622
+		if (typeof obj === "undefined") {
  623
+				return "undefined";
  624
+
  625
+		// consider: typeof null === object
  626
+		}
  627
+		if (obj === null) {
  628
+				return "null";
  629
+		}
  630
+
  631
+		var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || '';
  632
+
  633
+		switch (type) {
  634
+				case 'Number':
  635
+						if (isNaN(obj)) {
  636
+								return "nan";
  637
+						} else {
  638
+								return "number";
  639
+						}
  640
+				case 'String':
  641
+				case 'Boolean':
  642
+				case 'Array':
  643
+				case 'Date':
  644
+				case 'RegExp':
  645
+				case 'Function':
  646
+						return type.toLowerCase();
  647
+		}
  648
+		if (typeof obj === "object") {
  649
+				return "object";
  650
+		}
  651
+		return undefined;
  652
+	},
  653
+
  654
+	push: function(result, actual, expected, message) {
  655
+		if (!config.current) {
  656
+			throw new Error("assertion outside test context, was " + sourceFromStacktrace());
  657
+		}
  658
+		var details = {
  659
+			result: result,
  660
+			message: message,
  661
+			actual: actual,
  662
+			expected: expected
  663
+		};
  664
+
  665
+		message = escapeInnerText(message) || (result ? "okay" : "failed");
  666
+		message = '<span class="test-message">' + message + "</span>";
  667
+		var output = message;
  668
+		if (!result) {
  669
+			expected = escapeInnerText(QUnit.jsDump.parse(expected));
  670
+			actual = escapeInnerText(QUnit.jsDump.parse(actual));
  671
+			output += '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
  672
+			if (actual != expected) {
  673
+				output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
  674
+				output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
  675
+			}
  676
+			var source = sourceFromStacktrace();
  677
+			if (source) {
  678
+				details.source = source;
  679
+				output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr>';
  680
+			}
  681
+			output += "</table>";
  682
+		}
  683
+
  684
+		runLoggingCallbacks( 'log', QUnit, details );
  685
+
  686
+		config.current.assertions.push({
  687
+			result: !!result,
  688
+			message: output
  689
+		});
  690
+	},
  691
+
  692
+	url: function( params ) {
  693
+		params = extend( extend( {}, QUnit.urlParams ), params );
  694
+		var querystring = "?",
  695
+			key;
  696
+		for ( key in params ) {
  697
+			if ( !hasOwn.call( params, key ) ) {
  698
+				continue;
  699
+			}
  700
+			querystring += encodeURIComponent( key ) + "=" +
  701
+				encodeURIComponent( params[ key ] ) + "&";
  702
+		}
  703
+		return window.location.pathname + querystring.slice( 0, -1 );
  704
+	},
  705
+
  706
+	extend: extend,
  707
+	id: id,
  708
+	addEvent: addEvent
  709
+});
  710
+
  711
+//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later
  712
+//Doing this allows us to tell if the following methods have been overwritten on the actual
  713
+//QUnit object, which is a deprecated way of using the callbacks.
  714
+extend(QUnit.constructor.prototype, {
  715
+	// Logging callbacks; all receive a single argument with the listed properties
  716
+	// run test/logs.html for any related changes
  717
+	begin: registerLoggingCallback('begin'),
  718
+	// done: { failed, passed, total, runtime }
  719
+	done: registerLoggingCallback('done'),
  720
+	// log: { result, actual, expected, message }
  721
+	log: registerLoggingCallback('log'),
  722
+	// testStart: { name }
  723
+	testStart: registerLoggingCallback('testStart'),
  724
+	// testDone: { name, failed, passed, total }
  725
+	testDone: registerLoggingCallback('testDone'),
  726
+	// moduleStart: { name }
  727
+	moduleStart: registerLoggingCallback('moduleStart'),
  728
+	// moduleDone: { name, failed, passed, total }
  729
+	moduleDone: registerLoggingCallback('moduleDone')
  730
+});
  731
+
  732
+if ( typeof document === "undefined" || document.readyState === "complete" ) {
  733
+	config.autorun = true;
  734
+}
  735
+
  736
+QUnit.load = function() {
  737
+	runLoggingCallbacks( 'begin', QUnit, {} );
  738
+
  739
+	// Initialize the config, saving the execution queue
  740
+	var oldconfig = extend({}, config);
  741
+	QUnit.init();
  742
+	extend(config, oldconfig);
  743
+
  744
+	config.blocking = false;
  745
+
  746
+	var urlConfigHtml = '', len = config.urlConfig.length;
  747
+	for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
  748
+		config[val] = QUnit.urlParams[val];
  749
+		urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
  750
+	}
  751
+
  752
+	var userAgent = id("qunit-userAgent");
  753
+	if ( userAgent ) {
  754
+		userAgent.innerHTML = navigator.userAgent;
  755
+	}
  756
+	var banner = id("qunit-header");
  757
+	if ( banner ) {
  758
+		banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' + urlConfigHtml;
  759
+		addEvent( banner, "change", function( event ) {
  760
+			var params = {};
  761
+			params[ event.target.name ] = event.target.checked ? true : undefined;
  762
+			window.location = QUnit.url( params );
  763
+		});
  764
+	}
  765
+
  766
+	var toolbar = id("qunit-testrunner-toolbar");
  767
+	if ( toolbar ) {
  768
+		var filter = document.createElement("input");
  769
+		filter.type = "checkbox";
  770
+		filter.id = "qunit-filter-pass";
  771
+		addEvent( filter, "click", function() {
  772
+			var ol = document.getElementById("qunit-tests");
  773
+			if ( filter.checked ) {
  774
+				ol.className = ol.className + " hidepass";
  775
+			} else {
  776
+				var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
  777
+				ol.className = tmp.replace(/ hidepass /, " ");
  778
+			}
  779
+			if ( defined.sessionStorage ) {
  780
+				if (filter.checked) {
  781
+					sessionStorage.setItem("qunit-filter-passed-tests", "true");
  782
+				} else {
  783
+					sessionStorage.removeItem("qunit-filter-passed-tests");
  784
+				}
  785
+			}
  786
+		});
  787
+		if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
  788
+			filter.checked = true;
  789
+			var ol = document.getElementById("qunit-tests");
  790
+			ol.className = ol.className + " hidepass";
  791
+		}
  792
+		toolbar.appendChild( filter );
  793
+
  794
+		var label = document.createElement("label");
  795
+		label.setAttribute("for", "qunit-filter-pass");
  796
+		label.innerHTML = "Hide passed tests";
  797
+		toolbar.appendChild( label );
  798
+	}
  799
+
  800
+	var main = id('qunit-fixture');
  801
+	if ( main ) {
  802
+		config.fixture = main.cloneNode(true);
  803
+	}
  804
+
  805
+	if (config.autostart) {
  806
+		QUnit.start();
  807
+	}
  808
+};
  809
+
  810
+addEvent(window, "load", QUnit.load);
  811
+
  812
+// addEvent(window, "error") gives us a useless event object
  813
+window.onerror = function( message, file, line ) {
  814
+	if ( QUnit.config.current ) {
  815
+		ok( false, message + ", " + file + ":" + line );
  816
+	} else {
  817
+		test( "global failure", function() {
  818
+			ok( false, message + ", " + file + ":" + line );
  819
+		});
  820
+	}
  821
+};
  822
+
  823
+function done() {
  824
+	config.autorun = true;
  825
+
  826
+	// Log the last module results
  827
+	if ( config.currentModule ) {
  828
+		runLoggingCallbacks( 'moduleDone', QUnit, {
  829
+			name: config.currentModule,
  830
+			failed: config.moduleStats.bad,
  831
+			passed: config.moduleStats.all - config.moduleStats.bad,
  832
+			total: config.moduleStats.all
  833
+		} );
  834
+	}
  835
+
  836
+	var banner = id("qunit-banner"),
  837
+		tests = id("qunit-tests"),
  838
+		runtime = +new Date - config.started,
  839
+		passed = config.stats.all - config.stats.bad,
  840
+		html = [
  841
+			'Tests completed in ',
  842
+			runtime,
  843
+			' milliseconds.<br/>',
  844
+			'<span class="passed">',
  845
+			passed,
  846
+			'</span> tests of <span class="total">',
  847
+			config.stats.all,
  848
+			'</span> passed, <span class="failed">',
  849
+			config.stats.bad,
  850
+			'</span> failed.'
  851
+		].join('');
  852
+
  853
+	if ( banner ) {
  854
+		banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
  855
+	}
  856
+
  857
+	if ( tests ) {
  858
+		id( "qunit-testresult" ).innerHTML = html;
  859
+	}
  860
+
  861
+	if ( config.altertitle && typeof document !== "undefined" && document.title ) {
  862
+		// show ✖ for good, ✔ for bad suite result in title
  863
+		// use escape sequences in case file gets loaded with non-utf-8-charset
  864
+		document.title = [
  865
+			(config.stats.bad ? "\u2716" : "\u2714"),
  866
+			document.title.replace(/^[\u2714\u2716] /i, "")
  867
+		].join(" ");
  868
+	}
  869
+
  870
+	// clear own sessionStorage items if all tests passed
  871
+	if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
  872
+		for (var key in sessionStorage) {
  873
+			if (sessionStorage.hasOwnProperty(key) && key.indexOf("qunit-") === 0 ) {
  874
+				sessionStorage.removeItem(key);
  875
+			}
  876
+		}
  877
+	}
  878
+	
  879
+	runLoggingCallbacks( 'done', QUnit, {
  880
+		failed: config.stats.bad,
  881
+		passed: passed,
  882
+		total: config.stats.all,
  883
+		runtime: runtime
  884
+	} );
  885
+}
  886
+
  887
+function validTest( name ) {
  888
+	var filter = config.filter,
  889
+		run = false;
  890
+
  891
+	if ( !filter ) {
  892
+		return true;
  893
+	}
  894
+
  895
+	var not = filter.charAt( 0 ) === "!";
  896
+	if ( not ) {
  897
+		filter = filter.slice( 1 );
  898
+	}
  899
+
  900
+	if ( name.indexOf( filter ) !== -1 ) {
  901
+		return !not;
  902
+	}
  903
+
  904
+	if ( not ) {
  905
+		run = true;
  906
+	}
  907
+
  908
+	return run;
  909
+}
  910
+
  911
+// so far supports only Firefox, Chrome and Opera (buggy)
  912
+// could be extended in the future to use something like https://github.com/csnover/TraceKit
  913
+function sourceFromStacktrace(offset) {
  914
+	offset = offset || 3;
  915
+	try {
  916
+		throw new Error();
  917
+	} catch ( e ) {
  918
+		if (e.stacktrace) {
  919
+			// Opera
  920
+			return e.stacktrace.split("\n")[offset + 3];
  921
+		} else if (e.stack) {
  922
+			// Firefox, Chrome
  923
+			var stack = e.stack.split("\n");
  924
+			if (/^error$/i.test(stack[0])) {
  925
+				stack.shift();
  926
+			}
  927
+			return stack[offset];
  928
+		} else if (e.sourceURL) {
  929
+			// Safari, PhantomJS
  930
+			// TODO sourceURL points at the 'throw new Error' line above, useless
  931
+			//return e.sourceURL + ":" + e.line;
  932
+		}
  933
+	}
  934
+}
  935
+
  936
+function escapeInnerText(s) {
  937
+	if (!s) {
  938
+		return "";
  939
+	}
  940
+	s = s + "";
  941
+	return s.replace(/[\&<>]/g, function(s) {
  942
+		switch(s) {
  943
+			case "&": return "&amp;";
  944
+			case "<": return "&lt;";
  945
+			case ">": return "&gt;";
  946
+			default: return s;
  947
+		}
  948
+	});
  949
+}
  950
+
  951
+function synchronize( callback, last ) {
  952
+	config.queue.push( callback );
  953
+
  954
+	if ( config.autorun && !config.blocking ) {
  955
+		process(last);
  956
+	}
  957
+}
  958
+
  959
+function process( last ) {
  960
+	var start = new Date().getTime();
  961
+	config.depth = config.depth ? config.depth + 1 : 1;
  962
+
  963
+	while ( config.queue.length && !config.blocking ) {
  964
+		if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
  965
+			config.queue.shift()();
  966
+		} else {
  967
+			window.setTimeout( function(){
  968
+				process( last );
  969
+			}, 13 );
  970
+			break;
  971
+		}
  972
+	}
  973
+	config.depth--;
  974
+	if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
  975
+		done();
  976
+	}
  977
+}
  978
+
  979
+function saveGlobal() {
  980
+	config.pollution = [];
  981
+
  982
+	if ( config.noglobals ) {
  983
+		for ( var key in window ) {
  984
+			if ( !hasOwn.call( window, key ) ) {
  985
+				continue;
  986
+			}
  987
+			config.pollution.push( key );
  988
+		}
  989
+	}
  990
+}
  991
+
  992
+function checkPollution( name ) {
  993
+	var old = config.pollution;
  994
+	saveGlobal();
  995
+
  996
+	var newGlobals = diff( config.pollution, old );
  997
+	if ( newGlobals.length > 0 ) {
  998
+		ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
  999
+	}
  1000
+
  1001
+	var deletedGlobals = diff( old, config.pollution );
  1002
+	if ( deletedGlobals.length > 0 ) {
  1003
+		ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
  1004
+	}
  1005
+}
  1006
+
  1007
+// returns a new Array with the elements that are in a but not in b
  1008
+function diff( a, b ) {
  1009
+	var result = a.slice();
  1010
+	for ( var i = 0; i < result.length; i++ ) {
  1011
+		for ( var j = 0; j < b.length; j++ ) {
  1012
+			if ( result[i] === b[j] ) {
  1013
+				result.splice(i, 1);
  1014
+				i--;
  1015
+				break;
  1016
+			}
  1017
+		}
  1018
+	}
  1019
+	return result;
  1020
+}
  1021
+
  1022
+function fail(message, exception, callback) {
  1023
+	if ( typeof console !== "undefined" && console.error && console.warn ) {
  1024
+		console.error(message);
  1025
+		console.error(exception);
  1026
+		console.error(exception.stack);
  1027
+		console.warn(callback.toString());
  1028
+
  1029
+	} else if ( window.opera && opera.postError ) {
  1030
+		opera.postError(message, exception, callback.toString);
  1031
+	}
  1032
+}
  1033
+
  1034
+function extend(a, b) {
  1035
+	for ( var prop in b ) {
  1036
+		if ( b[prop] === undefined ) {
  1037
+			delete a[prop];
  1038
+
  1039
+		// Avoid "Member not found" error in IE8 caused by setting window.constructor
  1040
+		} else if ( prop !== "constructor" || a !== window ) {
  1041
+			a[prop] = b[prop];
  1042
+		}
  1043
+	}
  1044
+
  1045
+	return a;
  1046
+}
  1047
+
  1048
+function addEvent(elem, type, fn) {
  1049
+	if ( elem.addEventListener ) {
  1050
+		elem.addEventListener( type, fn, false );
  1051
+	} else if ( elem.attachEvent ) {
  1052
+		elem.attachEvent( "on" + type, fn );
  1053
+	} else {
  1054
+		fn();
  1055
+	}
  1056
+}
  1057
+
  1058
+function id(name) {
  1059
+	return !!(typeof document !== "undefined" && document && document.getElementById) &&
  1060
+		document.getElementById( name );
  1061
+}
  1062
+
  1063
+function registerLoggingCallback(key){
  1064
+	return function(callback){
  1065
+		config[key].push( callback );
  1066
+	};
  1067
+}
  1068
+
  1069
+// Supports deprecated method of completely overwriting logging callbacks
  1070
+function runLoggingCallbacks(key, scope, args) {
  1071
+	//debugger;
  1072
+	var callbacks;
  1073
+	if ( QUnit.hasOwnProperty(key) ) {
  1074
+		QUnit[key].call(scope, args);
  1075
+	} else {
  1076
+		callbacks = config[key];
  1077
+		for( var i = 0; i < callbacks.length; i++ ) {
  1078
+			callbacks[i].call( scope, args );
  1079
+		}
  1080
+	}
  1081
+}
  1082
+
  1083
+// Test for equality any JavaScript type.
  1084
+// Author: Philippe Rathé <prathe@gmail.com>
  1085
+QUnit.equiv = function () {
  1086
+
  1087
+	var innerEquiv; // the real equiv function
  1088
+	var callers = []; // stack to decide between skip/abort functions
  1089
+	var parents = []; // stack to avoiding loops from circular referencing
  1090
+
  1091
+	// Call the o related callback with the given arguments.
  1092
+	function bindCallbacks(o, callbacks, args) {
  1093
+		var prop = QUnit.objectType(o);
  1094
+		if (prop) {
  1095
+			if (QUnit.objectType(callbacks[prop]) === "function") {
  1096
+				return callbacks[prop].apply(callbacks, args);
  1097
+			} else {
  1098
+				return callbacks[prop]; // or undefined
  1099
+			}
  1100
+		}
  1101
+	}
  1102
+
  1103
+	var getProto = Object.getPrototypeOf || function (obj) {
  1104
+		return obj.__proto__;
  1105
+	};
  1106
+
  1107
+	var callbacks = function () {
  1108
+
  1109
+		// for string, boolean, number and null
  1110
+		function useStrictEquality(b, a) {
  1111
+			if (b instanceof a.constructor || a instanceof b.constructor) {
  1112
+				// to catch short annotaion VS 'new' annotation of a
  1113
+				// declaration
  1114
+				// e.g. var i = 1;
  1115
+				// var j = new Number(1);
  1116
+				return a == b;
  1117
+			} else {
  1118
+				return a === b;
  1119
+			}
  1120
+		}
  1121
+
  1122
+		return {
  1123
+			"string" : useStrictEquality,
  1124
+			"boolean" : useStrictEquality,
  1125
+			"number" : useStrictEquality,
  1126
+			"null" : useStrictEquality,
  1127
+			"undefined" : useStrictEquality,
  1128
+
  1129
+			"nan" : function(b) {
  1130
+				return isNaN(b);
  1131
+			},
  1132
+
  1133
+			"date" : function(b, a) {
  1134
+				return QUnit.objectType(b) === "date"
  1135
+						&& a.valueOf() === b.valueOf();
  1136
+			},
  1137
+
  1138
+			"regexp" : function(b, a) {
  1139
+				return QUnit.objectType(b) === "regexp"
  1140
+						&& a.source === b.source && // the regex itself
  1141
+						a.global === b.global && // and its modifers
  1142
+													// (gmi) ...
  1143
+						a.ignoreCase === b.ignoreCase
  1144
+						&& a.multiline === b.multiline;
  1145
+			},
  1146
+
  1147
+			// - skip when the property is a method of an instance (OOP)
  1148
+			// - abort otherwise,
  1149
+			// initial === would have catch identical references anyway
  1150
+			"function" : function() {
  1151
+				var caller = callers[callers.length - 1];
  1152
+				return caller !== Object && typeof caller !== "undefined";
  1153
+			},
  1154
+
  1155
+			"array" : function(b, a) {
  1156
+				var i, j, loop;
  1157
+				var len;
  1158
+
  1159
+				// b could be an object literal here
  1160
+				if (!(QUnit.objectType(b) === "array")) {
  1161
+					return false;
  1162
+				}
  1163
+
  1164
+				len = a.length;
  1165
+				if (len !== b.length) { // safe and faster
  1166
+					return false;
  1167
+				}
  1168
+
  1169
+				// track reference to avoid circular references
  1170
+				parents.push(a);
  1171
+				for (i = 0; i < len; i++) {
  1172
+					loop = false;
  1173
+					for (j = 0; j < parents.length; j++) {
  1174
+						if (parents[j] === a[i]) {
  1175
+							loop = true;// dont rewalk array
  1176
+						}
  1177
+					}
  1178
+					if (!loop && !innerEquiv(a[i], b[i])) {
  1179
+						parents.pop();
  1180
+						return false;
  1181
+					}
  1182
+				}
  1183
+				parents.pop();
  1184
+				return true;
  1185
+			},
  1186
+
  1187
+			"object" : function(b, a) {
  1188
+				var i, j, loop;
  1189
+				var eq = true; // unless we can proove it
  1190
+				var aProperties = [], bProperties = []; // collection of
  1191
+														// strings
  1192
+
  1193
+				// comparing constructors is more strict than using
  1194
+				// instanceof
  1195
+				if (a.constructor !== b.constructor) {
  1196
+					// Allow objects with no prototype to be equivalent to
  1197
+					// objects with Object as their constructor.
  1198
+					if (!((getProto(a) === null && getProto(b) === Object.prototype) ||
  1199
+						  (getProto(b) === null && getProto(a) === Object.prototype)))
  1200
+					{
  1201
+						return false;
  1202
+					}
  1203
+				}
  1204
+
  1205
+				// stack constructor before traversing properties
  1206
+				callers.push(a.constructor);
  1207
+				// track reference to avoid circular references
  1208
+				parents.push(a);
  1209
+
  1210
+				for (i in a) { // be strict: don't ensures hasOwnProperty
  1211
+								// and go deep
  1212
+					loop = false;
  1213
+					for (j = 0; j < parents.length; j++) {
  1214
+						if (parents[j] === a[i])
  1215
+							loop = true; // don't go down the same path
  1216
+											// twice
  1217
+					}
  1218
+					aProperties.push(i); // collect a's properties
  1219
+
  1220
+					if (!loop && !innerEquiv(a[i], b[i])) {
  1221
+						eq = false;
  1222
+						break;
  1223
+					}
  1224
+				}
  1225
+
  1226
+				callers.pop(); // unstack, we are done
  1227
+				parents.pop();
  1228
+
  1229
+				for (i in b) {
  1230
+					bProperties.push(i); // collect b's properties
  1231
+				}
  1232
+
  1233
+				// Ensures identical properties name
  1234
+				return eq
  1235
+						&& innerEquiv(aProperties.sort(), bProperties
  1236
+								.sort());
  1237
+			}
  1238
+		};
  1239
+	}();
  1240
+
  1241
+	innerEquiv = function() { // can take multiple arguments
  1242
+		var args = Array.prototype.slice.apply(arguments);
  1243
+		if (args.length < 2) {
  1244
+			return true; // end transition
  1245
+		}
  1246
+
  1247
+		return (function(a, b) {
  1248
+			if (a === b) {
  1249
+				return true; // catch the most you can
  1250
+			} else if (a === null || b === null || typeof a === "undefined"
  1251
+					|| typeof b === "undefined"
  1252
+					|| QUnit.objectType(a) !== QUnit.objectType(b)) {
  1253
+				return false; // don't lose time with error prone cases
  1254
+			} else {
  1255
+				return bindCallbacks(a, callbacks, [ b, a ]);
  1256
+			}
  1257
+
  1258
+			// apply transition with (1..n) arguments
  1259
+		})(args[0], args[1])
  1260
+				&& arguments.callee.apply(this, args.splice(1,
  1261
+						args.length - 1));
  1262
+	};
  1263
+
  1264
+	return innerEquiv;
  1265
+
  1266
+}();
  1267
+
  1268
+/**
  1269
+ * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
  1270
+ * http://flesler.blogspot.com Licensed under BSD
  1271
+ * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
  1272
+ *
  1273
+ * @projectDescription Advanced and extensible data dumping for Javascript.
  1274
+ * @version 1.0.0
  1275
+ * @author Ariel Flesler
  1276
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
  1277
+ */
  1278
+QUnit.jsDump = (function() {
  1279
+	function quote( str ) {
  1280
+		return '"' + str.toString().replace(/"/g, '\\"') + '"';
  1281
+	};
  1282
+	function literal( o ) {
  1283
+		return o + '';
  1284
+	};
  1285
+	function join( pre, arr, post ) {
  1286
+		var s = jsDump.separator(),
  1287
+			base = jsDump.indent(),
  1288
+			inner = jsDump.indent(1);
  1289
+		if ( arr.join )
  1290
+			arr = arr.join( ',' + s + inner );
  1291
+		if ( !arr )
  1292
+			return pre + post;
  1293
+		return [ pre, inner + arr, base + post ].join(s);
  1294
+	};
  1295
+	function array( arr, stack ) {
  1296
+		var i = arr.length, ret = Array(i);
  1297
+		this.up();
  1298
+		while ( i-- )
  1299
+			ret[i] = this.parse( arr[i] , undefined , stack);
  1300
+		this.down();
  1301
+		return join( '[', ret, ']' );
  1302
+	};
  1303
+
  1304
+	var reName = /^function (\w+)/;
  1305
+
  1306
+	var jsDump = {
  1307
+		parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance