Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

v1.2.0. Now supports visual search search strings. Added new demos. C…

…leaned up. See change log.

- v1.2.0 June 16, 2012
	- You can now pass the standard `models`, and `options` arguments to
`QueryCollection::createChildCollection` and
`QueryCollection::createLiveChildCollection`
	- If `options.collection` is specified when creating a child
collection, it will be used as the child collectiont type
	- Restructured directories and files
	- Cleaned up demos and added two new demos:
[search](http://bevry.github.com/query-engine/demo/search.html) and
[visual
search](http://bevry.github.com/query-engine/demo/visual-search.html)
	- Updated search string syntax to be compliant with [Visual
Search's](http://documentcloud.github.com/visualsearch/) search string
syntax
		- Adds support for quotes when using pills, e.g. `user:"Benjamin
Lupton"`
		- Adds support for using pills of the same name multiple times, e.g.
`tag:node tag:query`
			- Whether this Ors or ANDs is customisable via the pill's
`logicalOperator` which can be `AND` or `OR` (defaults to `OR`)
	- Moved tests to [Joe](https://github.com/bevry/joe)
	- Added browser tests
  • Loading branch information...
commit bbd64052b90a7dfb578b61c70bf5dbe1f1801f6c 1 parent e06e8d8
@balupton balupton authored
Showing with 4,451 additions and 42 deletions.
  1. +14 −1 .gitignore
  2. +5 −2 .npmignore
  3. +3 −1 .travis.yml
  4. +12 −0 History.md
  5. +1 −1  README.md
  6. +7 −7 demo/code.html
  7. +7 −7 demo/search.html
  8. 0  demo/{lib → vendor}/ace/ace-uncompressed.js
  9. 0  demo/{lib → vendor}/ace/ace.js
  10. 0  demo/{lib → vendor}/ace/cockpit-uncompressed.js
  11. 0  demo/{lib → vendor}/ace/cockpit.js
  12. 0  demo/{lib → vendor}/ace/keybinding-emacs.js
  13. 0  demo/{lib → vendor}/ace/keybinding-vim.js
  14. 0  demo/{lib → vendor}/ace/mode-c_cpp.js
  15. 0  demo/{lib → vendor}/ace/mode-clojure.js
  16. 0  demo/{lib → vendor}/ace/mode-coffee.js
  17. 0  demo/{lib → vendor}/ace/mode-csharp.js
  18. 0  demo/{lib → vendor}/ace/mode-css.js
  19. 0  demo/{lib → vendor}/ace/mode-groovy.js
  20. 0  demo/{lib → vendor}/ace/mode-html.js
  21. 0  demo/{lib → vendor}/ace/mode-java.js
  22. 0  demo/{lib → vendor}/ace/mode-javascript.js
  23. 0  demo/{lib → vendor}/ace/mode-json.js
  24. 0  demo/{lib → vendor}/ace/mode-ocaml.js
  25. 0  demo/{lib → vendor}/ace/mode-perl.js
  26. 0  demo/{lib → vendor}/ace/mode-php.js
  27. 0  demo/{lib → vendor}/ace/mode-python.js
  28. 0  demo/{lib → vendor}/ace/mode-ruby.js
  29. 0  demo/{lib → vendor}/ace/mode-scad.js
  30. 0  demo/{lib → vendor}/ace/mode-scala.js
  31. 0  demo/{lib → vendor}/ace/mode-scss.js
  32. 0  demo/{lib → vendor}/ace/mode-svg.js
  33. 0  demo/{lib → vendor}/ace/mode-textile.js
  34. 0  demo/{lib → vendor}/ace/mode-xml.js
  35. 0  demo/{lib → vendor}/ace/theme-clouds.js
  36. 0  demo/{lib → vendor}/ace/theme-clouds_midnight.js
  37. 0  demo/{lib → vendor}/ace/theme-cobalt.js
  38. 0  demo/{lib → vendor}/ace/theme-crimson_editor.js
  39. 0  demo/{lib → vendor}/ace/theme-dawn.js
  40. 0  demo/{lib → vendor}/ace/theme-eclipse.js
  41. 0  demo/{lib → vendor}/ace/theme-idle_fingers.js
  42. 0  demo/{lib → vendor}/ace/theme-kr_theme.js
  43. 0  demo/{lib → vendor}/ace/theme-merbivore.js
  44. 0  demo/{lib → vendor}/ace/theme-merbivore_soft.js
  45. 0  demo/{lib → vendor}/ace/theme-mono_industrial.js
  46. 0  demo/{lib → vendor}/ace/theme-monokai.js
  47. 0  demo/{lib → vendor}/ace/theme-pastel_on_dark.js
  48. 0  demo/{lib → vendor}/ace/theme-solarized_dark.js
  49. 0  demo/{lib → vendor}/ace/theme-solarized_light.js
  50. 0  demo/{lib → vendor}/ace/theme-textmate.js
  51. 0  demo/{lib → vendor}/ace/theme-twilight.js
  52. 0  demo/{lib → vendor}/ace/theme-vibrant_ink.js
  53. 0  demo/{lib → vendor}/ace/worker-coffee.js
  54. 0  demo/{lib → vendor}/ace/worker-css.js
  55. 0  demo/{lib → vendor}/ace/worker-javascript.js
  56. 0  demo/{lib → vendor}/backbone.js
  57. 0  demo/{lib → vendor}/coffeescript.js
  58. 0  demo/{lib → vendor}/jquery.js
  59. 0  demo/{lib → vendor}/js2coffee.js
  60. 0  demo/{lib → vendor}/underscore.js
  61. 0  demo/{lib → vendor}/visualsearch/LICENSE
  62. 0  demo/{lib → vendor}/visualsearch/build/visualsearch-datauri.css
  63. 0  demo/{lib → vendor}/visualsearch/build/visualsearch.css
  64. 0  demo/{lib → vendor}/visualsearch/build/visualsearch.js
  65. 0  demo/{lib → vendor}/visualsearch/images/embed/icons/cancel_search.png
  66. 0  demo/{lib → vendor}/visualsearch/images/embed/icons/search_glyph.png
  67. 0  demo/{lib → vendor}/visualsearch/vendor/jquery.ui.autocomplete.js
  68. 0  demo/{lib → vendor}/visualsearch/vendor/jquery.ui.core.js
  69. 0  demo/{lib → vendor}/visualsearch/vendor/jquery.ui.position.js
  70. 0  demo/{lib → vendor}/visualsearch/vendor/jquery.ui.widget.js
  71. +14 −14 demo/visual-search.html
  72. +1 −1  out/test/live.test.js
  73. +1 −1  out/test/misc.test.js
  74. +1 −1  out/test/queries.test.js
  75. +1 −1  out/test/sort.test.js
  76. +1 −1  package.json
  77. +1 −1  src/test/live.test.coffee
  78. +1 −1  src/test/misc.test.coffee
  79. +1 −1  src/test/queries.test.coffee
  80. +1 −1  src/test/sort.test.coffee
  81. +27 −0 test-web/index.html
  82. +456 −0 test-web/vendor/bal-util.flow.js
  83. +3,403 −0 test-web/vendor/chai.js
  84. +247 −0 test-web/vendor/joe/joe.js
  85. +167 −0 test-web/vendor/joe/reporters/console.js
  86. +79 −0 test-web/vendor/joe/reporters/list.js
View
15 .gitignore
@@ -1,2 +1,15 @@
-*node_modules*
+lib-cov
+*.seed
+*.log
+*.csv
+*.dat
+*.out
+*.pid
+*.gz
+
+pids
+logs
+results
+
+node_modules
npm-debug.log
View
7 .npmignore
@@ -3,6 +3,9 @@
.travis*
*.md
Makefile
+
+src/
+out/demo/
+out/test/
demo/
-test/
-lib/*.coffee
+test-web/
View
4 .travis.yml
@@ -1,10 +1,12 @@
language: node_js
+before_script: "make compile"
node_js:
- 0.4
- 0.6
+ - 0.7
notifications:
irc:
- "irc.freenode.org#bevry"
email:
recipients:
- - queryengine@bevry.me
+ - query-engine@bevry.me
View
12 History.md
@@ -1,5 +1,17 @@
## History
+- v1.2.0 June 16, 2012
+ - You can now pass the standard `models`, and `options` arguments to `QueryCollection::createChildCollection` and `QueryCollection::createLiveChildCollection`
+ - If `options.collection` is specified when creating a child collection, it will be used as the child collectiont type
+ - Restructured directories and files
+ - Cleaned up demos and added two new demos: [search](http://bevry.github.com/query-engine/demo/search.html) and [visual search](http://bevry.github.com/query-engine/demo/visual-search.html)
+ - Updated search string syntax to be compliant with [Visual Search's](http://documentcloud.github.com/visualsearch/) search string syntax
+ - Adds support for quotes when using pills, e.g. `user:"Benjamin Lupton"`
+ - Adds support for using pills of the same name multiple times, e.g. `tag:node tag:query`
+ - Whether this ORs or ANDs is customisable via the pill's `logicalOperator` which can be `AND` or `OR` (defaults to `OR`)
+ - Moved tests to [Joe](https://github.com/bevry/joe)
+ - Added browser tests
+
- v1.1.14 June 5, 2012
- Fixed using arrays in `queryEngine.generateComparator`
View
2  README.md
@@ -5,7 +5,7 @@ QueryEngine provides extensive Querying, Filtering, and Searching abilities for
## Features
-* includes a [live interactive demo](http://bevry.github.com/query-engine/demo/) with several examples, [wiki documentation](https://github.com/bevry/query-engine/wiki/Using) and [source-code documentation](https://github.com/bevry/query-engine/blob/master/lib/query-engine.coffee#files)
+* includes a [live interactive demos](http://bevry.github.com/query-engine/demo/) with several examples, [wiki documentation](https://github.com/bevry/query-engine/wiki/Using) and [source-code documentation](https://github.com/bevry/query-engine/blob/master/lib/query-engine.coffee#files)
* runs on [node.js](http://nodejs.org/) and in the browser
* supports [NoSQL](http://www.mongodb.org/display/DOCS/Advanced+Queries) queries (like [MongoDB](http://www.mongodb.org/))
* supports filters (applying a filter function to a collection)
View
14 demo/code.html
@@ -57,13 +57,13 @@
<!-- Scripts -->
- <script src="lib/coffeescript.js"></script>
- <script src="lib/jquery.js"></script>
- <script src="lib/underscore.js"></script>
- <script src="lib/backbone.js"></script>
- <script src="lib/js2coffee.js"></script>
- <script src="lib/ace/ace.js"></script>
- <script src="lib/ace/mode-coffee.js"></script>
+ <script src="vendor/coffeescript.js"></script>
+ <script src="vendor/jquery.js"></script>
+ <script src="vendor/underscore.js"></script>
+ <script src="vendor/backbone.js"></script>
+ <script src="vendor/js2coffee.js"></script>
+ <script src="vendor/ace/ace.js"></script>
+ <script src="vendor/ace/mode-coffee.js"></script>
<script src="../out/lib/query-engine.js"></script>
<script src="../out/demo/code.js"></script>
View
14 demo/search.html
@@ -64,13 +64,13 @@
</div>
<!-- Scripts -->
- <script src="lib/coffeescript.js"></script>
- <script src="lib/jquery.js"></script>
- <script src="lib/underscore.js"></script>
- <script src="lib/backbone.js"></script>
- <script src="lib/js2coffee.js"></script>
- <script src="lib/ace/ace.js"></script>
- <script src="lib/ace/mode-coffee.js"></script>
+ <script src="vendor/coffeescript.js"></script>
+ <script src="vendor/jquery.js"></script>
+ <script src="vendor/underscore.js"></script>
+ <script src="vendor/backbone.js"></script>
+ <script src="vendor/js2coffee.js"></script>
+ <script src="vendor/ace/ace.js"></script>
+ <script src="vendor/ace/mode-coffee.js"></script>
<script src="../out/lib/query-engine.js"></script>
<script src="../out/demo/search.js"></script>
View
0  demo/lib/ace/ace-uncompressed.js → demo/vendor/ace/ace-uncompressed.js
File renamed without changes
View
0  demo/lib/ace/ace.js → demo/vendor/ace/ace.js
File renamed without changes
View
0  demo/lib/ace/cockpit-uncompressed.js → demo/vendor/ace/cockpit-uncompressed.js
File renamed without changes
View
0  demo/lib/ace/cockpit.js → demo/vendor/ace/cockpit.js
File renamed without changes
View
0  demo/lib/ace/keybinding-emacs.js → demo/vendor/ace/keybinding-emacs.js
File renamed without changes
View
0  demo/lib/ace/keybinding-vim.js → demo/vendor/ace/keybinding-vim.js
File renamed without changes
View
0  demo/lib/ace/mode-c_cpp.js → demo/vendor/ace/mode-c_cpp.js
File renamed without changes
View
0  demo/lib/ace/mode-clojure.js → demo/vendor/ace/mode-clojure.js
File renamed without changes
View
0  demo/lib/ace/mode-coffee.js → demo/vendor/ace/mode-coffee.js
File renamed without changes
View
0  demo/lib/ace/mode-csharp.js → demo/vendor/ace/mode-csharp.js
File renamed without changes
View
0  demo/lib/ace/mode-css.js → demo/vendor/ace/mode-css.js
File renamed without changes
View
0  demo/lib/ace/mode-groovy.js → demo/vendor/ace/mode-groovy.js
File renamed without changes
View
0  demo/lib/ace/mode-html.js → demo/vendor/ace/mode-html.js
File renamed without changes
View
0  demo/lib/ace/mode-java.js → demo/vendor/ace/mode-java.js
File renamed without changes
View
0  demo/lib/ace/mode-javascript.js → demo/vendor/ace/mode-javascript.js
File renamed without changes
View
0  demo/lib/ace/mode-json.js → demo/vendor/ace/mode-json.js
File renamed without changes
View
0  demo/lib/ace/mode-ocaml.js → demo/vendor/ace/mode-ocaml.js
File renamed without changes
View
0  demo/lib/ace/mode-perl.js → demo/vendor/ace/mode-perl.js
File renamed without changes
View
0  demo/lib/ace/mode-php.js → demo/vendor/ace/mode-php.js
File renamed without changes
View
0  demo/lib/ace/mode-python.js → demo/vendor/ace/mode-python.js
File renamed without changes
View
0  demo/lib/ace/mode-ruby.js → demo/vendor/ace/mode-ruby.js
File renamed without changes
View
0  demo/lib/ace/mode-scad.js → demo/vendor/ace/mode-scad.js
File renamed without changes
View
0  demo/lib/ace/mode-scala.js → demo/vendor/ace/mode-scala.js
File renamed without changes
View
0  demo/lib/ace/mode-scss.js → demo/vendor/ace/mode-scss.js
File renamed without changes
View
0  demo/lib/ace/mode-svg.js → demo/vendor/ace/mode-svg.js
File renamed without changes
View
0  demo/lib/ace/mode-textile.js → demo/vendor/ace/mode-textile.js
File renamed without changes
View
0  demo/lib/ace/mode-xml.js → demo/vendor/ace/mode-xml.js
File renamed without changes
View
0  demo/lib/ace/theme-clouds.js → demo/vendor/ace/theme-clouds.js
File renamed without changes
View
0  demo/lib/ace/theme-clouds_midnight.js → demo/vendor/ace/theme-clouds_midnight.js
File renamed without changes
View
0  demo/lib/ace/theme-cobalt.js → demo/vendor/ace/theme-cobalt.js
File renamed without changes
View
0  demo/lib/ace/theme-crimson_editor.js → demo/vendor/ace/theme-crimson_editor.js
File renamed without changes
View
0  demo/lib/ace/theme-dawn.js → demo/vendor/ace/theme-dawn.js
File renamed without changes
View
0  demo/lib/ace/theme-eclipse.js → demo/vendor/ace/theme-eclipse.js
File renamed without changes
View
0  demo/lib/ace/theme-idle_fingers.js → demo/vendor/ace/theme-idle_fingers.js
File renamed without changes
View
0  demo/lib/ace/theme-kr_theme.js → demo/vendor/ace/theme-kr_theme.js
File renamed without changes
View
0  demo/lib/ace/theme-merbivore.js → demo/vendor/ace/theme-merbivore.js
File renamed without changes
View
0  demo/lib/ace/theme-merbivore_soft.js → demo/vendor/ace/theme-merbivore_soft.js
File renamed without changes
View
0  demo/lib/ace/theme-mono_industrial.js → demo/vendor/ace/theme-mono_industrial.js
File renamed without changes
View
0  demo/lib/ace/theme-monokai.js → demo/vendor/ace/theme-monokai.js
File renamed without changes
View
0  demo/lib/ace/theme-pastel_on_dark.js → demo/vendor/ace/theme-pastel_on_dark.js
File renamed without changes
View
0  demo/lib/ace/theme-solarized_dark.js → demo/vendor/ace/theme-solarized_dark.js
File renamed without changes
View
0  demo/lib/ace/theme-solarized_light.js → demo/vendor/ace/theme-solarized_light.js
File renamed without changes
View
0  demo/lib/ace/theme-textmate.js → demo/vendor/ace/theme-textmate.js
File renamed without changes
View
0  demo/lib/ace/theme-twilight.js → demo/vendor/ace/theme-twilight.js
File renamed without changes
View
0  demo/lib/ace/theme-vibrant_ink.js → demo/vendor/ace/theme-vibrant_ink.js
File renamed without changes
View
0  demo/lib/ace/worker-coffee.js → demo/vendor/ace/worker-coffee.js
File renamed without changes
View
0  demo/lib/ace/worker-css.js → demo/vendor/ace/worker-css.js
File renamed without changes
View
0  demo/lib/ace/worker-javascript.js → demo/vendor/ace/worker-javascript.js
File renamed without changes
View
0  demo/lib/backbone.js → demo/vendor/backbone.js
File renamed without changes
View
0  demo/lib/coffeescript.js → demo/vendor/coffeescript.js
File renamed without changes
View
0  demo/lib/jquery.js → demo/vendor/jquery.js
File renamed without changes
View
0  demo/lib/js2coffee.js → demo/vendor/js2coffee.js
File renamed without changes
View
0  demo/lib/underscore.js → demo/vendor/underscore.js
File renamed without changes
View
0  demo/lib/visualsearch/LICENSE → demo/vendor/visualsearch/LICENSE
File renamed without changes
View
0  demo/lib/visualsearch/build/visualsearch-datauri.css → ...endor/visualsearch/build/visualsearch-datauri.css
File renamed without changes
View
0  demo/lib/visualsearch/build/visualsearch.css → demo/vendor/visualsearch/build/visualsearch.css
File renamed without changes
View
0  demo/lib/visualsearch/build/visualsearch.js → demo/vendor/visualsearch/build/visualsearch.js
File renamed without changes
View
0  ...visualsearch/images/embed/icons/cancel_search.png → ...visualsearch/images/embed/icons/cancel_search.png
File renamed without changes
View
0  .../visualsearch/images/embed/icons/search_glyph.png → .../visualsearch/images/embed/icons/search_glyph.png
File renamed without changes
View
0  ...lib/visualsearch/vendor/jquery.ui.autocomplete.js → ...dor/visualsearch/vendor/jquery.ui.autocomplete.js
File renamed without changes
View
0  demo/lib/visualsearch/vendor/jquery.ui.core.js → demo/vendor/visualsearch/vendor/jquery.ui.core.js
File renamed without changes
View
0  demo/lib/visualsearch/vendor/jquery.ui.position.js → .../vendor/visualsearch/vendor/jquery.ui.position.js
File renamed without changes
View
0  demo/lib/visualsearch/vendor/jquery.ui.widget.js → demo/vendor/visualsearch/vendor/jquery.ui.widget.js
File renamed without changes
View
28 demo/visual-search.html
@@ -6,8 +6,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<!-- Stylesheets-->
- <link rel="stylesheet" href="lib/visualsearch/build/visualsearch-datauri.css" />
- <link rel="stylesheet" href="lib/visualsearch/build/visualsearch.css" />
+ <link rel="stylesheet" href="vendor/visualsearch/build/visualsearch-datauri.css" />
+ <link rel="stylesheet" href="vendor/visualsearch/build/visualsearch.css" />
<!-- Information -->
<title>Query-Engine Visual Search Demo</title>
@@ -67,18 +67,18 @@
</div>
<!-- Scripts -->
- <script src="lib/coffeescript.js"></script>
- <script src="lib/jquery.js"></script>
- <script src="lib/underscore.js"></script>
- <script src="lib/backbone.js"></script>
- <script src="lib/js2coffee.js"></script>
- <script src="lib/ace/ace.js"></script>
- <script src="lib/ace/mode-coffee.js"></script>
- <script src="lib/visualsearch/build/visualsearch.js"></script>
- <script src="lib/visualsearch/vendor/jquery.ui.core.js"></script>
- <script src="lib/visualsearch/vendor/jquery.ui.widget.js"></script>
- <script src="lib/visualsearch/vendor/jquery.ui.position.js"></script>
- <script src="lib/visualsearch/vendor/jquery.ui.autocomplete.js"></script>
+ <script src="vendor/coffeescript.js"></script>
+ <script src="vendor/jquery.js"></script>
+ <script src="vendor/underscore.js"></script>
+ <script src="vendor/backbone.js"></script>
+ <script src="vendor/js2coffee.js"></script>
+ <script src="vendor/ace/ace.js"></script>
+ <script src="vendor/ace/mode-coffee.js"></script>
+ <script src="vendor/visualsearch/build/visualsearch.js"></script>
+ <script src="vendor/visualsearch/vendor/jquery.ui.core.js"></script>
+ <script src="vendor/visualsearch/vendor/jquery.ui.widget.js"></script>
+ <script src="vendor/visualsearch/vendor/jquery.ui.position.js"></script>
+ <script src="vendor/visualsearch/vendor/jquery.ui.autocomplete.js"></script>
<script src="../out/lib/query-engine.js"></script>
<script src="../out/demo/visual-search.js"></script>
View
2  out/test/live.test.js
@@ -9,7 +9,7 @@
Backbone = (typeof require === "function" ? require('backbone') : void 0) || this.Backbone;
- joe = require('joe') || this.joe;
+ joe = (typeof require === "function" ? require('joe') : void 0) || this.joe;
describe = joe.describe;
View
2  out/test/misc.test.js
@@ -10,7 +10,7 @@
Backbone = (typeof require === "function" ? require('backbone') : void 0) || this.Backbone;
- joe = require('joe') || this.joe;
+ joe = (typeof require === "function" ? require('joe') : void 0) || this.joe;
describe = joe.describe;
View
2  out/test/queries.test.js
@@ -9,7 +9,7 @@
Backbone = (typeof require === "function" ? require('backbone') : void 0) || this.Backbone;
- joe = require('joe') || this.joe;
+ joe = (typeof require === "function" ? require('joe') : void 0) || this.joe;
describe = joe.describe;
View
2  out/test/sort.test.js
@@ -9,7 +9,7 @@
Backbone = (typeof require === "function" ? require('backbone') : void 0) || this.Backbone;
- joe = require('joe') || this.joe;
+ joe = (typeof require === "function" ? require('joe') : void 0) || this.joe;
describe = joe.describe;
View
2  package.json
@@ -1,6 +1,6 @@
{
"name": "query-engine",
- "version": "1.1.14",
+ "version": "1.2.0",
"description": "Query-Engine is a NoSQL and MongoDb compliant query engine. It can run on the server-side with Node.js, or on the client-side within web browsers",
"homepage": "https://github.com/bevry/query-engine",
"keywords": [
View
2  src/test/live.test.coffee
@@ -2,7 +2,7 @@
queryEngine = require?(__dirname+'/../lib/query-engine.js') or @queryEngine
assert = require?('assert') or @assert
Backbone = require?('backbone') or @Backbone
-joe = require('joe') or @joe
+joe = require?('joe') or @joe
{describe} = joe
View
2  src/test/misc.test.coffee
@@ -2,7 +2,7 @@
queryEngine = require?(__dirname+'/../lib/query-engine.js') or @queryEngine
assert = require?('assert') or @assert
Backbone = require?('backbone') or @Backbone
-joe = require('joe') or @joe
+joe = require?('joe') or @joe
{describe} = joe
View
2  src/test/queries.test.coffee
@@ -2,7 +2,7 @@
queryEngine = require?(__dirname+'/../lib/query-engine.js') or @queryEngine
assert = require?('assert') or @assert
Backbone = require?('backbone') or @Backbone
-joe = require('joe') or @joe
+joe = require?('joe') or @joe
{describe} = joe
View
2  src/test/sort.test.coffee
@@ -2,7 +2,7 @@
queryEngine = require?(__dirname+'/../lib/query-engine.js') or @queryEngine
assert = require?('assert') or @assert
Backbone = require?('backbone') or @Backbone
-joe = require('joe') or @joe
+joe = require?('joe') or @joe
{describe} = joe
View
27 test-web/index.html
@@ -0,0 +1,27 @@
+<html>
+<head>
+ <!-- Query Engine -->
+ <script src="../demo/vendor/underscore.js"></script>
+ <script src="../demo/vendor/backbone.js"></script>
+ <script src="../out/lib/query-engine.js"></script>
+
+ <!-- Joe -->
+ <script src="vendor/chai.js"></script>
+ <script>this.assert = this.chai.assert</script>
+ <script src="vendor/bal-util.flow.js"></script>
+ <script src="vendor/joe/joe.js"></script>
+ <script src="vendor/joe/reporters/console.js"></script>
+ <script src="vendor/joe/reporters/list.js"></script>
+ <script>this.joe.setReporter(new this.joe.ListReporter());</script>
+
+ <!-- Tests -->
+ <script src="../out/test/live.test.js"></script>
+ <script src="../out/test/misc.test.js"></script>
+ <script src="../out/test/queries.test.js"></script>
+ <script src="../out/test/sort.test.js"></script>
+</head>
+<body>
+ <p>open your developer console</p>
+ <button onclick="javascript:joe.exit();">I'm done, give me the results</button>
+</body>
+</html>
View
456 test-web/vendor/bal-util.flow.js
@@ -0,0 +1,456 @@
+// Generated by CoffeeScript 1.3.1
+(function() {
+ var balUtilFlow,
+ __hasProp = {}.hasOwnProperty,
+ __slice = [].slice,
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
+
+ balUtilFlow = {
+ toString: function(obj) {
+ return Object.prototype.toString.call(obj);
+ },
+ isArray: function(obj) {
+ return this.toString(obj) === '[object Array]';
+ },
+ each: function(obj, callback, context) {
+ var broke, item, key, _i, _len;
+ broke = false;
+ context || (context = obj);
+ if (this.isArray(obj)) {
+ for (key = _i = 0, _len = obj.length; _i < _len; key = ++_i) {
+ item = obj[key];
+ if (callback.call(context, item, key, obj) === false) {
+ broke = true;
+ break;
+ }
+ }
+ } else {
+ for (key in obj) {
+ if (!__hasProp.call(obj, key)) continue;
+ item = obj[key];
+ if (callback.call(context, item, key, obj) === false) {
+ broke = true;
+ break;
+ }
+ }
+ }
+ return this;
+ },
+ flow: function(opts) {
+ var action, actions, args, next, object, tasks;
+ object = opts.object, action = opts.action, args = opts.args, tasks = opts.tasks, next = opts.next;
+ if (!action) {
+ throw new Error('balUtilFlow.flow called without any action');
+ }
+ actions = action.split(/[,\s]+/g);
+ tasks || (tasks = new balUtilFlow.Group(next));
+ balUtilFlow.each(actions, function(action) {
+ return tasks.push(function(complete) {
+ var argsClone, fn;
+ argsClone = (args || []).slice();
+ argsClone.push(complete);
+ fn = object[action];
+ return fn.apply(object, argsClone);
+ });
+ });
+ tasks.sync();
+ return this;
+ }
+ };
+
+ /*
+ Usage:
+ # Add tasks to a queue then fire them in parallel (asynchronously)
+ tasks = new Group (err) -> next err
+ tasks.push (complete) -> someAsyncFunction(arg1, arg2, complete)
+ tasks.push (complete) -> anotherAsyncFunction(arg1, arg2, complete)
+ tasks.async()
+
+ # Add tasks to a queue then fire them in serial (synchronously)
+ tasks = new Group (err) -> next err
+ tasks.push (complete) -> someAsyncFunction(arg1, arg2, complete)
+ tasks.push (complete) -> anotherAsyncFunction(arg1, arg2, complete)
+ tasks.sync()
+ */
+
+
+ balUtilFlow.Group = (function() {
+
+ _Class.prototype.total = 0;
+
+ _Class.prototype.completed = 0;
+
+ _Class.prototype.running = 0;
+
+ _Class.prototype.exited = false;
+
+ _Class.prototype.breakOnError = true;
+
+ _Class.prototype.autoClear = false;
+
+ _Class.prototype.queue = [];
+
+ _Class.prototype.mode = 'async';
+
+ _Class.prototype.lastResult = null;
+
+ _Class.prototype.results = [];
+
+ _Class.prototype.errors = [];
+
+ _Class.prototype.next = function() {
+ throw new Error('Groups require a completion callback');
+ };
+
+ function _Class() {
+ var arg, args, autoClear, breakOnError, mode, next, _i, _len;
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
+ this.clear();
+ for (_i = 0, _len = args.length; _i < _len; _i++) {
+ arg = args[_i];
+ if (typeof arg === 'string') {
+ this.mode = arg;
+ } else if (typeof arg === 'function') {
+ this.next = arg;
+ } else if (typeof arg === 'object') {
+ next = arg.next, mode = arg.mode, breakOnError = arg.breakOnError, autoClear = arg.autoClear;
+ if (next) {
+ this.next = next;
+ }
+ if (mode) {
+ this.mode = mode;
+ }
+ if (breakOnError) {
+ this.breakOnError = breakOnError;
+ }
+ if (autoClear) {
+ this.autoClear = autoClear;
+ }
+ } else {
+ throw new Error('Unknown argument sent to Groups constructor');
+ }
+ }
+ }
+
+ _Class.prototype.clear = function() {
+ this.total = 0;
+ this.completed = 0;
+ this.running = 0;
+ this.exited = false;
+ this.queue = [];
+ this.results = [];
+ this.errors = [];
+ this.lastResult = null;
+ return this;
+ };
+
+ _Class.prototype.hasTasks = function() {
+ return this.queue.length !== 0;
+ };
+
+ _Class.prototype.hasCompleted = function() {
+ return this.total !== 0 && this.total === this.completed;
+ };
+
+ _Class.prototype.isRunning = function() {
+ return this.running !== 0;
+ };
+
+ _Class.prototype.hasExited = function(value) {
+ if (value != null) {
+ this.exited = value;
+ }
+ return this.exited === true;
+ };
+
+ _Class.prototype.complete = function() {
+ var args, err;
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
+ err = args[0] || void 0;
+ this.lastResult = args;
+ if (err) {
+ this.errors.push(err);
+ }
+ this.results.push(args);
+ if (this.running !== 0) {
+ --this.running;
+ }
+ if (this.hasExited()) {
+
+ } else {
+ if (err && this.breakOnError) {
+ this.exit();
+ } else {
+ ++this.completed;
+ if (this.hasTasks()) {
+ this.nextTask();
+ } else if (this.isRunning() === false && this.hasCompleted()) {
+ this.exit();
+ }
+ }
+ }
+ return this;
+ };
+
+ _Class.prototype.completer = function() {
+ var _this = this;
+ return function() {
+ var args;
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
+ return _this.complete.apply(_this, args);
+ };
+ };
+
+ _Class.prototype.exit = function(err) {
+ var errors, lastResult, results;
+ if (err == null) {
+ err = null;
+ }
+ if (this.hasExited()) {
+
+ } else {
+ lastResult = this.lastResult;
+ errors = this.errors.length !== 0 ? this.errors : null;
+ results = this.results;
+ if (this.autoClear) {
+ this.clear();
+ } else {
+ this.hasExited(true);
+ }
+ if (typeof this.next === "function") {
+ this.next(errors, lastResult, results);
+ }
+ }
+ return this;
+ };
+
+ _Class.prototype.tasks = function(tasks) {
+ var task, _i, _len;
+ for (_i = 0, _len = tasks.length; _i < _len; _i++) {
+ task = tasks[_i];
+ this.push(task);
+ }
+ return this;
+ };
+
+ _Class.prototype.push = function(task) {
+ ++this.total;
+ this.queue.push(task);
+ return this;
+ };
+
+ _Class.prototype.pushAndRun = function(task) {
+ if (this.mode === 'sync' && this.isRunning()) {
+ this.push(task);
+ } else {
+ ++this.total;
+ this.runTask(task);
+ }
+ return this;
+ };
+
+ _Class.prototype.nextTask = function() {
+ var task;
+ if (this.hasTasks()) {
+ task = this.queue.shift();
+ this.runTask(task);
+ }
+ return this;
+ };
+
+ _Class.prototype.runTask = function(task) {
+ try {
+ ++this.running;
+ task(this.completer());
+ } catch (err) {
+ this.complete(err);
+ }
+ return this;
+ };
+
+ _Class.prototype.run = function() {
+ var task, _i, _len, _ref;
+ if (this.isRunning() === false) {
+ this.hasExited(false);
+ if (this.hasTasks()) {
+ if (this.mode === 'sync') {
+ this.nextTask();
+ } else {
+ _ref = this.queue;
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ task = _ref[_i];
+ this.nextTask();
+ }
+ }
+ } else {
+ this.exit();
+ }
+ }
+ return this;
+ };
+
+ _Class.prototype.async = function() {
+ this.mode = 'async';
+ this.run();
+ return this;
+ };
+
+ _Class.prototype.sync = function() {
+ this.mode = 'sync';
+ this.run();
+ return this;
+ };
+
+ return _Class;
+
+ })();
+
+ balUtilFlow.Block = (function(_super) {
+
+ __extends(_Class, _super);
+
+ _Class.prototype.blockBefore = function(block) {};
+
+ _Class.prototype.blockAfter = function(block, err) {};
+
+ _Class.prototype.blockTaskBefore = function(block, task, err) {};
+
+ _Class.prototype.blockTaskAfter = function(block, task, err) {};
+
+ function _Class(name, initFunction, parentBlock) {
+ var block;
+ block = this;
+ _Class.__super__.constructor.call(this, function(err) {
+ var _ref;
+ block.blockAfter(block, err);
+ return (_ref = block.parentBlock) != null ? _ref.complete(err) : void 0;
+ });
+ block.blockName = name;
+ if (parentBlock != null) {
+ block.parentBlock = parentBlock;
+ }
+ block.mode = 'sync';
+ block.initFunction = initFunction;
+ block.blockBefore(block);
+ if (block.initFunction != null) {
+ if (block.initFunction.length === 3) {
+ block.total = Infinity;
+ }
+ try {
+ block.initFunction(function(name, fn) {
+ return block.block(name, fn);
+ }, function(name, fn) {
+ return block.task(name, fn);
+ }, function(err) {
+ return block.exit(err);
+ });
+ } catch (err) {
+ block.exit(err);
+ }
+ if (block.initFunction.length !== 3) {
+ block.run();
+ }
+ } else {
+ block.total = Infinity;
+ }
+ this;
+
+ }
+
+ _Class.prototype.block = function(name, fn) {
+ var block, push;
+ block = this;
+ push = function(complete) {
+ if (block.total === Infinity) {
+ return block.pushAndRun(complete);
+ } else {
+ return block.push(complete);
+ }
+ };
+ push(function() {
+ var subBlock;
+ return subBlock = block.createSubBlock(name, fn, block);
+ });
+ return this;
+ };
+
+ _Class.prototype.createSubBlock = function(name, fn, parentBlock) {
+ return new balUtilFlow.Block(name, fn, parentBlock);
+ };
+
+ _Class.prototype.task = function(name, fn) {
+ var block, pushTask;
+ block = this;
+ pushTask = function(complete) {
+ if (block.total === Infinity) {
+ return block.pushAndRun(complete);
+ } else {
+ return block.push(complete);
+ }
+ };
+ pushTask(function(complete) {
+ var preComplete;
+ preComplete = function(err) {
+ block.blockTaskAfter(block, name, err);
+ return complete(err);
+ };
+ block.blockTaskBefore(block, name);
+ if (fn.length < 1) {
+ try {
+ fn();
+ return preComplete();
+ } catch (err) {
+ return preComplete(err);
+ }
+ } else {
+ try {
+ return fn(preComplete);
+ } catch (err) {
+ return preComplete(err);
+ }
+ }
+ });
+ return this;
+ };
+
+ return _Class;
+
+ })(balUtilFlow.Group);
+
+ balUtilFlow.Runner = (function() {
+
+ _Class.prototype.runnerBlock = null;
+
+ function _Class() {
+ if (this.runnerBlock == null) {
+ this.runnerBlock = new balUtilFlow.Block();
+ }
+ }
+
+ _Class.prototype.getRunnerBlock = function() {
+ return this.runnerBlock;
+ };
+
+ _Class.prototype.block = function() {
+ var args, _ref;
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
+ return (_ref = this.getRunnerBlock()).block.apply(_ref, args);
+ };
+
+ _Class.prototype.task = function() {
+ var args, _ref;
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
+ return (_ref = this.getRunnerBlock()).task.apply(_ref, args);
+ };
+
+ return _Class;
+
+ })();
+
+ if (typeof module !== "undefined" && module !== null) {
+ module.exports = balUtilFlow;
+ } else {
+ this.balUtilFlow = balUtilFlow;
+ }
+
+}).call(this);
View
3,403 test-web/vendor/chai.js
@@ -0,0 +1,3403 @@
+!function (name, definition) {
+ if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
+ else this[name] = definition();
+}('chai', function () {
+
+// CommonJS require()
+
+function require(p){
+ var path = require.resolve(p)
+ , mod = require.modules[path];
+ if (!mod) throw new Error('failed to require "' + p + '"');
+ if (!mod.exports) {
+ mod.exports = {};
+ mod.call(mod.exports, mod, mod.exports, require.relative(path));
+ }
+ return mod.exports;
+ }
+
+require.modules = {};
+
+require.resolve = function (path){
+ var orig = path
+ , reg = path + '.js'
+ , index = path + '/index.js';
+ return require.modules[reg] && reg
+ || require.modules[index] && index
+ || orig;
+ };
+
+require.register = function (path, fn){
+ require.modules[path] = fn;
+ };
+
+require.relative = function (parent) {
+ return function(p){
+ if ('.' != p[0]) return require(p);
+
+ var path = parent.split('/')
+ , segs = p.split('/');
+ path.pop();
+
+ for (var i = 0; i < segs.length; i++) {
+ var seg = segs[i];
+ if ('..' == seg) path.pop();
+ else if ('.' != seg) path.push(seg);
+ }
+
+ return require(path.join('/'));
+ };
+ };
+
+
+require.register("assertion.js", function(module, exports, require){
+/*!
+ * chai
+ * http://chaijs.com
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+
+/*!
+ * Module dependencies.
+ */
+
+var AssertionError = require('./browser/error')
+ , toString = Object.prototype.toString
+ , util = require('./utils')
+ , flag = util.flag;
+
+/*!
+ * Module export.
+ */
+
+module.exports = Assertion;
+
+
+/*!
+ * Assertion Constructor
+ *
+ * Creates object for chaining.
+ *
+ * @api private
+ */
+
+function Assertion (obj, msg, stack) {
+ flag(this, 'ssfi', stack || arguments.callee);
+ flag(this, 'object', obj);
+ flag(this, 'message', msg);
+}
+
+/*!
+ * ### Assertion.includeStack
+ *
+ * User configurable property, influences whether stack trace
+ * is included in Assertion error message. Default of false
+ * suppresses stack trace in the error message
+ *
+ * Assertion.includeStack = true; // enable stack on error
+ *
+ * @api public
+ */
+
+Assertion.includeStack = false;
+
+Assertion.addProperty = function (name, fn) {
+ util.addProperty(this.prototype, name, fn);
+};
+
+Assertion.addMethod = function (name, fn) {
+ util.addMethod(this.prototype, name, fn);
+};
+
+Assertion.addChainableMethod = function (name, fn, chainingBehavior) {
+ util.addChainableMethod(this.prototype, name, fn, chainingBehavior);
+};
+
+Assertion.overwriteProperty = function (name, fn) {
+ util.overwriteProperty(this.prototype, name, fn);
+};
+
+Assertion.overwriteMethod = function (name, fn) {
+ util.overwriteMethod(this.prototype, name, fn);
+};
+
+/*!
+ * ### .assert(expression, message, negateMessage, expected, actual)
+ *
+ * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass.
+ *
+ * @name assert
+ * @param {Philosophical} expression to be tested
+ * @param {String} message to display if fails
+ * @param {String} negatedMessage to display if negated expression fails
+ * @param {Mixed} expected value (remember to check for negation)
+ * @param {Mixed} actual (optional) will default to `this.obj`
+ * @api private
+ */
+
+Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual) {
+ var msg = util.getMessage(this, arguments)
+ , actual = util.getActual(this, arguments)
+ , ok = util.test(this, arguments);
+
+ if (!ok) {
+ throw new AssertionError({
+ message: msg
+ , actual: actual
+ , expected: expected
+ , stackStartFunction: (Assertion.includeStack) ? this.assert : flag(this, 'ssfi')
+ });
+ }
+};
+
+/*!
+ *
+ * ### ._obj
+ *
+ * Quick reference to stored `actual` value for plugin developers.
+ *
+ * @api private
+ */
+
+Object.defineProperty(Assertion.prototype, '_obj',
+ { get: function () {
+ return flag(this, 'object');
+ }
+ , set: function (val) {
+ flag(this, 'object', val);
+ }
+});
+
+/**
+ * ### Language Chains
+ *
+ * The following are provide as chainable getters to
+ * improve the readability of your assertions. They
+ * do not provide an testing capability unless they
+ * have been overwritten by a plugin.
+ *
+ * **Chains**
+ *
+ * - to
+ * - be
+ * - been
+ * - is
+ * - and
+ * - have
+ * - with
+ *
+ * @name language chains
+ * @api public
+ */
+
+[ 'to', 'be', 'been'
+, 'is', 'and', 'have'
+, 'with' ].forEach(function (chain) {
+ Object.defineProperty(Assertion.prototype, chain,
+ { get: function () {
+ return this;
+ }
+ , configurable: true
+ });
+});
+
+/**
+ * ### .not
+ *
+ * Negates any of assertions following in the chain.
+ *
+ * expect(foo).to.not.equal('bar');
+ * expect(goodFn).to.not.throw(Error);
+ * expect({ foo: 'baz' }).to.have.property('foo')
+ * .and.not.equal('bar');
+ *
+ * @name not
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'not',
+ { get: function () {
+ flag(this, 'negate', true);
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .deep
+ *
+ * Sets the `deep` flag, later used by the `equal` and
+ * `property` assertions.
+ *
+ * expect(foo).to.deep.equal({ bar: 'baz' });
+ * expect({ foo: { bar: { baz: 'quux' } } })
+ * .to.have.deep.property('foo.bar.baz', 'quux');
+ *
+ * @name deep
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'deep',
+ { get: function () {
+ flag(this, 'deep', true);
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .a(type)
+ *
+ * The `a` and `an` assertions are aliases that can be
+ * used either as language chains or to assert a value's
+ * type (as revealed by `Object.prototype.toString`).
+ *
+ * // typeof
+ * expect('test').to.be.a('string');
+ * expect({ foo: 'bar' }).to.be.an('object');
+ * expect(null).to.be.a('null');
+ * expect(undefined).to.be.an('undefined');
+ *
+ * // language chain
+ * expect(foo).to.be.an.instanceof(Foo);
+ *
+ * @name a
+ * @alias an
+ * @param {String} type
+ * @api public
+ */
+
+function an(type) {
+ var obj = flag(this, 'object')
+ , klassStart = type.charAt(0).toUpperCase()
+ , klass = klassStart + type.slice(1)
+ , article = ~[ 'A', 'E', 'I', 'O', 'U' ].indexOf(klassStart) ? 'an ' : 'a ';
+
+ this.assert(
+ '[object ' + klass + ']' === toString.call(obj)
+ , 'expected #{this} to be ' + article + type
+ , 'expected #{this} not to be ' + article + type
+ , '[object ' + klass + ']'
+ , toString.call(obj)
+ );
+}
+
+Assertion.addChainableMethod('an', an);
+Assertion.addChainableMethod('a', an);
+
+/**
+ * ### .include(value)
+ *
+ * The `include` and `contain` assertions can be used as either property
+ * based language chains or as methods to assert the inclusion of an object
+ * in an array or a substring in a string. When used as language chains,
+ * they toggle the `contain` flag for the `keys` assertion.
+ *
+ * expect([1,2,3]).to.include(2);
+ * expect('foobar').to.contain('foo');
+ * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
+ *
+ * @name include
+ * @alias contain
+ * @param {Object|String|Number} obj
+ * @api public
+ */
+
+function includeChainingBehavior () {
+ flag(this, 'contains', true);
+}
+
+function include (val) {
+ var obj = flag(this, 'object')
+ this.assert(
+ ~obj.indexOf(val)
+ , 'expected #{this} to include ' + util.inspect(val)
+ , 'expected #{this} to not include ' + util.inspect(val));
+}
+
+Assertion.addChainableMethod('include', include, includeChainingBehavior);
+Assertion.addChainableMethod('contain', include, includeChainingBehavior);
+
+/**
+ * ### .ok
+ *
+ * Asserts that the target is truthy.
+ *
+ * expect('everthing').to.be.ok;
+ * expect(1).to.be.ok;
+ * expect(false).to.not.be.ok;
+ * expect(undefined).to.not.be.ok;
+ * expect(null).to.not.be.ok;
+ *
+ * @name ok
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'ok',
+ { get: function () {
+ this.assert(
+ flag(this, 'object')
+ , 'expected #{this} to be truthy'
+ , 'expected #{this} to be falsy');
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .true
+ *
+ * Asserts that the target is `true`.
+ *
+ * expect(true).to.be.true;
+ * expect(1).to.not.be.true;
+ *
+ * @name true
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'true',
+ { get: function () {
+ this.assert(
+ true === flag(this, 'object')
+ , 'expected #{this} to be true'
+ , 'expected #{this} to be false'
+ , this.negate ? false : true
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .false
+ *
+ * Asserts that the target is `false`.
+ *
+ * expect(false).to.be.false;
+ * expect(0).to.not.be.false;
+ *
+ * @name false
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'false',
+ { get: function () {
+ this.assert(
+ false === flag(this, 'object')
+ , 'expected #{this} to be false'
+ , 'expected #{this} to be true'
+ , this.negate ? true : false
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .null
+ *
+ * Asserts that the target is `null`.
+ *
+ * expect(null).to.be.null;
+ * expect(undefined).not.to.be.null;
+ *
+ * @name null
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'null',
+ { get: function () {
+ this.assert(
+ null === flag(this, 'object')
+ , 'expected #{this} to be null'
+ , 'expected #{this} not to be null'
+ , this.negate ? false : true
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .undefined
+ *
+ * Asserts that the target is `undefined`.
+ *
+ * expect(undefined).to.be.undefined;
+ * expect(null).to.not.be.undefined;
+ *
+ * @name undefined
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'undefined',
+ { get: function () {
+ this.assert(
+ undefined === flag(this, 'object')
+ , 'expected #{this} to be undefined'
+ , 'expected #{this} not to be undefined'
+ , this.negate ? false : true
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .exist
+ *
+ * Asserts that the target is neither `null` nor `undefined`.
+ *
+ * var foo = 'hi'
+ * , bar = null
+ * , baz;
+ *
+ * expect(foo).to.exist;
+ * expect(bar).to.not.exist;
+ * expect(baz).to.not.exist;
+ *
+ * @name exist
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'exist',
+ { get: function () {
+ this.assert(
+ null != flag(this, 'object')
+ , 'expected #{this} to exist'
+ , 'expected #{this} to not exist'
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .empty
+ *
+ * Asserts that the target's length is `0`. For arrays, it checks
+ * the `length` property. For objects, it gets the count of
+ * enumerable keys.
+ *
+ * expect([]).to.be.empty;
+ * expect('').to.be.empty;
+ * expect({}).to.be.empty;
+ *
+ * @name empty
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'empty',
+ { get: function () {
+ var obj = flag(this, 'object')
+ , expected = obj;
+
+ if (Array.isArray(obj) || 'string' === typeof object) {
+ expected = obj.length;
+ } else if (typeof obj === 'object') {
+ expected = Object.keys(obj).length;
+ }
+
+ this.assert(
+ !expected
+ , 'expected #{this} to be empty'
+ , 'expected #{this} not to be empty');
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .arguments
+ *
+ * Asserts that the target is an arguments object.
+ *
+ * function test () {
+ * expect(arguments).to.be.arguments;
+ * }
+ *
+ * @name arguments
+ * @alias Arguments
+ * @api public
+ */
+
+function checkArguments () {
+ var obj = flag(this, 'object')
+ , type = Object.prototype.toString.call(obj);
+ this.assert(
+ '[object Arguments]' === type
+ , 'expected #{this} to be arguments but got ' + type
+ , 'expected #{this} to not be arguments'
+ );
+}
+
+Assertion.addProperty('arguments', checkArguments);
+Assertion.addProperty('Arguments', checkArguments);
+
+/**
+ * ### .equal(value)
+ *
+ * Asserts that the target is strictly equal (`===`) to `value`.
+ * Alternately, if the `deep` flag is set, asserts that
+ * the target is deeply equal to `value`.
+ *
+ * expect('hello').to.equal('hello');
+ * expect(42).to.equal(42);
+ * expect(1).to.not.equal(true);
+ * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
+ * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
+ *
+ * @name equal
+ * @param {Mixed} value
+ * @api public
+ */
+
+Assertion.prototype.equal = function (val) {
+ var obj = flag(this, 'object');
+ if (flag(this, 'deep')) {
+ return this.eql(val);
+ } else {
+ this.assert(
+ val === obj
+ , 'expected #{this} to equal #{exp}'
+ , 'expected #{this} to not equal #{exp}'
+ , val);
+ }
+
+ return this;
+};
+
+/**
+ * ### .eql(value)
+ *
+ * Asserts that the target is deeply equal to `value`.
+ *
+ * expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
+ * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
+ *
+ * @name eql
+ * @param {Mixed} value
+ * @api public
+ */
+
+Assertion.prototype.eql = function (obj) {
+ this.assert(
+ util.eql(obj, flag(this, 'object'))
+ , 'expected #{this} to deeply equal #{exp}'
+ , 'expected #{this} to not deeply equal #{exp}'
+ , obj );
+
+ return this;
+};
+
+/**
+ * ### .above(value)
+ *
+ * Asserts that the target is greater than `value`.
+ *
+ * expect(10).to.be.above(5);
+ *
+ * @name above
+ * @alias gt
+ * @param {Number} value
+ * @api public
+ */
+
+Assertion.prototype.above = function (val) {
+ this.assert(
+ flag(this, 'object') > val
+ , 'expected #{this} to be above ' + val
+ , 'expected #{this} to be below ' + val);
+
+ return this;
+};
+
+/**
+ * ### .below(value)
+ *
+ * Asserts that the target is less than `value`.
+ *
+ * expect(5).to.be.below(10);
+ *
+ * @name below
+ * @alias lt
+ * @param {Number} value
+ * @api public
+ */
+
+Assertion.prototype.below = function (val) {
+ this.assert(
+ flag(this, 'object') < val
+ , 'expected #{this} to be below ' + val
+ , 'expected #{this} to be above ' + val);
+
+ return this;
+};
+
+/**
+ * ### .within(start, finish)
+ *
+ * Asserts that the target is within a range.
+ *
+ * expect(7).to.be.within(5,10);
+ *
+ * @name within
+ * @param {Number} start lowerbound inclusive
+ * @param {Number} finish upperbound inclusive
+ * @api public
+ */
+
+Assertion.prototype.within = function (start, finish) {
+ var obj = flag(this, 'object')
+ , range = start + '..' + finish;
+
+ this.assert(
+ obj >= start && obj <= finish
+ , 'expected #{this} to be within ' + range
+ , 'expected #{this} to not be within ' + range);
+
+ return this;
+};
+
+/**
+ * ### .instanceof(constructor)
+ *
+ * Asserts that the target is an instance of `constructor`.
+ *
+ * var Tea = function (name) { this.name = name; }
+ * , Chai = new Tea('chai');
+ *
+ * expect(Chai).to.be.an.instanceof(Tea);
+ * expect([ 1, 2, 3 ]).to.be.instanceof(Array);
+ *
+ * @name instanceof
+ * @param {Constructor} constructor
+ * @alias instanceOf
+ * @api public
+ */
+
+Assertion.prototype.instanceOf = function (constructor) {
+ var name = util.getName(constructor);
+ this.assert(
+ flag(this, 'object') instanceof constructor
+ , 'expected #{this} to be an instance of ' + name
+ , 'expected #{this} to not be an instance of ' + name);
+
+ return this;
+};
+
+/**
+ * ### .property(name, [value])
+ *
+ * Asserts that the target has a property `name`, optionally asserting that
+ * the value of that property is strictly equal to `value`.
+ * If the `deep` flag is set, you can use dot- and bracket-notation for deep
+ * references into objects and arrays.
+ *
+ * // simple referencing
+ * var obj = { foo: 'bar' };
+ * expect(obj).to.have.property('foo');
+ * expect(obj).to.have.property('foo', 'bar');
+ * expect(obj).to.have.property('foo').to.be.a('string');
+ *
+ * // deep referencing
+ * var deepObj = {
+ * green: { tea: 'matcha' }
+ * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
+ * };
+
+ * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
+ * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
+ * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
+ *
+ * @name property
+ * @param {String} name
+ * @param {Mixed} value (optional)
+ * @returns value of property for chaining
+ * @api public
+ */
+
+Assertion.prototype.property = function (name, val) {
+ var obj = flag(this, 'object')
+ , value = flag(this, 'deep') ? util.getPathValue(name, obj) : obj[name]
+ , descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
+ , negate = flag(this, 'negate');
+
+ if (negate && undefined !== val) {
+ if (undefined === value) {
+ throw new Error(util.inspect(obj) + ' has no ' + descriptor + util.inspect(name));
+ }
+ } else {
+ this.assert(
+ undefined !== value
+ , 'expected #{this} to have a ' + descriptor + util.inspect(name)
+ , 'expected #{this} to not have ' + descriptor + util.inspect(name));
+ }
+
+ if (undefined !== val) {
+ this.assert(
+ val === value
+ , 'expected #{this} to have a ' + descriptor + util.inspect(name) + ' of #{exp}, but got #{act}'
+ , 'expected #{this} to not have a ' + descriptor + util.inspect(name) + ' of #{act}'
+ , val
+ , value
+ );
+ }
+
+ flag(this, 'object', value);
+ return this;
+};
+
+/**
+ * ### .ownProperty(name)
+ *
+ * Asserts that the target has an own property `name`.
+ *
+ * expect('test').to.have.ownProperty('length');
+ *
+ * @name ownProperty
+ * @alias haveOwnProperty
+ * @param {String} name
+ * @api public
+ */
+
+Assertion.prototype.ownProperty = function (name) {
+ var obj = flag(this, 'object');
+ this.assert(
+ obj.hasOwnProperty(name)
+ , 'expected #{this} to have own property ' + util.inspect(name)
+ , 'expected #{this} to not have own property ' + util.inspect(name));
+ return this;
+};
+
+/**
+ * ### .length(value)
+ *
+ * Asserts that the target's `length` property has the expected value.
+ *
+ * expect([1,2,3]).to.have.length(3);
+ * expect('foobar').to.have.length(6);
+ *
+ * @name length
+ * @alias lengthOf
+ * @param {Number} length
+ * @api public
+ */
+
+Assertion.prototype.length = function (n) {
+ var obj = flag(this, 'object');
+ new Assertion(obj).to.have.property('length');
+ var len = obj.length;
+
+ this.assert(
+ len == n
+ , 'expected #{this} to have a length of #{exp} but got #{act}'
+ , 'expected #{this} to not have a length of #{act}'
+ , n
+ , len
+ );
+
+ return this;
+};
+
+/**
+ * ### .match(regexp)
+ *
+ * Asserts that the target matches a regular expression.
+ *
+ * expect('foobar').to.match(/^foo/);
+ *
+ * @name match
+ * @param {RegExp} RegularExpression
+ * @api public
+ */
+
+Assertion.prototype.match = function (re) {
+ var obj = flag(this, 'object');
+ this.assert(
+ re.exec(obj)
+ , 'expected #{this} to match ' + re
+ , 'expected #{this} not to match ' + re);
+
+ return this;
+};
+
+
+/**
+ * ### .string(string)
+ *
+ * Asserts that the string target contains another string.
+ *
+ * expect('foobar').to.have.string('bar');
+ *
+ * @name string
+ * @param {String} string
+ * @api public
+ */
+
+Assertion.prototype.string = function (str) {
+ var obj = flag(this, 'object');
+ new Assertion(obj).is.a('string');
+
+ this.assert(
+ ~obj.indexOf(str)
+ , 'expected #{this} to contain ' + util.inspect(str)
+ , 'expected #{this} to not contain ' + util.inspect(str));
+
+ return this;
+};
+
+/**
+ * ### .keys(key1, [key2], [...])
+ *
+ * Asserts that the target has exactly the given keys, or
+ * asserts the inclusion of some keys when using the
+ * `include` or `contain` modifiers.
+ *
+ * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
+ * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
+ *
+ * @name keys
+ * @alias key
+ * @param {String...|Array} keys
+ * @api public
+ */
+
+Assertion.prototype.keys = function(keys) {
+ var obj = flag(this, 'object')
+ , str
+ , ok = true;
+
+ keys = keys instanceof Array
+ ? keys
+ : Array.prototype.slice.call(arguments);
+
+ if (!keys.length) throw new Error('keys required');
+
+ var actual = Object.keys(obj)
+ , len = keys.length;
+
+ // Inclusion
+ ok = keys.every(function(key){
+ return ~actual.indexOf(key);
+ });
+
+ // Strict
+ if (!flag(this, 'negate') && !flag(this, 'contains')) {
+ ok = ok && keys.length == actual.length;
+ }
+
+ // Key string
+ if (len > 1) {
+ keys = keys.map(function(key){
+ return util.inspect(key);
+ });
+ var last = keys.pop();
+ str = keys.join(', ') + ', and ' + last;
+ } else {
+ str = util.inspect(keys[0]);
+ }
+
+ // Form
+ str = (len > 1 ? 'keys ' : 'key ') + str;
+
+ // Have / include
+ str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
+
+ // Assertion
+ this.assert(
+ ok
+ , 'expected #{this} to ' + str
+ , 'expected #{this} to not ' + str
+ , keys
+ , Object.keys(obj)
+ );
+
+ return this;
+}
+
+/**
+ * ### .throw(constructor)
+ *
+ * Asserts that the function target will throw a specific error, or specific type of error
+ * (as determined using `instanceof`), optionally with a RegExp or string inclusion test
+ * for the error's message.
+ *
+ * var err = new ReferenceError('This is a bad function.');
+ * var fn = function () { throw err; }
+ * expect(fn).to.throw(ReferenceError);
+ * expect(fn).to.throw(Error);
+ * expect(fn).to.throw(/bad function/);
+ * expect(fn).to.not.throw('good function');
+ * expect(fn).to.throw(ReferenceError, /bad function/);
+ * expect(fn).to.throw(err);
+ * expect(fn).to.not.throw(new RangeError('Out of range.'));
+ *
+ * Please note that when a throw expectation is negated, it will check each
+ * parameter independently, starting with error constructor type. The appropriate way
+ * to check for the existence of a type of error but for a message that does not match
+ * is to use `and`.
+ *
+ * expect(fn).to.throw(ReferenceError)
+ * .and.not.throw(/good function/);
+ *
+ * @name throw
+ * @alias throws
+ * @alias Throw
+ * @param {ErrorConstructor} constructor
+ * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
+ * @api public
+ */
+
+Assertion.prototype.Throw = function (constructor, msg) {
+ var obj = flag(this, 'object');
+ new Assertion(obj).is.a('function');
+
+ var thrown = false
+ , desiredError = null
+ , name = null;
+
+ if (arguments.length === 0) {
+ msg = null;
+ constructor = null;
+ } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
+ msg = constructor;
+ constructor = null;
+ } else if (constructor && constructor instanceof Error) {
+ desiredError = constructor;
+ constructor = null;
+ msg = null;
+ } else if (typeof constructor === 'function') {
+ name = (new constructor()).name;
+ } else {
+ constructor = null;
+ }
+
+ try {
+ obj();
+ } catch (err) {
+ // first, check desired error
+ if (desiredError) {
+ this.assert(
+ err === desiredError
+ , 'expected #{this} to throw ' + util.inspect(desiredError) + ' but ' + util.inspect(err) + ' was thrown'
+ , 'expected #{this} to not throw ' + util.inspect(desiredError)
+ );
+ return this;
+ }
+ // next, check constructor
+ if (constructor) {
+ this.assert(
+ err instanceof constructor
+ , 'expected #{this} to throw ' + name + ' but a ' + err.name + ' was thrown'
+ , 'expected #{this} to not throw ' + name );
+ if (!msg) return this;
+ }
+ // next, check message
+ if (err.message && msg && msg instanceof RegExp) {
+ this.assert(
+ msg.exec(err.message)
+ , 'expected #{this} to throw error matching ' + msg + ' but got ' + util.inspect(err.message)
+ , 'expected #{this} to throw error not matching ' + msg
+ );
+ return this;
+ } else if (err.message && msg && 'string' === typeof msg) {
+ this.assert(
+ ~err.message.indexOf(msg)
+ , 'expected #{this} to throw error including #{exp} but got #{act}'
+ , 'expected #{this} to throw error not including #{act}'
+ , msg
+ , err.message
+ );
+ return this;
+ } else {
+ thrown = true;
+ }
+ }
+
+ var expectedThrown = name ? name : desiredError ? util.inspect(desiredError) : 'an error';
+
+ this.assert(
+ thrown === true
+ , 'expected #{this} to throw ' + expectedThrown
+ , 'expected #{this} to not throw ' + expectedThrown);
+
+ return this;
+};
+
+/**
+ * ### .respondTo(method)
+ *
+ * Asserts that the object or class target will respond to a method.
+ *
+ * Klass.prototype.bar = function(){};
+ * expect(Klass).to.respondTo('bar');
+ * expect(obj).to.respondTo('bar');
+ *
+ * To check if a constructor will respond to a static function,
+ * set the `itself` flag.
+ *
+ * Klass.baz = function(){};
+ * expect(Klass).itself.to.respondTo('baz');
+ *
+ * @name respondTo
+ * @param {String} method
+ * @api public
+ */
+
+Assertion.prototype.respondTo = function (method) {
+ var obj = flag(this, 'object')
+ , itself = flag(this, 'itself')
+ , context = ('function' === typeof obj && !itself)
+ ? obj.prototype[method]
+ : obj[method];
+
+ this.assert(
+ 'function' === typeof context
+ , 'expected #{this} to respond to ' + util.inspect(method)
+ , 'expected #{this} to not respond to ' + util.inspect(method)
+ , 'function'
+ , typeof context
+ );
+
+ return this;
+};
+
+/**
+ * ### .itself
+ *
+ * Sets the `itself` flag, later used by the `respondTo` assertion.
+ *
+ * function Foo() {}
+ * Foo.bar = function() {}
+ * Foo.prototype.baz = function() {}
+ *
+ * expect(Foo).itself.to.respondTo('bar');
+ * expect(Foo).itself.not.to.respondTo('baz');
+ *
+ * @name itself
+ * @api public
+ */
+Object.defineProperty(Assertion.prototype, 'itself',
+ { get: function () {
+ flag(this, 'itself', true);
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .satisfy(method)
+ *
+ * Asserts that the target passes a given truth test.
+ *
+ * expect(1).to.satisfy(function(num) { return num > 0; });
+ *
+ * @name satisfy
+ * @param {Function} matcher
+ * @api public
+ */
+
+Assertion.prototype.satisfy = function (matcher) {
+ var obj = flag(this, 'object');
+ this.assert(
+ matcher(obj)
+ , 'expected #{this} to satisfy ' + util.inspect(matcher)
+ , 'expected #{this} to not satisfy' + util.inspect(matcher)
+ , this.negate ? false : true
+ , matcher(obj)
+ );
+
+ return this;
+};
+
+/**
+ * ### .closeTo(expected, delta)
+ *
+ * Asserts that the target is equal `expected`, to within a +/- `delta` range.
+ *
+ * expect(1.5).to.be.closeTo(1, 0.5);
+ *
+ * @name closeTo
+ * @param {Number} expected
+ * @param {Number} delta
+ * @api public
+ */
+
+Assertion.prototype.closeTo = function (expected, delta) {
+ var obj = flag(this, 'object');
+ this.assert(
+ (obj - delta === expected) || (obj + delta === expected)
+ , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
+ , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta);
+
+ return this;
+};
+
+/*!
+ * Aliases.
+ */
+
+(function alias(name, as){
+ Assertion.prototype[as] = Assertion.prototype[name];
+ return alias;
+})
+('equal', 'eq')
+('above', 'gt')
+('below', 'lt')
+('length', 'lengthOf')
+('keys', 'key')
+('ownProperty', 'haveOwnProperty')
+('above', 'greaterThan')
+('below', 'lessThan')
+('Throw', 'throws')
+('Throw', 'throw')
+('instanceOf', 'instanceof');
+
+}); // module: assertion.js
+
+require.register("browser/error.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+module.exports = AssertionError;
+
+function AssertionError (options) {
+ options = options || {};
+ this.message = options.message;
+ this.actual = options.actual;
+ this.expected = options.expected;
+ this.operator = options.operator;
+
+ if (options.stackStartFunction && Error.captureStackTrace) {
+ var stackStartFunction = options.stackStartFunction;
+ Error.captureStackTrace(this, stackStartFunction);
+ }
+}
+
+AssertionError.prototype = Object.create(Error.prototype);
+AssertionError.prototype.name = 'AssertionError';
+AssertionError.prototype.constructor = AssertionError;
+
+AssertionError.prototype.toString = function() {
+ return this.message;
+};
+
+}); // module: browser/error.js
+
+require.register("chai.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+var used = []
+ , exports = module.exports = {};
+
+/*!
+ * Chai version
+ */
+
+exports.version = '1.0.4';
+
+/*!
+ * Primary `Assertion` prototype
+ */
+
+exports.Assertion = require('./assertion');
+
+/*!
+ * Assertion Error
+ */
+
+exports.AssertionError = require('./browser/error');
+
+/*!
+ * Utils for plugins (not exported)
+ */
+
+var util = require('./utils');
+
+/**
+ * # .use(function)
+ *
+ * Provides a way to extend the internals of Chai
+ *
+ * @param {Function}
+ * @returns {this} for chaining
+ * @api public
+ */
+
+exports.use = function (fn) {
+ if (!~used.indexOf(fn)) {
+ fn(this, util);
+ used.push(fn);
+ }
+
+ return this;
+};
+
+/*!
+ * Expect interface
+ */
+
+var expect = require('./interface/expect');
+exports.use(expect);
+
+/*!
+ * Should interface
+ */
+
+var should = require('./interface/should');
+exports.use(should);
+
+/*!
+ * Assert interface
+ */
+
+var assert = require('./interface/assert');
+exports.use(assert);
+
+}); // module: chai.js
+
+require.register("interface/assert.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+
+module.exports = function (chai, util) {
+
+ /*!
+ * Chai dependencies.
+ */
+
+ var Assertion = chai.Assertion
+ , flag = util.flag;
+
+ /*!
+ * Module export.
+ */
+
+ /**
+ * ### assert(expression, message)
+ *
+ * Write your own test expressions.
+ *
+ * assert('foo' !== 'bar', 'foo is not bar');
+ * assert(Array.isArray([]), 'empty arrays are arrays');
+ *
+ * @param {Mixed} expression to test for truthiness
+ * @param {String} message to display on error
+ * @name assert
+ * @api public
+ */
+
+ var assert = chai.assert = function (express, errmsg) {
+ var test = new Assertion(null);
+ test.assert(
+ express
+ , errmsg
+ , '[ negation message unavailable ]'
+ );
+ };
+
+ /**
+ * ### .fail(actual, expected, [message], [operator])
+ *
+ * Throw a failure. Node.js `assert` module-compatible.
+ *
+ * @name fail
+ * @param {Mixed} actual
+ * @param {Mixed} expected
+ * @param {String} message
+ * @param {String} operator
+ * @api public
+ */
+
+ assert.fail = function (actual, expected, message, operator) {
+ throw new chai.AssertionError({
+ actual: actual
+ , expected: expected
+ , message: message
+ , operator: operator
+ , stackStartFunction: assert.fail
+ });
+ };
+
+ /**
+ * ### .ok(object, [message])
+ *
+ * Asserts that `object` is truthy.
+ *
+ * assert.ok('everything', 'everything is ok');
+ * assert.ok(false, 'this will fail');
+ *
+ * @name ok
+ * @param {Mixed} object to test
+ * @param {String} message
+ * @api public
+ */
+
+ assert.ok = function (val, msg) {
+ new Assertion(val, msg).is.ok;
+ };
+
+ /**
+ * ### .equal(actual, expected, [message])
+ *
+ * Asserts non-strict equality (`==`) of `actual` and `expected`.
+ *
+ * assert.equal(3, '3', '== coerces values to strings');
+ *
+ * @name equal
+ * @param {Mixed} actual
+ * @param {Mixed} expected
+ * @param {String} message
+ * @api public
+ */
+
+ assert.equal = function (act, exp, msg) {
+ var test = new Assertion(act, msg);
+
+ test.assert(
+ exp == flag(test, 'object')
+ , 'expected #{this} to equal #{exp}'
+ , 'expected #{this} to not equal #{act}'
+ , exp
+ , act
+ );
+ };
+
+ /**
+ * ### .notEqual(actual, expected, [message])
+ *
+ * Asserts non-strict inequality (`!=`) of `actual` and `expected`.
+ *
+ * assert.notEqual(3, 4, 'these numbers are not equal');
+ *
+ * @name notEqual
+ * @param {Mixed} actual
+ * @param {Mixed} expected
+ * @param {String} message
+ * @api public
+ */
+
+ assert.notEqual = function (act, exp, msg) {
+ var test = new Assertion(act, msg);
+
+ test.assert(
+ exp != flag(test, 'object')
+ , 'expected #{this} to not equal #{exp}'
+ , 'expected #{this} to equal #{act}'
+ , exp
+ , act
+ );
+ };
+
+ /**
+ * ### .strictEqual(actual, expected, [message])
+ *
+ * Asserts strict equality (`===`) of `actual` and `expected`.
+ *
+ * assert.strictEqual(true, true, 'these booleans are strictly equal');
+ *
+ * @name strictEqual
+ * @param {Mixed} actual
+ * @param {Mixed} expected
+ * @param {String} message
+ * @api public
+ */
+
+ assert.strictEqual = function<