From 0019bdbef3331bbf20f0b794e3e5c1f1f6677d79 Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Sun, 1 Sep 2013 07:54:36 -0400 Subject: [PATCH] Begin framework comparison. --- angular/.bowerrc | 3 + angular/.editorconfig | 21 + angular/.gitattributes | 1 + angular/.gitignore | 5 + angular/.jshintrc | 24 + angular/.travis.yml | 7 + angular/Gruntfile.js | 390 ++ angular/app/.buildignore | 1 + angular/app/.htaccess | 543 ++ angular/app/404.html | 157 + angular/app/favicon.ico | Bin 0 -> 4286 bytes .../app/images/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes angular/app/images/glyphicons-halflings.png | Bin 0 -> 12727 bytes angular/app/index.html | 61 + angular/app/robots.txt | 3 + angular/app/scripts/app.js | 13 + angular/app/scripts/controllers/main.js | 10 + angular/app/styles/main.sass | 11 + angular/app/views/main.html | 8 + angular/bower.json | 16 + angular/karma-e2e.conf.js | 54 + angular/karma.conf.js | 52 + angular/package.json | 49 + angular/test/.jshintrc | 35 + angular/test/runner.html | 10 + angular/test/spec/controllers/main.js | 22 + ember/.bowerrc | 3 + ember/.editorconfig | 21 + ember/.gitattributes | 1 + ember/.gitignore | 6 + ember/.jshintrc | 24 + ember/Gruntfile.js | 373 ++ ember/app/index.html | 43 + ember/app/scripts/app.js | 9 + .../controllers/file_edit_controller.js | 8 + .../scripts/controllers/files_controller.js | 4 + ember/app/scripts/models/file_model.js | 42 + ember/app/scripts/router.js | 11 + ember/app/scripts/routes/application_route.js | 7 + ember/app/scripts/routes/file_edit_route.js | 6 + ember/app/scripts/routes/file_route.js | 6 + ember/app/scripts/routes/files_route.js | 6 + ember/app/scripts/store.js | 3 + .../scripts/views/bound_text_field_view.js | 9 + ember/app/scripts/views/file_edit_view.js | 3 + ember/app/scripts/views/file_view.js | 3 + ember/app/scripts/views/files_view.js | 3 + ember/app/styles/style.scss | 6 + ember/app/templates/application.hbs | 30 + ember/app/templates/file.hbs | 18 + ember/app/templates/file_edit.hbs | 18 + ember/app/templates/files.hbs | 9 + ember/app/templates/index.hbs | 3 + ember/bower.json | 11 + ember/package.json | 34 + ember/test/index.html | 23 + ember/test/lib/chai.js | 3809 ++++++++++++ ember/test/lib/expect.js | 12 + ember/test/lib/mocha/mocha.css | 231 + ember/test/lib/mocha/mocha.js | 5340 +++++++++++++++++ ember/test/spec/test.js | 11 + Gruntfile.js => jquery-spaghetti/Gruntfile.js | 0 README.md => jquery-spaghetti/README.md | 0 {app => jquery-spaghetti/app}/README.md | 0 {app => jquery-spaghetti/app}/crypto.js | 0 {app => jquery-spaghetti/app}/dom.js | 0 {app => jquery-spaghetti/app}/downloader.js | 0 {app => jquery-spaghetti/app}/formatters.js | 0 {app => jquery-spaghetti/app}/shared.js | 0 {app => jquery-spaghetti/app}/uploader.js | 0 .../app}/views/DownloadView.js | 0 .../app}/views/FooterView.js | 0 .../app}/views/MainView.js | 0 .../app}/views/UploadView.js | 0 {app => jquery-spaghetti/app}/xhrWorker.js | 0 .../css}/bootstrap.min.css | 0 {css => jquery-spaghetti/css}/style.css | 0 {css => jquery-spaghetti/css}/style.sass | 0 favicon.ico => jquery-spaghetti/favicon.ico | Bin .../fonts}/glyphicons-halflings-regular.eot | Bin .../fonts}/glyphicons-halflings-regular.svg | 0 .../fonts}/glyphicons-halflings-regular.ttf | Bin .../fonts}/glyphicons-halflings-regular.woff | Bin .../img}/ajax-loader-pacman-inverse.gif | Bin .../img}/ajax-loader-pacman.gif | Bin {img => jquery-spaghetti/img}/bg-texture.png | Bin {img => jquery-spaghetti/img}/bx_loader.gif | Bin {img => jquery-spaghetti/img}/controls.png | Bin jquery-spaghetti/img/download.png | Bin 0 -> 38393 bytes .../img}/people/anthony_weiner.jpg | Bin .../img}/people/brett_favre.jpg | Bin .../img}/people/facepalm.jpg | Bin .../img}/people/julian_assange.jpg | Bin .../img}/people/petraeus.jpg | Bin {img => jquery-spaghetti/img}/tsecret.png | Bin .../includes}/footer.jade | 0 .../includes}/head.jade | 0 index.jade => jquery-spaghetti/index.jade | 0 package.json => jquery-spaghetti/package.json | 0 .../vendor}/BrowserDetect.js | 0 .../vendor}/bootstrap-modal.js | 0 .../vendor}/cryptoJS/components/aes-min.js | 0 .../vendor}/cryptoJS/components/aes.js | 0 .../cryptoJS/components/cipher-core-min.js | 0 .../cryptoJS/components/cipher-core.js | 0 .../vendor}/cryptoJS/components/core-min.js | 0 .../vendor}/cryptoJS/components/core.js | 0 .../cryptoJS/components/enc-base64-min.js | 0 .../vendor}/cryptoJS/components/enc-base64.js | 0 .../cryptoJS/components/enc-utf16-min.js | 0 .../vendor}/cryptoJS/components/enc-utf16.js | 0 .../vendor}/cryptoJS/components/evpkdf-min.js | 0 .../vendor}/cryptoJS/components/evpkdf.js | 0 .../vendor}/cryptoJS/components/hmac-min.js | 0 .../vendor}/cryptoJS/components/hmac.js | 0 .../vendor}/cryptoJS/components/md5-min.js | 0 .../vendor}/cryptoJS/components/md5.js | 0 .../cryptoJS/components/mode-cfb-min.js | 0 .../vendor}/cryptoJS/components/mode-cfb.js | 0 .../cryptoJS/components/mode-ctr-min.js | 0 .../vendor}/cryptoJS/components/mode-ctr.js | 0 .../cryptoJS/components/mode-ecb-min.js | 0 .../vendor}/cryptoJS/components/mode-ecb.js | 0 .../cryptoJS/components/mode-ofb-min.js | 0 .../vendor}/cryptoJS/components/mode-ofb.js | 0 .../cryptoJS/components/pad-ansix923-min.js | 0 .../cryptoJS/components/pad-ansix923.js | 0 .../cryptoJS/components/pad-iso10126-min.js | 0 .../cryptoJS/components/pad-iso10126.js | 0 .../cryptoJS/components/pad-iso97971-min.js | 0 .../cryptoJS/components/pad-iso97971.js | 0 .../cryptoJS/components/pad-nopadding-min.js | 0 .../cryptoJS/components/pad-nopadding.js | 0 .../components/pad-zeropadding-min.js | 0 .../cryptoJS/components/pad-zeropadding.js | 0 .../vendor}/cryptoJS/components/pbkdf2-min.js | 0 .../vendor}/cryptoJS/components/pbkdf2.js | 0 .../vendor}/cryptoJS/components/rabbit-min.js | 0 .../vendor}/cryptoJS/components/rabbit.js | 0 .../vendor}/cryptoJS/components/rc4-min.js | 0 .../vendor}/cryptoJS/components/rc4.js | 0 .../vendor}/cryptoJS/components/sha1-min.js | 0 .../vendor}/cryptoJS/components/sha1.js | 0 .../vendor}/cryptoJS/components/sha224-min.js | 0 .../vendor}/cryptoJS/components/sha224.js | 0 .../vendor}/cryptoJS/components/sha256-min.js | 0 .../vendor}/cryptoJS/components/sha256.js | 0 .../vendor}/cryptoJS/components/sha384-min.js | 0 .../vendor}/cryptoJS/components/sha384.js | 0 .../vendor}/cryptoJS/components/sha512-min.js | 0 .../vendor}/cryptoJS/components/sha512.js | 0 .../cryptoJS/components/tripledes-min.js | 0 .../vendor}/cryptoJS/components/tripledes.js | 0 .../cryptoJS/components/x64-core-min.js | 0 .../vendor}/cryptoJS/components/x64-core.js | 0 .../vendor}/cryptoJS/rollups/aes.js | 0 .../vendor}/cryptoJS/rollups/hmac-md5.js | 0 .../vendor}/cryptoJS/rollups/hmac-sha1.js | 0 .../vendor}/cryptoJS/rollups/hmac-sha224.js | 0 .../vendor}/cryptoJS/rollups/hmac-sha256.js | 0 .../vendor}/cryptoJS/rollups/hmac-sha384.js | 0 .../vendor}/cryptoJS/rollups/hmac-sha512.js | 0 .../vendor}/cryptoJS/rollups/md5.js | 0 .../vendor}/cryptoJS/rollups/pbkdf2.js | 0 .../vendor}/cryptoJS/rollups/rabbit.js | 0 .../vendor}/cryptoJS/rollups/rc4.js | 0 .../vendor}/cryptoJS/rollups/sha1.js | 0 .../vendor}/cryptoJS/rollups/sha224.js | 0 .../vendor}/cryptoJS/rollups/sha256.js | 0 .../vendor}/cryptoJS/rollups/sha384.js | 0 .../vendor}/cryptoJS/rollups/sha512.js | 0 .../vendor}/cryptoJS/rollups/tripledes.js | 0 {vendor => jquery-spaghetti/vendor}/jquery.js | 0 {vendor => jquery-spaghetti/vendor}/lodash.js | 0 {vendor => jquery-spaghetti/vendor}/lzw.js | 0 175 files changed, 11642 insertions(+) create mode 100644 angular/.bowerrc create mode 100644 angular/.editorconfig create mode 100644 angular/.gitattributes create mode 100644 angular/.gitignore create mode 100644 angular/.jshintrc create mode 100644 angular/.travis.yml create mode 100644 angular/Gruntfile.js create mode 100644 angular/app/.buildignore create mode 100644 angular/app/.htaccess create mode 100644 angular/app/404.html create mode 100644 angular/app/favicon.ico create mode 100644 angular/app/images/glyphicons-halflings-white.png create mode 100644 angular/app/images/glyphicons-halflings.png create mode 100644 angular/app/index.html create mode 100644 angular/app/robots.txt create mode 100644 angular/app/scripts/app.js create mode 100644 angular/app/scripts/controllers/main.js create mode 100644 angular/app/styles/main.sass create mode 100644 angular/app/views/main.html create mode 100644 angular/bower.json create mode 100644 angular/karma-e2e.conf.js create mode 100644 angular/karma.conf.js create mode 100644 angular/package.json create mode 100644 angular/test/.jshintrc create mode 100644 angular/test/runner.html create mode 100644 angular/test/spec/controllers/main.js create mode 100644 ember/.bowerrc create mode 100644 ember/.editorconfig create mode 100644 ember/.gitattributes create mode 100644 ember/.gitignore create mode 100644 ember/.jshintrc create mode 100644 ember/Gruntfile.js create mode 100644 ember/app/index.html create mode 100755 ember/app/scripts/app.js create mode 100644 ember/app/scripts/controllers/file_edit_controller.js create mode 100644 ember/app/scripts/controllers/files_controller.js create mode 100644 ember/app/scripts/models/file_model.js create mode 100644 ember/app/scripts/router.js create mode 100644 ember/app/scripts/routes/application_route.js create mode 100644 ember/app/scripts/routes/file_edit_route.js create mode 100644 ember/app/scripts/routes/file_route.js create mode 100644 ember/app/scripts/routes/files_route.js create mode 100644 ember/app/scripts/store.js create mode 100644 ember/app/scripts/views/bound_text_field_view.js create mode 100644 ember/app/scripts/views/file_edit_view.js create mode 100644 ember/app/scripts/views/file_view.js create mode 100644 ember/app/scripts/views/files_view.js create mode 100644 ember/app/styles/style.scss create mode 100644 ember/app/templates/application.hbs create mode 100644 ember/app/templates/file.hbs create mode 100644 ember/app/templates/file_edit.hbs create mode 100644 ember/app/templates/files.hbs create mode 100644 ember/app/templates/index.hbs create mode 100644 ember/bower.json create mode 100644 ember/package.json create mode 100644 ember/test/index.html create mode 100755 ember/test/lib/chai.js create mode 100755 ember/test/lib/expect.js create mode 100755 ember/test/lib/mocha/mocha.css create mode 100755 ember/test/lib/mocha/mocha.js create mode 100644 ember/test/spec/test.js rename Gruntfile.js => jquery-spaghetti/Gruntfile.js (100%) rename README.md => jquery-spaghetti/README.md (100%) rename {app => jquery-spaghetti/app}/README.md (100%) rename {app => jquery-spaghetti/app}/crypto.js (100%) rename {app => jquery-spaghetti/app}/dom.js (100%) rename {app => jquery-spaghetti/app}/downloader.js (100%) rename {app => jquery-spaghetti/app}/formatters.js (100%) rename {app => jquery-spaghetti/app}/shared.js (100%) rename {app => jquery-spaghetti/app}/uploader.js (100%) rename {app => jquery-spaghetti/app}/views/DownloadView.js (100%) rename {app => jquery-spaghetti/app}/views/FooterView.js (100%) rename {app => jquery-spaghetti/app}/views/MainView.js (100%) rename {app => jquery-spaghetti/app}/views/UploadView.js (100%) rename {app => jquery-spaghetti/app}/xhrWorker.js (100%) rename {css => jquery-spaghetti/css}/bootstrap.min.css (100%) rename {css => jquery-spaghetti/css}/style.css (100%) rename {css => jquery-spaghetti/css}/style.sass (100%) rename favicon.ico => jquery-spaghetti/favicon.ico (100%) rename {fonts => jquery-spaghetti/fonts}/glyphicons-halflings-regular.eot (100%) rename {fonts => jquery-spaghetti/fonts}/glyphicons-halflings-regular.svg (100%) rename {fonts => jquery-spaghetti/fonts}/glyphicons-halflings-regular.ttf (100%) rename {fonts => jquery-spaghetti/fonts}/glyphicons-halflings-regular.woff (100%) rename {img => jquery-spaghetti/img}/ajax-loader-pacman-inverse.gif (100%) rename {img => jquery-spaghetti/img}/ajax-loader-pacman.gif (100%) rename {img => jquery-spaghetti/img}/bg-texture.png (100%) rename {img => jquery-spaghetti/img}/bx_loader.gif (100%) rename {img => jquery-spaghetti/img}/controls.png (100%) create mode 100644 jquery-spaghetti/img/download.png rename {img => jquery-spaghetti/img}/people/anthony_weiner.jpg (100%) rename {img => jquery-spaghetti/img}/people/brett_favre.jpg (100%) rename {img => jquery-spaghetti/img}/people/facepalm.jpg (100%) rename {img => jquery-spaghetti/img}/people/julian_assange.jpg (100%) rename {img => jquery-spaghetti/img}/people/petraeus.jpg (100%) rename {img => jquery-spaghetti/img}/tsecret.png (100%) rename {includes => jquery-spaghetti/includes}/footer.jade (100%) rename {includes => jquery-spaghetti/includes}/head.jade (100%) rename index.jade => jquery-spaghetti/index.jade (100%) rename package.json => jquery-spaghetti/package.json (100%) rename {vendor => jquery-spaghetti/vendor}/BrowserDetect.js (100%) rename {vendor => jquery-spaghetti/vendor}/bootstrap-modal.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/aes-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/aes.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/cipher-core-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/cipher-core.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/core-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/core.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/enc-base64-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/enc-base64.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/enc-utf16-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/enc-utf16.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/evpkdf-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/evpkdf.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/hmac-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/hmac.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/md5-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/md5.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-cfb-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-cfb.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-ctr-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-ctr.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-ecb-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-ecb.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-ofb-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/mode-ofb.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-ansix923-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-ansix923.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-iso10126-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-iso10126.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-iso97971-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-iso97971.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-nopadding-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-nopadding.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-zeropadding-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pad-zeropadding.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pbkdf2-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/pbkdf2.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/rabbit-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/rabbit.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/rc4-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/rc4.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha1-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha1.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha224-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha224.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha256-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha256.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha384-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha384.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha512-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/sha512.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/tripledes-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/tripledes.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/x64-core-min.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/components/x64-core.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/aes.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/hmac-md5.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/hmac-sha1.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/hmac-sha224.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/hmac-sha256.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/hmac-sha384.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/hmac-sha512.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/md5.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/pbkdf2.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/rabbit.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/rc4.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/sha1.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/sha224.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/sha256.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/sha384.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/sha512.js (100%) rename {vendor => jquery-spaghetti/vendor}/cryptoJS/rollups/tripledes.js (100%) rename {vendor => jquery-spaghetti/vendor}/jquery.js (100%) rename {vendor => jquery-spaghetti/vendor}/lodash.js (100%) rename {vendor => jquery-spaghetti/vendor}/lzw.js (100%) diff --git a/angular/.bowerrc b/angular/.bowerrc new file mode 100644 index 0000000..ba0accc --- /dev/null +++ b/angular/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "app/bower_components" +} diff --git a/angular/.editorconfig b/angular/.editorconfig new file mode 100644 index 0000000..c2cdfb8 --- /dev/null +++ b/angular/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 2 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/angular/.gitattributes b/angular/.gitattributes new file mode 100644 index 0000000..2125666 --- /dev/null +++ b/angular/.gitattributes @@ -0,0 +1 @@ +* text=auto \ No newline at end of file diff --git a/angular/.gitignore b/angular/.gitignore new file mode 100644 index 0000000..7911b28 --- /dev/null +++ b/angular/.gitignore @@ -0,0 +1,5 @@ +node_modules +dist +.tmp +.sass-cache +app/bower_components diff --git a/angular/.jshintrc b/angular/.jshintrc new file mode 100644 index 0000000..40377ba --- /dev/null +++ b/angular/.jshintrc @@ -0,0 +1,24 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": true, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "globals": { + "angular": false + } +} diff --git a/angular/.travis.yml b/angular/.travis.yml new file mode 100644 index 0000000..83f4e22 --- /dev/null +++ b/angular/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - '0.8' + - '0.10' +before_script: + - 'npm install -g bower grunt-cli' + - 'bower install' diff --git a/angular/Gruntfile.js b/angular/Gruntfile.js new file mode 100644 index 0000000..91f4a3e --- /dev/null +++ b/angular/Gruntfile.js @@ -0,0 +1,390 @@ +// Generated on 2013-08-25 using generator-angular 0.4.0 +'use strict'; +var LIVERELOAD_PORT = 35729; +var lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT }); +var mountFolder = function (connect, dir) { + return connect.static(require('path').resolve(dir)); +}; + +// # Globbing +// for performance reasons we're only matching one level down: +// 'test/spec/{,*/}*.js' +// use this if you want to recursively match all subfolders: +// 'test/spec/**/*.js' + +module.exports = function (grunt) { + require('load-grunt-tasks')(grunt); + require('time-grunt')(grunt); + + // configurable paths + var yeomanConfig = { + app: 'app', + dist: 'dist' + }; + + try { + yeomanConfig.app = require('./bower.json').appPath || yeomanConfig.app; + } catch (e) {} + + grunt.initConfig({ + yeoman: yeomanConfig, + watch: { + coffee: { + files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'], + tasks: ['coffee:dist'] + }, + coffeeTest: { + files: ['test/spec/{,*/}*.coffee'], + tasks: ['coffee:test'] + }, + compass: { + files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], + tasks: ['compass:server', 'autoprefixer'] + }, + styles: { + files: ['<%= yeoman.app %>/styles/{,*/}*.css'], + tasks: ['copy:styles', 'autoprefixer'] + }, + livereload: { + options: { + livereload: LIVERELOAD_PORT + }, + files: [ + '<%= yeoman.app %>/{,*/}*.html', + '.tmp/styles/{,*/}*.css', + '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js', + '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' + ] + } + }, + autoprefixer: { + options: ['last 1 version'], + dist: { + files: [{ + expand: true, + cwd: '.tmp/styles/', + src: '{,*/}*.css', + dest: '.tmp/styles/' + }] + } + }, + connect: { + options: { + port: 9000, + // Change this to '0.0.0.0' to access the server from outside. + hostname: 'localhost' + }, + livereload: { + options: { + middleware: function (connect) { + return [ + lrSnippet, + mountFolder(connect, '.tmp'), + mountFolder(connect, yeomanConfig.app) + ]; + } + } + }, + test: { + options: { + middleware: function (connect) { + return [ + mountFolder(connect, '.tmp'), + mountFolder(connect, 'test') + ]; + } + } + }, + dist: { + options: { + middleware: function (connect) { + return [ + mountFolder(connect, yeomanConfig.dist) + ]; + } + } + } + }, + open: { + server: { + url: 'http://localhost:<%= connect.options.port %>' + } + }, + clean: { + dist: { + files: [{ + dot: true, + src: [ + '.tmp', + '<%= yeoman.dist %>/*', + '!<%= yeoman.dist %>/.git*' + ] + }] + }, + server: '.tmp' + }, + jshint: { + options: { + jshintrc: '.jshintrc' + }, + all: [ + 'Gruntfile.js', + '<%= yeoman.app %>/scripts/{,*/}*.js' + ] + }, + coffee: { + options: { + sourceMap: true, + sourceRoot: '' + }, + dist: { + files: [{ + expand: true, + cwd: '<%= yeoman.app %>/scripts', + src: '{,*/}*.coffee', + dest: '.tmp/scripts', + ext: '.js' + }] + }, + test: { + files: [{ + expand: true, + cwd: 'test/spec', + src: '{,*/}*.coffee', + dest: '.tmp/spec', + ext: '.js' + }] + } + }, + compass: { + options: { + sassDir: '<%= yeoman.app %>/styles', + cssDir: '.tmp/styles', + generatedImagesDir: '.tmp/images/generated', + imagesDir: '<%= yeoman.app %>/images', + javascriptsDir: '<%= yeoman.app %>/scripts', + fontsDir: '<%= yeoman.app %>/styles/fonts', + importPath: '<%= yeoman.app %>/bower_components', + httpImagesPath: '/images', + httpGeneratedImagesPath: '/images/generated', + httpFontsPath: '/styles/fonts', + relativeAssets: false + }, + dist: {}, + server: { + options: { + debugInfo: true + } + } + }, + // not used since Uglify task does concat, + // but still available if needed + /*concat: { + dist: {} + },*/ + rev: { + dist: { + files: { + src: [ + '<%= yeoman.dist %>/scripts/{,*/}*.js', + '<%= yeoman.dist %>/styles/{,*/}*.css', + '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', + '<%= yeoman.dist %>/styles/fonts/*' + ] + } + } + }, + useminPrepare: { + html: '<%= yeoman.app %>/index.html', + options: { + dest: '<%= yeoman.dist %>' + } + }, + usemin: { + html: ['<%= yeoman.dist %>/{,*/}*.html'], + css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], + options: { + dirs: ['<%= yeoman.dist %>'] + } + }, + imagemin: { + dist: { + files: [{ + expand: true, + cwd: '<%= yeoman.app %>/images', + src: '{,*/}*.{png,jpg,jpeg}', + dest: '<%= yeoman.dist %>/images' + }] + } + }, + svgmin: { + dist: { + files: [{ + expand: true, + cwd: '<%= yeoman.app %>/images', + src: '{,*/}*.svg', + dest: '<%= yeoman.dist %>/images' + }] + } + }, + cssmin: { + // By default, your `index.html` will take care of + // minification. This option is pre-configured if you do not wish to use + // Usemin blocks. + // dist: { + // files: { + // '<%= yeoman.dist %>/styles/main.css': [ + // '.tmp/styles/{,*/}*.css', + // '<%= yeoman.app %>/styles/{,*/}*.css' + // ] + // } + // } + }, + htmlmin: { + dist: { + options: { + /*removeCommentsFromCDATA: true, + // https://github.com/yeoman/grunt-usemin/issues/44 + //collapseWhitespace: true, + collapseBooleanAttributes: true, + removeAttributeQuotes: true, + removeRedundantAttributes: true, + useShortDoctype: true, + removeEmptyAttributes: true, + removeOptionalTags: true*/ + }, + files: [{ + expand: true, + cwd: '<%= yeoman.app %>', + src: ['*.html', 'views/*.html'], + dest: '<%= yeoman.dist %>' + }] + } + }, + // Put files not handled in other tasks here + copy: { + dist: { + files: [{ + expand: true, + dot: true, + cwd: '<%= yeoman.app %>', + dest: '<%= yeoman.dist %>', + src: [ + '*.{ico,png,txt}', + '.htaccess', + 'bower_components/**/*', + 'images/{,*/}*.{gif,webp}', + 'styles/fonts/*' + ] + }, { + expand: true, + cwd: '.tmp/images', + dest: '<%= yeoman.dist %>/images', + src: [ + 'generated/*' + ] + }] + }, + styles: { + expand: true, + cwd: '<%= yeoman.app %>/styles', + dest: '.tmp/styles/', + src: '{,*/}*.css' + } + }, + concurrent: { + server: [ + 'coffee:dist', + 'compass:server', + 'copy:styles' + ], + test: [ + 'coffee', + 'compass', + 'copy:styles' + ], + dist: [ + 'coffee', + 'compass:dist', + 'copy:styles', + 'imagemin', + 'svgmin', + 'htmlmin' + ] + }, + karma: { + unit: { + configFile: 'karma.conf.js', + singleRun: true + } + }, + cdnify: { + dist: { + html: ['<%= yeoman.dist %>/*.html'] + } + }, + ngmin: { + dist: { + files: [{ + expand: true, + cwd: '<%= yeoman.dist %>/scripts', + src: '*.js', + dest: '<%= yeoman.dist %>/scripts' + }] + } + }, + uglify: { + dist: { + files: { + '<%= yeoman.dist %>/scripts/scripts.js': [ + '<%= yeoman.dist %>/scripts/scripts.js' + ] + } + } + } + }); + + grunt.registerTask('server', function (target) { + if (target === 'dist') { + return grunt.task.run(['build', 'open', 'connect:dist:keepalive']); + } + + grunt.task.run([ + 'clean:server', + 'concurrent:server', + 'autoprefixer', + 'connect:livereload', + 'open', + 'watch' + ]); + }); + + grunt.registerTask('test', [ + 'clean:server', + 'concurrent:test', + 'autoprefixer', + 'connect:test', + 'karma' + ]); + + grunt.registerTask('build', [ + 'clean:dist', + 'useminPrepare', + 'concurrent:dist', + 'autoprefixer', + 'concat', + 'copy:dist', + 'cdnify', + 'ngmin', + 'cssmin', + 'uglify', + 'rev', + 'usemin' + ]); + + grunt.registerTask('default', [ + 'jshint', + 'test', + 'build' + ]); +}; diff --git a/angular/app/.buildignore b/angular/app/.buildignore new file mode 100644 index 0000000..fc98b8e --- /dev/null +++ b/angular/app/.buildignore @@ -0,0 +1 @@ +*.coffee \ No newline at end of file diff --git a/angular/app/.htaccess b/angular/app/.htaccess new file mode 100644 index 0000000..cb84cb9 --- /dev/null +++ b/angular/app/.htaccess @@ -0,0 +1,543 @@ +# Apache Configuration File + +# (!) Using `.htaccess` files slows down Apache, therefore, if you have access +# to the main server config file (usually called `httpd.conf`), you should add +# this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. + +# ############################################################################## +# # CROSS-ORIGIN RESOURCE SHARING (CORS) # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Cross-domain AJAX requests | +# ------------------------------------------------------------------------------ + +# Enable cross-origin AJAX requests. +# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity +# http://enable-cors.org/ + +# +# Header set Access-Control-Allow-Origin "*" +# + +# ------------------------------------------------------------------------------ +# | CORS-enabled images | +# ------------------------------------------------------------------------------ + +# Send the CORS header for images when browsers request it. +# https://developer.mozilla.org/en/CORS_Enabled_Image +# http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html +# http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ + + + + + SetEnvIf Origin ":" IS_CORS + Header set Access-Control-Allow-Origin "*" env=IS_CORS + + + + +# ------------------------------------------------------------------------------ +# | Web fonts access | +# ------------------------------------------------------------------------------ + +# Allow access from all domains for web fonts + + + + Header set Access-Control-Allow-Origin "*" + + + + +# ############################################################################## +# # ERRORS # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | 404 error prevention for non-existing redirected folders | +# ------------------------------------------------------------------------------ + +# Prevent Apache from returning a 404 error for a rewrite if a directory +# with the same name does not exist. +# http://httpd.apache.org/docs/current/content-negotiation.html#multiviews +# http://www.webmasterworld.com/apache/3808792.htm + +Options -MultiViews + +# ------------------------------------------------------------------------------ +# | Custom error messages / pages | +# ------------------------------------------------------------------------------ + +# You can customize what Apache returns to the client in case of an error (see +# http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.: + +ErrorDocument 404 /404.html + + +# ############################################################################## +# # INTERNET EXPLORER # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Better website experience | +# ------------------------------------------------------------------------------ + +# Force IE to render pages in the highest available mode in the various +# cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf. + + + Header set X-UA-Compatible "IE=edge" + # `mod_headers` can't match based on the content-type, however, we only + # want to send this header for HTML pages and not for the other resources + + Header unset X-UA-Compatible + + + +# ------------------------------------------------------------------------------ +# | Cookie setting from iframes | +# ------------------------------------------------------------------------------ + +# Allow cookies to be set from iframes in IE. + +# +# Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" +# + +# ------------------------------------------------------------------------------ +# | Screen flicker | +# ------------------------------------------------------------------------------ + +# Stop screen flicker in IE on CSS rollovers (this only works in +# combination with the `ExpiresByType` directives for images from below). + +# BrowserMatch "MSIE" brokenvary=1 +# BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 +# BrowserMatch "Opera" !brokenvary +# SetEnvIf brokenvary 1 force-no-vary + + +# ############################################################################## +# # MIME TYPES AND ENCODING # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Proper MIME types for all files | +# ------------------------------------------------------------------------------ + + + + # Audio + AddType audio/mp4 m4a f4a f4b + AddType audio/ogg oga ogg + + # JavaScript + # Normalize to standard type (it's sniffed in IE anyways): + # http://tools.ietf.org/html/rfc4329#section-7.2 + AddType application/javascript js jsonp + AddType application/json json + + # Video + AddType video/mp4 mp4 m4v f4v f4p + AddType video/ogg ogv + AddType video/webm webm + AddType video/x-flv flv + + # Web fonts + AddType application/font-woff woff + AddType application/vnd.ms-fontobject eot + + # Browsers usually ignore the font MIME types and sniff the content, + # however, Chrome shows a warning if other MIME types are used for the + # following fonts. + AddType application/x-font-ttf ttc ttf + AddType font/opentype otf + + # Make SVGZ fonts work on iPad: + # https://twitter.com/FontSquirrel/status/14855840545 + AddType image/svg+xml svg svgz + AddEncoding gzip svgz + + # Other + AddType application/octet-stream safariextz + AddType application/x-chrome-extension crx + AddType application/x-opera-extension oex + AddType application/x-shockwave-flash swf + AddType application/x-web-app-manifest+json webapp + AddType application/x-xpinstall xpi + AddType application/xml atom rdf rss xml + AddType image/webp webp + AddType image/x-icon ico + AddType text/cache-manifest appcache manifest + AddType text/vtt vtt + AddType text/x-component htc + AddType text/x-vcard vcf + + + +# ------------------------------------------------------------------------------ +# | UTF-8 encoding | +# ------------------------------------------------------------------------------ + +# Use UTF-8 encoding for anything served as `text/html` or `text/plain`. +AddDefaultCharset utf-8 + +# Force UTF-8 for certain file formats. + + AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml + + + +# ############################################################################## +# # URL REWRITES # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Rewrite engine | +# ------------------------------------------------------------------------------ + +# Turning on the rewrite engine and enabling the `FollowSymLinks` option is +# necessary for the following directives to work. + +# If your web host doesn't allow the `FollowSymlinks` option, you may need to +# comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the +# performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks + +# Also, some cloud hosting services require `RewriteBase` to be set: +# http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site + + + Options +FollowSymlinks + # Options +SymLinksIfOwnerMatch + RewriteEngine On + # RewriteBase / + + +# ------------------------------------------------------------------------------ +# | Suppressing / Forcing the "www." at the beginning of URLs | +# ------------------------------------------------------------------------------ + +# The same content should never be available under two different URLs especially +# not with and without "www." at the beginning. This can cause SEO problems +# (duplicate content), therefore, you should choose one of the alternatives and +# redirect the other one. + +# By default option 1 (no "www.") is activated: +# http://no-www.org/faq.php?q=class_b + +# If you'd prefer to use option 2, just comment out all the lines from option 1 +# and uncomment the ones from option 2. + +# IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# Option 1: rewrite www.example.com → example.com + + + RewriteCond %{HTTPS} !=on + RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] + RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# Option 2: rewrite example.com → www.example.com + +# Be aware that the following might not be a good idea if you use "real" +# subdomains for certain parts of your website. + +# +# RewriteCond %{HTTPS} !=on +# RewriteCond %{HTTP_HOST} !^www\..+$ [NC] +# RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] +# + + +# ############################################################################## +# # SECURITY # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Content Security Policy (CSP) | +# ------------------------------------------------------------------------------ + +# You can mitigate the risk of cross-site scripting and other content-injection +# attacks by setting a Content Security Policy which whitelists trusted sources +# of content for your site. + +# The example header below allows ONLY scripts that are loaded from the current +# site's origin (no inline scripts, no CDN, etc). This almost certainly won't +# work as-is for your site! + +# To get all the details you'll need to craft a reasonable policy for your site, +# read: http://html5rocks.com/en/tutorials/security/content-security-policy (or +# see the specification: http://w3.org/TR/CSP). + +# +# Header set Content-Security-Policy "script-src 'self'; object-src 'self'" +# +# Header unset Content-Security-Policy +# +# + +# ------------------------------------------------------------------------------ +# | File access | +# ------------------------------------------------------------------------------ + +# Block access to directories without a default document. +# Usually you should leave this uncommented because you shouldn't allow anyone +# to surf through every directory on your server (which may includes rather +# private places like the CMS's directories). + + + Options -Indexes + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# Block access to hidden files and directories. +# This includes directories used by version control systems such as Git and SVN. + + + RewriteCond %{SCRIPT_FILENAME} -d [OR] + RewriteCond %{SCRIPT_FILENAME} -f + RewriteRule "(^|/)\." - [F] + + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# Block access to backup and source files. +# These files may be left by some text editors and can pose a great security +# danger when anyone has access to them. + + + Order allow,deny + Deny from all + Satisfy All + + +# ------------------------------------------------------------------------------ +# | Secure Sockets Layer (SSL) | +# ------------------------------------------------------------------------------ + +# Rewrite secure requests properly to prevent SSL certificate warnings, e.g.: +# prevent `https://www.example.com` when your certificate only allows +# `https://secure.example.com`. + +# +# RewriteCond %{SERVER_PORT} !^443 +# RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] +# + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +# Force client-side SSL redirection. + +# If a user types "example.com" in his browser, the above rule will redirect him +# to the secure version of the site. That still leaves a window of opportunity +# (the initial HTTP connection) for an attacker to downgrade or redirect the +# request. The following header ensures that browser will ONLY connect to your +# server via HTTPS, regardless of what the users type in the address bar. +# http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ + +# +# Header set Strict-Transport-Security max-age=16070400; +# + +# ------------------------------------------------------------------------------ +# | Server software information | +# ------------------------------------------------------------------------------ + +# Avoid displaying the exact Apache version number, the description of the +# generic OS-type and the information about Apache's compiled-in modules. + +# ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! + +# ServerTokens Prod + + +# ############################################################################## +# # WEB PERFORMANCE # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Compression | +# ------------------------------------------------------------------------------ + + + + # Force compression for mangled headers. + # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping + + + SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding + RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding + + + + # Compress all output labeled with one of the following MIME-types + # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` + # and can remove the `` and `` lines + # as `AddOutputFilterByType` is still in the core directives). + + AddOutputFilterByType DEFLATE application/atom+xml \ + application/javascript \ + application/json \ + application/rss+xml \ + application/vnd.ms-fontobject \ + application/x-font-ttf \ + application/x-web-app-manifest+json \ + application/xhtml+xml \ + application/xml \ + font/opentype \ + image/svg+xml \ + image/x-icon \ + text/css \ + text/html \ + text/plain \ + text/x-component \ + text/xml + + + + +# ------------------------------------------------------------------------------ +# | Content transformations | +# ------------------------------------------------------------------------------ + +# Prevent some of the mobile network providers from modifying the content of +# your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. + +# +# Header set Cache-Control "no-transform" +# + +# ------------------------------------------------------------------------------ +# | ETag removal | +# ------------------------------------------------------------------------------ + +# Since we're sending far-future expires headers (see below), ETags can +# be removed: http://developer.yahoo.com/performance/rules.html#etags. + +# `FileETag None` is not enough for every server. + + Header unset ETag + + +FileETag None + +# ------------------------------------------------------------------------------ +# | Expires headers (for better cache control) | +# ------------------------------------------------------------------------------ + +# The following expires headers are set pretty far in the future. If you don't +# control versioning with filename-based cache busting, consider lowering the +# cache time for resources like CSS and JS to something like 1 week. + + + + ExpiresActive on + ExpiresDefault "access plus 1 month" + + # CSS + ExpiresByType text/css "access plus 1 year" + + # Data interchange + ExpiresByType application/json "access plus 0 seconds" + ExpiresByType application/xml "access plus 0 seconds" + ExpiresByType text/xml "access plus 0 seconds" + + # Favicon (cannot be renamed!) + ExpiresByType image/x-icon "access plus 1 week" + + # HTML components (HTCs) + ExpiresByType text/x-component "access plus 1 month" + + # HTML + ExpiresByType text/html "access plus 0 seconds" + + # JavaScript + ExpiresByType application/javascript "access plus 1 year" + + # Manifest files + ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" + ExpiresByType text/cache-manifest "access plus 0 seconds" + + # Media + ExpiresByType audio/ogg "access plus 1 month" + ExpiresByType image/gif "access plus 1 month" + ExpiresByType image/jpeg "access plus 1 month" + ExpiresByType image/png "access plus 1 month" + ExpiresByType video/mp4 "access plus 1 month" + ExpiresByType video/ogg "access plus 1 month" + ExpiresByType video/webm "access plus 1 month" + + # Web feeds + ExpiresByType application/atom+xml "access plus 1 hour" + ExpiresByType application/rss+xml "access plus 1 hour" + + # Web fonts + ExpiresByType application/font-woff "access plus 1 month" + ExpiresByType application/vnd.ms-fontobject "access plus 1 month" + ExpiresByType application/x-font-ttf "access plus 1 month" + ExpiresByType font/opentype "access plus 1 month" + ExpiresByType image/svg+xml "access plus 1 month" + + + +# ------------------------------------------------------------------------------ +# | Filename-based cache busting | +# ------------------------------------------------------------------------------ + +# If you're not using a build process to manage your filename version revving, +# you might want to consider enabling the following directives to route all +# requests such as `/css/style.12345.css` to `/css/style.css`. + +# To understand why this is important and a better idea than `*.css?v231`, read: +# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring + +# +# RewriteCond %{REQUEST_FILENAME} !-f +# RewriteCond %{REQUEST_FILENAME} !-d +# RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] +# + +# ------------------------------------------------------------------------------ +# | File concatenation | +# ------------------------------------------------------------------------------ + +# Allow concatenation from within specific CSS and JS files, e.g.: +# Inside of `script.combined.js` you could have +# +# +# and they would be included into this single file. + +# +# +# Options +Includes +# AddOutputFilterByType INCLUDES application/javascript application/json +# SetOutputFilter INCLUDES +# +# +# Options +Includes +# AddOutputFilterByType INCLUDES text/css +# SetOutputFilter INCLUDES +# +# + +# ------------------------------------------------------------------------------ +# | Persistent connections | +# ------------------------------------------------------------------------------ + +# Allow multiple requests to be sent over the same TCP connection: +# http://httpd.apache.org/docs/current/en/mod/core.html#keepalive. + +# Enable if you serve a lot of static content but, be aware of the +# possible disadvantages! + +# +# Header set Connection Keep-Alive +# diff --git a/angular/app/404.html b/angular/app/404.html new file mode 100644 index 0000000..fdace4a --- /dev/null +++ b/angular/app/404.html @@ -0,0 +1,157 @@ + + + + + Page Not Found :( + + + +
+

Not found :(

+

Sorry, but the page you were trying to view does not exist.

+

It looks like this was the result of either:

+ + + +
+ + diff --git a/angular/app/favicon.ico b/angular/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..6527905307f19ba00762f9241f7eb535fa84a2f9 GIT binary patch literal 4286 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 B7G?kd literal 0 HcmV?d00001 diff --git a/angular/app/images/glyphicons-halflings.png b/angular/app/images/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5686e89076393550df2769b2624047525dd407 GIT binary patch literal 12727 zcma)jWmFX4)31ntf;31;DAEnmjdaH@2ofT_2uriHbeEI@OXn^f(%s!4xun1%ES(Fy zzW1Jc&->|r@0U6A;W=mK%$a9qp5JetNNr6ed|YbWCr_T>t0>FsK6!#M_fOA${_LN` zdKTUN^4Zq<`oMY0wqsTHmovv#r%dhb;-<{3W- z%vvkhS01Ma8K;_ z6XJ+7f!RKyFd=2Rs7C@!HG5s5uVNn~44#91e!mY0=yiy;HjDstMhboI!6yIm4GdxY zlWO^rdTr9cwKVt};r^7DZ^>~=42yBDyg-V+ur~UUDscUG%sgWZy7;BU#0Sz2>4A$a z<^-?&jC}KNjl=zTV-##`7Iu|eY*8+rt*7D0FEwv6vff!fYB$`(VW*OyGN)fbHL>m?!XiMnl8DroGy95i4@PxM3%R61 z5e4Wpg^J|#`&4=`5^|W8LWaqs>m3C0vP6E{yZTqzWNZ) zo?qVKw%!@7jWV?xo5jE}S~DnIffNB|rXWS{#m?pVYtew)sebrdu}Re8nT7Cd!$tV{p`UsFHrmV1M2^Ca zyU{wshlfB8X??2~Leb;9EHKb>pvd+#enZG3vN z(6)&ck^H6CHz1>^@XpkdmQjGt+Y(z0a20#Kv0${46M-+>6@bPOT$3zj zkTl(e}T? zS8+f)LOl~#mSn;PJNnzSdv*PISiU)aaxd9|T5~1^6pmSNv9M^$!pCVI2|RlhWc6R+ zc8rvskh%|la3wOg`)gROWMvoeatzCC1Ddttw=FK&jFvvj2@kmDyT5N|*KxCAd=$S}bc?uPl`>1=F#%3Sn1IWNxqG}k#Z_L) z4`!M4@-@@lY)k0+A7eX=O9$5({P1YV8p5wV5U0*t;=sbd%Kta;Vy5nN09Hq}t{M*v zShg~{HAQg@l)dRQE#Hp~U=SI-HsFT~VnhV@nHHAT47FRErGDv&pCsv5&6iiO%rosh@Oa43 zv*jY!Q6M@?HP2j<6eh6_kv95n^k~@3osZPCq?bUKuyHi!NWe4diq#6L^u;qcVSjW!F5eR-OTOuHL@x z7S{8Yl3TfsG-gh}DO@g1(pd}6&59>jp#mf_(PJF2*Lqu*+}(~6^#Nh9U#n+pnEVsk zKBbSj?I}GhYU9c*va9e{njC(MS@5?zVSjAp$L5^FJ6)PR_K@?V0i!2B!iP!&)s=o7 z+{Q&G>G6X(lz`4DHkb6v8XURfUpcgTCYOb|Z!gMEqU zu^H3=csRVF7O?QHQGH}!#`+t0%oS+LoS0HEm2ygtn|0OG+OS18TjBqFS8~?y;gioA zH7Kp$RrlkqB(Pybq#On>Gi*_Ku(%&f7qp)*`_~TtgW_;uC|VQs?^Mg2yoNAw2&IXo zXi$>H-&Xjjch)pRm6-57Bf4`z%)5d;iC#d0#+2DY&^Qszc`RUU;t=&-)GtnnPs8Y5 zw@<G@7xmUYDfHO5qLB;Z-@>kA!=s4(Q=2s;l zY%=IvETVVzuIR4l#C=PcO+jv9PGBsaP3mE56Uc__+uQkrW2LY})Io#=x{WZyan70J zaj?RN+h1%LT|_mmbGHwKiM(mkN_srgnEVsv+I-bAY&kgxo6*$t{#4OQfz>vRS7>g#>LrAv!te70$45Spo?EKYF8egt< zaCZk@+oX&TR`df9o_wYTnxRb#O{ueZoBLPv&>WRn0MOy%*PQ}K`Pi5iorvPdw!0I~I#V_UL1P`_vGgVE75AU{q)Mm00)luk zI3|^{9G5jQ=uPB!NwerHk|4S-hs?O%+PDd-zyN>By|b+zty;UMQps*uIg$rZEx9V( zz%(g;{vkqtke6WL!I>{azj(lBe1~v;R&Av48(mqhu3(DU0L{$b@y@tja~It1FM*7+ zG7uN`3jEr|L`7i_qOANY`baav-f|(A>;AsqgOkPwEXbBVCKm!o2v-tp1W4hweWnNO z_)FuiAAgwoQ%3yPr}A3w1=+;gsTWhK;!X=)DfuvI>8F+B@x8U}&)Ki9_K$zu$zhO? zvD*2lX4BJMGw=7GUg_i?7gm&zd~(n$Pz)+|Orno4N%H zw58uu+yf+q$lf&Vo&5gotzdx~$cL#M@UU5EMI!E0w+$vx0Kq=fA?0rVST~s`K((R# zy+Py#s~$ntIBYaa(?;;LRN2pFVmwpcW?N6=#Og;HqsH&8iTJ@pG3lohNFo2faT(Iq z?$qcI|Dbyn|6N+wFGNT1%cfGx>YU!jqa^@vd6;{ zrSH#DUM53-W`Z{JKdo^rXdeTC@sebp^7@k_9{*$s$r!GEuGR*NY}}@c|Iijp4FvS* zdwA)a!a5~0eNyYW5HYrR6+b;;Q?X7+kq>6BpZR%3gj}p3umOiTn-Vj69=-r#V zklhNy>=H*g0?i|jX;UUJs6Be82aYB;@pp15k)QAoP z0r{hMZjRp^CbhjUM}rkAhb@xdm4#A2lq zHmndW)PNU66kOI4)tkLqIN!$8KXK&CKi7W#o6z>3%}4eRn?OaN0Cet`+2DKBjimpp zJHL{4MeWSAD#b&D@zvZ*vn6++DD100uhRA3xo2iK)$FUkl*x(i;l9Deee*g+ENU|fA^R2PuIJ?bR4myiyo=rEA zWK?0#n{I08-es4h%-)dV)KNbhli0B)5{hPyS9r_EoIF^gtr3e7+!NsJ{?=}-AE$=AQM#+4ODIarl0T_)3)lW>!N`BBE; zUX;=!AB_eb8>4)2S!wtNCGvl`yF{wa&7xFQ{8L=mkM?N4U|E>DJ8L+BzXoxcK2?f& zehYr!1TB%Z-pFaN708X$zW}QFxbm9yW|8;NL~WNuZ42mOaQDN9j0|CKr?e+$#M@8f zV27u-h&8WVSCLyi=xgRMdxvB6cv}G6{y7?871=L9uxD8>(W5&T*+`z2IV5MFSJ1Q( zC)kexDv9~_YZIdib5W>ypQ)G=Q}EZKS}F{5B{^(++3SY z@eD6p??nrDFYsUKx2 z#h{v;dvy|6yXS+`fcHnjaPfkmDrWS(+W?QDnF~i=hFMOd_)%pLse%S-O6Y^?g8|Ob zBYi_Qtcd#69~i|S42PYkpU=~tUzuvDOuoCy0~m_s?M0^foTVSS)yf{|ft$aAz9l?jqa?fk-zPF0X1=d5P-cKbx1?8Aq zG85$Ps>qA&bp9g!XV6NLT|lDeolN=HCov&3KLaDApA@aa!PKnXdd~|yUVNe^qc z#?hMR7F7u$trQ1=~hEaK^uXVv@>Gs?Kg51aYBJv0o}}7x$VO`^=zICe=wYw ztiKtkJu#NRRHwjr55+hdC9v#$b4?lp9>w4IBC8Smjy|-c4??b^rsr;}>F(HYEK){=%#S3yzK@mljdlZ9 z_^d`+Y{&i-dK$sWP82v;)Kpr0#Bk1G- zYV*v{T|oy;{@j93J@hrRc+i=9Y_#r}=_p0`t6)^AuzBE*vvJkMqy=vwU=P4`V$AoqVVL)bWgy#{IDu^CLAAp;_-twc`)lLherpJMvSoTv+1D{6L(TT4(gRi1CKvfebJ9B5 zn8){af&@A>EiViZR(fdR0UK5lW(}0+B>Dx`P?#6vldN??At4&Fkq*D>vqsn~>pj-j z-rvN2?b@;|Aco+hloV0@fK;k11Q-E38EkEsL|coRaz^Gu6}oPR1vE&vPE?_5kh41A zRkS9Zx2JW9XZtRrJAEWx4>o_kov|(LT-gu#&>w-L`}dQK3z0&`^Va9eD|70&Z3QgT zVJo`E)#E91_-oY{Us1jZ>czdD)&pAWOI;V8%&hxbn)qYx)>?*P{E4z@ zJM=huoI9KXz9ik9TTG|C$`z}e2I~s$1m4k3hA8N8>Q>)(ktIX2GJ`A~-8l4)mSbzv zBkPgDyH_~x4hsE&av5tbp)J*l%ZX(fYr0cn+*S2!My-uuD`k~};W4(s>wmOfQ)=v{ z;<~?Fn{sN}IPDvoB(9TUiAM!u)1?;E+R8SR%@mnU2+Rb_E08!!!ntk9YKHgq}9gOluVQ*5FZV43sC=Z!W_mt4ZzFn}<(VKb*#p4zZtr=J+Q< z07f!M(=R3l1S_Sc5n;L{Jv`A@B~e6}g5~jt+!b%@(~tV&CAa$(+;u+3R7>@Zc|y&KAbD16DVKirP<=U--sXDy(ypy-wjmrt72 zh@p;Oc2BJhFg9H>IeT`@*=%lTqdmwgvo)wt0} z7z3P22M+sXO0;ZV#rQ?-B~awIdmH1Yyr>$OKg5>c4%zx-r1-o#g8>#rNz&o z7wpxVtJ6yWwbsI$g3ox7ux!7?9faR1z@qTZd+I)&q#lM`m&z@fPuByAy9e<8x*{xX zwf*7gdY=Z^xcEitH$x}%f(#ax6|s9-ne~1MwL%g|?JL=WhXl@!*vZaiErnNyFu+vD zlY}0Rd+DKKv*}>((!H8hFJ#4i<>rtueel;QLEIAY}ES*y59fm29~D+>u3+ z-rGlKhdGKBHGC<^TkVV_pe>1@oy$9*>CVsFDx5@J<&;eTU8+m!tY3jy-^t;DtD79T z>k2z84=h%2R6v%c3Z$NQGoY_T=YKw}Vm9*a$Ytr>q7u`Y@`rv0N+l#FiD6KcqoAI_ zJ0Ts1x+*CSZA9Vt(gz*yrjSr$Uggf8s!}DeaL_E%fcA&@39YBJkt8SDcw@KcScc9# zl`9_w%L#o}9vaf~yp3ZDp;l38LGUe>ZElx_G+4K=-Kq+kgrI(|#TXg!*pN|BiLd3g z(ha0v-v1>m9@Xbxd3P%=DaL6n5GG#64RJ`r4Y2-XBa}|Tc{DnFv-RyWnr($a^_RoJ z%2*zOl>6OrXwuWV$PnWM4Q)x&xPR8d2JHVf4u)gn!#B)h-3*LY3~;q_>1jX3<>e^p zCxr`QU5&_zbT8jEG!Fv)BNQ8d8A1Pe14 zd|3@f`<7<&vTYw$p>UGWE zZRBV`pC4 zCEh}S5Py8|Fz&edCqAobnc>RrpM(?UmMreypQC4vD9TUN??}FP2ZCGcoOSZeGiM~% zJP7@lJP6+<`XbTFP)kqqT#PIxBS-Di`0lOPXlILoJiTCirPDmSx`dV4IYasknfqaU z8A2_l6HOF-dj5L;%? zJ^&}>u6{Ixu@3+I(?L4mad67$&fPnY3utwd=X_IN!Jo0#X)?J|T{8PQH#XX|ynZF; zypOqJJgzE~w+_O8)VtPxq4XVc&h$W_9bu#blfzd%Ds-7{c6{iQo9q4l*WCDHMe&RI z{fpz%$t}J1s*)4+s068DFurBN`WB|L18vq72hmNP4-PyUlj-r4;Jmq)b$W9>f+$Y& zHT3g}x$dw|)TCtCQm*Jqt+g!y;wf|?Vecv3%0oComk#f9AcT&~SSCaKPT z*rTg`_TO;N=3O$sbVPRSmv!!0x98V<(mHe3N%4@V#vNUt7Jibyi}fJS>*b$NDqZaA zj$W$hM5-9O0&YH@!ljfSeOxxFji-Rnhnc%J5@fr-cfk0vcClyE0rtVUH{>z5zu1^B z;C0K!U;U_rc8*5`OQh;ZymZdomQ`ov0#g_=S2R;yZsiZSfrl2N^WRxU3G%`?s}_AU zX*mhvmVP}ka9n|>Zvfms(ZEWg2T9C+8Ggtyx5UX;WPAPnL^mTr>0+oT(&wtl&Kv{pi`n- zPQ|2Qp+d4{q}Z6%-CMl$U!gUJc%^C=7c&$dIj8CTtDjd-&Gm|NvD$Y;Q73Jy3v>Ci zx}NR)wT;38YQ|nLRobb{UoIL`CK>zZ4?7z>5y3Ggu{V`Mo>Yu(9Xc;^quj7U9N20b z`z!@nVEd~^|BLQdfT2Ek%zJT`9NMH@g=# zF^x6#cOUyuKB*W$f~4KsR-Gj(Xtylgi$VmAF-KdF)#+=xLTNuXKXGS!vhWLcx0!lN zSab%Y#Z#(@3|nZds3*Y~3Ds)VXdb2%15+AptReOm-i4S(^$1^4zJF4y%=FMQ@eJ`0 zfNE2`(-otMKAFx{`&5%av^+bLOkM&KvDzO|3`A%R8EuX6B#XQXnn6m&DeY^SDcbws zx{D`gHRbT6oSu9yX*9iK9sHN5hJO|}_>Y0fa7M-gfv(Evm zZaslqgiU^i&|iDjJ(JkVg+gm&&qN*A(5uJm6L|88m=nbOSu_--e!R1jsVYBlzbUg2 zi(R%3d?b1X#w)1@44vy$O#{e5(L3in$Th_W10=nj)k>0TB`&RzK}ThxMV8;6MH_9cayB0JSH`iqeU_SR)-K464?3F8 zCY9lRQ&m`^~yqX@6IBZpIu&|vgy(qlsDc{jPxG(TTlY<|q2WFe+`shqK}kv@sp zX!t4YTXbur3go*G!BKy-hQgvaskz_;v5gIVW(A^~>V)~uy^GAz8tYmd(2VBAI7DCKxE)(ST?O&Xg)T-cI}SY>%9zuZch{9YaBC| z&kJm5dtOsbR(G>(*Snjhk5?Bz{Ffs`5`0L*5) z&Ql=)n74dNM(X5H`Y5TOEl7)%Cqv}^TIK|LYFcIe4~Wu(gYOH@MSaYgykLLaYN81m z{3T6RQqlUD$S34%M!u}8ASIj2sa?6~YG0&s@n_!^2XJB#&KZ}bi~VHdKR7{hQ(Thv zQT%TaT9fcH6OFsUAVF9%6EW~WyZggXjFN{X+4NcnfNE^qdJE_{cJPFUi;?T_@uv8p z9b(ZokXCeT6rL>nKN^=-GrR@FNp(K?}KZXEG4KNU91ST6hf`g~M=utOGYpFxv zPBZ=}wTk!X9>44&`7n4Ab$&kHAh+k`kGuAf|6HD<@?o8WL27uQNcxdo46n>wDNj{G zlhrxu^g!BoZ{q_*SXpY$-zK*&?(fEj$*d8tyNwUDi<6tG7cfc^m7CEMN=NzGl1vP4 z4`V}|E(4;w{p$Az7B5m?jcM@i|H>L87TnahPtICrSJ0=`NfQ?tf419ej#-qKGl1HI zE_QW%Qh}XHU8EIGtXpZ-_+w1-G&&Ee8v%Bq)HTqL}_u(;_9-uoU6Z=N)W5XM+nO%`DEMta<}&4 zd3BBUI0&t6`CL9KuGYC!+w#lwW2q@ncPypHP576+q=u_v&c@HCg$3~RqSy`sr8yTCU<3KG73E1T_hku#Ab&9Y`eGq+lkAj~u~IFasX ztO65)vc~SNE>oL)RCD+YP_QnDwpX01;8;-sxi~72IESQP(XDS+3=n@rNoef8ns*9% zcQaMN&MWON4#sY;jZLzRg=xfn&<6Gk5;`=mv?*$$P|X#t3TM?w7rkaj=nI`b26IbA z$6j9ke7Xw2QWRa3{P`G0<%~bLSbDG6OCSZ7;h5YneVZv&)~1p-oSIz0k-_sz{5sbU zX8GscO@BVKXCXoJc=?84x-5tC7)_dgU#>((npL@Wi=a#2!|AzIO2sD)(hF{pd{N=e zgAEi6-tNY%rfv4U$Sjcc^@}?KN$^_^nc1jUOKDYk<^OrP;r|W`hmU4GK-sTLslkFN zNg+{IEG5IPiUy^wGZg|(t786?B9(Bh)?=&k(C4E^G0$KooGk`5`lkQr`3b!D&|P3u z_KwCP@WE$vaCf}L%FR+ia#0zNBS61j!P>Tzrz8FDjgT&<#NxR-W1benqF_mHGnV=% zF4ONk>qO0tJv(6|#7>nmQ(f@r6-w#Er@^4n?Wm0iS&J$ek8&&l9Oow&1+&pf_qH&C zq~f#8w@8UfMc)IK`^WdENx@o@#{!aTwPC_eh38W*Qa1CNG+n$#I5v-rvPERS{^FHv zl2d+nx@Cpe>aXtRu_jazzQ=-dG%Kopy#=VCdfow7^K_l@Hl=MGeVLY1J?i~?rC>s1 z?b}&|mUdoyx5?NS)tX#na&vBWEhJ9@9te1S7xVTx<2@-;P?%YdRb1D$ zW?%>Bi43SD-B+kJ=6BC+QD@*&=S!><`iO^xSayLtrLi0L&EPLEW+?^{NAFeLgMre= znTtx5Zy;!q$#loK-VC#x2FiCO90gst66Bo1ML=F`VX6kyU4#HESAY4Of4X`QMHdO( zFXBhzWCvaTGAkitlb}hrzr(7d_XYL5&0sq3{MOA11ma|)wf0*OoA`5HCXPn3bcr-b z5e1|~bm-WP80E~CBJJ|Hg+B zJpUB%-zoiA#gG}2ejDu({uT75N-5~dj$%64(wYb6UWQLidhJVlYzuRQ;tpe^4 z9D>$}X$&0Gf=vbdy&3Q>e*ZjPV=@WoSA**Qm4{sLB1EyEEpUbh5*W~VtGDBFi}3K` z7lke&Jaod@-yJg3p}+W&c;b9>7S6-^Y z*^}dmbLT4ckf!`EN`UL!6sT+}g}DG~VD4>8b=TwRMZnjoO%t2aG@zHG*56v)z27!c zSoz-SW|`&e*=?2b{-N(&(%cqIo6d#^-0d9E*FIW4@NaMO=(6#kHlle!-YeZ90~%`V zz9@95pX1Tl(?w7#hx{gYd6@Uq*4{r96TiP$%5$9q6>&AjqwNNB#W&JC`lLLb>1(;u z5BsR4hhw>7dX)|j;?O#sjeO>SVaVp?X zNyqoygA&}0+1;-nVb41|diu2m>jjUQFHuceb6n!+ z?JbizMk2llq8Bq8UX#ChZi$Gkakj)eoSZ&Y5{Y+L{CZ?Vr1{A*A}3e&?{_bc{R>n1 z^)I}EtLN{^sD5^xD_OfemCd5qBDV!x$e9sikLVvA>H_eWmhlUv)k}xtIPq-BUGp0; zS5Ci4K#G6Jv7boUj7XAZJUF03a65J^Q4)@R8&Ye5iga(W;x%w*;zc4Ypk|G8i^es+ zEB0tu z=BULK^KgvYp}Fs*JNvL`bNLrhi?}PuQclXPd>&lr%B0qhRGAwSb-JD$jG-uj{bL`E z(sU|;d|cngP0Mm9M359n!?3G&rjxSGO9W+1_6_wX%WYjHL~# zSH+=z_DC+95TITuuKmCHAu-xP5Uazrm|4KoRrY;5yG)Zo;IDO5_L)w>bv1sE@(S#9N z_G`7y!&s3-*0YQt;~QQk`pLXOH+M^)zdItY5pb@(C2*_TLM)3O+jNXG>SUaA*eFc+ zQeugKrJnG!=4JhdiTsV&yzp5)ax9fL-oMh>`Y+0wwss=a=Ik@1Rv*~IJcpAH+G@Ts z?n(Gu3k6uHbk4XHFwxO3haxnn3bKQ`SQ6hJy0W)Y>5S08y|ZLLQ0>1=%f#>qr|3%> z5{b=8PbKzoh^*$EmBFmrDzSJ^yK?KKPU0;^DIw7xyCaFy76u8OB*bT6^V67I zeE$1}&+|5X`(Xg9uDD9&8~560kgEmk%ol#_96?irxP3um{j)_HurU_VjBa9gC}T%{ zJ6#`l^TaGO6ejd7*#~Jfw{P9rIqQx>*Yu?fx=%hfLO}BLyk9@AR4GsKkWJ??3Q#_Y z8EwRWdRP``d`waVAO@iP3PX9B6Wg4mv{kneX*BQ*nvUZp4 zKtn@Ixy$T`H~4g6R?(We!dyU6(_~M=LSFBYsjuOTGAKun3;VgEsbSHhf#O`lZ_Hs} p*sotk5vws>m0aN+ukQjBGJG*o!GA3OeaLvCqM#{XA@@1xzW~_Fw&VZ+ literal 0 HcmV?d00001 diff --git a/angular/app/index.html b/angular/app/index.html new file mode 100644 index 0000000..33e5fb6 --- /dev/null +++ b/angular/app/index.html @@ -0,0 +1,61 @@ + + + + + + + + + Securesha.re: Private, Self-Destructing, Single-Use File Sharing + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/angular/app/robots.txt b/angular/app/robots.txt new file mode 100644 index 0000000..9417495 --- /dev/null +++ b/angular/app/robots.txt @@ -0,0 +1,3 @@ +# robotstxt.org + +User-agent: * diff --git a/angular/app/scripts/app.js b/angular/app/scripts/app.js new file mode 100644 index 0000000..06c0bc6 --- /dev/null +++ b/angular/app/scripts/app.js @@ -0,0 +1,13 @@ +'use strict'; + +angular.module('secureshareApp', []) + .config(function ($routeProvider) { + $routeProvider + .when('/', { + templateUrl: 'views/main.html', + controller: 'MainCtrl' + }) + .otherwise({ + redirectTo: '/' + }); + }); diff --git a/angular/app/scripts/controllers/main.js b/angular/app/scripts/controllers/main.js new file mode 100644 index 0000000..8b4dc37 --- /dev/null +++ b/angular/app/scripts/controllers/main.js @@ -0,0 +1,10 @@ +'use strict'; + +angular.module('secureshareApp') + .controller('MainCtrl', function ($scope) { + $scope.awesomeThings = [ + 'HTML5 Boilerplate', + 'AngularJS', + 'Karma' + ]; + }); diff --git a/angular/app/styles/main.sass b/angular/app/styles/main.sass new file mode 100644 index 0000000..255aea8 --- /dev/null +++ b/angular/app/styles/main.sass @@ -0,0 +1,11 @@ +$iconSpritePath: "../images/glyphicons-halflings.png" +$iconWhiteSpritePath: "../images/glyphicons-halflings-white.png" + +@import "bootstrap-sass/lib/bootstrap" + +.jumbotron + position: absolute + left: 50% + top: 50% + margin: -232px 0 0 -220px + width: 500px diff --git a/angular/app/views/main.html b/angular/app/views/main.html new file mode 100644 index 0000000..ecf2413 --- /dev/null +++ b/angular/app/views/main.html @@ -0,0 +1,8 @@ +
+

'Allo, 'Allo!

+

You now have installed:

+
    +
  • {{thing}}
  • +
+

Enjoy coding! - Yeoman

+
\ No newline at end of file diff --git a/angular/bower.json b/angular/bower.json new file mode 100644 index 0000000..1f448dd --- /dev/null +++ b/angular/bower.json @@ -0,0 +1,16 @@ +{ + "name": "secureshare", + "version": "0.0.0", + "dependencies": { + "angular": "~1.0.7", + "json3": "~3.2.4", + "jquery": "~1.9.1", + "bootstrap-sass": "~3.0.0", + "es5-shim": "~2.0.8", + "angular-resource": "~1.0.7" + }, + "devDependencies": { + "angular-mocks": "~1.0.7", + "angular-scenario": "~1.0.7" + } +} diff --git a/angular/karma-e2e.conf.js b/angular/karma-e2e.conf.js new file mode 100644 index 0000000..fa01484 --- /dev/null +++ b/angular/karma-e2e.conf.js @@ -0,0 +1,54 @@ +// Karma configuration +// http://karma-runner.github.io/0.10/config/configuration-file.html + +module.exports = function(config) { + config.set({ + // base path, that will be used to resolve files and exclude + basePath: '', + + // testing framework to use (jasmine/mocha/qunit/...) + frameworks: ['ng-scenario'], + + // list of files / patterns to load in the browser + files: [ + 'test/e2e/**/*.js' + ], + + // list of files / patterns to exclude + exclude: [], + + // web server port + port: 8080, + + // level of logging + // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera + // - Safari (only Mac) + // - PhantomJS + // - IE (only Windows) + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, it capture browsers, run tests and exit + singleRun: false + + // Uncomment the following lines if you are using grunt's server to run the tests + // proxies: { + // '/': 'http://localhost:9000/' + // }, + // URL root prevent conflicts with the site root + // urlRoot: '_karma_' + }); +}; diff --git a/angular/karma.conf.js b/angular/karma.conf.js new file mode 100644 index 0000000..fae04e3 --- /dev/null +++ b/angular/karma.conf.js @@ -0,0 +1,52 @@ +// Karma configuration +// http://karma-runner.github.io/0.10/config/configuration-file.html + +module.exports = function(config) { + config.set({ + // base path, that will be used to resolve files and exclude + basePath: '', + + // testing framework to use (jasmine/mocha/qunit/...) + frameworks: ['jasmine'], + + // list of files / patterns to load in the browser + files: [ + 'app/bower_components/angular/angular.js', + 'app/bower_components/angular-mocks/angular-mocks.js', + 'app/scripts/*.js', + 'app/scripts/**/*.js', + 'test/mock/**/*.js', + 'test/spec/**/*.js' + ], + + // list of files / patterns to exclude + exclude: [], + + // web server port + port: 8080, + + // level of logging + // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera + // - Safari (only Mac) + // - PhantomJS + // - IE (only Windows) + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, it capture browsers, run tests and exit + singleRun: false + }); +}; diff --git a/angular/package.json b/angular/package.json new file mode 100644 index 0000000..e469962 --- /dev/null +++ b/angular/package.json @@ -0,0 +1,49 @@ +{ + "name": "secureshare", + "version": "0.0.0", + "dependencies": {}, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-contrib-copy": "~0.4.1", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-coffee": "~0.7.0", + "grunt-contrib-uglify": "~0.2.0", + "grunt-contrib-compass": "~0.5.0", + "grunt-contrib-jshint": "~0.6.0", + "grunt-contrib-cssmin": "~0.6.0", + "grunt-contrib-connect": "~0.3.0", + "grunt-contrib-clean": "~0.5.0", + "grunt-contrib-htmlmin": "~0.1.3", + "grunt-contrib-imagemin": "~0.2.0", + "grunt-contrib-watch": "~0.5.2", + "grunt-autoprefixer": "~0.2.0", + "grunt-usemin": "~0.1.11", + "grunt-svgmin": "~0.2.0", + "grunt-rev": "~0.1.0", + "grunt-open": "~0.2.0", + "grunt-concurrent": "~0.3.0", + "load-grunt-tasks": "~0.1.0", + "connect-livereload": "~0.2.0", + "grunt-google-cdn": "~0.2.0", + "grunt-ngmin": "~0.0.2", + "time-grunt": "~0.1.0", + "karma-ng-scenario": "~0.1.0", + "grunt-karma": "~0.6.1", + "karma-script-launcher": "~0.1.0", + "karma-firefox-launcher": "~0.1.0", + "karma-chrome-launcher": "~0.1.0", + "karma-html2js-preprocessor": "~0.1.0", + "karma-jasmine": "~0.1.2", + "karma-requirejs": "~0.1.0", + "karma-coffee-preprocessor": "~0.1.0", + "karma-phantomjs-launcher": "~0.1.0", + "karma": "~0.10.2", + "karma-ng-html2js-preprocessor": "~0.1.0" + }, + "engines": { + "node": ">=0.8.0" + }, + "scripts": { + "test": "grunt test" + } +} diff --git a/angular/test/.jshintrc b/angular/test/.jshintrc new file mode 100644 index 0000000..aa37e7a --- /dev/null +++ b/angular/test/.jshintrc @@ -0,0 +1,35 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": true, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "globals": { + "after": false, + "afterEach": false, + "angular": false, + "before": false, + "beforeEach": false, + "browser": false, + "describe": false, + "expect": false, + "inject": false, + "it": false, + "spyOn": false + } +} + diff --git a/angular/test/runner.html b/angular/test/runner.html new file mode 100644 index 0000000..f4a00a1 --- /dev/null +++ b/angular/test/runner.html @@ -0,0 +1,10 @@ + + + + End2end Test Runner + + + + + + \ No newline at end of file diff --git a/angular/test/spec/controllers/main.js b/angular/test/spec/controllers/main.js new file mode 100644 index 0000000..f587556 --- /dev/null +++ b/angular/test/spec/controllers/main.js @@ -0,0 +1,22 @@ +'use strict'; + +describe('Controller: MainCtrl', function () { + + // load the controller's module + beforeEach(module('secureshareApp')); + + var MainCtrl, + scope; + + // Initialize the controller and a mock scope + beforeEach(inject(function ($controller, $rootScope) { + scope = $rootScope.$new(); + MainCtrl = $controller('MainCtrl', { + $scope: scope + }); + })); + + it('should attach a list of awesomeThings to the scope', function () { + expect(scope.awesomeThings.length).toBe(3); + }); +}); diff --git a/ember/.bowerrc b/ember/.bowerrc new file mode 100644 index 0000000..ba0accc --- /dev/null +++ b/ember/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "app/bower_components" +} diff --git a/ember/.editorconfig b/ember/.editorconfig new file mode 100644 index 0000000..8a80734 --- /dev/null +++ b/ember/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 4 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/ember/.gitattributes b/ember/.gitattributes new file mode 100644 index 0000000..2125666 --- /dev/null +++ b/ember/.gitattributes @@ -0,0 +1 @@ +* text=auto \ No newline at end of file diff --git a/ember/.gitignore b/ember/.gitignore new file mode 100644 index 0000000..11c17af --- /dev/null +++ b/ember/.gitignore @@ -0,0 +1,6 @@ +node_modules +temp +dist +.sass-cache +.tmp +app/bower_components diff --git a/ember/.jshintrc b/ember/.jshintrc new file mode 100644 index 0000000..14a26cf --- /dev/null +++ b/ember/.jshintrc @@ -0,0 +1,24 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": false, + "curly": false, + "eqeqeq": true, + "eqnull": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "undef": true, + "strict": false, + "trailing": false, + "smarttabs": true, + "globals": { + "SecureShare": true, + "jQuery": true, + "Ember": true, + "Handlebars": true, + "DS": true + } +} diff --git a/ember/Gruntfile.js b/ember/Gruntfile.js new file mode 100644 index 0000000..683b604 --- /dev/null +++ b/ember/Gruntfile.js @@ -0,0 +1,373 @@ +// Generated on 2013-09-01 using generator-ember 0.6.2 +'use strict'; +var LIVERELOAD_PORT = 35729; +var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT}); +var mountFolder = function (connect, dir) { + return connect.static(require('path').resolve(dir)); +}; + +// # Globbing +// for performance reasons we're only matching one level down: +// 'test/spec/{,*/}*.js' +// use this if you want to match all subfolders: +// 'test/spec/**/*.js' + +module.exports = function (grunt) { + // show elapsed time at the end + require('time-grunt')(grunt); + // load all grunt tasks + require('load-grunt-tasks')(grunt); + + // configurable paths + var yeomanConfig = { + app: 'app', + dist: 'dist' + }; + + grunt.initConfig({ + yeoman: yeomanConfig, + watch: { + emberTemplates: { + files: '<%= yeoman.app %>/templates/**/*.hbs', + tasks: ['emberTemplates'] + }, + coffee: { + files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'], + tasks: ['coffee:dist'] + }, + coffeeTest: { + files: ['test/spec/{,*/}*.coffee'], + tasks: ['coffee:test'] + }, + compass: { + files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], + tasks: ['compass:server'] + }, + neuter: { + files: ['<%= yeoman.app %>/scripts/{,*/}*.js'], + tasks: ['neuter'] + }, + livereload: { + options: { + livereload: LIVERELOAD_PORT + }, + files: [ + '.tmp/scripts/*.js', + '<%= yeoman.app %>/*.html', + '{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css', + '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' + ] + } + }, + connect: { + options: { + port: 9000, + // change this to '0.0.0.0' to access the server from outside + hostname: 'localhost' + }, + livereload: { + options: { + middleware: function (connect) { + return [ + lrSnippet, + mountFolder(connect, '.tmp'), + mountFolder(connect, yeomanConfig.app) + ]; + } + } + }, + test: { + options: { + middleware: function (connect) { + return [ + mountFolder(connect, '.tmp'), + mountFolder(connect, 'test') + ]; + } + } + }, + dist: { + options: { + middleware: function (connect) { + return [ + mountFolder(connect, yeomanConfig.dist) + ]; + } + } + } + }, + open: { + server: { + path: 'http://localhost:<%= connect.options.port %>' + } + }, + clean: { + dist: { + files: [{ + dot: true, + src: [ + '.tmp', + '<%= yeoman.dist %>/*', + '!<%= yeoman.dist %>/.git*' + ] + }] + }, + server: '.tmp' + }, + jshint: { + options: { + jshintrc: '.jshintrc' + }, + all: [ + 'Gruntfile.js', + '<%= yeoman.app %>/scripts/{,*/}*.js', + '!<%= yeoman.app %>/scripts/vendor/*', + 'test/spec/{,*/}*.js' + ] + }, + mocha: { + all: { + options: { + run: true, + urls: ['http://localhost:<%= connect.options.port %>/index.html'] + } + } + }, + coffee: { + dist: { + files: [{ + expand: true, + cwd: '<%= yeoman.app %>/scripts', + src: '{,*/}*.coffee', + dest: '.tmp/scripts', + ext: '.js' + }] + }, + test: { + files: [{ + expand: true, + cwd: 'test/spec', + src: '{,*/}*.coffee', + dest: '.tmp/spec', + ext: '.js' + }] + } + }, + compass: { + options: { + sassDir: '<%= yeoman.app %>/styles', + cssDir: '.tmp/styles', + generatedImagesDir: '.tmp/images/generated', + imagesDir: '<%= yeoman.app %>/images', + javascriptsDir: '<%= yeoman.app %>/scripts', + fontsDir: '<%= yeoman.app %>/styles/fonts', + importPath: 'app/bower_components', + httpImagesPath: '/images', + httpGeneratedImagesPath: '/images/generated', + httpFontsPath: '/styles/fonts', + relativeAssets: false + }, + dist: {}, + server: { + options: { + debugInfo: true + } + } + }, + // not used since Uglify task does concat, + // but still available if needed + /*concat: { + dist: {} + },*/ + // not enabled since usemin task does concat and uglify + // check index.html to edit your build targets + // enable this task if you prefer defining your build targets here + /*uglify: { + dist: {} + },*/ + rev: { + dist: { + files: { + src: [ + '<%= yeoman.dist %>/scripts/{,*/}*.js', + '<%= yeoman.dist %>/styles/{,*/}*.css', + '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp}', + '<%= yeoman.dist %>/styles/fonts/*' + ] + } + } + }, + useminPrepare: { + html: '<%= yeoman.app %>/index.html', + options: { + dest: '<%= yeoman.dist %>' + } + }, + usemin: { + html: ['<%= yeoman.dist %>/{,*/}*.html'], + css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], + options: { + dirs: ['<%= yeoman.dist %>'] + } + }, + imagemin: { + dist: { + files: [{ + expand: true, + cwd: '<%= yeoman.app %>/images', + src: '{,*/}*.{png,jpg,jpeg}', + dest: '<%= yeoman.dist %>/images' + }] + } + }, + svgmin: { + dist: { + files: [{ + expand: true, + cwd: '<%= yeoman.app %>/images', + src: '{,*/}*.svg', + dest: '<%= yeoman.dist %>/images' + }] + } + }, + cssmin: { + dist: { + files: { + '<%= yeoman.dist %>/styles/main.css': [ + '.tmp/styles/{,*/}*.css', + '<%= yeoman.app %>/styles/{,*/}*.css' + ] + } + } + }, + htmlmin: { + dist: { + options: { + /*removeCommentsFromCDATA: true, + // https://github.com/yeoman/grunt-usemin/issues/44 + //collapseWhitespace: true, + collapseBooleanAttributes: true, + removeAttributeQuotes: true, + removeRedundantAttributes: true, + useShortDoctype: true, + removeEmptyAttributes: true, + removeOptionalTags: true*/ + }, + files: [{ + expand: true, + cwd: '<%= yeoman.app %>', + src: '*.html', + dest: '<%= yeoman.dist %>' + }] + } + }, + // Put files not handled in other tasks here + copy: { + dist: { + files: [{ + expand: true, + dot: true, + cwd: '<%= yeoman.app %>', + dest: '<%= yeoman.dist %>', + src: [ + '*.{ico,txt}', + '.htaccess', + 'images/{,*/}*.{webp,gif}', + 'styles/fonts/*' + ] + }] + } + }, + concurrent: { + server: [ + 'emberTemplates', + 'coffee:dist', + 'compass:server' + ], + test: [ + 'emberTemplates', + 'coffee', + 'compass' + ], + dist: [ + 'emberTemplates', + 'coffee', + 'compass:dist', + 'imagemin', + 'svgmin', + 'htmlmin' + ] + }, + karma: { + unit: { + configFile: 'karma.conf.js' + } + }, + emberTemplates: { + options: { + templateName: function (sourceFile) { + var templatePath = yeomanConfig.app + '/templates/'; + return sourceFile.replace(templatePath, ''); + } + }, + dist: { + files: { + '.tmp/scripts/compiled-templates.js': '<%= yeoman.app %>/templates/{,*/}*.hbs' + } + } + }, + neuter: { + app: { + options: { + filepathTransform: function (filepath) { + return 'app/' + filepath; + } + }, + src: '<%= yeoman.app %>/scripts/app.js', + dest: '.tmp/scripts/combined-scripts.js' + } + } + }); + + grunt.registerTask('server', function (target) { + if (target === 'dist') { + return grunt.task.run(['build', 'open', 'connect:dist:keepalive']); + } + + grunt.task.run([ + 'clean:server', + 'concurrent:server', + 'neuter:app', + 'connect:livereload', + 'open', + 'watch' + ]); + }); + + grunt.registerTask('test', [ + 'clean:server', + 'concurrent:test', + 'connect:test', + 'neuter:app', + 'mocha' + ]); + + grunt.registerTask('build', [ + 'clean:dist', + 'useminPrepare', + 'concurrent:dist', + 'neuter:app', + 'concat', + 'cssmin', + 'uglify', + 'copy', + 'rev', + 'usemin' + ]); + + grunt.registerTask('default', [ + 'jshint', + 'test', + 'build' + ]); +}; diff --git a/ember/app/index.html b/ember/app/index.html new file mode 100644 index 0000000..45476e2 --- /dev/null +++ b/ember/app/index.html @@ -0,0 +1,43 @@ + + + + + Yeoman Ember Starter Kit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ember/app/scripts/app.js b/ember/app/scripts/app.js new file mode 100755 index 0000000..1192d90 --- /dev/null +++ b/ember/app/scripts/app.js @@ -0,0 +1,9 @@ +var SecureShare = window.SecureShare = Ember.Application.create(); + +/* Order and include as you please. */ +require('scripts/controllers/*'); +require('scripts/store'); +require('scripts/models/*'); +require('scripts/routes/*'); +require('scripts/views/*'); +require('scripts/router'); diff --git a/ember/app/scripts/controllers/file_edit_controller.js b/ember/app/scripts/controllers/file_edit_controller.js new file mode 100644 index 0000000..6e5e815 --- /dev/null +++ b/ember/app/scripts/controllers/file_edit_controller.js @@ -0,0 +1,8 @@ +SecureShare.FileEditController = Ember.ObjectController.extend({ + save: function(){ + // we're cheating here that there's no commit() + // but the UI element is already bound to the model + this.transitionToRoute('user',this.get('model')); + } +}); + diff --git a/ember/app/scripts/controllers/files_controller.js b/ember/app/scripts/controllers/files_controller.js new file mode 100644 index 0000000..104eed3 --- /dev/null +++ b/ember/app/scripts/controllers/files_controller.js @@ -0,0 +1,4 @@ +SecureShare.FilesController = Ember.ObjectController.extend({ + // Implement your controller here. +}); + diff --git a/ember/app/scripts/models/file_model.js b/ember/app/scripts/models/file_model.js new file mode 100644 index 0000000..79f63b8 --- /dev/null +++ b/ember/app/scripts/models/file_model.js @@ -0,0 +1,42 @@ +SecureShare.File = DS.Model.extend({ + name: DS.attr('string'), + + contents: DS.attr('ArrayBuffer') +}); + +// probably should be mixed-in... +SecureShare.File.reopen({ + // certainly I'm duplicating something that exists elsewhere... + attributes: function(){ + var attrs = []; + var model = this; + $.each(Em.A(Ember.keys(this.get('data.attributes'))), function(idx, key){ + var pair = { key: key, value: model.get(key) }; + attrs.push(pair); + }); + return attrs; + }.property() +}); + +// delete below here if you do not want fixtures +SecureShare.File.FIXTURES = [ + + { + id: 0, + + name: 'foo', + + contents: 'foo' + + }, + + { + id: 1, + + name: 'foo', + + contents: 'foo' + + } + +]; diff --git a/ember/app/scripts/router.js b/ember/app/scripts/router.js new file mode 100644 index 0000000..f84cc10 --- /dev/null +++ b/ember/app/scripts/router.js @@ -0,0 +1,11 @@ +SecureShare.Router.map(function () { + + this.resource('file_edit'); + this.resource('file_edit', { path: '/file_edit/:file_edit_id' }); + this.resource('file_edit.edit', { path: '/file_edit/:file_edit_id/edit' }); + + this.resource('files'); + this.resource('file', { path: '/file/:file_id' }); + this.resource('file.edit', { path: '/file/:file_id/edit' }); + +}); diff --git a/ember/app/scripts/routes/application_route.js b/ember/app/scripts/routes/application_route.js new file mode 100644 index 0000000..a857f21 --- /dev/null +++ b/ember/app/scripts/routes/application_route.js @@ -0,0 +1,7 @@ +SecureShare.ApplicationRoute = Ember.Route.extend({ + // admittedly, this should be in IndexRoute and not in the + // top level ApplicationRoute; we're in transition... :-) + model: function () { + return ['red', 'yellow', 'blue']; + } +}); diff --git a/ember/app/scripts/routes/file_edit_route.js b/ember/app/scripts/routes/file_edit_route.js new file mode 100644 index 0000000..bf85658 --- /dev/null +++ b/ember/app/scripts/routes/file_edit_route.js @@ -0,0 +1,6 @@ +SecureShare.FileEditRoute = Ember.Route.extend({ + model: function(model) { + return SecureShare.File.find(model.file_id); + } +}); + diff --git a/ember/app/scripts/routes/file_route.js b/ember/app/scripts/routes/file_route.js new file mode 100644 index 0000000..32ea3b8 --- /dev/null +++ b/ember/app/scripts/routes/file_route.js @@ -0,0 +1,6 @@ +SecureShare.FileRoute = Ember.Route.extend({ + model: function(model) { + return SecureShare.File.find(model.file_id); + } +}); + diff --git a/ember/app/scripts/routes/files_route.js b/ember/app/scripts/routes/files_route.js new file mode 100644 index 0000000..280c755 --- /dev/null +++ b/ember/app/scripts/routes/files_route.js @@ -0,0 +1,6 @@ +SecureShare.FilesRoute = Ember.Route.extend({ + model: function() { + return SecureShare.File.find(); + } +}); + diff --git a/ember/app/scripts/store.js b/ember/app/scripts/store.js new file mode 100644 index 0000000..dd0a971 --- /dev/null +++ b/ember/app/scripts/store.js @@ -0,0 +1,3 @@ +SecureShare.Store = DS.Store.extend({ + adapter: DS.FixtureAdapter.create() +}); diff --git a/ember/app/scripts/views/bound_text_field_view.js b/ember/app/scripts/views/bound_text_field_view.js new file mode 100644 index 0000000..2085886 --- /dev/null +++ b/ember/app/scripts/views/bound_text_field_view.js @@ -0,0 +1,9 @@ +SecureShare.BoundTextFieldView = Ember.TextField.extend({ + valueBinding: 'content.value', + contentChanged: function() { + this.get('controller').get('model').set( + this.get('content').key, + this.get('content').value + ); // ugly, but gets the job done + }.observes('content.value') +}); diff --git a/ember/app/scripts/views/file_edit_view.js b/ember/app/scripts/views/file_edit_view.js new file mode 100644 index 0000000..83eddda --- /dev/null +++ b/ember/app/scripts/views/file_edit_view.js @@ -0,0 +1,3 @@ +SecureShare.FileEditView = Ember.View.extend({ + templateName: 'file_edit' +}); diff --git a/ember/app/scripts/views/file_view.js b/ember/app/scripts/views/file_view.js new file mode 100644 index 0000000..a3919b6 --- /dev/null +++ b/ember/app/scripts/views/file_view.js @@ -0,0 +1,3 @@ +SecureShare.FileView = Ember.View.extend({ + templateName: 'file' +}); diff --git a/ember/app/scripts/views/files_view.js b/ember/app/scripts/views/files_view.js new file mode 100644 index 0000000..4333044 --- /dev/null +++ b/ember/app/scripts/views/files_view.js @@ -0,0 +1,3 @@ +SecureShare.FilesView = Ember.View.extend({ + templateName: 'files' +}); diff --git a/ember/app/styles/style.scss b/ember/app/styles/style.scss new file mode 100644 index 0000000..ab1703c --- /dev/null +++ b/ember/app/styles/style.scss @@ -0,0 +1,6 @@ +@import "bootstrap-sass/lib/bootstrap"; + +/* Put your CSS here */ +html, body { + margin: 30px 0; +} diff --git a/ember/app/templates/application.hbs b/ember/app/templates/application.hbs new file mode 100644 index 0000000..36571b6 --- /dev/null +++ b/ember/app/templates/application.hbs @@ -0,0 +1,30 @@ +
+ +
+
+
+
+ +
+
+ {{outlet}} +
+
+
+
+
diff --git a/ember/app/templates/file.hbs b/ember/app/templates/file.hbs new file mode 100644 index 0000000..42cbc52 --- /dev/null +++ b/ember/app/templates/file.hbs @@ -0,0 +1,18 @@ +

File

+ + + {{#each model.attributes}} + + + + + {{/each}} +
+ {{this.key}}: + + {{this.value}} +
+ +{{#linkTo 'user.edit' model}}Change{{/linkTo}} + +{{outlet}} diff --git a/ember/app/templates/file_edit.hbs b/ember/app/templates/file_edit.hbs new file mode 100644 index 0000000..4b36143 --- /dev/null +++ b/ember/app/templates/file_edit.hbs @@ -0,0 +1,18 @@ +

File

+ + + {{#each model.attributes}} + + + + + {{/each}} +
+ {{this.key}}: + + {{view SecureShare.BoundTextFieldView contentBinding="this"}} +
+ + + +{{outlet}} diff --git a/ember/app/templates/files.hbs b/ember/app/templates/files.hbs new file mode 100644 index 0000000..d9b3e39 --- /dev/null +++ b/ember/app/templates/files.hbs @@ -0,0 +1,9 @@ +

Files

+ +
    + {{#each model}} +
  • {{#linkTo 'file' this}}{{this.id}}{{/linkTo}}
  • + {{/each}} +
+ +{{outlet}} diff --git a/ember/app/templates/index.hbs b/ember/app/templates/index.hbs new file mode 100644 index 0000000..ce54dae --- /dev/null +++ b/ember/app/templates/index.hbs @@ -0,0 +1,3 @@ +
+ Welcome to Yeoman and Ember.js! +
diff --git a/ember/bower.json b/ember/bower.json new file mode 100644 index 0000000..022a914 --- /dev/null +++ b/ember/bower.json @@ -0,0 +1,11 @@ +{ + "name": "securesha-re-ember", + "version": "0.0.0", + "dependencies": { + "jquery": "~1.9.1", + "bootstrap-sass": "~2.3.1" + }, + "devDependencies": { + "ember-mocha-adapter": "0.1.1" + } +} diff --git a/ember/package.json b/ember/package.json new file mode 100644 index 0000000..2c3321a --- /dev/null +++ b/ember/package.json @@ -0,0 +1,34 @@ +{ + "name": "securesha-re-ember", + "version": "0.0.0", + "dependencies": {}, + "devDependencies": { + "grunt": "~0.4.1", + "grunt-contrib-copy": "~0.4.1", + "grunt-contrib-concat": "~0.3.0", + "grunt-contrib-coffee": "~0.7.0", + "grunt-contrib-uglify": "~0.2.0", + "grunt-contrib-compass": "~0.5.0", + "grunt-contrib-jshint": "~0.6.3", + "grunt-contrib-cssmin": "~0.6.0", + "grunt-contrib-connect": "~0.3.0", + "grunt-contrib-clean": "~0.5.0", + "grunt-contrib-htmlmin": "~0.1.3", + "grunt-contrib-imagemin": "~0.2.0", + "grunt-contrib-watch": "~0.5.2", + "grunt-rev": "~0.1.0", + "grunt-usemin": "~0.1.12", + "grunt-mocha": "~0.4.1", + "grunt-open": "~0.2.0", + "grunt-svgmin": "~0.2.0", + "grunt-concurrent": "~0.3.0", + "load-grunt-tasks": "~0.1.0", + "connect-livereload": "~0.2.0", + "grunt-ember-templates": "0.4.7", + "time-grunt": "~0.1.1", + "grunt-neuter": "~0.5.0" + }, + "engines": { + "node": ">=0.8.0" + } +} diff --git a/ember/test/index.html b/ember/test/index.html new file mode 100644 index 0000000..d0f4d33 --- /dev/null +++ b/ember/test/index.html @@ -0,0 +1,23 @@ + + + + + Mocha Spec Runner + + + +
+ + + + + + + + + + + + + + diff --git a/ember/test/lib/chai.js b/ember/test/lib/chai.js new file mode 100755 index 0000000..88e1d25 --- /dev/null +++ b/ember/test/lib/chai.js @@ -0,0 +1,3809 @@ +!function (name, context, definition) { + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { + module.exports = definition(); + } else if (typeof define === 'function' && typeof define.amd === 'object') { + define(function () { + return definition(); + }); + } else { + context[name] = definition(); + } +}('chai', this, function () { + + 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.charAt(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.alias = function (from, to) { + var fn = require.modules[from]; + require.modules[to] = fn; + }; + + + require.register("chai.js", function(module, exports, require){ + /*! + * chai + * Copyright(c) 2011-2012 Jake Luer + * MIT Licensed + */ + + var used = [] + , exports = module.exports = {}; + + /*! + * Chai version + */ + + exports.version = '1.4.2'; + + /*! + * Primary `Assertion` prototype + */ + + exports.Assertion = require('./chai/assertion'); + + /*! + * Assertion Error + */ + + exports.AssertionError = require('./chai/error'); + + /*! + * Utils for plugins (not exported) + */ + + var util = require('./chai/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; + }; + + /*! + * Core Assertions + */ + + var core = require('./chai/core/assertions'); + exports.use(core); + + /*! + * Expect interface + */ + + var expect = require('./chai/interface/expect'); + exports.use(expect); + + /*! + * Should interface + */ + + var should = require('./chai/interface/should'); + exports.use(should); + + /*! + * Assert interface + */ + + var assert = require('./chai/interface/assert'); + exports.use(assert); + + }); // module: chai.js + + require.register("chai/assertion.js", function(module, exports, require){ + /*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2012 Jake Luer + * MIT Licensed + */ + + /*! + * Module dependencies. + */ + + var AssertionError = require('./error') + , 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, showDiff) { + var ok = util.test(this, arguments); + if (true !== showDiff) showDiff = false; + + if (!ok) { + var msg = util.getMessage(this, arguments) + , actual = util.getActual(this, arguments); + throw new AssertionError({ + message: msg + , actual: actual + , expected: expected + , stackStartFunction: (Assertion.includeStack) ? this.assert : flag(this, 'ssfi') + , showDiff: showDiff + }); + } + }; + + /*! + * ### ._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); + } + }); + + }); // module: chai/assertion.js + + require.register("chai/core/assertions.js", function(module, exports, require){ + /*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2012 Jake Luer + * MIT Licensed + */ + + module.exports = function (chai, _) { + var Assertion = chai.Assertion + , toString = Object.prototype.toString + , flag = _.flag; + + /** + * ### 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 + * - that + * - and + * - have + * - with + * - at + * - of + * + * @name language chains + * @api public + */ + + [ 'to', 'be', 'been' + , 'is', 'and', 'have' + , 'with', 'that', 'at' + , 'of' ].forEach(function (chain) { + Assertion.addProperty(chain, function () { + return this; + }); + }); + + /** + * ### .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 + */ + + Assertion.addProperty('not', function () { + flag(this, 'negate', 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 + */ + + Assertion.addProperty('deep', function () { + flag(this, 'deep', 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 + * @param {String} message _optional_ + * @api public + */ + + function an(type, msg) { + if (msg) flag(this, 'message', msg); + 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 + ); + } + + 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 + * @param {String} message _optional_ + * @api public + */ + + function includeChainingBehavior () { + flag(this, 'contains', true); + } + + function include (val, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + this.assert( + ~obj.indexOf(val) + , 'expected #{this} to include ' + _.inspect(val) + , 'expected #{this} to not include ' + _.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 + */ + + Assertion.addProperty('ok', function () { + this.assert( + flag(this, 'object') + , 'expected #{this} to be truthy' + , 'expected #{this} to be falsy'); + }); + + /** + * ### .true + * + * Asserts that the target is `true`. + * + * expect(true).to.be.true; + * expect(1).to.not.be.true; + * + * @name true + * @api public + */ + + Assertion.addProperty('true', function () { + this.assert( + true === flag(this, 'object') + , 'expected #{this} to be true' + , 'expected #{this} to be false' + , this.negate ? false : true + ); + }); + + /** + * ### .false + * + * Asserts that the target is `false`. + * + * expect(false).to.be.false; + * expect(0).to.not.be.false; + * + * @name false + * @api public + */ + + Assertion.addProperty('false', function () { + this.assert( + false === flag(this, 'object') + , 'expected #{this} to be false' + , 'expected #{this} to be true' + , this.negate ? true : false + ); + }); + + /** + * ### .null + * + * Asserts that the target is `null`. + * + * expect(null).to.be.null; + * expect(undefined).not.to.be.null; + * + * @name null + * @api public + */ + + Assertion.addProperty('null', function () { + this.assert( + null === flag(this, 'object') + , 'expected #{this} to be null' + , 'expected #{this} not to be null' + ); + }); + + /** + * ### .undefined + * + * Asserts that the target is `undefined`. + * + * expect(undefined).to.be.undefined; + * expect(null).to.not.be.undefined; + * + * @name undefined + * @api public + */ + + Assertion.addProperty('undefined', function () { + this.assert( + undefined === flag(this, 'object') + , 'expected #{this} to be undefined' + , 'expected #{this} not to be undefined' + ); + }); + + /** + * ### .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 + */ + + Assertion.addProperty('exist', function () { + this.assert( + null != flag(this, 'object') + , 'expected #{this} to exist' + , 'expected #{this} to not exist' + ); + }); + + + /** + * ### .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 + */ + + Assertion.addProperty('empty', 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' + ); + }); + + /** + * ### .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 + * @alias equals + * @alias eq + * @alias deep.equal + * @param {Mixed} value + * @param {String} message _optional_ + * @api public + */ + + function assertEqual (val, msg) { + if (msg) flag(this, 'message', msg); + 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 + , this._obj + , true + ); + } + } + + Assertion.addMethod('equal', assertEqual); + Assertion.addMethod('equals', assertEqual); + Assertion.addMethod('eq', assertEqual); + + /** + * ### .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 + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('eql', function (obj, msg) { + if (msg) flag(this, 'message', msg); + this.assert( + _.eql(obj, flag(this, 'object')) + , 'expected #{this} to deeply equal #{exp}' + , 'expected #{this} to not deeply equal #{exp}' + , obj + , this._obj + , true + ); + }); + + /** + * ### .above(value) + * + * Asserts that the target is greater than `value`. + * + * expect(10).to.be.above(5); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * + * @name above + * @alias gt + * @alias greaterThan + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertAbove (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len > n + , 'expected #{this} to have a length above #{exp} but got #{act}' + , 'expected #{this} to not have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj > n + , 'expected #{this} to be above ' + n + , 'expected #{this} to be at most ' + n + ); + } + } + + Assertion.addMethod('above', assertAbove); + Assertion.addMethod('gt', assertAbove); + Assertion.addMethod('greaterThan', assertAbove); + + /** + * ### .least(value) + * + * Asserts that the target is greater than or equal to `value`. + * + * expect(10).to.be.at.least(10); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.least(2); + * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); + * + * @name least + * @alias gte + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertLeast (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= n + , 'expected #{this} to have a length at least #{exp} but got #{act}' + , 'expected #{this} to not have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj >= n + , 'expected #{this} to be at least ' + n + , 'expected #{this} to be below ' + n + ); + } + } + + Assertion.addMethod('least', assertLeast); + Assertion.addMethod('gte', assertLeast); + + /** + * ### .below(value) + * + * Asserts that the target is less than `value`. + * + * expect(5).to.be.below(10); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * + * @name below + * @alias lt + * @alias lessThan + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertBelow (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len < n + , 'expected #{this} to have a length below #{exp} but got #{act}' + , 'expected #{this} to not have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj < n + , 'expected #{this} to be below ' + n + , 'expected #{this} to be at least ' + n + ); + } + } + + Assertion.addMethod('below', assertBelow); + Assertion.addMethod('lt', assertBelow); + Assertion.addMethod('lessThan', assertBelow); + + /** + * ### .most(value) + * + * Asserts that the target is less than or equal to `value`. + * + * expect(5).to.be.at.most(5); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.most(4); + * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); + * + * @name most + * @alias lte + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertMost (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len <= n + , 'expected #{this} to have a length at most #{exp} but got #{act}' + , 'expected #{this} to not have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj <= n + , 'expected #{this} to be at most ' + n + , 'expected #{this} to be above ' + n + ); + } + } + + Assertion.addMethod('most', assertMost); + Assertion.addMethod('lte', assertMost); + + /** + * ### .within(start, finish) + * + * Asserts that the target is within a range. + * + * expect(7).to.be.within(5,10); + * + * Can also be used in conjunction with `length` to + * assert a length range. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * @name within + * @param {Number} start lowerbound inclusive + * @param {Number} finish upperbound inclusive + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('within', function (start, finish, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , range = start + '..' + finish; + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= start && len <= finish + , 'expected #{this} to have a length within ' + range + , 'expected #{this} to not have a length within ' + range + ); + } else { + this.assert( + obj >= start && obj <= finish + , 'expected #{this} to be within ' + range + , 'expected #{this} to not be within ' + range + ); + } + }); + + /** + * ### .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 + * @param {String} message _optional_ + * @alias instanceOf + * @api public + */ + + function assertInstanceOf (constructor, msg) { + if (msg) flag(this, 'message', msg); + var name = _.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 + ); + }; + + Assertion.addMethod('instanceof', assertInstanceOf); + Assertion.addMethod('instanceOf', assertInstanceOf); + + /** + * ### .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'); + * + * // 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'); + * + * You can also use an array as the starting point of a `deep.property` + * assertion, or traverse nested arrays. + * + * var arr = [ + * [ 'chai', 'matcha', 'konacha' ] + * , [ { tea: 'chai' } + * , { tea: 'matcha' } + * , { tea: 'konacha' } ] + * ]; + * + * expect(arr).to.have.deep.property('[0][1]', 'matcha'); + * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); + * + * Furthermore, `property` changes the subject of the assertion + * to be the value of that property from the original object. This + * permits for further chainable assertions on that property. + * + * expect(obj).to.have.property('foo') + * .that.is.a('string'); + * expect(deepObj).to.have.property('green') + * .that.is.an('object') + * .that.deep.equals({ tea: 'matcha' }); + * expect(deepObj).to.have.property('teas') + * .that.is.an('array') + * .with.deep.property('[2]') + * .that.deep.equals({ tea: 'konacha' }); + * + * @name property + * @alias deep.property + * @param {String} name + * @param {Mixed} value (optional) + * @param {String} message _optional_ + * @returns value of property for chaining + * @api public + */ + + Assertion.addMethod('property', function (name, val, msg) { + if (msg) flag(this, 'message', msg); + + var descriptor = flag(this, 'deep') ? 'deep property ' : 'property ' + , negate = flag(this, 'negate') + , obj = flag(this, 'object') + , value = flag(this, 'deep') + ? _.getPathValue(name, obj) + : obj[name]; + + if (negate && undefined !== val) { + if (undefined === value) { + msg = (msg != null) ? msg + ': ' : ''; + throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); + } + } else { + this.assert( + undefined !== value + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + , 'expected #{this} to not have ' + descriptor + _.inspect(name)); + } + + if (undefined !== val) { + this.assert( + val === value + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' + , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' + , val + , value + ); + } + + flag(this, 'object', value); + }); + + + /** + * ### .ownProperty(name) + * + * Asserts that the target has an own property `name`. + * + * expect('test').to.have.ownProperty('length'); + * + * @name ownProperty + * @alias haveOwnProperty + * @param {String} name + * @param {String} message _optional_ + * @api public + */ + + function assertOwnProperty (name, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + obj.hasOwnProperty(name) + , 'expected #{this} to have own property ' + _.inspect(name) + , 'expected #{this} to not have own property ' + _.inspect(name) + ); + } + + Assertion.addMethod('ownProperty', assertOwnProperty); + Assertion.addMethod('haveOwnProperty', assertOwnProperty); + + /** + * ### .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); + * + * Can also be used as a chain precursor to a value + * comparison for the length property. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * @name length + * @alias lengthOf + * @param {Number} length + * @param {String} message _optional_ + * @api public + */ + + function assertLengthChain () { + flag(this, 'doLength', true); + } + + function assertLength (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).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 + ); + } + + Assertion.addChainableMethod('length', assertLength, assertLengthChain); + Assertion.addMethod('lengthOf', assertLength, assertLengthChain); + + /** + * ### .match(regexp) + * + * Asserts that the target matches a regular expression. + * + * expect('foobar').to.match(/^foo/); + * + * @name match + * @param {RegExp} RegularExpression + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('match', function (re, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + re.exec(obj) + , 'expected #{this} to match ' + re + , 'expected #{this} not to match ' + re + ); + }); + + /** + * ### .string(string) + * + * Asserts that the string target contains another string. + * + * expect('foobar').to.have.string('bar'); + * + * @name string + * @param {String} string + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('string', function (str, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('string'); + + this.assert( + ~obj.indexOf(str) + , 'expected #{this} to contain ' + _.inspect(str) + , 'expected #{this} to not contain ' + _.inspect(str) + ); + }); + + + /** + * ### .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 + */ + + function assertKeys (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 _.inspect(key); + }); + var last = keys.pop(); + str = keys.join(', ') + ', and ' + last; + } else { + str = _.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 + ); + } + + Assertion.addMethod('keys', assertKeys); + Assertion.addMethod('key', assertKeys); + + /** + * ### .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 + * @param {String|RegExp} expected error message + * @param {String} message _optional_ + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @api public + */ + + function assertThrows (constructor, errMsg, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('function'); + + var thrown = false + , desiredError = null + , name = null + , thrownError = null; + + if (arguments.length === 0) { + errMsg = null; + constructor = null; + } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { + errMsg = constructor; + constructor = null; + } else if (constructor && constructor instanceof Error) { + desiredError = constructor; + constructor = null; + errMsg = 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 ' + _.inspect(desiredError) + ' but ' + _.inspect(err) + ' was thrown' + , 'expected #{this} to not throw ' + _.inspect(desiredError) + ); + return this; + } + // next, check constructor + if (constructor) { + this.assert( + err instanceof constructor + , 'expected #{this} to throw ' + name + ' but ' + _.inspect(err) + ' was thrown' + , 'expected #{this} to not throw ' + name + ' but ' + _.inspect(err) + ' was thrown'); + if (!errMsg) return this; + } + // next, check message + if (err.message && errMsg && errMsg instanceof RegExp) { + this.assert( + errMsg.exec(err.message) + , 'expected #{this} to throw error matching ' + errMsg + ' but got ' + _.inspect(err.message) + , 'expected #{this} to throw error not matching ' + errMsg + ); + return this; + } else if (err.message && errMsg && 'string' === typeof errMsg) { + this.assert( + ~err.message.indexOf(errMsg) + , 'expected #{this} to throw error including #{exp} but got #{act}' + , 'expected #{this} to throw error not including #{act}' + , errMsg + , err.message + ); + return this; + } else { + thrown = true; + thrownError = err; + } + } + + var expectedThrown = name ? name : desiredError ? _.inspect(desiredError) : 'an error'; + var actuallyGot = '' + if (thrown) { + actuallyGot = ' but ' + _.inspect(thrownError) + ' was thrown' + } + + this.assert( + thrown === true + , 'expected #{this} to throw ' + expectedThrown + actuallyGot + , 'expected #{this} to not throw ' + expectedThrown + actuallyGot + ); + }; + + Assertion.addMethod('throw', assertThrows); + Assertion.addMethod('throws', assertThrows); + Assertion.addMethod('Throw', assertThrows); + + /** + * ### .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 + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('respondTo', function (method, msg) { + if (msg) flag(this, 'message', msg); + 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 ' + _.inspect(method) + , 'expected #{this} to not respond to ' + _.inspect(method) + ); + }); + + /** + * ### .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 + */ + + Assertion.addProperty('itself', function () { + flag(this, 'itself', 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 + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('satisfy', function (matcher, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + matcher(obj) + , 'expected #{this} to satisfy ' + _.inspect(matcher) + , 'expected #{this} to not satisfy' + _.inspect(matcher) + , this.negate ? false : true + , matcher(obj) + ); + }); + + /** + * ### .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 + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('closeTo', function (expected, delta, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + Math.abs(obj - expected) <= delta + , 'expected #{this} to be close to ' + expected + ' +/- ' + delta + , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta + ); + }); + + }; + + }); // module: chai/core/assertions.js + + require.register("chai/error.js", function(module, exports, require){ + /*! + * chai + * Copyright(c) 2011-2012 Jake Luer + * MIT Licensed + */ + + /*! + * Main export + */ + + module.exports = AssertionError; + + /** + * # AssertionError (constructor) + * + * Create a new assertion error based on the Javascript + * `Error` prototype. + * + * **Options** + * - message + * - actual + * - expected + * - operator + * - startStackFunction + * + * @param {Object} options + * @api public + */ + + function AssertionError (options) { + options = options || {}; + this.message = options.message; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + this.showDiff = options.showDiff; + + if (options.stackStartFunction && Error.captureStackTrace) { + var stackStartFunction = options.stackStartFunction; + Error.captureStackTrace(this, stackStartFunction); + } + } + + /*! + * Inherit from Error + */ + + AssertionError.prototype = Object.create(Error.prototype); + AssertionError.prototype.name = 'AssertionError'; + AssertionError.prototype.constructor = AssertionError; + + /** + * # toString() + * + * Override default to string method + */ + + AssertionError.prototype.toString = function() { + return this.message; + }; + + }); // module: chai/error.js + + require.register("chai/interface/assert.js", function(module, exports, require){ + /*! + * chai + * Copyright(c) 2011-2012 Jake Luer + * 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 (act, exp, msg) { + new Assertion(act, msg).to.equal(exp); + }; + + /** + * ### .notStrictEqual(actual, expected, [message]) + * + * Asserts strict inequality (`!==`) of `actual` and `expected`. + * + * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); + * + * @name notStrictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notStrictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.equal(exp); + }; + + /** + * ### .deepEqual(actual, expected, [message]) + * + * Asserts that `actual` is deeply equal to `expected`. + * + * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); + * + * @name deepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.deepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.eql(exp); + }; + + /** + * ### .notDeepEqual(actual, expected, [message]) + * + * Assert that `actual` is not deeply equal to `expected`. + * + * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); + * + * @name notDeepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notDeepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.eql(exp); + }; + + /** + * ### .isTrue(value, [message]) + * + * Asserts that `value` is true. + * + * var teaServed = true; + * assert.isTrue(teaServed, 'the tea has been served'); + * + * @name isTrue + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isTrue = function (val, msg) { + new Assertion(val, msg).is['true']; + }; + + /** + * ### .isFalse(value, [message]) + * + * Asserts that `value` is false. + * + * var teaServed = false; + * assert.isFalse(teaServed, 'no tea yet? hmm...'); + * + * @name isFalse + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isFalse = function (val, msg) { + new Assertion(val, msg).is['false']; + }; + + /** + * ### .isNull(value, [message]) + * + * Asserts that `value` is null. + * + * assert.isNull(err, 'there was no error'); + * + * @name isNull + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNull = function (val, msg) { + new Assertion(val, msg).to.equal(null); + }; + + /** + * ### .isNotNull(value, [message]) + * + * Asserts that `value` is not null. + * + * var tea = 'tasty chai'; + * assert.isNotNull(tea, 'great, time for tea!'); + * + * @name isNotNull + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotNull = function (val, msg) { + new Assertion(val, msg).to.not.equal(null); + }; + + /** + * ### .isUndefined(value, [message]) + * + * Asserts that `value` is `undefined`. + * + * var tea; + * assert.isUndefined(tea, 'no tea defined'); + * + * @name isUndefined + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isUndefined = function (val, msg) { + new Assertion(val, msg).to.equal(undefined); + }; + + /** + * ### .isDefined(value, [message]) + * + * Asserts that `value` is not `undefined`. + * + * var tea = 'cup of chai'; + * assert.isDefined(tea, 'tea has been defined'); + * + * @name isUndefined + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isDefined = function (val, msg) { + new Assertion(val, msg).to.not.equal(undefined); + }; + + /** + * ### .isFunction(value, [message]) + * + * Asserts that `value` is a function. + * + * function serveTea() { return 'cup of tea'; }; + * assert.isFunction(serveTea, 'great, we can have tea now'); + * + * @name isFunction + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isFunction = function (val, msg) { + new Assertion(val, msg).to.be.a('function'); + }; + + /** + * ### .isNotFunction(value, [message]) + * + * Asserts that `value` is _not_ a function. + * + * var serveTea = [ 'heat', 'pour', 'sip' ]; + * assert.isNotFunction(serveTea, 'great, we have listed the steps'); + * + * @name isNotFunction + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotFunction = function (val, msg) { + new Assertion(val, msg).to.not.be.a('function'); + }; + + /** + * ### .isObject(value, [message]) + * + * Asserts that `value` is an object (as revealed by + * `Object.prototype.toString`). + * + * var selection = { name: 'Chai', serve: 'with spices' }; + * assert.isObject(selection, 'tea selection is an object'); + * + * @name isObject + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isObject = function (val, msg) { + new Assertion(val, msg).to.be.a('object'); + }; + + /** + * ### .isNotObject(value, [message]) + * + * Asserts that `value` is _not_ an object. + * + * var selection = 'chai' + * assert.isObject(selection, 'tea selection is not an object'); + * assert.isObject(null, 'null is not an object'); + * + * @name isNotObject + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotObject = function (val, msg) { + new Assertion(val, msg).to.not.be.a('object'); + }; + + /** + * ### .isArray(value, [message]) + * + * Asserts that `value` is an array. + * + * var menu = [ 'green', 'chai', 'oolong' ]; + * assert.isArray(menu, 'what kind of tea do we want?'); + * + * @name isArray + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isArray = function (val, msg) { + new Assertion(val, msg).to.be.an('array'); + }; + + /** + * ### .isNotArray(value, [message]) + * + * Asserts that `value` is _not_ an array. + * + * var menu = 'green|chai|oolong'; + * assert.isNotArray(menu, 'what kind of tea do we want?'); + * + * @name isNotArray + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotArray = function (val, msg) { + new Assertion(val, msg).to.not.be.an('array'); + }; + + /** + * ### .isString(value, [message]) + * + * Asserts that `value` is a string. + * + * var teaOrder = 'chai'; + * assert.isString(teaOrder, 'order placed'); + * + * @name isString + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isString = function (val, msg) { + new Assertion(val, msg).to.be.a('string'); + }; + + /** + * ### .isNotString(value, [message]) + * + * Asserts that `value` is _not_ a string. + * + * var teaOrder = 4; + * assert.isNotString(teaOrder, 'order placed'); + * + * @name isNotString + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotString = function (val, msg) { + new Assertion(val, msg).to.not.be.a('string'); + }; + + /** + * ### .isNumber(value, [message]) + * + * Asserts that `value` is a number. + * + * var cups = 2; + * assert.isNumber(cups, 'how many cups'); + * + * @name isNumber + * @param {Number} value + * @param {String} message + * @api public + */ + + assert.isNumber = function (val, msg) { + new Assertion(val, msg).to.be.a('number'); + }; + + /** + * ### .isNotNumber(value, [message]) + * + * Asserts that `value` is _not_ a number. + * + * var cups = '2 cups please'; + * assert.isNotNumber(cups, 'how many cups'); + * + * @name isNotNumber + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotNumber = function (val, msg) { + new Assertion(val, msg).to.not.be.a('number'); + }; + + /** + * ### .isBoolean(value, [message]) + * + * Asserts that `value` is a boolean. + * + * var teaReady = true + * , teaServed = false; + * + * assert.isBoolean(teaReady, 'is the tea ready'); + * assert.isBoolean(teaServed, 'has tea been served'); + * + * @name isBoolean + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isBoolean = function (val, msg) { + new Assertion(val, msg).to.be.a('boolean'); + }; + + /** + * ### .isNotBoolean(value, [message]) + * + * Asserts that `value` is _not_ a boolean. + * + * var teaReady = 'yep' + * , teaServed = 'nope'; + * + * assert.isNotBoolean(teaReady, 'is the tea ready'); + * assert.isNotBoolean(teaServed, 'has tea been served'); + * + * @name isNotBoolean + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotBoolean = function (val, msg) { + new Assertion(val, msg).to.not.be.a('boolean'); + }; + + /** + * ### .typeOf(value, name, [message]) + * + * Asserts that `value`'s type is `name`, as determined by + * `Object.prototype.toString`. + * + * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); + * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); + * assert.typeOf('tea', 'string', 'we have a string'); + * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); + * assert.typeOf(null, 'null', 'we have a null'); + * assert.typeOf(undefined, 'undefined', 'we have an undefined'); + * + * @name typeOf + * @param {Mixed} value + * @param {String} name + * @param {String} message + * @api public + */ + + assert.typeOf = function (val, type, msg) { + new Assertion(val, msg).to.be.a(type); + }; + + /** + * ### .notTypeOf(value, name, [message]) + * + * Asserts that `value`'s type is _not_ `name`, as determined by + * `Object.prototype.toString`. + * + * assert.notTypeOf('tea', 'number', 'strings are not numbers'); + * + * @name notTypeOf + * @param {Mixed} value + * @param {String} typeof name + * @param {String} message + * @api public + */ + + assert.notTypeOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.a(type); + }; + + /** + * ### .instanceOf(object, constructor, [message]) + * + * Asserts that `value` is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new Tea('chai'); + * + * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); + * + * @name instanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @api public + */ + + assert.instanceOf = function (val, type, msg) { + new Assertion(val, msg).to.be.instanceOf(type); + }; + + /** + * ### .notInstanceOf(object, constructor, [message]) + * + * Asserts `value` is not an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new String('chai'); + * + * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); + * + * @name notInstanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @api public + */ + + assert.notInstanceOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.instanceOf(type); + }; + + /** + * ### .include(haystack, needle, [message]) + * + * Asserts that `haystack` includes `needle`. Works + * for strings and arrays. + * + * assert.include('foobar', 'bar', 'foobar contains string "bar"'); + * assert.include([ 1, 2, 3 ], 3, 'array contains value'); + * + * @name include + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @api public + */ + + assert.include = function (exp, inc, msg) { + var obj = new Assertion(exp, msg); + + if (Array.isArray(exp)) { + obj.to.include(inc); + } else if ('string' === typeof exp) { + obj.to.contain.string(inc); + } + }; + + /** + * ### .match(value, regexp, [message]) + * + * Asserts that `value` matches the regular expression `regexp`. + * + * assert.match('foobar', /^foo/, 'regexp matches'); + * + * @name match + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @api public + */ + + assert.match = function (exp, re, msg) { + new Assertion(exp, msg).to.match(re); + }; + + /** + * ### .notMatch(value, regexp, [message]) + * + * Asserts that `value` does not match the regular expression `regexp`. + * + * assert.notMatch('foobar', /^foo/, 'regexp does not match'); + * + * @name notMatch + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @api public + */ + + assert.notMatch = function (exp, re, msg) { + new Assertion(exp, msg).to.not.match(re); + }; + + /** + * ### .property(object, property, [message]) + * + * Asserts that `object` has a property named by `property`. + * + * assert.property({ tea: { green: 'matcha' }}, 'tea'); + * + * @name property + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.property = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.property(prop); + }; + + /** + * ### .notProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`. + * + * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); + * + * @name notProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.notProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.property(prop); + }; + + /** + * ### .deepProperty(object, property, [message]) + * + * Asserts that `object` has a property named by `property`, which can be a + * string using dot- and bracket-notation for deep reference. + * + * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); + * + * @name deepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.deepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.deep.property(prop); + }; + + /** + * ### .notDeepProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`, which + * can be a string using dot- and bracket-notation for deep reference. + * + * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); + * + * @name notDeepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.notDeepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop); + }; + + /** + * ### .propertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. + * + * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); + * + * @name propertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.propertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.property(prop, val); + }; + + /** + * ### .propertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. + * + * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); + * + * @name propertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.propertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.property(prop, val); + }; + + /** + * ### .deepPropertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. `property` can use dot- and bracket-notation for deep + * reference. + * + * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); + * + * @name deepPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.deepPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.deep.property(prop, val); + }; + + /** + * ### .deepPropertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. `property` can use dot- and + * bracket-notation for deep reference. + * + * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); + * + * @name deepPropertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.deepPropertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop, val); + }; + + /** + * ### .lengthOf(object, length, [message]) + * + * Asserts that `object` has a `length` property with the expected value. + * + * assert.lengthOf([1,2,3], 3, 'array has length of 3'); + * assert.lengthOf('foobar', 5, 'string has length of 6'); + * + * @name lengthOf + * @param {Mixed} object + * @param {Number} length + * @param {String} message + * @api public + */ + + assert.lengthOf = function (exp, len, msg) { + new Assertion(exp, msg).to.have.length(len); + }; + + /** + * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) + * + * Asserts that `function` will throw an error that is an instance of + * `constructor`, or alternately that it will throw an error with message + * matching `regexp`. + * + * assert.throw(fn, 'function throws a reference error'); + * assert.throw(fn, /function throws a reference error/); + * assert.throw(fn, ReferenceError); + * assert.throw(fn, ReferenceError, 'function throws a reference error'); + * assert.throw(fn, ReferenceError, /function throws a reference error/); + * + * @name throws + * @alias throw + * @alias Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @api public + */ + + assert.Throw = function (fn, errt, errs, msg) { + if ('string' === typeof errt || errt instanceof RegExp) { + errs = errt; + errt = null; + } + + new Assertion(fn, msg).to.Throw(errt, errs); + }; + + /** + * ### .doesNotThrow(function, [constructor/regexp], [message]) + * + * Asserts that `function` will _not_ throw an error that is an instance of + * `constructor`, or alternately that it will not throw an error with message + * matching `regexp`. + * + * assert.doesNotThrow(fn, Error, 'function does not throw'); + * + * @name doesNotThrow + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @api public + */ + + assert.doesNotThrow = function (fn, type, msg) { + if ('string' === typeof type) { + msg = type; + type = null; + } + + new Assertion(fn, msg).to.not.Throw(type); + }; + + /** + * ### .operator(val1, operator, val2, [message]) + * + * Compares two values using `operator`. + * + * assert.operator(1, '<', 2, 'everything is ok'); + * assert.operator(1, '>', 2, 'this will fail'); + * + * @name operator + * @param {Mixed} val1 + * @param {String} operator + * @param {Mixed} val2 + * @param {String} message + * @api public + */ + + assert.operator = function (val, operator, val2, msg) { + if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) { + throw new Error('Invalid operator "' + operator + '"'); + } + var test = new Assertion(eval(val + operator + val2), msg); + test.assert( + true === flag(test, 'object') + , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) + , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); + }; + + /** + * ### .closeTo(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); + * + * @name closeTo + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @api public + */ + + assert.closeTo = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.closeTo(exp, delta); + }; + + /*! + * Undocumented / untested + */ + + assert.ifError = function (val, msg) { + new Assertion(val, msg).to.not.be.ok; + }; + + /*! + * Aliases. + */ + + (function alias(name, as){ + assert[as] = assert[name]; + return alias; + }) + ('Throw', 'throw') + ('Throw', 'throws'); + }; + + }); // module: chai/interface/assert.js + + require.register("chai/interface/expect.js", function(module, exports, require){ + /*! + * chai + * Copyright(c) 2011-2012 Jake Luer + * MIT Licensed + */ + + module.exports = function (chai, util) { + chai.expect = function (val, message) { + return new chai.Assertion(val, message); + }; + }; + + + }); // module: chai/interface/expect.js + + require.register("chai/interface/should.js", function(module, exports, require){ + /*! + * chai + * Copyright(c) 2011-2012 Jake Luer + * MIT Licensed + */ + + module.exports = function (chai, util) { + var Assertion = chai.Assertion; + + function loadShould () { + // modify Object.prototype to have `should` + Object.defineProperty(Object.prototype, 'should', + { + set: function (value) { + // See https://github.com/chaijs/chai/issues/86: this makes + // `whatever.should = someValue` actually set `someValue`, which is + // especially useful for `global.should = require('chai').should()`. + // + // Note that we have to use [[DefineProperty]] instead of [[Put]] + // since otherwise we would trigger this very setter! + Object.defineProperty(this, 'should', { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } + , get: function(){ + if (this instanceof String || this instanceof Number) { + return new Assertion(this.constructor(this)); + } else if (this instanceof Boolean) { + return new Assertion(this == true); + } + return new Assertion(this); + } + , configurable: true + }); + + var should = {}; + + should.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.equal(val2); + }; + + should.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.Throw(errt, errs); + }; + + should.exist = function (val, msg) { + new Assertion(val, msg).to.exist; + } + + // negation + should.not = {} + + should.not.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.not.equal(val2); + }; + + should.not.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.not.Throw(errt, errs); + }; + + should.not.exist = function (val, msg) { + new Assertion(val, msg).to.not.exist; + } + + should['throw'] = should['Throw']; + should.not['throw'] = should.not['Throw']; + + return should; + }; + + chai.should = loadShould; + chai.Should = loadShould; + }; + + }); // module: chai/interface/should.js + + require.register("chai/utils/addChainableMethod.js", function(module, exports, require){ + /*! + * Chai - addChainingMethod utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /*! + * Module dependencies + */ + + var transferFlags = require('./transferFlags'); + + /** + * ### addChainableMethod (ctx, name, method, chainingBehavior) + * + * Adds a method to an object, such that the method can also be chained. + * + * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); + * + * The result can then be used as both a method assertion, executing both `method` and + * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. + * + * expect(fooStr).to.be.foo('bar'); + * expect(fooStr).to.be.foo.equal('foo'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for `name`, when called + * @param {Function} chainingBehavior function to be called every time the property is accessed + * @name addChainableMethod + * @api public + */ + + module.exports = function (ctx, name, method, chainingBehavior) { + if (typeof chainingBehavior !== 'function') + chainingBehavior = function () { }; + + Object.defineProperty(ctx, name, + { get: function () { + chainingBehavior.call(this); + + var assert = function () { + var result = method.apply(this, arguments); + return result === undefined ? this : result; + }; + + // Re-enumerate every time to better accomodate plugins. + var asserterNames = Object.getOwnPropertyNames(ctx); + asserterNames.forEach(function (asserterName) { + var pd = Object.getOwnPropertyDescriptor(ctx, asserterName) + , functionProtoPD = Object.getOwnPropertyDescriptor(Function.prototype, asserterName); + // Avoid trying to overwrite things that we can't, like `length` and `arguments`. + if (functionProtoPD && !functionProtoPD.configurable) return; + if (asserterName === 'arguments') return; // @see chaijs/chai/issues/69 + Object.defineProperty(assert, asserterName, pd); + }); + + transferFlags(this, assert); + return assert; + } + , configurable: true + }); + }; + + }); // module: chai/utils/addChainableMethod.js + + require.register("chai/utils/addMethod.js", function(module, exports, require){ + /*! + * Chai - addMethod utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * ### .addMethod (ctx, name, method) + * + * Adds a method to the prototype of an object. + * + * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(fooStr).to.be.foo('bar'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for name + * @name addMethod + * @api public + */ + + module.exports = function (ctx, name, method) { + ctx[name] = function () { + var result = method.apply(this, arguments); + return result === undefined ? this : result; + }; + }; + + }); // module: chai/utils/addMethod.js + + require.register("chai/utils/addProperty.js", function(module, exports, require){ + /*! + * Chai - addProperty utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * ### addProperty (ctx, name, getter) + * + * Adds a property to the prototype of an object. + * + * utils.addProperty(chai.Assertion.prototype, 'foo', function () { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.instanceof(Foo); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.foo; + * + * @param {Object} ctx object to which the property is added + * @param {String} name of property to add + * @param {Function} getter function to be used for name + * @name addProperty + * @api public + */ + + module.exports = function (ctx, name, getter) { + Object.defineProperty(ctx, name, + { get: function () { + var result = getter.call(this); + return result === undefined ? this : result; + } + , configurable: true + }); + }; + + }); // module: chai/utils/addProperty.js + + require.register("chai/utils/eql.js", function(module, exports, require){ + // This is (almost) directly from Node.js assert + // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js + + module.exports = _deepEqual; + + // for the browser + var Buffer; + try { + Buffer = require('buffer').Buffer; + } catch (ex) { + Buffer = { + isBuffer: function () { return false; } + }; + } + + function _deepEqual(actual, expected, memos) { + + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { + if (actual.length != expected.length) return false; + + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) return false; + } + + return true; + + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (actual instanceof Date && expected instanceof Date) { + return actual.getTime() === expected.getTime(); + + // 7.3. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (typeof actual != 'object' && typeof expected != 'object') { + return actual === expected; + + // 7.4. For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected, memos); + } + } + + function isUndefinedOrNull(value) { + return value === null || value === undefined; + } + + function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; + } + + function objEquiv(a, b, memos) { + if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) + return false; + + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + + // check if we have already compared a and b + var i; + if (memos) { + for(i = 0; i < memos.length; i++) { + if ((memos[i][0] === a && memos[i][1] === b) || + (memos[i][0] === b && memos[i][1] === a)) + return true; + } + } else { + memos = []; + } + + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + if (isArguments(a)) { + if (!isArguments(b)) { + return false; + } + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b, memos); + } + try { + var ka = Object.keys(a), + kb = Object.keys(b), + key; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + + // remember objects we have compared to guard against circular references + memos.push([ a, b ]); + + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key], memos)) return false; + } + + return true; + } + + }); // module: chai/utils/eql.js + + require.register("chai/utils/flag.js", function(module, exports, require){ + /*! + * Chai - flag utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * ### flag(object ,key, [value]) + * + * Get or set a flag value on an object. If a + * value is provided it will be set, else it will + * return the currently set value or `undefined` if + * the value is not set. + * + * utils.flag(this, 'foo', 'bar'); // setter + * utils.flag(this, 'foo'); // getter, returns `bar` + * + * @param {Object} object (constructed Assertion + * @param {String} key + * @param {Mixed} value (optional) + * @name flag + * @api private + */ + + module.exports = function (obj, key, value) { + var flags = obj.__flags || (obj.__flags = Object.create(null)); + if (arguments.length === 3) { + flags[key] = value; + } else { + return flags[key]; + } + }; + + }); // module: chai/utils/flag.js + + require.register("chai/utils/getActual.js", function(module, exports, require){ + /*! + * Chai - getActual utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * # getActual(object, [actual]) + * + * Returns the `actual` value for an Assertion + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + */ + + module.exports = function (obj, args) { + var actual = args[4]; + return 'undefined' !== typeof actual ? actual : obj._obj; + }; + + }); // module: chai/utils/getActual.js + + require.register("chai/utils/getMessage.js", function(module, exports, require){ + /*! + * Chai - message composition utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /*! + * Module dependancies + */ + + var flag = require('./flag') + , getActual = require('./getActual') + , inspect = require('./inspect') + , objDisplay = require('./objDisplay'); + + /** + * ### .getMessage(object, message, negateMessage) + * + * Construct the error message based on flags + * and template tags. Template tags will return + * a stringified inspection of the object referenced. + * + * Messsage template tags: + * - `#{this}` current asserted object + * - `#{act}` actual value + * - `#{exp}` expected value + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @name getMessage + * @api public + */ + + module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , val = flag(obj, 'object') + , expected = args[3] + , actual = getActual(obj, args) + , msg = negate ? args[2] : args[1] + , flagMsg = flag(obj, 'message'); + + msg = msg || ''; + msg = msg + .replace(/#{this}/g, objDisplay(val)) + .replace(/#{act}/g, objDisplay(actual)) + .replace(/#{exp}/g, objDisplay(expected)); + + return flagMsg ? flagMsg + ': ' + msg : msg; + }; + + }); // module: chai/utils/getMessage.js + + require.register("chai/utils/getName.js", function(module, exports, require){ + /*! + * Chai - getName utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * # getName(func) + * + * Gets the name of a function, in a cross-browser way. + * + * @param {Function} a function (usually a constructor) + */ + + module.exports = function (func) { + if (func.name) return func.name; + + var match = /^\s?function ([^(]*)\(/.exec(func); + return match && match[1] ? match[1] : ""; + }; + + }); // module: chai/utils/getName.js + + require.register("chai/utils/getPathValue.js", function(module, exports, require){ + /*! + * Chai - getPathValue utility + * Copyright(c) 2012 Jake Luer + * @see https://github.com/logicalparadox/filtr + * MIT Licensed + */ + + /** + * ### .getPathValue(path, object) + * + * This allows the retrieval of values in an + * object given a string path. + * + * var obj = { + * prop1: { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * , prop2: { + * arr: [ { nested: 'Universe' } ] + * , str: 'Hello again!' + * } + * } + * + * The following would be the results. + * + * getPathValue('prop1.str', obj); // Hello + * getPathValue('prop1.att[2]', obj); // b + * getPathValue('prop2.arr[0].nested', obj); // Universe + * + * @param {String} path + * @param {Object} object + * @returns {Object} value or `undefined` + * @name getPathValue + * @api public + */ + + var getPathValue = module.exports = function (path, obj) { + var parsed = parsePath(path); + return _getPathValue(parsed, obj); + }; + + /*! + * ## parsePath(path) + * + * Helper function used to parse string object + * paths. Use in conjunction with `_getPathValue`. + * + * var parsed = parsePath('myobject.property.subprop'); + * + * ### Paths: + * + * * Can be as near infinitely deep and nested + * * Arrays are also valid using the formal `myobject.document[3].property`. + * + * @param {String} path + * @returns {Object} parsed + * @api private + */ + + function parsePath (path) { + var str = path.replace(/\[/g, '.[') + , parts = str.match(/(\\\.|[^.]+?)+/g); + return parts.map(function (value) { + var re = /\[(\d+)\]$/ + , mArr = re.exec(value) + if (mArr) return { i: parseFloat(mArr[1]) }; + else return { p: value }; + }); + }; + + /*! + * ## _getPathValue(parsed, obj) + * + * Helper companion function for `.parsePath` that returns + * the value located at the parsed address. + * + * var value = getPathValue(parsed, obj); + * + * @param {Object} parsed definition from `parsePath`. + * @param {Object} object to search against + * @returns {Object|Undefined} value + * @api private + */ + + function _getPathValue (parsed, obj) { + var tmp = obj + , res; + for (var i = 0, l = parsed.length; i < l; i++) { + var part = parsed[i]; + if (tmp) { + if ('undefined' !== typeof part.p) + tmp = tmp[part.p]; + else if ('undefined' !== typeof part.i) + tmp = tmp[part.i]; + if (i == (l - 1)) res = tmp; + } else { + res = undefined; + } + } + return res; + }; + + }); // module: chai/utils/getPathValue.js + + require.register("chai/utils/index.js", function(module, exports, require){ + /*! + * chai + * Copyright(c) 2011 Jake Luer + * MIT Licensed + */ + + /*! + * Main exports + */ + + var exports = module.exports = {}; + + /*! + * test utility + */ + + exports.test = require('./test'); + + /*! + * message utility + */ + + exports.getMessage = require('./getMessage'); + + /*! + * actual utility + */ + + exports.getActual = require('./getActual'); + + /*! + * Inspect util + */ + + exports.inspect = require('./inspect'); + + /*! + * Object Display util + */ + + exports.objDisplay = require('./objDisplay'); + + /*! + * Flag utility + */ + + exports.flag = require('./flag'); + + /*! + * Flag transferring utility + */ + + exports.transferFlags = require('./transferFlags'); + + /*! + * Deep equal utility + */ + + exports.eql = require('./eql'); + + /*! + * Deep path value + */ + + exports.getPathValue = require('./getPathValue'); + + /*! + * Function name + */ + + exports.getName = require('./getName'); + + /*! + * add Property + */ + + exports.addProperty = require('./addProperty'); + + /*! + * add Method + */ + + exports.addMethod = require('./addMethod'); + + /*! + * overwrite Property + */ + + exports.overwriteProperty = require('./overwriteProperty'); + + /*! + * overwrite Method + */ + + exports.overwriteMethod = require('./overwriteMethod'); + + /*! + * Add a chainable method + */ + + exports.addChainableMethod = require('./addChainableMethod'); + + + }); // module: chai/utils/index.js + + require.register("chai/utils/inspect.js", function(module, exports, require){ + // This is (almost) directly from Node.js utils + // https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js + + var getName = require('./getName'); + + module.exports = inspect; + + /** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Boolean} showHidden Flag that shows hidden (not enumerable) + * properties of objects. + * @param {Number} depth Depth in which to descend in object. Default is 2. + * @param {Boolean} colors Flag to turn on ANSI escape codes to color the + * output. Default is false (no coloring). + */ + function inspect(obj, showHidden, depth, colors) { + var ctx = { + showHidden: showHidden, + seen: [], + stylize: function (str) { return str; } + }; + return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); + } + + // https://gist.github.com/1044128/ + var getOuterHTML = function(element) { + if ('outerHTML' in element) return element.outerHTML; + var ns = "http://www.w3.org/1999/xhtml"; + var container = document.createElementNS(ns, '_'); + var elemProto = (window.HTMLElement || window.Element).prototype; + var xmlSerializer = new XMLSerializer(); + var html; + if (document.xmlVersion) { + return xmlSerializer.serializeToString(element); + } else { + container.appendChild(element.cloneNode(false)); + html = container.innerHTML.replace('><', '>' + element.innerHTML + '<'); + container.innerHTML = ''; + return html; + } + }; + + // Returns true if object is a DOM element. + var isDOMElement = function (object) { + if (typeof HTMLElement === 'object') { + return object instanceof HTMLElement; + } else { + return object && + typeof object === 'object' && + object.nodeType === 1 && + typeof object.nodeName === 'string'; + } + }; + + function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (value && typeof value.inspect === 'function' && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + return value.inspect(recurseTimes); + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // If it's DOM elem, get outer HTML. + if (isDOMElement(value)) { + return getOuterHTML(value); + } + + // Look up the keys of the object. + var visibleKeys = Object.keys(value); + var keys = ctx.showHidden ? Object.getOwnPropertyNames(value) : visibleKeys; + + // Some type of object without properties can be shortcutted. + // In IE, errors have a single `stack` property, or if they are vanilla `Error`, + // a `stack` plus `description` property; ignore those for consistency. + if (keys.length === 0 || (isError(value) && ( + (keys.length === 1 && keys[0] === 'stack') || + (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') + ))) { + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + return ctx.stylize('[Function' + nameSuffix + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + base = ' [Function' + nameSuffix + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + return formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); + } + + + function formatPrimitive(ctx, value) { + switch (typeof value) { + case 'undefined': + return ctx.stylize('undefined', 'undefined'); + + case 'string': + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + + case 'number': + return ctx.stylize('' + value, 'number'); + + case 'boolean': + return ctx.stylize('' + value, 'boolean'); + } + // For some reason typeof null is "object", so special case here. + if (value === null) { + return ctx.stylize('null', 'null'); + } + } + + + function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; + } + + + function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (Object.prototype.hasOwnProperty.call(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; + } + + + function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str; + if (value.__lookupGetter__) { + if (value.__lookupGetter__(key)) { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Setter]', 'special'); + } + } + } + if (visibleKeys.indexOf(key) < 0) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(value[key]) < 0) { + if (recurseTimes === null) { + str = formatValue(ctx, value[key], null); + } else { + str = formatValue(ctx, value[key], recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (typeof name === 'undefined') { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; + } + + + function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; + } + + function isArray(ar) { + return Array.isArray(ar) || + (typeof ar === 'object' && objectToString(ar) === '[object Array]'); + } + + function isRegExp(re) { + return typeof re === 'object' && objectToString(re) === '[object RegExp]'; + } + + function isDate(d) { + return typeof d === 'object' && objectToString(d) === '[object Date]'; + } + + function isError(e) { + return typeof e === 'object' && objectToString(e) === '[object Error]'; + } + + function objectToString(o) { + return Object.prototype.toString.call(o); + } + + }); // module: chai/utils/inspect.js + + require.register("chai/utils/objDisplay.js", function(module, exports, require){ + /*! + * Chai - flag utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /*! + * Module dependancies + */ + + var inspect = require('./inspect'); + + /** + * ### .objDisplay (object) + * + * Determines if an object or an array matches + * criteria to be inspected in-line for error + * messages or should be truncated. + * + * @param {Mixed} javascript object to inspect + * @name objDisplay + * @api public + */ + + module.exports = function (obj) { + var str = inspect(obj) + , type = Object.prototype.toString.call(obj); + + if (str.length >= 40) { + if (type === '[object Array]') { + return '[ Array(' + obj.length + ') ]'; + } else if (type === '[object Object]') { + var keys = Object.keys(obj) + , kstr = keys.length > 2 + ? keys.splice(0, 2).join(', ') + ', ...' + : keys.join(', '); + return '{ Object (' + kstr + ') }'; + } else { + return str; + } + } else { + return str; + } + }; + + }); // module: chai/utils/objDisplay.js + + require.register("chai/utils/overwriteMethod.js", function(module, exports, require){ + /*! + * Chai - overwriteMethod utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * ### overwriteMethod (ctx, name, fn) + * + * Overwites an already existing method and provides + * access to previous function. Must return function + * to be used for name. + * + * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { + * return function (str) { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.value).to.equal(str); + * } else { + * _super.apply(this, arguments); + * } + * } + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.equal('bar'); + * + * @param {Object} ctx object whose method is to be overwritten + * @param {String} name of method to overwrite + * @param {Function} method function that returns a function to be used for name + * @name overwriteMethod + * @api public + */ + + module.exports = function (ctx, name, method) { + var _method = ctx[name] + , _super = function () { return this; }; + + if (_method && 'function' === typeof _method) + _super = _method; + + ctx[name] = function () { + var result = method(_super).apply(this, arguments); + return result === undefined ? this : result; + } + }; + + }); // module: chai/utils/overwriteMethod.js + + require.register("chai/utils/overwriteProperty.js", function(module, exports, require){ + /*! + * Chai - overwriteProperty utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * ### overwriteProperty (ctx, name, fn) + * + * Overwites an already existing property getter and provides + * access to previous value. Must return function to use as getter. + * + * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { + * return function () { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.name).to.equal('bar'); + * } else { + * _super.call(this); + * } + * } + * }); + * + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.ok; + * + * @param {Object} ctx object whose property is to be overwritten + * @param {String} name of property to overwrite + * @param {Function} getter function that returns a getter function to be used for name + * @name overwriteProperty + * @api public + */ + + module.exports = function (ctx, name, getter) { + var _get = Object.getOwnPropertyDescriptor(ctx, name) + , _super = function () {}; + + if (_get && 'function' === typeof _get.get) + _super = _get.get + + Object.defineProperty(ctx, name, + { get: function () { + var result = getter(_super).call(this); + return result === undefined ? this : result; + } + , configurable: true + }); + }; + + }); // module: chai/utils/overwriteProperty.js + + require.register("chai/utils/test.js", function(module, exports, require){ + /*! + * Chai - test utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /*! + * Module dependancies + */ + + var flag = require('./flag'); + + /** + * # test(object, expression) + * + * Test and object for expression. + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + */ + + module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , expr = args[0]; + return negate ? !expr : expr; + }; + + }); // module: chai/utils/test.js + + require.register("chai/utils/transferFlags.js", function(module, exports, require){ + /*! + * Chai - transferFlags utility + * Copyright(c) 2012 Jake Luer + * MIT Licensed + */ + + /** + * ### transferFlags(assertion, object, includeAll = true) + * + * Transfer all the flags for `assertion` to `object`. If + * `includeAll` is set to `false`, then the base Chai + * assertion flags (namely `object`, `ssfi`, and `message`) + * will not be transferred. + * + * + * var newAssertion = new Assertion(); + * utils.transferFlags(assertion, newAssertion); + * + * var anotherAsseriton = new Assertion(myObj); + * utils.transferFlags(assertion, anotherAssertion, false); + * + * @param {Assertion} assertion the assertion to transfer the flags from + * @param {Object} object the object to transfer the flags too; usually a new assertion + * @param {Boolean} includeAll + * @name getAllFlags + * @api private + */ + + module.exports = function (assertion, object, includeAll) { + var flags = assertion.__flags || (assertion.__flags = Object.create(null)); + + if (!object.__flags) { + object.__flags = Object.create(null); + } + + includeAll = arguments.length === 3 ? includeAll : true; + + for (var flag in flags) { + if (includeAll || + (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { + object.__flags[flag] = flags[flag]; + } + } + }; + + }); // module: chai/utils/transferFlags.js + + require.alias("./chai.js", "chai"); + + return require('chai'); +}); \ No newline at end of file diff --git a/ember/test/lib/expect.js b/ember/test/lib/expect.js new file mode 100755 index 0000000..272ea06 --- /dev/null +++ b/ember/test/lib/expect.js @@ -0,0 +1,12 @@ +/*! + * chai + * Copyright(c) 2011-2012 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, util) { + chai.expect = function (val, message) { + return new chai.Assertion(val, message); + }; +}; + diff --git a/ember/test/lib/mocha/mocha.css b/ember/test/lib/mocha/mocha.css new file mode 100755 index 0000000..3b8afb1 --- /dev/null +++ b/ember/test/lib/mocha/mocha.css @@ -0,0 +1,231 @@ +@charset "utf-8"; + +body { + font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; + padding: 60px 50px; +} + +#mocha ul, #mocha li { + margin: 0; + padding: 0; +} + +#mocha ul { + list-style: none; +} + +#mocha h1, #mocha h2 { + margin: 0; +} + +#mocha h1 { + margin-top: 15px; + font-size: 1em; + font-weight: 200; +} + +#mocha h1 a { + text-decoration: none; + color: inherit; +} + +#mocha h1 a:hover { + text-decoration: underline; +} + +#mocha .suite .suite h1 { + margin-top: 0; + font-size: .8em; +} + +.hidden { + display: none; +} + +#mocha h2 { + font-size: 12px; + font-weight: normal; + cursor: pointer; +} + +#mocha .suite { + margin-left: 15px; +} + +#mocha .test { + margin-left: 15px; + overflow: hidden; +} + +#mocha .test.pending:hover h2::after { + content: '(pending)'; + font-family: arial; +} + +#mocha .test.pass.medium .duration { + background: #C09853; +} + +#mocha .test.pass.slow .duration { + background: #B94A48; +} + +#mocha .test.pass::before { + content: '✓'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #00d6b2; +} + +#mocha .test.pass .duration { + font-size: 9px; + margin-left: 5px; + padding: 2px 5px; + color: white; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; +} + +#mocha .test.pass.fast .duration { + display: none; +} + +#mocha .test.pending { + color: #0b97c4; +} + +#mocha .test.pending::before { + content: '◦'; + color: #0b97c4; +} + +#mocha .test.fail { + color: #c00; +} + +#mocha .test.fail pre { + color: black; +} + +#mocha .test.fail::before { + content: '✖'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #c00; +} + +#mocha .test pre.error { + color: #c00; + max-height: 300px; + overflow: auto; +} + +#mocha .test pre { + display: block; + float: left; + clear: left; + font: 12px/1.5 monaco, monospace; + margin: 5px; + padding: 15px; + border: 1px solid #eee; + border-bottom-color: #ddd; + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 3px #eee; + -moz-border-radius: 3px; + -moz-box-shadow: 0 1px 3px #eee; +} + +#mocha .test h2 { + position: relative; +} + +#mocha .test a.replay { + position: absolute; + top: 3px; + right: 0; + text-decoration: none; + vertical-align: middle; + display: block; + width: 15px; + height: 15px; + line-height: 15px; + text-align: center; + background: #eee; + font-size: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + -webkit-transition: opacity 200ms; + -moz-transition: opacity 200ms; + transition: opacity 200ms; + opacity: 0.3; + color: #888; +} + +#mocha .test:hover a.replay { + opacity: 1; +} + +#mocha-report.pass .test.fail { + display: none; +} + +#mocha-report.fail .test.pass { + display: none; +} + +#mocha-error { + color: #c00; + font-size: 1.5 em; + font-weight: 100; + letter-spacing: 1px; +} + +#mocha-stats { + position: fixed; + top: 15px; + right: 10px; + font-size: 12px; + margin: 0; + color: #888; +} + +#mocha-stats .progress { + float: right; + padding-top: 0; +} + +#mocha-stats em { + color: black; +} + +#mocha-stats a { + text-decoration: none; + color: inherit; +} + +#mocha-stats a:hover { + border-bottom: 1px solid #eee; +} + +#mocha-stats li { + display: inline-block; + margin: 0 5px; + list-style: none; + padding-top: 11px; +} + +code .comment { color: #ddd } +code .init { color: #2F6FAD } +code .string { color: #5890AD } +code .keyword { color: #8A6343 } +code .number { color: #2F6FAD } diff --git a/ember/test/lib/mocha/mocha.js b/ember/test/lib/mocha/mocha.js new file mode 100755 index 0000000..f01d356 --- /dev/null +++ b/ember/test/lib/mocha/mocha.js @@ -0,0 +1,5340 @@ +;(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.charAt(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("browser/debug.js", function(module, exports, require){ + +module.exports = function(type){ + return function(){ + + } +}; +}); // module: browser/debug.js + +require.register("browser/diff.js", function(module, exports, require){ +/* See license.txt for terms of usage */ + +/* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ +var JsDiff = (function() { + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } + function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + } + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, "&"); + n = n.replace(//g, ">"); + n = n.replace(/"/g, """); + + return n; + } + + + var fbDiff = function(ignoreWhitespace) { + this.ignoreWhitespace = ignoreWhitespace; + }; + fbDiff.prototype = { + diff: function(oldString, newString) { + // Handle the identity case (this is due to unrolling editLength == 0 + if (newString == oldString) { + return [{ value: newString }]; + } + if (!newString) { + return [{ value: oldString, removed: true }]; + } + if (!oldString) { + return [{ value: newString, added: true }]; + } + + newString = this.tokenize(newString); + oldString = this.tokenize(oldString); + + var newLen = newString.length, oldLen = oldString.length; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0 + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { + return bestPath[0].components; + } + + for (var editLength = 1; editLength <= maxEditLength; editLength++) { + for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { + var basePath; + var addPath = bestPath[diagonalPath-1], + removePath = bestPath[diagonalPath+1]; + oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath-1] = undefined; + } + + var canAdd = addPath && addPath.newPos+1 < newLen; + var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; + if (!canAdd && !canRemove) { + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { + basePath = clonePath(removePath); + this.pushComponent(basePath.components, oldString[oldPos], undefined, true); + } else { + basePath = clonePath(addPath); + basePath.newPos++; + this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); + } + + var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); + + if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { + return basePath.components; + } else { + bestPath[diagonalPath] = basePath; + } + } + } + }, + + pushComponent: function(components, value, added, removed) { + var last = components[components.length-1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length-1] = + {value: this.join(last.value, value), added: added, removed: removed }; + } else { + components.push({value: value, added: added, removed: removed }); + } + }, + extractCommon: function(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath; + while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { + newPos++; + oldPos++; + + this.pushComponent(basePath.components, newString[newPos], undefined, undefined); + } + basePath.newPos = newPos; + return oldPos; + }, + + equals: function(left, right) { + var reWhitespace = /\S/; + if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { + return true; + } else { + return left == right; + } + }, + join: function(left, right) { + return left + right; + }, + tokenize: function(value) { + return value; + } + }; + + var CharDiff = new fbDiff(); + + var WordDiff = new fbDiff(true); + WordDiff.tokenize = function(value) { + return removeEmpty(value.split(/(\s+|\b)/)); + }; + + var CssDiff = new fbDiff(true); + CssDiff.tokenize = function(value) { + return removeEmpty(value.split(/([{}:;,]|\s+)/)); + }; + + var LineDiff = new fbDiff(); + LineDiff.tokenize = function(value) { + return value.split(/^/m); + }; + + return { + diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, + diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, + diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, + + diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, + + createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { + var ret = []; + + ret.push("Index: " + fileName); + ret.push("==================================================================="); + ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader)); + ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader)); + + var diff = LineDiff.diff(oldStr, newStr); + if (!diff[diff.length-1].value) { + diff.pop(); // Remove trailing newline add + } + diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier + + function contextLines(lines) { + return lines.map(function(entry) { return ' ' + entry; }); + } + function eofNL(curRange, i, current) { + var last = diff[diff.length-2], + isLast = i === diff.length-2, + isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed); + + // Figure out if this is the last line for the given file and missing NL + if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { + curRange.push('\\ No newline at end of file'); + } + } + + var oldRangeStart = 0, newRangeStart = 0, curRange = [], + oldLine = 1, newLine = 1; + for (var i = 0; i < diff.length; i++) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, "").split("\n"); + current.lines = lines; + + if (current.added || current.removed) { + if (!oldRangeStart) { + var prev = diff[i-1]; + oldRangeStart = oldLine; + newRangeStart = newLine; + + if (prev) { + curRange = contextLines(prev.lines.slice(-4)); + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } + curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; })); + eofNL(curRange, i, current); + + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= 8 && i < diff.length-2) { + // Overlapping + curRange.push.apply(curRange, contextLines(lines)); + } else { + // end the range and output + var contextSize = Math.min(lines.length, 4); + ret.push( + "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize) + + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize) + + " @@"); + ret.push.apply(ret, curRange); + ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); + if (lines.length <= 4) { + eofNL(ret, i, current); + } + + oldRangeStart = 0; newRangeStart = 0; curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + } + + return ret.join('\n') + '\n'; + }, + + convertChangesToXML: function(changes){ + var ret = []; + for ( var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push(""); + } else if (change.removed) { + ret.push(""); + } + + ret.push(escapeHTML(change.value)); + + if (change.added) { + ret.push(""); + } else if (change.removed) { + ret.push(""); + } + } + return ret.join(""); + } + }; +})(); + +if (typeof module !== "undefined") { + module.exports = JsDiff; +} + +}); // module: browser/diff.js + +require.register("browser/events.js", function(module, exports, require){ + +/** + * Module exports. + */ + +exports.EventEmitter = EventEmitter; + +/** + * Check if `obj` is an array. + */ + +function isArray(obj) { + return '[object Array]' == {}.toString.call(obj); +} + +/** + * Event emitter constructor. + * + * @api public + */ + +function EventEmitter(){}; + +/** + * Adds a listener. + * + * @api public + */ + +EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; +}; + +EventEmitter.prototype.addListener = EventEmitter.prototype.on; + +/** + * Adds a volatile listener. + * + * @api public + */ + +EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; +}; + +/** + * Removes a listener. + * + * @api public + */ + +EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; +}; + +/** + * Removes all listeners for an event. + * + * @api public + */ + +EventEmitter.prototype.removeAllListeners = function (name) { + if (name === undefined) { + this.$events = {}; + return this; + } + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; +}; + +/** + * Gets all listeners for a certain event. + * + * @api public + */ + +EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; +}; + +/** + * Emits an event. + * + * @api public + */ + +EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = [].slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; +}; +}); // module: browser/events.js + +require.register("browser/fs.js", function(module, exports, require){ + +}); // module: browser/fs.js + +require.register("browser/path.js", function(module, exports, require){ + +}); // module: browser/path.js + +require.register("browser/progress.js", function(module, exports, require){ + +/** + * Expose `Progress`. + */ + +module.exports = Progress; + +/** + * Initialize a new `Progress` indicator. + */ + +function Progress() { + this.percent = 0; + this.size(0); + this.fontSize(11); + this.font('helvetica, arial, sans-serif'); +} + +/** + * Set progress size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.size = function(n){ + this._size = n; + return this; +}; + +/** + * Set text to `str`. + * + * @param {String} str + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.text = function(str){ + this._text = str; + return this; +}; + +/** + * Set font size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.fontSize = function(n){ + this._fontSize = n; + return this; +}; + +/** + * Set font `family`. + * + * @param {String} family + * @return {Progress} for chaining + */ + +Progress.prototype.font = function(family){ + this._font = family; + return this; +}; + +/** + * Update percentage to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + */ + +Progress.prototype.update = function(n){ + this.percent = n; + return this; +}; + +/** + * Draw on `ctx`. + * + * @param {CanvasRenderingContext2d} ctx + * @return {Progress} for chaining + */ + +Progress.prototype.draw = function(ctx){ + var percent = Math.min(this.percent, 100) + , size = this._size + , half = size / 2 + , x = half + , y = half + , rad = half - 1 + , fontSize = this._fontSize; + + ctx.font = fontSize + 'px ' + this._font; + + var angle = Math.PI * 2 * (percent / 100); + ctx.clearRect(0, 0, size, size); + + // outer circle + ctx.strokeStyle = '#9f9f9f'; + ctx.beginPath(); + ctx.arc(x, y, rad, 0, angle, false); + ctx.stroke(); + + // inner circle + ctx.strokeStyle = '#eee'; + ctx.beginPath(); + ctx.arc(x, y, rad - 1, 0, angle, true); + ctx.stroke(); + + // text + var text = this._text || (percent | 0) + '%' + , w = ctx.measureText(text).width; + + ctx.fillText( + text + , x - w / 2 + 1 + , y + fontSize / 2 - 1); + + return this; +}; + +}); // module: browser/progress.js + +require.register("browser/tty.js", function(module, exports, require){ + +exports.isatty = function(){ + return true; +}; + +exports.getWindowSize = function(){ + return [window.innerHeight, window.innerWidth]; +}; +}); // module: browser/tty.js + +require.register("context.js", function(module, exports, require){ + +/** + * Expose `Context`. + */ + +module.exports = Context; + +/** + * Initialize a new `Context`. + * + * @api private + */ + +function Context(){} + +/** + * Set or get the context `Runnable` to `runnable`. + * + * @param {Runnable} runnable + * @return {Context} + * @api private + */ + +Context.prototype.runnable = function(runnable){ + if (0 == arguments.length) return this._runnable; + this.test = this._runnable = runnable; + return this; +}; + +/** + * Set test timeout `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.timeout = function(ms){ + this.runnable().timeout(ms); + return this; +}; + +/** + * Set test slowness threshold `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.slow = function(ms){ + this.runnable().slow(ms); + return this; +}; + +/** + * Inspect the context void of `._runnable`. + * + * @return {String} + * @api private + */ + +Context.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_runnable' == key) return; + if ('test' == key) return; + return val; + }, 2); +}; + +}); // module: context.js + +require.register("hook.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Hook`. + */ + +module.exports = Hook; + +/** + * Initialize a new `Hook` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Hook(title, fn) { + Runnable.call(this, title, fn); + this.type = 'hook'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Hook.prototype = new F; +Hook.prototype.constructor = Hook; + + +/** + * Get or set the test `err`. + * + * @param {Error} err + * @return {Error} + * @api public + */ + +Hook.prototype.error = function(err){ + if (0 == arguments.length) { + var err = this._error; + this._error = null; + return err; + } + + this._error = err; +}; + + +}); // module: hook.js + +require.register("interfaces/bdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * BDD-style interface: + * + * describe('Array', function(){ + * describe('#indexOf()', function(){ + * it('should return -1 when not present', function(){ + * + * }); + * + * it('should return the index when present', function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.describe = context.context = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Pending describe. + */ + + context.xdescribe = + context.xcontext = + context.describe.skip = function(title, fn){ + var suite = Suite.create(suites[0], title); + suite.pending = true; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + }; + + /** + * Exclusive suite. + */ + + context.describe.only = function(title, fn){ + var suite = context.describe(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.it = context.specify = function(title, fn){ + var suite = suites[0]; + if (suite.pending) var fn = null; + var test = new Test(title, fn); + suite.addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.it.only = function(title, fn){ + var test = context.it(title, fn); + mocha.grep(test.fullTitle()); + }; + + /** + * Pending test case. + */ + + context.xit = + context.xspecify = + context.it.skip = function(title){ + context.it(title); + }; + }); +}; + +}); // module: interfaces/bdd.js + +require.register("interfaces/exports.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * exports.Array = { + * '#indexOf()': { + * 'should return -1 when the value is not present': function(){ + * + * }, + * + * 'should return the correct index when the value is present': function(){ + * + * } + * } + * }; + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('require', visit); + + function visit(obj) { + var suite; + for (var key in obj) { + if ('function' == typeof obj[key]) { + var fn = obj[key]; + switch (key) { + case 'before': + suites[0].beforeAll(fn); + break; + case 'after': + suites[0].afterAll(fn); + break; + case 'beforeEach': + suites[0].beforeEach(fn); + break; + case 'afterEach': + suites[0].afterEach(fn); + break; + default: + suites[0].addTest(new Test(key, fn)); + } + } else { + var suite = Suite.create(suites[0], key); + suites.unshift(suite); + visit(obj[key]); + suites.shift(); + } + } + } +}; +}); // module: interfaces/exports.js + +require.register("interfaces/index.js", function(module, exports, require){ + +exports.bdd = require('./bdd'); +exports.tdd = require('./tdd'); +exports.qunit = require('./qunit'); +exports.exports = require('./exports'); + +}); // module: interfaces/index.js + +require.register("interfaces/qunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * QUnit-style interface: + * + * suite('Array'); + * + * test('#length', function(){ + * var arr = [1,2,3]; + * ok(arr.length == 3); + * }); + * + * test('#indexOf()', function(){ + * var arr = [1,2,3]; + * ok(arr.indexOf(1) == 0); + * ok(arr.indexOf(2) == 1); + * ok(arr.indexOf(3) == 2); + * }); + * + * suite('String'); + * + * test('#length', function(){ + * ok('foo'.length == 3); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context){ + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title`. + */ + + context.suite = function(title){ + if (suites.length > 1) suites.shift(); + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + suites[0].addTest(new Test(title, fn)); + }; + }); +}; + +}); // module: interfaces/qunit.js + +require.register("interfaces/tdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * suite('Array', function(){ + * suite('#indexOf()', function(){ + * suiteSetup(function(){ + * + * }); + * + * test('should return -1 when not present', function(){ + * + * }); + * + * test('should return the index when present', function(){ + * + * }); + * + * suiteTeardown(function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before each test case. + */ + + context.setup = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.teardown = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Execute before the suite. + */ + + context.suiteSetup = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after the suite. + */ + + context.suiteTeardown = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.suite = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Exclusive test-case. + */ + + context.suite.only = function(title, fn){ + var suite = context.suite(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + var test = new Test(title, fn); + suites[0].addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.test.only = function(title, fn){ + var test = context.test(title, fn); + mocha.grep(test.fullTitle()); + }; + + /** + * Pending test case. + */ + + context.test.skip = function(title){ + context.test(title); + }; + }); +}; + +}); // module: interfaces/tdd.js + +require.register("mocha.js", function(module, exports, require){ +/*! + * mocha + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('browser/path') + , utils = require('./utils'); + +/** + * Expose `Mocha`. + */ + +exports = module.exports = Mocha; + +/** + * Expose internals. + */ + +exports.utils = utils; +exports.interfaces = require('./interfaces'); +exports.reporters = require('./reporters'); +exports.Runnable = require('./runnable'); +exports.Context = require('./context'); +exports.Runner = require('./runner'); +exports.Suite = require('./suite'); +exports.Hook = require('./hook'); +exports.Test = require('./test'); + +/** + * Return image `name` path. + * + * @param {String} name + * @return {String} + * @api private + */ + +function image(name) { + return __dirname + '/../images/' + name + '.png'; +} + +/** + * Setup mocha with `options`. + * + * Options: + * + * - `ui` name "bdd", "tdd", "exports" etc + * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` + * - `globals` array of accepted globals + * - `timeout` timeout in milliseconds + * - `bail` bail on the first test failure + * - `slow` milliseconds to wait before considering a test slow + * - `ignoreLeaks` ignore global leaks + * - `grep` string or regexp to filter tests with + * + * @param {Object} options + * @api public + */ + +function Mocha(options) { + options = options || {}; + this.files = []; + this.options = options; + this.grep(options.grep); + this.suite = new exports.Suite('', new exports.Context); + this.ui(options.ui); + this.bail(options.bail); + this.reporter(options.reporter); + if (options.timeout) this.timeout(options.timeout); + if (options.slow) this.slow(options.slow); +} + +/** + * Enable or disable bailing on the first failure. + * + * @param {Boolean} [bail] + * @api public + */ + +Mocha.prototype.bail = function(bail){ + if (null == bail) bail = true; + this.suite.bail(bail); + return this; +}; + +/** + * Add test `file`. + * + * @param {String} file + * @api public + */ + +Mocha.prototype.addFile = function(file){ + this.files.push(file); + return this; +}; + +/** + * Set reporter to `reporter`, defaults to "dot". + * + * @param {String|Function} reporter name or constructor + * @api public + */ + +Mocha.prototype.reporter = function(reporter){ + if ('function' == typeof reporter) { + this._reporter = reporter; + } else { + reporter = reporter || 'dot'; + try { + this._reporter = require('./reporters/' + reporter); + } catch (err) { + this._reporter = require(reporter); + } + if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"'); + } + return this; +}; + +/** + * Set test UI `name`, defaults to "bdd". + * + * @param {String} bdd + * @api public + */ + +Mocha.prototype.ui = function(name){ + name = name || 'bdd'; + this._ui = exports.interfaces[name]; + if (!this._ui) throw new Error('invalid interface "' + name + '"'); + this._ui = this._ui(this.suite); + return this; +}; + +/** + * Load registered files. + * + * @api private + */ + +Mocha.prototype.loadFiles = function(fn){ + var self = this; + var suite = this.suite; + var pending = this.files.length; + this.files.forEach(function(file){ + file = path.resolve(file); + suite.emit('pre-require', global, file, self); + suite.emit('require', require(file), file, self); + suite.emit('post-require', global, file, self); + --pending || (fn && fn()); + }); +}; + +/** + * Enable growl support. + * + * @api private + */ + +Mocha.prototype._growl = function(runner, reporter) { + var notify = require('growl'); + + runner.on('end', function(){ + var stats = reporter.stats; + if (stats.failures) { + var msg = stats.failures + ' of ' + runner.total + ' tests failed'; + notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); + } else { + notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { + name: 'mocha' + , title: 'Passed' + , image: image('ok') + }); + } + }); +}; + +/** + * Add regexp to grep, if `re` is a string it is escaped. + * + * @param {RegExp|String} re + * @return {Mocha} + * @api public + */ + +Mocha.prototype.grep = function(re){ + this.options.grep = 'string' == typeof re + ? new RegExp(utils.escapeRegexp(re)) + : re; + return this; +}; + +/** + * Invert `.grep()` matches. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.invert = function(){ + this.options.invert = true; + return this; +}; + +/** + * Ignore global leaks. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.ignoreLeaks = function(){ + this.options.ignoreLeaks = true; + return this; +}; + +/** + * Enable global leak checking. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.checkLeaks = function(){ + this.options.ignoreLeaks = false; + return this; +}; + +/** + * Enable growl support. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.growl = function(){ + this.options.growl = true; + return this; +}; + +/** + * Ignore `globals` array or string. + * + * @param {Array|String} globals + * @return {Mocha} + * @api public + */ + +Mocha.prototype.globals = function(globals){ + this.options.globals = (this.options.globals || []).concat(globals); + return this; +}; + +/** + * Set the timeout in milliseconds. + * + * @param {Number} timeout + * @return {Mocha} + * @api public + */ + +Mocha.prototype.timeout = function(timeout){ + this.suite.timeout(timeout); + return this; +}; + +/** + * Set slowness threshold in milliseconds. + * + * @param {Number} slow + * @return {Mocha} + * @api public + */ + +Mocha.prototype.slow = function(slow){ + this.suite.slow(slow); + return this; +}; + +/** + * Makes all tests async (accepting a callback) + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.asyncOnly = function(){ + this.options.asyncOnly = true; + return this; +}; + +/** + * Run tests and invoke `fn()` when complete. + * + * @param {Function} fn + * @return {Runner} + * @api public + */ + +Mocha.prototype.run = function(fn){ + if (this.files.length) this.loadFiles(); + var suite = this.suite; + var options = this.options; + var runner = new exports.Runner(suite); + var reporter = new this._reporter(runner); + runner.ignoreLeaks = options.ignoreLeaks; + runner.asyncOnly = options.asyncOnly; + if (options.grep) runner.grep(options.grep, options.invert); + if (options.globals) runner.globals(options.globals); + if (options.growl) this._growl(runner, reporter); + return runner.run(fn); +}; + +}); // module: mocha.js + +require.register("ms.js", function(module, exports, require){ + +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; + +/** + * Parse or format the given `val`. + * + * @param {String|Number} val + * @return {String|Number} + * @api public + */ + +module.exports = function(val){ + if ('string' == typeof val) return parse(val); + return format(val); +} + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); + if (!m) return; + var n = parseFloat(m[1]); + var type = (m[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'y': + return n * 31557600000; + case 'days': + case 'day': + case 'd': + return n * 86400000; + case 'hours': + case 'hour': + case 'h': + return n * 3600000; + case 'minutes': + case 'minute': + case 'm': + return n * 60000; + case 'seconds': + case 'second': + case 's': + return n * 1000; + case 'ms': + return n; + } +} + +/** + * Format the given `ms`. + * + * @param {Number} ms + * @return {String} + * @api public + */ + +function format(ms) { + if (ms == d) return Math.round(ms / d) + ' day'; + if (ms > d) return Math.round(ms / d) + ' days'; + if (ms == h) return Math.round(ms / h) + ' hour'; + if (ms > h) return Math.round(ms / h) + ' hours'; + if (ms == m) return Math.round(ms / m) + ' minute'; + if (ms > m) return Math.round(ms / m) + ' minutes'; + if (ms == s) return Math.round(ms / s) + ' second'; + if (ms > s) return Math.round(ms / s) + ' seconds'; + return ms + ' ms'; +} +}); // module: ms.js + +require.register("reporters/base.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var tty = require('browser/tty') + , diff = require('browser/diff') + , ms = require('../ms'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Check if both stdio streams are associated with a tty. + */ + +var isatty = tty.isatty(1) && tty.isatty(2); + +/** + * Expose `Base`. + */ + +exports = module.exports = Base; + +/** + * Enable coloring by default. + */ + +exports.useColors = isatty; + +/** + * Default color map. + */ + +exports.colors = { + 'pass': 90 + , 'fail': 31 + , 'bright pass': 92 + , 'bright fail': 91 + , 'bright yellow': 93 + , 'pending': 36 + , 'suite': 0 + , 'error title': 0 + , 'error message': 31 + , 'error stack': 90 + , 'checkmark': 32 + , 'fast': 90 + , 'medium': 33 + , 'slow': 31 + , 'green': 32 + , 'light': 90 + , 'diff gutter': 90 + , 'diff added': 42 + , 'diff removed': 41 +}; + +/** + * Default symbol map. + */ + +exports.symbols = { + ok: '✓', + err: '✖', + dot: '․' +}; + +// With node.js on Windows: use symbols available in terminal default fonts +if ('win32' == process.platform) { + exports.symbols.ok = '\u221A'; + exports.symbols.err = '\u00D7'; + exports.symbols.dot = '.'; +} + +/** + * Color `str` with the given `type`, + * allowing colors to be disabled, + * as well as user-defined color + * schemes. + * + * @param {String} type + * @param {String} str + * @return {String} + * @api private + */ + +var color = exports.color = function(type, str) { + if (!exports.useColors) return str; + return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; +}; + +/** + * Expose term window size, with some + * defaults for when stderr is not a tty. + */ + +exports.window = { + width: isatty + ? process.stdout.getWindowSize + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1] + : 75 +}; + +/** + * Expose some basic cursor interactions + * that are common among reporters. + */ + +exports.cursor = { + hide: function(){ + process.stdout.write('\u001b[?25l'); + }, + + show: function(){ + process.stdout.write('\u001b[?25h'); + }, + + deleteLine: function(){ + process.stdout.write('\u001b[2K'); + }, + + beginningOfLine: function(){ + process.stdout.write('\u001b[0G'); + }, + + CR: function(){ + exports.cursor.deleteLine(); + exports.cursor.beginningOfLine(); + } +}; + +/** + * Outut the given `failures` as a list. + * + * @param {Array} failures + * @api public + */ + +exports.list = function(failures){ + console.error(); + failures.forEach(function(test, i){ + // format + var fmt = color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); + + // msg + var err = test.err + , message = err.message || '' + , stack = err.stack || message + , index = stack.indexOf(message) + message.length + , msg = stack.slice(0, index) + , actual = err.actual + , expected = err.expected + , escape = true; + + // explicitly show diff + if (err.showDiff) { + escape = false; + err.actual = actual = JSON.stringify(actual, null, 2); + err.expected = expected = JSON.stringify(expected, null, 2); + } + + // actual / expected diff + if ('string' == typeof actual && 'string' == typeof expected) { + var len = Math.max(actual.length, expected.length); + + if (len < 20) msg = errorDiff(err, 'Chars', escape); + else msg = errorDiff(err, 'Words', escape); + + // linenos + var lines = msg.split('\n'); + if (lines.length > 4) { + var width = String(lines.length).length; + msg = lines.map(function(str, i){ + return pad(++i, width) + ' |' + ' ' + str; + }).join('\n'); + } + + // legend + msg = '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; + + // indent + msg = msg.replace(/^/gm, ' '); + + fmt = color('error title', ' %s) %s:\n%s') + + color('error stack', '\n%s\n'); + } + + // indent stack trace without msg + stack = stack.slice(index ? index + 1 : index) + .replace(/^/gm, ' '); + + console.error(fmt, (i + 1), test.fullTitle(), msg, stack); + }); +}; + +/** + * Initialize a new `Base` reporter. + * + * All other reporters generally + * inherit from this reporter, providing + * stats such as test duration, number + * of tests passed / failed etc. + * + * @param {Runner} runner + * @api public + */ + +function Base(runner) { + var self = this + , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } + , failures = this.failures = []; + + if (!runner) return; + this.runner = runner; + + runner.stats = stats; + + runner.on('start', function(){ + stats.start = new Date; + }); + + runner.on('suite', function(suite){ + stats.suites = stats.suites || 0; + suite.root || stats.suites++; + }); + + runner.on('test end', function(test){ + stats.tests = stats.tests || 0; + stats.tests++; + }); + + runner.on('pass', function(test){ + stats.passes = stats.passes || 0; + + var medium = test.slow() / 2; + test.speed = test.duration > test.slow() + ? 'slow' + : test.duration > medium + ? 'medium' + : 'fast'; + + stats.passes++; + }); + + runner.on('fail', function(test, err){ + stats.failures = stats.failures || 0; + stats.failures++; + test.err = err; + failures.push(test); + }); + + runner.on('end', function(){ + stats.end = new Date; + stats.duration = new Date - stats.start; + }); + + runner.on('pending', function(){ + stats.pending++; + }); +} + +/** + * Output common epilogue used by many of + * the bundled reporters. + * + * @api public + */ + +Base.prototype.epilogue = function(){ + var stats = this.stats + , fmt + , tests; + + console.log(); + + function pluralize(n) { + return 1 == n ? 'test' : 'tests'; + } + + // failure + if (stats.failures) { + fmt = color('bright fail', ' ' + exports.symbols.err) + + color('fail', ' %d of %d %s failed') + + color('light', ':') + + console.error(fmt, + stats.failures, + this.runner.total, + pluralize(this.runner.total)); + + Base.list(this.failures); + console.error(); + return; + } + + // pass + fmt = color('bright pass', ' ') + + color('green', ' %d %s complete') + + color('light', ' (%s)'); + + console.log(fmt, + stats.tests || 0, + pluralize(stats.tests), + ms(stats.duration)); + + // pending + if (stats.pending) { + fmt = color('pending', ' ') + + color('pending', ' %d %s pending'); + + console.log(fmt, stats.pending, pluralize(stats.pending)); + } + + console.log(); +}; + +/** + * Pad the given `str` to `len`. + * + * @param {String} str + * @param {String} len + * @return {String} + * @api private + */ + +function pad(str, len) { + str = String(str); + return Array(len - str.length + 1).join(' ') + str; +} + +/** + * Return a character diff for `err`. + * + * @param {Error} err + * @return {String} + * @api private + */ + +function errorDiff(err, type, escape) { + return diff['diff' + type](err.actual, err.expected).map(function(str){ + if (escape) { + str.value = str.value + .replace(/\t/g, '') + .replace(/\r/g, '') + .replace(/\n/g, '\n'); + } + if (str.added) return colorLines('diff added', str.value); + if (str.removed) return colorLines('diff removed', str.value); + return str.value; + }).join(''); +} + +/** + * Color lines for `str`, using the color `name`. + * + * @param {String} name + * @param {String} str + * @return {String} + * @api private + */ + +function colorLines(name, str) { + return str.split('\n').map(function(str){ + return color(name, str); + }).join('\n'); +} + +}); // module: reporters/base.js + +require.register("reporters/doc.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Doc`. + */ + +exports = module.exports = Doc; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Doc(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , indents = 2; + + function indent() { + return Array(indents).join(' '); + } + + runner.on('suite', function(suite){ + if (suite.root) return; + ++indents; + console.log('%s
', indent()); + ++indents; + console.log('%s

%s

', indent(), utils.escape(suite.title)); + console.log('%s
', indent()); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + console.log('%s
', indent()); + --indents; + console.log('%s
', indent()); + --indents; + }); + + runner.on('pass', function(test){ + console.log('%s
%s
', indent(), utils.escape(test.title)); + var code = utils.escape(utils.clean(test.fn.toString())); + console.log('%s
%s
', indent(), code); + }); +} + +}); // module: reporters/doc.js + +require.register("reporters/dot.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = Dot; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Dot(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , n = 0; + + runner.on('start', function(){ + process.stdout.write('\n '); + }); + + runner.on('pending', function(test){ + process.stdout.write(color('pending', Base.symbols.dot)); + }); + + runner.on('pass', function(test){ + if (++n % width == 0) process.stdout.write('\n '); + if ('slow' == test.speed) { + process.stdout.write(color('bright yellow', Base.symbols.dot)); + } else { + process.stdout.write(color(test.speed, Base.symbols.dot)); + } + }); + + runner.on('fail', function(test, err){ + if (++n % width == 0) process.stdout.write('\n '); + process.stdout.write(color('fail', Base.symbols.dot)); + }); + + runner.on('end', function(){ + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Dot.prototype = new F; +Dot.prototype.constructor = Dot; + +}); // module: reporters/dot.js + +require.register("reporters/html-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var JSONCov = require('./json-cov') + , fs = require('browser/fs'); + +/** + * Expose `HTMLCov`. + */ + +exports = module.exports = HTMLCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTMLCov(runner) { + var jade = require('jade') + , file = __dirname + '/templates/coverage.jade' + , str = fs.readFileSync(file, 'utf8') + , fn = jade.compile(str, { filename: file }) + , self = this; + + JSONCov.call(this, runner, false); + + runner.on('end', function(){ + process.stdout.write(fn({ + cov: self.cov + , coverageClass: coverageClass + })); + }); +} + +/** + * Return coverage class for `n`. + * + * @return {String} + * @api private + */ + +function coverageClass(n) { + if (n >= 75) return 'high'; + if (n >= 50) return 'medium'; + if (n >= 25) return 'low'; + return 'terrible'; +} +}); // module: reporters/html-cov.js + +require.register("reporters/html.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , Progress = require('../browser/progress') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `Doc`. + */ + +exports = module.exports = HTML; + +/** + * Stats template. + */ + +var statsTemplate = ''; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTML(runner, root) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , stat = fragment(statsTemplate) + , items = stat.getElementsByTagName('li') + , passes = items[1].getElementsByTagName('em')[0] + , passesLink = items[1].getElementsByTagName('a')[0] + , failures = items[2].getElementsByTagName('em')[0] + , failuresLink = items[2].getElementsByTagName('a')[0] + , duration = items[3].getElementsByTagName('em')[0] + , canvas = stat.getElementsByTagName('canvas')[0] + , report = fragment('
    ') + , stack = [report] + , progress + , ctx + + root = root || document.getElementById('mocha'); + + if (canvas.getContext) { + var ratio = window.devicePixelRatio || 1; + canvas.style.width = canvas.width; + canvas.style.height = canvas.height; + canvas.width *= ratio; + canvas.height *= ratio; + ctx = canvas.getContext('2d'); + ctx.scale(ratio, ratio); + progress = new Progress; + } + + if (!root) return error('#mocha div missing, add it to your document'); + + // pass toggle + on(passesLink, 'click', function(){ + unhide(); + var name = /pass/.test(report.className) ? '' : ' pass'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test pass'); + }); + + // failure toggle + on(failuresLink, 'click', function(){ + unhide(); + var name = /fail/.test(report.className) ? '' : ' fail'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test fail'); + }); + + root.appendChild(stat); + root.appendChild(report); + + if (progress) progress.size(40); + + runner.on('suite', function(suite){ + if (suite.root) return; + + // suite + var url = '?grep=' + encodeURIComponent(suite.fullTitle()); + var el = fragment('
  • %s

  • ', url, escape(suite.title)); + + // container + stack[0].appendChild(el); + stack.unshift(document.createElement('ul')); + el.appendChild(stack[0]); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + stack.shift(); + }); + + runner.on('fail', function(test, err){ + if ('hook' == test.type) runner.emit('test end', test); + }); + + runner.on('test end', function(test){ + window.scrollTo(0, document.body.scrollHeight); + + // TODO: add to stats + var percent = stats.tests / this.total * 100 | 0; + if (progress) progress.update(percent).draw(ctx); + + // update stats + var ms = new Date - stats.start; + text(passes, stats.passes); + text(failures, stats.failures); + text(duration, (ms / 1000).toFixed(2)); + + // test + if ('passed' == test.state) { + var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle())); + } else if (test.pending) { + var el = fragment('
  • %e

  • ', test.title); + } else { + var el = fragment('
  • %e

  • ', test.title, encodeURIComponent(test.fullTitle())); + var str = test.err.stack || test.err.toString(); + + // FF / Opera do not add the message + if (!~str.indexOf(test.err.message)) { + str = test.err.message + '\n' + str; + } + + // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we + // check for the result of the stringifying. + if ('[object Error]' == str) str = test.err.message; + + // Safari doesn't give you a stack. Let's at least provide a source line. + if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { + str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + } + + el.appendChild(fragment('
    %e
    ', str)); + } + + // toggle code + // TODO: defer + if (!test.pending) { + var h2 = el.getElementsByTagName('h2')[0]; + + on(h2, 'click', function(){ + pre.style.display = 'none' == pre.style.display + ? 'block' + : 'none'; + }); + + var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); + el.appendChild(pre); + pre.style.display = 'none'; + } + + // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. + if (stack[0]) stack[0].appendChild(el); + }); +} + +/** + * Display error `msg`. + */ + +function error(msg) { + document.body.appendChild(fragment('
    %s
    ', msg)); +} + +/** + * Return a DOM fragment from `html`. + */ + +function fragment(html) { + var args = arguments + , div = document.createElement('div') + , i = 1; + + div.innerHTML = html.replace(/%([se])/g, function(_, type){ + switch (type) { + case 's': return String(args[i++]); + case 'e': return escape(args[i++]); + } + }); + + return div.firstChild; +} + +/** + * Check for suites that do not have elements + * with `classname`, and hide them. + */ + +function hideSuitesWithout(classname) { + var suites = document.getElementsByClassName('suite'); + for (var i = 0; i < suites.length; i++) { + var els = suites[i].getElementsByClassName(classname); + if (0 == els.length) suites[i].className += ' hidden'; + } +} + +/** + * Unhide .hidden suites. + */ + +function unhide() { + var els = document.getElementsByClassName('suite hidden'); + for (var i = 0; i < els.length; ++i) { + els[i].className = els[i].className.replace('suite hidden', 'suite'); + } +} + +/** + * Set `el` text to `str`. + */ + +function text(el, str) { + if (el.textContent) { + el.textContent = str; + } else { + el.innerText = str; + } +} + +/** + * Listen on `event` with callback `fn`. + */ + +function on(el, event, fn) { + if (el.addEventListener) { + el.addEventListener(event, fn, false); + } else { + el.attachEvent('on' + event, fn); + } +} + +}); // module: reporters/html.js + +require.register("reporters/index.js", function(module, exports, require){ + +exports.Base = require('./base'); +exports.Dot = require('./dot'); +exports.Doc = require('./doc'); +exports.TAP = require('./tap'); +exports.JSON = require('./json'); +exports.HTML = require('./html'); +exports.List = require('./list'); +exports.Min = require('./min'); +exports.Spec = require('./spec'); +exports.Nyan = require('./nyan'); +exports.XUnit = require('./xunit'); +exports.Markdown = require('./markdown'); +exports.Progress = require('./progress'); +exports.Landing = require('./landing'); +exports.JSONCov = require('./json-cov'); +exports.HTMLCov = require('./html-cov'); +exports.JSONStream = require('./json-stream'); +exports.Teamcity = require('./teamcity'); + +}); // module: reporters/index.js + +require.register("reporters/json-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `JSONCov`. + */ + +exports = module.exports = JSONCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @param {Boolean} output + * @api public + */ + +function JSONCov(runner, output) { + var self = this + , output = 1 == arguments.length ? true : output; + + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var cov = global._$jscoverage || {}; + var result = self.cov = map(cov); + result.stats = self.stats; + result.tests = tests.map(clean); + result.failures = failures.map(clean); + result.passes = passes.map(clean); + if (!output) return; + process.stdout.write(JSON.stringify(result, null, 2 )); + }); +} + +/** + * Map jscoverage data to a JSON structure + * suitable for reporting. + * + * @param {Object} cov + * @return {Object} + * @api private + */ + +function map(cov) { + var ret = { + instrumentation: 'node-jscoverage' + , sloc: 0 + , hits: 0 + , misses: 0 + , coverage: 0 + , files: [] + }; + + for (var filename in cov) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } + + ret.files.sort(function(a, b) { + return a.filename.localeCompare(b.filename); + }); + + if (ret.sloc > 0) { + ret.coverage = (ret.hits / ret.sloc) * 100; + } + + return ret; +}; + +/** + * Map jscoverage data for a single source file + * to a JSON structure suitable for reporting. + * + * @param {String} filename name of the source file + * @param {Object} data jscoverage coverage data + * @return {Object} + * @api private + */ + +function coverage(filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc: 0, + source: {} + }; + + data.source.forEach(function(line, num){ + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + ret.source[num] = { + source: line + , coverage: data[num] === undefined + ? '' + : data[num] + }; + }); + + ret.coverage = ret.hits / ret.sloc * 100; + + return ret; +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-cov.js + +require.register("reporters/json-stream.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total; + + runner.on('start', function(){ + console.log(JSON.stringify(['start', { total: total }])); + }); + + runner.on('pass', function(test){ + console.log(JSON.stringify(['pass', clean(test)])); + }); + + runner.on('fail', function(test, err){ + console.log(JSON.stringify(['fail', clean(test)])); + }); + + runner.on('end', function(){ + process.stdout.write(JSON.stringify(['end', self.stats])); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json-stream.js + +require.register("reporters/json.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `JSON`. + */ + +exports = module.exports = JSONReporter; + +/** + * Initialize a new `JSON` reporter. + * + * @param {Runner} runner + * @api public + */ + +function JSONReporter(runner) { + var self = this; + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var obj = { + stats: self.stats + , tests: tests.map(clean) + , failures: failures.map(clean) + , passes: passes.map(clean) + }; + + process.stdout.write(JSON.stringify(obj, null, 2)); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json.js + +require.register("reporters/landing.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Landing`. + */ + +exports = module.exports = Landing; + +/** + * Airplane color. + */ + +Base.colors.plane = 0; + +/** + * Airplane crash color. + */ + +Base.colors['plane crash'] = 31; + +/** + * Runway color. + */ + +Base.colors.runway = 90; + +/** + * Initialize a new `Landing` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Landing(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , total = runner.total + , stream = process.stdout + , plane = color('plane', '✈') + , crashed = -1 + , n = 0; + + function runway() { + var buf = Array(width).join('-'); + return ' ' + color('runway', buf); + } + + runner.on('start', function(){ + stream.write('\n '); + cursor.hide(); + }); + + runner.on('test end', function(test){ + // check if the plane crashed + var col = -1 == crashed + ? width * ++n / total | 0 + : crashed; + + // show the crash + if ('failed' == test.state) { + plane = color('plane crash', '✈'); + crashed = col; + } + + // render landing strip + stream.write('\u001b[4F\n\n'); + stream.write(runway()); + stream.write('\n '); + stream.write(color('runway', Array(col).join('⋅'))); + stream.write(plane) + stream.write(color('runway', Array(width - col).join('⋅') + '\n')); + stream.write(runway()); + stream.write('\u001b[0m'); + }); + + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Landing.prototype = new F; +Landing.prototype.constructor = Landing; + +}); // module: reporters/landing.js + +require.register("reporters/list.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 0; + + runner.on('start', function(){ + console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = color('checkmark', ' -') + + color('pending', ' %s'); + console.log(fmt, test.fullTitle()); + }); + + runner.on('pass', function(test){ + var fmt = color('checkmark', ' '+Base.symbols.dot) + + color('pass', ' %s: ') + + color(test.speed, '%dms'); + cursor.CR(); + console.log(fmt, test.fullTitle(), test.duration); + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +List.prototype = new F; +List.prototype.constructor = List; + + +}); // module: reporters/list.js + +require.register("reporters/markdown.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Markdown`. + */ + +exports = module.exports = Markdown; + +/** + * Initialize a new `Markdown` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Markdown(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , level = 0 + , buf = ''; + + function title(str) { + return Array(level).join('#') + ' ' + str; + } + + function indent() { + return Array(level).join(' '); + } + + function mapTOC(suite, obj) { + var ret = obj; + obj = obj[suite.title] = obj[suite.title] || { suite: suite }; + suite.suites.forEach(function(suite){ + mapTOC(suite, obj); + }); + return ret; + } + + function stringifyTOC(obj, level) { + ++level; + var buf = ''; + var link; + for (var key in obj) { + if ('suite' == key) continue; + if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; + if (key) buf += Array(level).join(' ') + link; + buf += stringifyTOC(obj[key], level); + } + --level; + return buf; + } + + function generateTOC(suite) { + var obj = mapTOC(suite, {}); + return stringifyTOC(obj, 0); + } + + generateTOC(runner.suite); + + runner.on('suite', function(suite){ + ++level; + var slug = utils.slug(suite.fullTitle()); + buf += '' + '\n'; + buf += title(suite.title) + '\n'; + }); + + runner.on('suite end', function(suite){ + --level; + }); + + runner.on('pass', function(test){ + var code = utils.clean(test.fn.toString()); + buf += test.title + '.\n'; + buf += '\n```js\n'; + buf += code + '\n'; + buf += '```\n\n'; + }); + + runner.on('end', function(){ + process.stdout.write('# TOC\n'); + process.stdout.write(generateTOC(runner.suite)); + process.stdout.write(buf); + }); +} +}); // module: reporters/markdown.js + +require.register("reporters/min.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Min`. + */ + +exports = module.exports = Min; + +/** + * Initialize a new `Min` minimal test reporter (best used with --watch). + * + * @param {Runner} runner + * @api public + */ + +function Min(runner) { + Base.call(this, runner); + + runner.on('start', function(){ + // clear screen + process.stdout.write('\u001b[2J'); + // set cursor position + process.stdout.write('\u001b[1;3H'); + }); + + runner.on('end', this.epilogue.bind(this)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Min.prototype = new F; +Min.prototype.constructor = Min; + +}); // module: reporters/min.js + +require.register("reporters/nyan.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = NyanCat; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function NyanCat(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , rainbowColors = this.rainbowColors = self.generateColors() + , colorIndex = this.colorIndex = 0 + , numerOfLines = this.numberOfLines = 4 + , trajectories = this.trajectories = [[], [], [], []] + , nyanCatWidth = this.nyanCatWidth = 11 + , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) + , scoreboardWidth = this.scoreboardWidth = 5 + , tick = this.tick = 0 + , n = 0; + + runner.on('start', function(){ + Base.cursor.hide(); + self.draw('start'); + }); + + runner.on('pending', function(test){ + self.draw('pending'); + }); + + runner.on('pass', function(test){ + self.draw('pass'); + }); + + runner.on('fail', function(test, err){ + self.draw('fail'); + }); + + runner.on('end', function(){ + Base.cursor.show(); + for (var i = 0; i < self.numberOfLines; i++) write('\n'); + self.epilogue(); + }); +} + +/** + * Draw the nyan cat with runner `status`. + * + * @param {String} status + * @api private + */ + +NyanCat.prototype.draw = function(status){ + this.appendRainbow(); + this.drawScoreboard(); + this.drawRainbow(); + this.drawNyanCat(status); + this.tick = !this.tick; +}; + +/** + * Draw the "scoreboard" showing the number + * of passes, failures and pending tests. + * + * @api private + */ + +NyanCat.prototype.drawScoreboard = function(){ + var stats = this.stats; + var colors = Base.colors; + + function draw(color, n) { + write(' '); + write('\u001b[' + color + 'm' + n + '\u001b[0m'); + write('\n'); + } + + draw(colors.green, stats.passes); + draw(colors.fail, stats.failures); + draw(colors.pending, stats.pending); + write('\n'); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Append the rainbow. + * + * @api private + */ + +NyanCat.prototype.appendRainbow = function(){ + var segment = this.tick ? '_' : '-'; + var rainbowified = this.rainbowify(segment); + + for (var index = 0; index < this.numberOfLines; index++) { + var trajectory = this.trajectories[index]; + if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); + trajectory.push(rainbowified); + } +}; + +/** + * Draw the rainbow. + * + * @api private + */ + +NyanCat.prototype.drawRainbow = function(){ + var self = this; + + this.trajectories.forEach(function(line, index) { + write('\u001b[' + self.scoreboardWidth + 'C'); + write(line.join('')); + write('\n'); + }); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Draw the nyan cat with `status`. + * + * @param {String} status + * @api private + */ + +NyanCat.prototype.drawNyanCat = function(status) { + var self = this; + var startWidth = this.scoreboardWidth + this.trajectories[0].length; + + [0, 1, 2, 3].forEach(function(index) { + write('\u001b[' + startWidth + 'C'); + + switch (index) { + case 0: + write('_,------,'); + write('\n'); + break; + case 1: + var padding = self.tick ? ' ' : ' '; + write('_|' + padding + '/\\_/\\ '); + write('\n'); + break; + case 2: + var padding = self.tick ? '_' : '__'; + var tail = self.tick ? '~' : '^'; + var face; + switch (status) { + case 'pass': + face = '( ^ .^)'; + break; + case 'fail': + face = '( o .o)'; + break; + default: + face = '( - .-)'; + } + write(tail + '|' + padding + face + ' '); + write('\n'); + break; + case 3: + var padding = self.tick ? ' ' : ' '; + write(padding + '"" "" '); + write('\n'); + break; + } + }); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Move cursor up `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorUp = function(n) { + write('\u001b[' + n + 'A'); +}; + +/** + * Move cursor down `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorDown = function(n) { + write('\u001b[' + n + 'B'); +}; + +/** + * Generate rainbow colors. + * + * @return {Array} + * @api private + */ + +NyanCat.prototype.generateColors = function(){ + var colors = []; + + for (var i = 0; i < (6 * 7); i++) { + var pi3 = Math.floor(Math.PI / 3); + var n = (i * (1.0 / 6)); + var r = Math.floor(3 * Math.sin(n) + 3); + var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); + var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); + colors.push(36 * r + 6 * g + b + 16); + } + + return colors; +}; + +/** + * Apply rainbow to the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +NyanCat.prototype.rainbowify = function(str){ + var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; + this.colorIndex += 1; + return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; +}; + +/** + * Stdout helper. + */ + +function write(string) { + process.stdout.write(string); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +NyanCat.prototype = new F; +NyanCat.prototype.constructor = NyanCat; + + +}); // module: reporters/nyan.js + +require.register("reporters/progress.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Progress`. + */ + +exports = module.exports = Progress; + +/** + * General progress bar color. + */ + +Base.colors.progress = 90; + +/** + * Initialize a new `Progress` bar test reporter. + * + * @param {Runner} runner + * @param {Object} options + * @api public + */ + +function Progress(runner, options) { + Base.call(this, runner); + + var self = this + , options = options || {} + , stats = this.stats + , width = Base.window.width * .50 | 0 + , total = runner.total + , complete = 0 + , max = Math.max; + + // default chars + options.open = options.open || '['; + options.complete = options.complete || '▬'; + options.incomplete = options.incomplete || Base.symbols.dot; + options.close = options.close || ']'; + options.verbose = false; + + // tests started + runner.on('start', function(){ + console.log(); + cursor.hide(); + }); + + // tests complete + runner.on('test end', function(){ + complete++; + var incomplete = total - complete + , percent = complete / total + , n = width * percent | 0 + , i = width - n; + + cursor.CR(); + process.stdout.write('\u001b[J'); + process.stdout.write(color('progress', ' ' + options.open)); + process.stdout.write(Array(n).join(options.complete)); + process.stdout.write(Array(i).join(options.incomplete)); + process.stdout.write(color('progress', options.close)); + if (options.verbose) { + process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); + } + }); + + // tests are complete, output some stats + // and the failures if any + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Progress.prototype = new F; +Progress.prototype.constructor = Progress; + + +}); // module: reporters/progress.js + +require.register("reporters/spec.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Spec`. + */ + +exports = module.exports = Spec; + +/** + * Initialize a new `Spec` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Spec(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , indents = 0 + , n = 0; + + function indent() { + return Array(indents).join(' ') + } + + runner.on('start', function(){ + console.log(); + }); + + runner.on('suite', function(suite){ + ++indents; + console.log(color('suite', '%s%s'), indent(), suite.title); + }); + + runner.on('suite end', function(suite){ + --indents; + if (1 == indents) console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = indent() + color('pending', ' - %s'); + console.log(fmt, test.title); + }); + + runner.on('pass', function(test){ + if ('fast' == test.speed) { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s '); + cursor.CR(); + console.log(fmt, test.title); + } else { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s ') + + color(test.speed, '(%dms)'); + cursor.CR(); + console.log(fmt, test.title, test.duration); + } + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Spec.prototype = new F; +Spec.prototype.constructor = Spec; + + +}); // module: reporters/spec.js + +require.register("reporters/tap.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `TAP`. + */ + +exports = module.exports = TAP; + +/** + * Initialize a new `TAP` reporter. + * + * @param {Runner} runner + * @api public + */ + +function TAP(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 1 + , passes = 0 + , failures = 0; + + runner.on('start', function(){ + var total = runner.grepTotal(runner.suite); + console.log('%d..%d', 1, total); + }); + + runner.on('test end', function(){ + ++n; + }); + + runner.on('pending', function(test){ + console.log('ok %d %s # SKIP -', n, title(test)); + }); + + runner.on('pass', function(test){ + passes++; + console.log('ok %d %s', n, title(test)); + }); + + runner.on('fail', function(test, err){ + failures++; + console.log('not ok %d %s', n, title(test)); + if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); + }); + + runner.on('end', function(){ + console.log('# tests ' + (passes + failures)); + console.log('# pass ' + passes); + console.log('# fail ' + failures); + }); +} + +/** + * Return a TAP-safe title of `test` + * + * @param {Object} test + * @return {String} + * @api private + */ + +function title(test) { + return test.fullTitle().replace(/#/g, ''); +} + +}); // module: reporters/tap.js + +require.register("reporters/teamcity.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Teamcity`. + */ + +exports = module.exports = Teamcity; + +/** + * Initialize a new `Teamcity` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Teamcity(runner) { + Base.call(this, runner); + var stats = this.stats; + + runner.on('start', function() { + console.log("##teamcity[testSuiteStarted name='mocha.suite']"); + }); + + runner.on('test', function(test) { + console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']"); + }); + + runner.on('fail', function(test, err) { + console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']"); + }); + + runner.on('pending', function(test) { + console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']"); + }); + + runner.on('test end', function(test) { + console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']"); + }); + + runner.on('end', function() { + console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']"); + }); +} + +/** + * Escape the given `str`. + */ + +function escape(str) { + return str + .replace(/\|/g, "||") + .replace(/\n/g, "|n") + .replace(/\r/g, "|r") + .replace(/\[/g, "|[") + .replace(/\]/g, "|]") + .replace(/\u0085/g, "|x") + .replace(/\u2028/g, "|l") + .replace(/\u2029/g, "|p") + .replace(/'/g, "|'"); +} + +}); // module: reporters/teamcity.js + +require.register("reporters/xunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `XUnit`. + */ + +exports = module.exports = XUnit; + +/** + * Initialize a new `XUnit` reporter. + * + * @param {Runner} runner + * @api public + */ + +function XUnit(runner) { + Base.call(this, runner); + var stats = this.stats + , tests = [] + , self = this; + + runner.on('pass', function(test){ + tests.push(test); + }); + + runner.on('fail', function(test){ + tests.push(test); + }); + + runner.on('end', function(){ + console.log(tag('testsuite', { + name: 'Mocha Tests' + , tests: stats.tests + , failures: stats.failures + , errors: stats.failures + , skip: stats.tests - stats.failures - stats.passes + , timestamp: (new Date).toUTCString() + , time: stats.duration / 1000 + }, false)); + + tests.forEach(test); + console.log(''); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +XUnit.prototype = new F; +XUnit.prototype.constructor = XUnit; + + +/** + * Output tag for the given `test.` + */ + +function test(test) { + var attrs = { + classname: test.parent.fullTitle() + , name: test.title + , time: test.duration / 1000 + }; + + if ('failed' == test.state) { + var err = test.err; + attrs.message = escape(err.message); + console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); + } else if (test.pending) { + console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); + } else { + console.log(tag('testcase', attrs, true) ); + } +} + +/** + * HTML tag helper. + */ + +function tag(name, attrs, close, content) { + var end = close ? '/>' : '>' + , pairs = [] + , tag; + + for (var key in attrs) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } + + tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; + if (content) tag += content + ''; +} + +}); // module: reporters/xunit.js + +require.register("runnable.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runnable') + , milliseconds = require('./ms'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Object#toString(). + */ + +var toString = Object.prototype.toString; + +/** + * Expose `Runnable`. + */ + +module.exports = Runnable; + +/** + * Initialize a new `Runnable` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Runnable(title, fn) { + this.title = title; + this.fn = fn; + this.async = fn && fn.length; + this.sync = ! this.async; + this._timeout = 2000; + this._slow = 75; + this.timedOut = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runnable.prototype = new F; +Runnable.prototype.constructor = Runnable; + + +/** + * Set & get timeout `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = ms; + if (this.timer) this.resetTimeout(); + return this; +}; + +/** + * Set & get slow `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._slow = ms; + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Runnable.prototype.fullTitle = function(){ + return this.parent.fullTitle() + ' ' + this.title; +}; + +/** + * Clear the timeout. + * + * @api private + */ + +Runnable.prototype.clearTimeout = function(){ + clearTimeout(this.timer); +}; + +/** + * Inspect the runnable void of private properties. + * + * @return {String} + * @api private + */ + +Runnable.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_' == key[0]) return; + if ('parent' == key) return '#'; + if ('ctx' == key) return '#'; + return val; + }, 2); +}; + +/** + * Reset the timeout. + * + * @api private + */ + +Runnable.prototype.resetTimeout = function(){ + var self = this + , ms = this.timeout(); + + this.clearTimeout(); + if (ms) { + this.timer = setTimeout(function(){ + self.callback(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); + } +}; + +/** + * Run the test and invoke `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runnable.prototype.run = function(fn){ + var self = this + , ms = this.timeout() + , start = new Date + , ctx = this.ctx + , finished + , emitted; + + if (ctx) ctx.runnable(this); + + // timeout + if (this.async) { + if (ms) { + this.timer = setTimeout(function(){ + done(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); + } + } + + // called multiple times + function multiple(err) { + if (emitted) return; + emitted = true; + self.emit('error', err || new Error('done() called multiple times')); + } + + // finished + function done(err) { + if (self.timedOut) return; + if (finished) return multiple(err); + self.clearTimeout(); + self.duration = new Date - start; + finished = true; + fn(err); + } + + // for .resetTimeout() + this.callback = done; + + // async + if (this.async) { + try { + this.fn.call(ctx, function(err){ + if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); + if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); + done(); + }); + } catch (err) { + done(err); + } + return; + } + + if (this.asyncOnly) { + return done(new Error('--async-only option in use without declaring `done()`')); + } + + // sync + try { + if (!this.pending) this.fn.call(ctx); + this.duration = new Date - start; + fn(); + } catch (err) { + fn(err); + } +}; + +}); // module: runnable.js + +require.register("runner.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runner') + , Test = require('./test') + , utils = require('./utils') + , filter = utils.filter + , keys = utils.keys + , noop = function(){}; + +/** + * Non-enumerable globals. + */ + +var globals = [ + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'XMLHttpRequest', + 'Date' +]; + +/** + * Expose `Runner`. + */ + +module.exports = Runner; + +/** + * Initialize a `Runner` for the given `suite`. + * + * Events: + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * + * @api public + */ + +function Runner(suite) { + var self = this; + this._globals = []; + this.suite = suite; + this.total = suite.total(); + this.failures = 0; + this.on('test end', function(test){ self.checkGlobals(test); }); + this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.grep(/.*/); + this.globals(this.globalProps().concat(['errno'])); +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runner.prototype = new F; +Runner.prototype.constructor = Runner; + + +/** + * Run tests with full titles matching `re`. Updates runner.total + * with number of tests matched. + * + * @param {RegExp} re + * @param {Boolean} invert + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.grep = function(re, invert){ + debug('grep %s', re); + this._grep = re; + this._invert = invert; + this.total = this.grepTotal(this.suite); + return this; +}; + +/** + * Returns the number of tests matching the grep search for the + * given suite. + * + * @param {Suite} suite + * @return {Number} + * @api public + */ + +Runner.prototype.grepTotal = function(suite) { + var self = this; + var total = 0; + + suite.eachTest(function(test){ + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (match) total++; + }); + + return total; +}; + +/** + * Return a list of global properties. + * + * @return {Array} + * @api private + */ + +Runner.prototype.globalProps = function() { + var props = utils.keys(global); + + // non-enumerables + for (var i = 0; i < globals.length; ++i) { + if (~utils.indexOf(props, globals[i])) continue; + props.push(globals[i]); + } + + return props; +}; + +/** + * Allow the given `arr` of globals. + * + * @param {Array} arr + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; + debug('globals %j', arr); + utils.forEach(arr, function(arr){ + this._globals.push(arr); + }, this); + return this; +}; + +/** + * Check for global variable leaks. + * + * @api private + */ + +Runner.prototype.checkGlobals = function(test){ + if (this.ignoreLeaks) return; + var ok = this._globals; + var globals = this.globalProps(); + var isNode = process.kill; + var leaks; + + // check length - 2 ('errno' and 'location' globals) + if (isNode && 1 == ok.length - globals.length) return + else if (2 == ok.length - globals.length) return; + + leaks = filterLeaks(ok, globals); + this._globals = this._globals.concat(leaks); + + if (leaks.length > 1) { + this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); + } else if (leaks.length) { + this.fail(test, new Error('global leak detected: ' + leaks[0])); + } +}; + +/** + * Fail the given `test`. + * + * @param {Test} test + * @param {Error} err + * @api private + */ + +Runner.prototype.fail = function(test, err){ + ++this.failures; + test.state = 'failed'; + + if ('string' == typeof err) { + err = new Error('the string "' + err + '" was thrown, throw an Error :)'); + } + + this.emit('fail', test, err); +}; + +/** + * Fail the given `hook` with `err`. + * + * Hook failures (currently) hard-end due + * to that fact that a failing hook will + * surely cause subsequent tests to fail, + * causing jumbled reporting. + * + * @param {Hook} hook + * @param {Error} err + * @api private + */ + +Runner.prototype.failHook = function(hook, err){ + this.fail(hook, err); + this.emit('end'); +}; + +/** + * Run hook `name` callbacks and then invoke `fn()`. + * + * @param {String} name + * @param {Function} function + * @api private + */ + +Runner.prototype.hook = function(name, fn){ + var suite = this.suite + , hooks = suite['_' + name] + , self = this + , timer; + + function next(i) { + var hook = hooks[i]; + if (!hook) return fn(); + self.currentRunnable = hook; + + self.emit('hook', hook); + + hook.on('error', function(err){ + self.failHook(hook, err); + }); + + hook.run(function(err){ + hook.removeAllListeners('error'); + var testError = hook.error(); + if (testError) self.fail(self.test, testError); + if (err) return self.failHook(hook, err); + self.emit('hook end', hook); + next(++i); + }); + } + + process.nextTick(function(){ + next(0); + }); +}; + +/** + * Run hook `name` for the given array of `suites` + * in order, and callback `fn(err)`. + * + * @param {String} name + * @param {Array} suites + * @param {Function} fn + * @api private + */ + +Runner.prototype.hooks = function(name, suites, fn){ + var self = this + , orig = this.suite; + + function next(suite) { + self.suite = suite; + + if (!suite) { + self.suite = orig; + return fn(); + } + + self.hook(name, function(err){ + if (err) { + self.suite = orig; + return fn(err); + } + + next(suites.pop()); + }); + } + + next(suites.pop()); +}; + +/** + * Run hooks from the top level down. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookUp = function(name, fn){ + var suites = [this.suite].concat(this.parents()).reverse(); + this.hooks(name, suites, fn); +}; + +/** + * Run hooks from the bottom up. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookDown = function(name, fn){ + var suites = [this.suite].concat(this.parents()); + this.hooks(name, suites, fn); +}; + +/** + * Return an array of parent Suites from + * closest to furthest. + * + * @return {Array} + * @api private + */ + +Runner.prototype.parents = function(){ + var suite = this.suite + , suites = []; + while (suite = suite.parent) suites.push(suite); + return suites; +}; + +/** + * Run the current test and callback `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTest = function(fn){ + var test = this.test + , self = this; + + if (this.asyncOnly) test.asyncOnly = true; + + try { + test.on('error', function(err){ + self.fail(test, err); + }); + test.run(fn); + } catch (err) { + fn(err); + } +}; + +/** + * Run tests in the given `suite` and invoke + * the callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTests = function(suite, fn){ + var self = this + , tests = suite.tests.slice() + , test; + + function next(err) { + // if we bail after first err + if (self.failures && suite._bail) return fn(); + + // next test + test = tests.shift(); + + // all done + if (!test) return fn(); + + // grep + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (!match) return next(); + + // pending + if (test.pending) { + self.emit('pending', test); + self.emit('test end', test); + return next(); + } + + // execute test and hook(s) + self.emit('test', self.test = test); + self.hookDown('beforeEach', function(){ + self.currentRunnable = self.test; + self.runTest(function(err){ + test = self.test; + + if (err) { + self.fail(test, err); + self.emit('test end', test); + return self.hookUp('afterEach', next); + } + + test.state = 'passed'; + self.emit('pass', test); + self.emit('test end', test); + self.hookUp('afterEach', next); + }); + }); + } + + this.next = next; + next(); +}; + +/** + * Run the given `suite` and invoke the + * callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runSuite = function(suite, fn){ + var total = this.grepTotal(suite) + , self = this + , i = 0; + + debug('run suite %s', suite.fullTitle()); + + if (!total) return fn(); + + this.emit('suite', this.suite = suite); + + function next() { + var curr = suite.suites[i++]; + if (!curr) return done(); + self.runSuite(curr, next); + } + + function done() { + self.suite = suite; + self.hook('afterAll', function(){ + self.emit('suite end', suite); + fn(); + }); + } + + this.hook('beforeAll', function(){ + self.runTests(suite, next); + }); +}; + +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + debug('uncaught exception %s', err.message); + var runnable = this.currentRunnable; + if (!runnable || 'failed' == runnable.state) return; + runnable.clearTimeout(); + err.uncaught = true; + this.fail(runnable, err); + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + +/** + * Run the root suite and invoke `fn(failures)` + * on completion. + * + * @param {Function} fn + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.run = function(fn){ + var self = this + , fn = fn || function(){}; + + debug('start'); + + // callback + this.on('end', function(){ + debug('end'); + process.removeListener('uncaughtException', function(err){ + self.uncaught(err); + }); + fn(self.failures); + }); + + // run suites + this.emit('start'); + this.runSuite(this.suite, function(){ + debug('finished running'); + self.emit('end'); + }); + + // uncaught exception + process.on('uncaughtException', function(err){ + self.uncaught(err); + }); + + return this; +}; + +/** + * Filter leaks with the given globals flagged as `ok`. + * + * @param {Array} ok + * @param {Array} globals + * @return {Array} + * @api private + */ + +function filterLeaks(ok, globals) { + return filter(globals, function(key){ + var matched = filter(ok, function(ok){ + if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); + // Opera and IE expose global variables for HTML element IDs (issue #243) + if (/^mocha-/.test(key)) return true; + return key == ok; + }); + return matched.length == 0 && (!global.navigator || 'onerror' !== key); + }); +} + +}); // module: runner.js + +require.register("suite.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:suite') + , milliseconds = require('./ms') + , utils = require('./utils') + , Hook = require('./hook'); + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` + * and parent `Suite`. When a suite with the + * same title is already present, that suite + * is returned to provide nicer reporter + * and more flexible meta-testing. + * + * @param {Suite} parent + * @param {String} title + * @return {Suite} + * @api public + */ + +exports.create = function(parent, title){ + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + if (parent.pending) suite.pending = true; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Initialize a new `Suite` with the given + * `title` and `ctx`. + * + * @param {String} title + * @param {Context} ctx + * @api private + */ + +function Suite(title, ctx) { + this.title = title; + this.ctx = ctx; + this.suites = []; + this.tests = []; + this.pending = false; + this._beforeEach = []; + this._beforeAll = []; + this._afterEach = []; + this._afterAll = []; + this.root = !title; + this._timeout = 2000; + this._slow = 75; + this._bail = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Suite.prototype = new F; +Suite.prototype.constructor = Suite; + + +/** + * Return a clone of this `Suite`. + * + * @return {Suite} + * @api private + */ + +Suite.prototype.clone = function(){ + var suite = new Suite(this.title); + debug('clone'); + suite.ctx = this.ctx; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + return suite; +}; + +/** + * Set timeout `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = parseInt(ms, 10); + return this; +}; + +/** + * Set slow `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('slow %d', ms); + this._slow = ms; + return this; +}; + +/** + * Sets whether to bail after first error. + * + * @parma {Boolean} bail + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.bail = function(bail){ + if (0 == arguments.length) return this._bail; + debug('bail %s', bail); + this._bail = bail; + return this; +}; + +/** + * Run `fn(test[, done])` before running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeAll = function(fn){ + if (this.pending) return this; + var hook = new Hook('"before all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeAll.push(hook); + this.emit('beforeAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterAll = function(fn){ + if (this.pending) return this; + var hook = new Hook('"after all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterAll.push(hook); + this.emit('afterAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` before each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeEach = function(fn){ + if (this.pending) return this; + var hook = new Hook('"before each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeEach.push(hook); + this.emit('beforeEach', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterEach = function(fn){ + if (this.pending) return this; + var hook = new Hook('"after each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterEach.push(hook); + this.emit('afterEach', hook); + return this; +}; + +/** + * Add a test `suite`. + * + * @param {Suite} suite + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addSuite = function(suite){ + suite.parent = this; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + this.suites.push(suite); + this.emit('suite', suite); + return this; +}; + +/** + * Add a `test` to this suite. + * + * @param {Test} test + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addTest = function(test){ + test.parent = this; + test.timeout(this.timeout()); + test.slow(this.slow()); + test.ctx = this.ctx; + this.tests.push(test); + this.emit('test', test); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Suite.prototype.fullTitle = function(){ + if (this.parent) { + var full = this.parent.fullTitle(); + if (full) return full + ' ' + this.title; + } + return this.title; +}; + +/** + * Return the total number of tests. + * + * @return {Number} + * @api public + */ + +Suite.prototype.total = function(){ + return utils.reduce(this.suites, function(sum, suite){ + return sum + suite.total(); + }, 0) + this.tests.length; +}; + +/** + * Iterates through each suite recursively to find + * all tests. Applies a function in the format + * `fn(test)`. + * + * @param {Function} fn + * @return {Suite} + * @api private + */ + +Suite.prototype.eachTest = function(fn){ + utils.forEach(this.tests, fn); + utils.forEach(this.suites, function(suite){ + suite.eachTest(fn); + }); + return this; +}; + +}); // module: suite.js + +require.register("test.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Test`. + */ + +module.exports = Test; + +/** + * Initialize a new `Test` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Test(title, fn) { + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Test.prototype = new F; +Test.prototype.constructor = Test; + + +}); // module: test.js + +require.register("utils.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var fs = require('browser/fs') + , path = require('browser/path') + , join = path.join + , debug = require('browser/debug')('mocha:watch'); + +/** + * Ignored directories. + */ + +var ignore = ['node_modules', '.git']; + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +}; + +/** + * Array#forEach (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.forEach = function(arr, fn, scope){ + for (var i = 0, l = arr.length; i < l; i++) + fn.call(scope, arr[i], i); +}; + +/** + * Array#indexOf (<=IE8) + * + * @parma {Array} arr + * @param {Object} obj to find index of + * @param {Number} start + * @api private + */ + +exports.indexOf = function(arr, obj, start){ + for (var i = start || 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) + return i; + } + return -1; +}; + +/** + * Array#reduce (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} initial value + * @api private + */ + +exports.reduce = function(arr, fn, val){ + var rval = val; + + for (var i = 0, l = arr.length; i < l; i++) { + rval = fn(rval, arr[i], i, arr); + } + + return rval; +}; + +/** + * Array#filter (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @api private + */ + +exports.filter = function(arr, fn){ + var ret = []; + + for (var i = 0, l = arr.length; i < l; i++) { + var val = arr[i]; + if (fn(val, i, arr)) ret.push(val); + } + + return ret; +}; + +/** + * Object.keys (<=IE8) + * + * @param {Object} obj + * @return {Array} keys + * @api private + */ + +exports.keys = Object.keys || function(obj) { + var keys = [] + , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 + + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); + } + } + + return keys; +}; + +/** + * Watch the given `files` for changes + * and invoke `fn(file)` on modification. + * + * @param {Array} files + * @param {Function} fn + * @api private + */ + +exports.watch = function(files, fn){ + var options = { interval: 100 }; + files.forEach(function(file){ + debug('file %s', file); + fs.watchFile(file, options, function(curr, prev){ + if (prev.mtime < curr.mtime) fn(file); + }); + }); +}; + +/** + * Ignored files. + */ + +function ignored(path){ + return !~ignore.indexOf(path); +} + +/** + * Lookup files in the given `dir`. + * + * @return {Array} + * @api private + */ + +exports.files = function(dir, ret){ + ret = ret || []; + + fs.readdirSync(dir) + .filter(ignored) + .forEach(function(path){ + path = join(dir, path); + if (fs.statSync(path).isDirectory()) { + exports.files(path, ret); + } else if (path.match(/\.(js|coffee)$/)) { + ret.push(path); + } + }); + + return ret; +}; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +exports.clean = function(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , re = new RegExp('^ {' + spaces + '}', 'gm'); + + str = str.replace(re, ''); + + return exports.trim(str); +}; + +/** + * Escape regular expression characters in `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.escapeRegexp = function(str){ + return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); +}; + +/** + * Trim the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.trim = function(str){ + return str.replace(/^\s+|\s+$/g, ''); +}; + +/** + * Parse the given `qs`. + * + * @param {String} qs + * @return {Object} + * @api private + */ + +exports.parseQuery = function(qs){ + return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ + var i = pair.indexOf('=') + , key = pair.slice(0, i) + , val = pair.slice(++i); + + obj[key] = decodeURIComponent(val); + return obj; + }, {}); +}; + +/** + * Highlight the given string of `js`. + * + * @param {String} js + * @return {String} + * @api private + */ + +function highlight(js) { + return js + .replace(//g, '>') + .replace(/\/\/(.*)/gm, '//$1') + .replace(/('.*?')/gm, '$1') + .replace(/(\d+\.\d+)/gm, '$1') + .replace(/(\d+)/gm, '$1') + .replace(/\bnew *(\w+)/gm, 'new $1') + .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') +} + +/** + * Highlight the contents of tag `name`. + * + * @param {String} name + * @api private + */ + +exports.highlightTags = function(name) { + var code = document.getElementsByTagName(name); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } +}; + +}); // module: utils.js +/** + * Node shims. + * + * These are meant only to allow + * mocha.js to run untouched, not + * to allow running node code in + * the browser. + */ + +process = {}; +process.exit = function(status){}; +process.stdout = {}; +global = window; + +/** + * next tick implementation. + */ + +process.nextTick = (function(){ + // postMessage behaves badly on IE8 + if (window.ActiveXObject || !window.postMessage) { + return function(fn){ fn() }; + } + + // based on setZeroTimeout by David Baron + // - http://dbaron.org/log/20100309-faster-timeouts + var timeouts = [] + , name = 'mocha-zero-timeout' + + window.addEventListener('message', function(e){ + if (e.source == window && e.data == name) { + if (e.stopPropagation) e.stopPropagation(); + if (timeouts.length) timeouts.shift()(); + } + }, true); + + return function(fn){ + timeouts.push(fn); + window.postMessage(name, '*'); + } +})(); + +/** + * Remove uncaughtException listener. + */ + +process.removeListener = function(e){ + if ('uncaughtException' == e) { + window.onerror = null; + } +}; + +/** + * Implements uncaughtException listener. + */ + +process.on = function(e, fn){ + if ('uncaughtException' == e) { + window.onerror = function(err, url, line){ + fn(new Error(err + ' (' + url + ':' + line + ')')); + }; + } +}; + +// boot +;(function(){ + + /** + * Expose mocha. + */ + + var Mocha = window.Mocha = require('mocha'), + mocha = window.mocha = new Mocha({ reporter: 'html' }); + + /** + * Override ui to ensure that the ui functions are initialized. + * Normally this would happen in Mocha.prototype.loadFiles. + */ + + mocha.ui = function(ui){ + Mocha.prototype.ui.call(this, ui); + this.suite.emit('pre-require', window, null, this); + return this; + }; + + /** + * Setup mocha with the given setting options. + */ + + mocha.setup = function(opts){ + if ('string' == typeof opts) opts = { ui: opts }; + for (var opt in opts) this[opt](opts[opt]); + return this; + }; + + /** + * Run mocha, returning the Runner. + */ + + mocha.run = function(fn){ + var options = mocha.options; + mocha.globals('location'); + + var query = Mocha.utils.parseQuery(window.location.search || ''); + if (query.grep) mocha.grep(query.grep); + if (query.invert) mocha.invert(); + + return Mocha.prototype.run.call(mocha, function(){ + Mocha.utils.highlightTags('code'); + if (fn) fn(); + }); + }; +})(); +})(); \ No newline at end of file diff --git a/ember/test/spec/test.js b/ember/test/spec/test.js new file mode 100644 index 0000000..c6da5f0 --- /dev/null +++ b/ember/test/spec/test.js @@ -0,0 +1,11 @@ +/*global describe, it */ +'use strict'; +(function () { + describe('Give it some context', function () { + describe('maybe a bit more context here', function () { + it('should run here few assertions', function () { + + }); + }); + }); +})(); diff --git a/Gruntfile.js b/jquery-spaghetti/Gruntfile.js similarity index 100% rename from Gruntfile.js rename to jquery-spaghetti/Gruntfile.js diff --git a/README.md b/jquery-spaghetti/README.md similarity index 100% rename from README.md rename to jquery-spaghetti/README.md diff --git a/app/README.md b/jquery-spaghetti/app/README.md similarity index 100% rename from app/README.md rename to jquery-spaghetti/app/README.md diff --git a/app/crypto.js b/jquery-spaghetti/app/crypto.js similarity index 100% rename from app/crypto.js rename to jquery-spaghetti/app/crypto.js diff --git a/app/dom.js b/jquery-spaghetti/app/dom.js similarity index 100% rename from app/dom.js rename to jquery-spaghetti/app/dom.js diff --git a/app/downloader.js b/jquery-spaghetti/app/downloader.js similarity index 100% rename from app/downloader.js rename to jquery-spaghetti/app/downloader.js diff --git a/app/formatters.js b/jquery-spaghetti/app/formatters.js similarity index 100% rename from app/formatters.js rename to jquery-spaghetti/app/formatters.js diff --git a/app/shared.js b/jquery-spaghetti/app/shared.js similarity index 100% rename from app/shared.js rename to jquery-spaghetti/app/shared.js diff --git a/app/uploader.js b/jquery-spaghetti/app/uploader.js similarity index 100% rename from app/uploader.js rename to jquery-spaghetti/app/uploader.js diff --git a/app/views/DownloadView.js b/jquery-spaghetti/app/views/DownloadView.js similarity index 100% rename from app/views/DownloadView.js rename to jquery-spaghetti/app/views/DownloadView.js diff --git a/app/views/FooterView.js b/jquery-spaghetti/app/views/FooterView.js similarity index 100% rename from app/views/FooterView.js rename to jquery-spaghetti/app/views/FooterView.js diff --git a/app/views/MainView.js b/jquery-spaghetti/app/views/MainView.js similarity index 100% rename from app/views/MainView.js rename to jquery-spaghetti/app/views/MainView.js diff --git a/app/views/UploadView.js b/jquery-spaghetti/app/views/UploadView.js similarity index 100% rename from app/views/UploadView.js rename to jquery-spaghetti/app/views/UploadView.js diff --git a/app/xhrWorker.js b/jquery-spaghetti/app/xhrWorker.js similarity index 100% rename from app/xhrWorker.js rename to jquery-spaghetti/app/xhrWorker.js diff --git a/css/bootstrap.min.css b/jquery-spaghetti/css/bootstrap.min.css similarity index 100% rename from css/bootstrap.min.css rename to jquery-spaghetti/css/bootstrap.min.css diff --git a/css/style.css b/jquery-spaghetti/css/style.css similarity index 100% rename from css/style.css rename to jquery-spaghetti/css/style.css diff --git a/css/style.sass b/jquery-spaghetti/css/style.sass similarity index 100% rename from css/style.sass rename to jquery-spaghetti/css/style.sass diff --git a/favicon.ico b/jquery-spaghetti/favicon.ico similarity index 100% rename from favicon.ico rename to jquery-spaghetti/favicon.ico diff --git a/fonts/glyphicons-halflings-regular.eot b/jquery-spaghetti/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from fonts/glyphicons-halflings-regular.eot rename to jquery-spaghetti/fonts/glyphicons-halflings-regular.eot diff --git a/fonts/glyphicons-halflings-regular.svg b/jquery-spaghetti/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from fonts/glyphicons-halflings-regular.svg rename to jquery-spaghetti/fonts/glyphicons-halflings-regular.svg diff --git a/fonts/glyphicons-halflings-regular.ttf b/jquery-spaghetti/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from fonts/glyphicons-halflings-regular.ttf rename to jquery-spaghetti/fonts/glyphicons-halflings-regular.ttf diff --git a/fonts/glyphicons-halflings-regular.woff b/jquery-spaghetti/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from fonts/glyphicons-halflings-regular.woff rename to jquery-spaghetti/fonts/glyphicons-halflings-regular.woff diff --git a/img/ajax-loader-pacman-inverse.gif b/jquery-spaghetti/img/ajax-loader-pacman-inverse.gif similarity index 100% rename from img/ajax-loader-pacman-inverse.gif rename to jquery-spaghetti/img/ajax-loader-pacman-inverse.gif diff --git a/img/ajax-loader-pacman.gif b/jquery-spaghetti/img/ajax-loader-pacman.gif similarity index 100% rename from img/ajax-loader-pacman.gif rename to jquery-spaghetti/img/ajax-loader-pacman.gif diff --git a/img/bg-texture.png b/jquery-spaghetti/img/bg-texture.png similarity index 100% rename from img/bg-texture.png rename to jquery-spaghetti/img/bg-texture.png diff --git a/img/bx_loader.gif b/jquery-spaghetti/img/bx_loader.gif similarity index 100% rename from img/bx_loader.gif rename to jquery-spaghetti/img/bx_loader.gif diff --git a/img/controls.png b/jquery-spaghetti/img/controls.png similarity index 100% rename from img/controls.png rename to jquery-spaghetti/img/controls.png diff --git a/jquery-spaghetti/img/download.png b/jquery-spaghetti/img/download.png new file mode 100644 index 0000000000000000000000000000000000000000..1fab2cb8af642df5a10a258ee39d0de2f85b24a3 GIT binary patch literal 38393 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 YUt$P#K(9Tz0ssI207*qoM6N<$g2}9FhX4Qo literal 0 HcmV?d00001 diff --git a/img/people/anthony_weiner.jpg b/jquery-spaghetti/img/people/anthony_weiner.jpg similarity index 100% rename from img/people/anthony_weiner.jpg rename to jquery-spaghetti/img/people/anthony_weiner.jpg diff --git a/img/people/brett_favre.jpg b/jquery-spaghetti/img/people/brett_favre.jpg similarity index 100% rename from img/people/brett_favre.jpg rename to jquery-spaghetti/img/people/brett_favre.jpg diff --git a/img/people/facepalm.jpg b/jquery-spaghetti/img/people/facepalm.jpg similarity index 100% rename from img/people/facepalm.jpg rename to jquery-spaghetti/img/people/facepalm.jpg diff --git a/img/people/julian_assange.jpg b/jquery-spaghetti/img/people/julian_assange.jpg similarity index 100% rename from img/people/julian_assange.jpg rename to jquery-spaghetti/img/people/julian_assange.jpg diff --git a/img/people/petraeus.jpg b/jquery-spaghetti/img/people/petraeus.jpg similarity index 100% rename from img/people/petraeus.jpg rename to jquery-spaghetti/img/people/petraeus.jpg diff --git a/img/tsecret.png b/jquery-spaghetti/img/tsecret.png similarity index 100% rename from img/tsecret.png rename to jquery-spaghetti/img/tsecret.png diff --git a/includes/footer.jade b/jquery-spaghetti/includes/footer.jade similarity index 100% rename from includes/footer.jade rename to jquery-spaghetti/includes/footer.jade diff --git a/includes/head.jade b/jquery-spaghetti/includes/head.jade similarity index 100% rename from includes/head.jade rename to jquery-spaghetti/includes/head.jade diff --git a/index.jade b/jquery-spaghetti/index.jade similarity index 100% rename from index.jade rename to jquery-spaghetti/index.jade diff --git a/package.json b/jquery-spaghetti/package.json similarity index 100% rename from package.json rename to jquery-spaghetti/package.json diff --git a/vendor/BrowserDetect.js b/jquery-spaghetti/vendor/BrowserDetect.js similarity index 100% rename from vendor/BrowserDetect.js rename to jquery-spaghetti/vendor/BrowserDetect.js diff --git a/vendor/bootstrap-modal.js b/jquery-spaghetti/vendor/bootstrap-modal.js similarity index 100% rename from vendor/bootstrap-modal.js rename to jquery-spaghetti/vendor/bootstrap-modal.js diff --git a/vendor/cryptoJS/components/aes-min.js b/jquery-spaghetti/vendor/cryptoJS/components/aes-min.js similarity index 100% rename from vendor/cryptoJS/components/aes-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/aes-min.js diff --git a/vendor/cryptoJS/components/aes.js b/jquery-spaghetti/vendor/cryptoJS/components/aes.js similarity index 100% rename from vendor/cryptoJS/components/aes.js rename to jquery-spaghetti/vendor/cryptoJS/components/aes.js diff --git a/vendor/cryptoJS/components/cipher-core-min.js b/jquery-spaghetti/vendor/cryptoJS/components/cipher-core-min.js similarity index 100% rename from vendor/cryptoJS/components/cipher-core-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/cipher-core-min.js diff --git a/vendor/cryptoJS/components/cipher-core.js b/jquery-spaghetti/vendor/cryptoJS/components/cipher-core.js similarity index 100% rename from vendor/cryptoJS/components/cipher-core.js rename to jquery-spaghetti/vendor/cryptoJS/components/cipher-core.js diff --git a/vendor/cryptoJS/components/core-min.js b/jquery-spaghetti/vendor/cryptoJS/components/core-min.js similarity index 100% rename from vendor/cryptoJS/components/core-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/core-min.js diff --git a/vendor/cryptoJS/components/core.js b/jquery-spaghetti/vendor/cryptoJS/components/core.js similarity index 100% rename from vendor/cryptoJS/components/core.js rename to jquery-spaghetti/vendor/cryptoJS/components/core.js diff --git a/vendor/cryptoJS/components/enc-base64-min.js b/jquery-spaghetti/vendor/cryptoJS/components/enc-base64-min.js similarity index 100% rename from vendor/cryptoJS/components/enc-base64-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/enc-base64-min.js diff --git a/vendor/cryptoJS/components/enc-base64.js b/jquery-spaghetti/vendor/cryptoJS/components/enc-base64.js similarity index 100% rename from vendor/cryptoJS/components/enc-base64.js rename to jquery-spaghetti/vendor/cryptoJS/components/enc-base64.js diff --git a/vendor/cryptoJS/components/enc-utf16-min.js b/jquery-spaghetti/vendor/cryptoJS/components/enc-utf16-min.js similarity index 100% rename from vendor/cryptoJS/components/enc-utf16-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/enc-utf16-min.js diff --git a/vendor/cryptoJS/components/enc-utf16.js b/jquery-spaghetti/vendor/cryptoJS/components/enc-utf16.js similarity index 100% rename from vendor/cryptoJS/components/enc-utf16.js rename to jquery-spaghetti/vendor/cryptoJS/components/enc-utf16.js diff --git a/vendor/cryptoJS/components/evpkdf-min.js b/jquery-spaghetti/vendor/cryptoJS/components/evpkdf-min.js similarity index 100% rename from vendor/cryptoJS/components/evpkdf-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/evpkdf-min.js diff --git a/vendor/cryptoJS/components/evpkdf.js b/jquery-spaghetti/vendor/cryptoJS/components/evpkdf.js similarity index 100% rename from vendor/cryptoJS/components/evpkdf.js rename to jquery-spaghetti/vendor/cryptoJS/components/evpkdf.js diff --git a/vendor/cryptoJS/components/hmac-min.js b/jquery-spaghetti/vendor/cryptoJS/components/hmac-min.js similarity index 100% rename from vendor/cryptoJS/components/hmac-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/hmac-min.js diff --git a/vendor/cryptoJS/components/hmac.js b/jquery-spaghetti/vendor/cryptoJS/components/hmac.js similarity index 100% rename from vendor/cryptoJS/components/hmac.js rename to jquery-spaghetti/vendor/cryptoJS/components/hmac.js diff --git a/vendor/cryptoJS/components/md5-min.js b/jquery-spaghetti/vendor/cryptoJS/components/md5-min.js similarity index 100% rename from vendor/cryptoJS/components/md5-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/md5-min.js diff --git a/vendor/cryptoJS/components/md5.js b/jquery-spaghetti/vendor/cryptoJS/components/md5.js similarity index 100% rename from vendor/cryptoJS/components/md5.js rename to jquery-spaghetti/vendor/cryptoJS/components/md5.js diff --git a/vendor/cryptoJS/components/mode-cfb-min.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-cfb-min.js similarity index 100% rename from vendor/cryptoJS/components/mode-cfb-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-cfb-min.js diff --git a/vendor/cryptoJS/components/mode-cfb.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-cfb.js similarity index 100% rename from vendor/cryptoJS/components/mode-cfb.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-cfb.js diff --git a/vendor/cryptoJS/components/mode-ctr-min.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-ctr-min.js similarity index 100% rename from vendor/cryptoJS/components/mode-ctr-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-ctr-min.js diff --git a/vendor/cryptoJS/components/mode-ctr.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-ctr.js similarity index 100% rename from vendor/cryptoJS/components/mode-ctr.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-ctr.js diff --git a/vendor/cryptoJS/components/mode-ecb-min.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-ecb-min.js similarity index 100% rename from vendor/cryptoJS/components/mode-ecb-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-ecb-min.js diff --git a/vendor/cryptoJS/components/mode-ecb.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-ecb.js similarity index 100% rename from vendor/cryptoJS/components/mode-ecb.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-ecb.js diff --git a/vendor/cryptoJS/components/mode-ofb-min.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-ofb-min.js similarity index 100% rename from vendor/cryptoJS/components/mode-ofb-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-ofb-min.js diff --git a/vendor/cryptoJS/components/mode-ofb.js b/jquery-spaghetti/vendor/cryptoJS/components/mode-ofb.js similarity index 100% rename from vendor/cryptoJS/components/mode-ofb.js rename to jquery-spaghetti/vendor/cryptoJS/components/mode-ofb.js diff --git a/vendor/cryptoJS/components/pad-ansix923-min.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-ansix923-min.js similarity index 100% rename from vendor/cryptoJS/components/pad-ansix923-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-ansix923-min.js diff --git a/vendor/cryptoJS/components/pad-ansix923.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-ansix923.js similarity index 100% rename from vendor/cryptoJS/components/pad-ansix923.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-ansix923.js diff --git a/vendor/cryptoJS/components/pad-iso10126-min.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-iso10126-min.js similarity index 100% rename from vendor/cryptoJS/components/pad-iso10126-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-iso10126-min.js diff --git a/vendor/cryptoJS/components/pad-iso10126.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-iso10126.js similarity index 100% rename from vendor/cryptoJS/components/pad-iso10126.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-iso10126.js diff --git a/vendor/cryptoJS/components/pad-iso97971-min.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-iso97971-min.js similarity index 100% rename from vendor/cryptoJS/components/pad-iso97971-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-iso97971-min.js diff --git a/vendor/cryptoJS/components/pad-iso97971.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-iso97971.js similarity index 100% rename from vendor/cryptoJS/components/pad-iso97971.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-iso97971.js diff --git a/vendor/cryptoJS/components/pad-nopadding-min.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-nopadding-min.js similarity index 100% rename from vendor/cryptoJS/components/pad-nopadding-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-nopadding-min.js diff --git a/vendor/cryptoJS/components/pad-nopadding.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-nopadding.js similarity index 100% rename from vendor/cryptoJS/components/pad-nopadding.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-nopadding.js diff --git a/vendor/cryptoJS/components/pad-zeropadding-min.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-zeropadding-min.js similarity index 100% rename from vendor/cryptoJS/components/pad-zeropadding-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-zeropadding-min.js diff --git a/vendor/cryptoJS/components/pad-zeropadding.js b/jquery-spaghetti/vendor/cryptoJS/components/pad-zeropadding.js similarity index 100% rename from vendor/cryptoJS/components/pad-zeropadding.js rename to jquery-spaghetti/vendor/cryptoJS/components/pad-zeropadding.js diff --git a/vendor/cryptoJS/components/pbkdf2-min.js b/jquery-spaghetti/vendor/cryptoJS/components/pbkdf2-min.js similarity index 100% rename from vendor/cryptoJS/components/pbkdf2-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/pbkdf2-min.js diff --git a/vendor/cryptoJS/components/pbkdf2.js b/jquery-spaghetti/vendor/cryptoJS/components/pbkdf2.js similarity index 100% rename from vendor/cryptoJS/components/pbkdf2.js rename to jquery-spaghetti/vendor/cryptoJS/components/pbkdf2.js diff --git a/vendor/cryptoJS/components/rabbit-min.js b/jquery-spaghetti/vendor/cryptoJS/components/rabbit-min.js similarity index 100% rename from vendor/cryptoJS/components/rabbit-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/rabbit-min.js diff --git a/vendor/cryptoJS/components/rabbit.js b/jquery-spaghetti/vendor/cryptoJS/components/rabbit.js similarity index 100% rename from vendor/cryptoJS/components/rabbit.js rename to jquery-spaghetti/vendor/cryptoJS/components/rabbit.js diff --git a/vendor/cryptoJS/components/rc4-min.js b/jquery-spaghetti/vendor/cryptoJS/components/rc4-min.js similarity index 100% rename from vendor/cryptoJS/components/rc4-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/rc4-min.js diff --git a/vendor/cryptoJS/components/rc4.js b/jquery-spaghetti/vendor/cryptoJS/components/rc4.js similarity index 100% rename from vendor/cryptoJS/components/rc4.js rename to jquery-spaghetti/vendor/cryptoJS/components/rc4.js diff --git a/vendor/cryptoJS/components/sha1-min.js b/jquery-spaghetti/vendor/cryptoJS/components/sha1-min.js similarity index 100% rename from vendor/cryptoJS/components/sha1-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha1-min.js diff --git a/vendor/cryptoJS/components/sha1.js b/jquery-spaghetti/vendor/cryptoJS/components/sha1.js similarity index 100% rename from vendor/cryptoJS/components/sha1.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha1.js diff --git a/vendor/cryptoJS/components/sha224-min.js b/jquery-spaghetti/vendor/cryptoJS/components/sha224-min.js similarity index 100% rename from vendor/cryptoJS/components/sha224-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha224-min.js diff --git a/vendor/cryptoJS/components/sha224.js b/jquery-spaghetti/vendor/cryptoJS/components/sha224.js similarity index 100% rename from vendor/cryptoJS/components/sha224.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha224.js diff --git a/vendor/cryptoJS/components/sha256-min.js b/jquery-spaghetti/vendor/cryptoJS/components/sha256-min.js similarity index 100% rename from vendor/cryptoJS/components/sha256-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha256-min.js diff --git a/vendor/cryptoJS/components/sha256.js b/jquery-spaghetti/vendor/cryptoJS/components/sha256.js similarity index 100% rename from vendor/cryptoJS/components/sha256.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha256.js diff --git a/vendor/cryptoJS/components/sha384-min.js b/jquery-spaghetti/vendor/cryptoJS/components/sha384-min.js similarity index 100% rename from vendor/cryptoJS/components/sha384-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha384-min.js diff --git a/vendor/cryptoJS/components/sha384.js b/jquery-spaghetti/vendor/cryptoJS/components/sha384.js similarity index 100% rename from vendor/cryptoJS/components/sha384.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha384.js diff --git a/vendor/cryptoJS/components/sha512-min.js b/jquery-spaghetti/vendor/cryptoJS/components/sha512-min.js similarity index 100% rename from vendor/cryptoJS/components/sha512-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha512-min.js diff --git a/vendor/cryptoJS/components/sha512.js b/jquery-spaghetti/vendor/cryptoJS/components/sha512.js similarity index 100% rename from vendor/cryptoJS/components/sha512.js rename to jquery-spaghetti/vendor/cryptoJS/components/sha512.js diff --git a/vendor/cryptoJS/components/tripledes-min.js b/jquery-spaghetti/vendor/cryptoJS/components/tripledes-min.js similarity index 100% rename from vendor/cryptoJS/components/tripledes-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/tripledes-min.js diff --git a/vendor/cryptoJS/components/tripledes.js b/jquery-spaghetti/vendor/cryptoJS/components/tripledes.js similarity index 100% rename from vendor/cryptoJS/components/tripledes.js rename to jquery-spaghetti/vendor/cryptoJS/components/tripledes.js diff --git a/vendor/cryptoJS/components/x64-core-min.js b/jquery-spaghetti/vendor/cryptoJS/components/x64-core-min.js similarity index 100% rename from vendor/cryptoJS/components/x64-core-min.js rename to jquery-spaghetti/vendor/cryptoJS/components/x64-core-min.js diff --git a/vendor/cryptoJS/components/x64-core.js b/jquery-spaghetti/vendor/cryptoJS/components/x64-core.js similarity index 100% rename from vendor/cryptoJS/components/x64-core.js rename to jquery-spaghetti/vendor/cryptoJS/components/x64-core.js diff --git a/vendor/cryptoJS/rollups/aes.js b/jquery-spaghetti/vendor/cryptoJS/rollups/aes.js similarity index 100% rename from vendor/cryptoJS/rollups/aes.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/aes.js diff --git a/vendor/cryptoJS/rollups/hmac-md5.js b/jquery-spaghetti/vendor/cryptoJS/rollups/hmac-md5.js similarity index 100% rename from vendor/cryptoJS/rollups/hmac-md5.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/hmac-md5.js diff --git a/vendor/cryptoJS/rollups/hmac-sha1.js b/jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha1.js similarity index 100% rename from vendor/cryptoJS/rollups/hmac-sha1.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha1.js diff --git a/vendor/cryptoJS/rollups/hmac-sha224.js b/jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha224.js similarity index 100% rename from vendor/cryptoJS/rollups/hmac-sha224.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha224.js diff --git a/vendor/cryptoJS/rollups/hmac-sha256.js b/jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha256.js similarity index 100% rename from vendor/cryptoJS/rollups/hmac-sha256.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha256.js diff --git a/vendor/cryptoJS/rollups/hmac-sha384.js b/jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha384.js similarity index 100% rename from vendor/cryptoJS/rollups/hmac-sha384.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha384.js diff --git a/vendor/cryptoJS/rollups/hmac-sha512.js b/jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha512.js similarity index 100% rename from vendor/cryptoJS/rollups/hmac-sha512.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/hmac-sha512.js diff --git a/vendor/cryptoJS/rollups/md5.js b/jquery-spaghetti/vendor/cryptoJS/rollups/md5.js similarity index 100% rename from vendor/cryptoJS/rollups/md5.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/md5.js diff --git a/vendor/cryptoJS/rollups/pbkdf2.js b/jquery-spaghetti/vendor/cryptoJS/rollups/pbkdf2.js similarity index 100% rename from vendor/cryptoJS/rollups/pbkdf2.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/pbkdf2.js diff --git a/vendor/cryptoJS/rollups/rabbit.js b/jquery-spaghetti/vendor/cryptoJS/rollups/rabbit.js similarity index 100% rename from vendor/cryptoJS/rollups/rabbit.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/rabbit.js diff --git a/vendor/cryptoJS/rollups/rc4.js b/jquery-spaghetti/vendor/cryptoJS/rollups/rc4.js similarity index 100% rename from vendor/cryptoJS/rollups/rc4.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/rc4.js diff --git a/vendor/cryptoJS/rollups/sha1.js b/jquery-spaghetti/vendor/cryptoJS/rollups/sha1.js similarity index 100% rename from vendor/cryptoJS/rollups/sha1.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/sha1.js diff --git a/vendor/cryptoJS/rollups/sha224.js b/jquery-spaghetti/vendor/cryptoJS/rollups/sha224.js similarity index 100% rename from vendor/cryptoJS/rollups/sha224.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/sha224.js diff --git a/vendor/cryptoJS/rollups/sha256.js b/jquery-spaghetti/vendor/cryptoJS/rollups/sha256.js similarity index 100% rename from vendor/cryptoJS/rollups/sha256.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/sha256.js diff --git a/vendor/cryptoJS/rollups/sha384.js b/jquery-spaghetti/vendor/cryptoJS/rollups/sha384.js similarity index 100% rename from vendor/cryptoJS/rollups/sha384.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/sha384.js diff --git a/vendor/cryptoJS/rollups/sha512.js b/jquery-spaghetti/vendor/cryptoJS/rollups/sha512.js similarity index 100% rename from vendor/cryptoJS/rollups/sha512.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/sha512.js diff --git a/vendor/cryptoJS/rollups/tripledes.js b/jquery-spaghetti/vendor/cryptoJS/rollups/tripledes.js similarity index 100% rename from vendor/cryptoJS/rollups/tripledes.js rename to jquery-spaghetti/vendor/cryptoJS/rollups/tripledes.js diff --git a/vendor/jquery.js b/jquery-spaghetti/vendor/jquery.js similarity index 100% rename from vendor/jquery.js rename to jquery-spaghetti/vendor/jquery.js diff --git a/vendor/lodash.js b/jquery-spaghetti/vendor/lodash.js similarity index 100% rename from vendor/lodash.js rename to jquery-spaghetti/vendor/lodash.js diff --git a/vendor/lzw.js b/jquery-spaghetti/vendor/lzw.js similarity index 100% rename from vendor/lzw.js rename to jquery-spaghetti/vendor/lzw.js