[
  {
    "path": ".gitignore",
    "content": "lib-cov\n*.seed\n*.log\n*.csv\n*.dat\n*.out\n*.pid\n*.gz\n.idea\npids\nlogs\nresults\n\nnpm-debug.log\nworkspace\nnode_modules\n\nbrowser-version/src\nbrowser-version/node_modules\n\n*.swp\n*~\n*.swo"
  },
  {
    "path": "LICENSE",
    "content": "(The MIT License)\n\nCopyright (c) 2013 Louis Chatriot &lt;louis.chatriot@gmail.com&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "<img src=\"http://i.imgur.com/9O1xHFb.png\" style=\"width: 25%; height: 25%; float: left;\">\n\n## The JavaScript Database\n\n> :warning: :warning: :warning: **WARNING:** this library is no longer maintained, and may have bugs and security issues. Feel free to fork but no pull request or security alert will be answered.\n\n\n**Embedded persistent or in memory database for Node.js, nw.js, Electron and browsers, 100% JavaScript, no binary dependency**. API is a subset of MongoDB's and it's <a href=\"#speed\">plenty fast</a>.\n\n**IMPORTANT NOTE**: Please don't submit issues for questions regarding your code. Only actual bugs or feature requests will be answered, all others will be closed without comment. Also, please follow the <a href=\"#bug-reporting-guidelines\">bug reporting guidelines</a> and check the <a href=\"https://github.com/louischatriot/nedb/wiki/Change-log\" target=\"_blank\">change log</a> before submitting an already fixed bug :)\n\n\n## Installation, tests\nModule name on npm and bower is `nedb`.\n\n```\nnpm install nedb --save    # Put latest version in your package.json\nnpm test                   # You'll need the dev dependencies to launch tests\nbower install nedb         # For the browser versions, which will be in browser-version/out\n```\n\n## API\nIt is a subset of MongoDB's API (the most used operations).\n\n* <a href=\"#creatingloading-a-database\">Creating/loading a database</a>\n* <a href=\"#persistence\">Persistence</a>\n* <a href=\"#inserting-documents\">Inserting documents</a>\n* <a href=\"#finding-documents\">Finding documents</a>\n  * <a href=\"#basic-querying\">Basic Querying</a>\n  * <a href=\"#operators-lt-lte-gt-gte-in-nin-ne-exists-regex\">Operators ($lt, $lte, $gt, $gte, $in, $nin, $ne, $exists, $regex)</a>\n  * <a href=\"#array-fields\">Array fields</a>\n  * <a href=\"#logical-operators-or-and-not-where\">Logical operators $or, $and, $not, $where</a>\n  * <a href=\"#sorting-and-paginating\">Sorting and paginating</a>\n  * <a href=\"#projections\">Projections</a>\n* <a href=\"#counting-documents\">Counting documents</a>\n* <a href=\"#updating-documents\">Updating documents</a>\n* <a href=\"#removing-documents\">Removing documents</a>\n* <a href=\"#indexing\">Indexing</a>\n* <a href=\"#browser-version\">Browser version</a>\n\n### Creating/loading a database\nYou can use NeDB as an in-memory only datastore or as a persistent datastore. One datastore is the equivalent of a MongoDB collection. The constructor is used as follows `new Datastore(options)` where `options` is an object with the following fields:\n\n* `filename` (optional): path to the file where the data is persisted. If left blank, the datastore is automatically considered in-memory only. It cannot end with a `~` which is used in the temporary files NeDB uses to perform crash-safe writes.\n* `inMemoryOnly` (optional, defaults to `false`): as the name implies.\n* `timestampData` (optional, defaults to `false`): timestamp the insertion and last update of all documents, with the fields `createdAt` and `updatedAt`. User-specified values override automatic generation, usually useful for testing.\n* `autoload` (optional, defaults to `false`): if used, the database will automatically be loaded from the datafile upon creation (you don't need to call `loadDatabase`). Any command issued before load is finished is buffered and will be executed when load is done.\n* `onload` (optional): if you use autoloading, this is the handler called after the `loadDatabase`. It takes one `error` argument. If you use autoloading without specifying this handler, and an error happens during load, an error will be thrown.\n* `afterSerialization` (optional): hook you can use to transform data after it was serialized and before it is written to disk. Can be used for example to encrypt data before writing database to disk. This function takes a string as parameter (one line of an NeDB data file) and outputs the transformed string, **which must absolutely not contain a `\\n` character** (or data will be lost).\n* `beforeDeserialization` (optional): inverse of `afterSerialization`. Make sure to include both and not just one or you risk data loss. For the same reason, make sure both functions are inverses of one another. Some failsafe mechanisms are in place to prevent data loss if you misuse the serialization hooks: NeDB checks that never one is declared without the other, and checks that they are reverse of one another by testing on random strings of various lengths. In addition, if too much data is detected as corrupt, NeDB will refuse to start as it could mean you're not using the deserialization hook corresponding to the serialization hook used before (see below).\n* `corruptAlertThreshold` (optional): between 0 and 1, defaults to 10%. NeDB will refuse to start if more than this percentage of the datafile is corrupt. 0 means you don't tolerate any corruption, 1 means you don't care.\n* `compareStrings` (optional): function compareStrings(a, b) compares\n  strings a and b and return -1, 0 or 1. If specified, it overrides\ndefault string comparison which is not well adapted to non-US characters\nin particular accented letters. Native `localCompare` will most of the\ntime be the right choice\n* `nodeWebkitAppName` (optional, **DEPRECATED**): if you are using NeDB from whithin a Node Webkit app, specify its name (the same one you use in the `package.json`) in this field and the `filename` will be relative to the directory Node Webkit uses to store the rest of the application's data (local storage etc.). It works on Linux, OS X and Windows. Now that you can use `require('nw.gui').App.dataPath` in Node Webkit to get the path to the data directory for your application, you should not use this option anymore and it will be removed.\n\nIf you use a persistent datastore without the `autoload` option, you need to call `loadDatabase` manually.\nThis function fetches the data from datafile and prepares the database. **Don't forget it!** If you use a\npersistent datastore, no command (insert, find, update, remove) will be executed before `loadDatabase`\nis called, so make sure to call it yourself or use the `autoload` option.\n\nAlso, if `loadDatabase` fails, all commands registered to the executor afterwards will not be executed. They will be registered and executed, in sequence, only after a successful `loadDatabase`.\n\n```javascript\n// Type 1: In-memory only datastore (no need to load the database)\nvar Datastore = require('nedb')\n  , db = new Datastore();\n\n\n// Type 2: Persistent datastore with manual loading\nvar Datastore = require('nedb')\n  , db = new Datastore({ filename: 'path/to/datafile' });\ndb.loadDatabase(function (err) {    // Callback is optional\n  // Now commands will be executed\n});\n\n\n// Type 3: Persistent datastore with automatic loading\nvar Datastore = require('nedb')\n  , db = new Datastore({ filename: 'path/to/datafile', autoload: true });\n// You can issue commands right away\n\n\n// Type 4: Persistent datastore for a Node Webkit app called 'nwtest'\n// For example on Linux, the datafile will be ~/.config/nwtest/nedb-data/something.db\nvar Datastore = require('nedb')\n  , path = require('path')\n  , db = new Datastore({ filename: path.join(require('nw.gui').App.dataPath, 'something.db') });\n\n\n// Of course you can create multiple datastores if you need several\n// collections. In this case it's usually a good idea to use autoload for all collections.\ndb = {};\ndb.users = new Datastore('path/to/users.db');\ndb.robots = new Datastore('path/to/robots.db');\n\n// You need to load each database (here we do it asynchronously)\ndb.users.loadDatabase();\ndb.robots.loadDatabase();\n```\n\n### Persistence\nUnder the hood, NeDB's persistence uses an append-only format, meaning that all updates and deletes actually result in lines added at the end of the datafile, for performance reasons. The database is automatically compacted (i.e. put back in the one-line-per-document format) every time you load each database within your application.\n\nYou can manually call the compaction function with `yourDatabase.persistence.compactDatafile` which takes no argument. It queues a compaction of the datafile in the executor, to be executed sequentially after all pending operations. The datastore will fire a `compaction.done` event once compaction is finished.\n\nYou can also set automatic compaction at regular intervals with `yourDatabase.persistence.setAutocompactionInterval(interval)`, `interval` in milliseconds (a minimum of 5s is enforced), and stop automatic compaction with `yourDatabase.persistence.stopAutocompaction()`.\n\nKeep in mind that compaction takes a bit of time (not too much: 130ms for 50k records on a typical development machine) and no other operation can happen when it does, so most projects actually don't need to use it.\n\nCompaction will also immediately remove any documents whose data line has become corrupted, assuming that the total percentage of all corrupted documents in that database still falls below the specified `corruptAlertThreshold` option's value.\n\nDurability works similarly to major databases: compaction forces the OS to physically flush data to disk, while appends to the data file do not (the OS is responsible for flushing the data). That guarantees that a server crash can never cause complete data loss, while preserving performance. The worst that can happen is a crash between two syncs, causing a loss of all data between the two syncs. Usually syncs are 30 seconds appart so that's at most 30 seconds of data. <a href=\"http://oldblog.antirez.com/post/redis-persistence-demystified.html\" target=\"_blank\">This post by Antirez on Redis persistence</a> explains this in more details, NeDB being very close to Redis AOF persistence with `appendfsync` option set to `no`.\n\n\n### Inserting documents\nThe native types are `String`, `Number`, `Boolean`, `Date` and `null`. You can also use\narrays and subdocuments (objects). If a field is `undefined`, it will not be saved (this is different from \nMongoDB which transforms `undefined` in `null`, something I find counter-intuitive).\n\nIf the document does not contain an `_id` field, NeDB will automatically generated one for you (a 16-characters alphanumerical string). The `_id` of a document, once set, cannot be modified.\n\nField names cannot begin by '$' or contain a '.'.\n\n```javascript\nvar doc = { hello: 'world'\n               , n: 5\n               , today: new Date()\n               , nedbIsAwesome: true\n               , notthere: null\n               , notToBeSaved: undefined  // Will not be saved\n               , fruits: [ 'apple', 'orange', 'pear' ]\n               , infos: { name: 'nedb' }\n               };\n\ndb.insert(doc, function (err, newDoc) {   // Callback is optional\n  // newDoc is the newly inserted document, including its _id\n  // newDoc has no key called notToBeSaved since its value was undefined\n});\n```\n\nYou can also bulk-insert an array of documents. This operation is atomic, meaning that if one insert fails due to a unique constraint being violated, all changes are rolled back.\n\n```javascript\ndb.insert([{ a: 5 }, { a: 42 }], function (err, newDocs) {\n  // Two documents were inserted in the database\n  // newDocs is an array with these documents, augmented with their _id\n});\n\n// If there is a unique constraint on field 'a', this will fail\ndb.insert([{ a: 5 }, { a: 42 }, { a: 5 }], function (err) {\n  // err is a 'uniqueViolated' error\n  // The database was not modified\n});\n```\n\n### Finding documents\nUse `find` to look for multiple documents matching you query, or `findOne` to look for one specific document. You can select documents based on field equality or use comparison operators (`$lt`, `$lte`, `$gt`, `$gte`, `$in`, `$nin`, `$ne`). You can also use logical operators `$or`, `$and`, `$not` and `$where`. See below for the syntax.\n\nYou can use regular expressions in two ways: in basic querying in place of a string, or with the `$regex` operator.\n\nYou can sort and paginate results using the cursor API (see below).\n\nYou can use standard projections to restrict the fields to appear in the results (see below).\n\n#### Basic querying\nBasic querying means are looking for documents whose fields match the ones you specify. You can use regular expression to match strings.\nYou can use the dot notation to navigate inside nested documents, arrays, arrays of subdocuments and to match a specific element of an array.\n\n```javascript\n// Let's say our datastore contains the following collection\n// { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false, satellites: ['Phobos', 'Deimos'] }\n// { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true, humans: { genders: 2, eyes: true } }\n// { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false }\n// { _id: 'id4', planet: 'Omicron Persei 8', system: 'futurama', inhabited: true, humans: { genders: 7 } }\n// { _id: 'id5', completeData: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } }\n\n// Finding all planets in the solar system\ndb.find({ system: 'solar' }, function (err, docs) {\n  // docs is an array containing documents Mars, Earth, Jupiter\n  // If no document is found, docs is equal to []\n});\n\n// Finding all planets whose name contain the substring 'ar' using a regular expression\ndb.find({ planet: /ar/ }, function (err, docs) {\n  // docs contains Mars and Earth\n});\n\n// Finding all inhabited planets in the solar system\ndb.find({ system: 'solar', inhabited: true }, function (err, docs) {\n  // docs is an array containing document Earth only\n});\n\n// Use the dot-notation to match fields in subdocuments\ndb.find({ \"humans.genders\": 2 }, function (err, docs) {\n  // docs contains Earth\n});\n\n// Use the dot-notation to navigate arrays of subdocuments\ndb.find({ \"completeData.planets.name\": \"Mars\" }, function (err, docs) {\n  // docs contains document 5\n});\n\ndb.find({ \"completeData.planets.name\": \"Jupiter\" }, function (err, docs) {\n  // docs is empty\n});\n\ndb.find({ \"completeData.planets.0.name\": \"Earth\" }, function (err, docs) {\n  // docs contains document 5\n  // If we had tested against \"Mars\" docs would be empty because we are matching against a specific array element\n});\n\n\n// You can also deep-compare objects. Don't confuse this with dot-notation!\ndb.find({ humans: { genders: 2 } }, function (err, docs) {\n  // docs is empty, because { genders: 2 } is not equal to { genders: 2, eyes: true }\n});\n\n// Find all documents in the collection\ndb.find({}, function (err, docs) {\n});\n\n// The same rules apply when you want to only find one document\ndb.findOne({ _id: 'id1' }, function (err, doc) {\n  // doc is the document Mars\n  // If no document is found, doc is null\n});\n```\n\n#### Operators ($lt, $lte, $gt, $gte, $in, $nin, $ne, $exists, $regex)\nThe syntax is `{ field: { $op: value } }` where `$op` is any comparison operator:  \n\n* `$lt`, `$lte`: less than, less than or equal\n* `$gt`, `$gte`: greater than, greater than or equal\n* `$in`: member of. `value` must be an array of values\n* `$ne`, `$nin`: not equal, not a member of\n* `$exists`: checks whether the document posses the property `field`. `value` should be true or false\n* `$regex`: checks whether a string is matched by the regular expression. Contrary to MongoDB, the use of `$options` with `$regex` is not supported, because it doesn't give you more power than regex flags. Basic queries are more readable so only use the `$regex` operator when you need to use another operator with it (see example below)\n\n```javascript\n// $lt, $lte, $gt and $gte work on numbers and strings\ndb.find({ \"humans.genders\": { $gt: 5 } }, function (err, docs) {\n  // docs contains Omicron Persei 8, whose humans have more than 5 genders (7).\n});\n\n// When used with strings, lexicographical order is used\ndb.find({ planet: { $gt: 'Mercury' }}, function (err, docs) {\n  // docs contains Omicron Persei 8\n})\n\n// Using $in. $nin is used in the same way\ndb.find({ planet: { $in: ['Earth', 'Jupiter'] }}, function (err, docs) {\n  // docs contains Earth and Jupiter\n});\n\n// Using $exists\ndb.find({ satellites: { $exists: true } }, function (err, docs) {\n  // docs contains only Mars\n});\n\n// Using $regex with another operator\ndb.find({ planet: { $regex: /ar/, $nin: ['Jupiter', 'Earth'] } }, function (err, docs) {\n  // docs only contains Mars because Earth was excluded from the match by $nin\n});\n```\n\n#### Array fields\nWhen a field in a document is an array, NeDB first tries to see if the query value is an array to perform an exact match, then whether there is an array-specific comparison function (for now there is only `$size` and `$elemMatch`) being used. If not, the query is treated as a query on every element and there is a match if at least one element matches.  \n\n* `$size`: match on the size of the array\n* `$elemMatch`: matches if at least one array element matches the query entirely\n\n```javascript\n// Exact match\ndb.find({ satellites: ['Phobos', 'Deimos'] }, function (err, docs) {\n  // docs contains Mars\n})\ndb.find({ satellites: ['Deimos', 'Phobos'] }, function (err, docs) {\n  // docs is empty\n})\n\n// Using an array-specific comparison function\n// $elemMatch operator will provide match for a document, if an element from the array field satisfies all the conditions specified with the `$elemMatch` operator\ndb.find({ completeData: { planets: { $elemMatch: { name: 'Earth', number: 3 } } } }, function (err, docs) {\n  // docs contains documents with id 5 (completeData)\n});\n\ndb.find({ completeData: { planets: { $elemMatch: { name: 'Earth', number: 5 } } } }, function (err, docs) {\n  // docs is empty\n});\n\n// You can use inside #elemMatch query any known document query operator\ndb.find({ completeData: { planets: { $elemMatch: { name: 'Earth', number: { $gt: 2 } } } } }, function (err, docs) {\n  // docs contains documents with id 5 (completeData)\n});\n\n// Note: you can't use nested comparison functions, e.g. { $size: { $lt: 5 } } will throw an error\ndb.find({ satellites: { $size: 2 } }, function (err, docs) {\n  // docs contains Mars\n});\n\ndb.find({ satellites: { $size: 1 } }, function (err, docs) {\n  // docs is empty\n});\n\n// If a document's field is an array, matching it means matching any element of the array\ndb.find({ satellites: 'Phobos' }, function (err, docs) {\n  // docs contains Mars. Result would have been the same if query had been { satellites: 'Deimos' }\n});\n\n// This also works for queries that use comparison operators\ndb.find({ satellites: { $lt: 'Amos' } }, function (err, docs) {\n  // docs is empty since Phobos and Deimos are after Amos in lexicographical order\n});\n\n// This also works with the $in and $nin operator\ndb.find({ satellites: { $in: ['Moon', 'Deimos'] } }, function (err, docs) {\n  // docs contains Mars (the Earth document is not complete!)\n});\n```\n\n#### Logical operators $or, $and, $not, $where\nYou can combine queries using logical operators:  \n\n* For `$or` and `$and`, the syntax is `{ $op: [query1, query2, ...] }`.\n* For `$not`, the syntax is `{ $not: query }`\n* For `$where`, the syntax is `{ $where: function () { /* object is \"this\", return a boolean */ } }`\n\n```javascript\ndb.find({ $or: [{ planet: 'Earth' }, { planet: 'Mars' }] }, function (err, docs) {\n  // docs contains Earth and Mars\n});\n\ndb.find({ $not: { planet: 'Earth' } }, function (err, docs) {\n  // docs contains Mars, Jupiter, Omicron Persei 8\n});\n\ndb.find({ $where: function () { return Object.keys(this) > 6; } }, function (err, docs) {\n  // docs with more than 6 properties\n});\n\n// You can mix normal queries, comparison queries and logical operators\ndb.find({ $or: [{ planet: 'Earth' }, { planet: 'Mars' }], inhabited: true }, function (err, docs) {\n  // docs contains Earth\n});\n\n```\n\n#### Sorting and paginating\nIf you don't specify a callback to `find`, `findOne` or `count`, a `Cursor` object is returned. You can modify the cursor with `sort`, `skip` and `limit` and then execute it with `exec(callback)`.\n\n```javascript\n// Let's say the database contains these 4 documents\n// doc1 = { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false, satellites: ['Phobos', 'Deimos'] }\n// doc2 = { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true, humans: { genders: 2, eyes: true } }\n// doc3 = { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false }\n// doc4 = { _id: 'id4', planet: 'Omicron Persei 8', system: 'futurama', inhabited: true, humans: { genders: 7 } }\n\n// No query used means all results are returned (before the Cursor modifiers)\ndb.find({}).sort({ planet: 1 }).skip(1).limit(2).exec(function (err, docs) {\n  // docs is [doc3, doc1]\n});\n\n// You can sort in reverse order like this\ndb.find({ system: 'solar' }).sort({ planet: -1 }).exec(function (err, docs) {\n  // docs is [doc1, doc3, doc2]\n});\n\n// You can sort on one field, then another, and so on like this:\ndb.find({}).sort({ firstField: 1, secondField: -1 }) ...   // You understand how this works!\n```\n\n#### Projections\nYou can give `find` and `findOne` an optional second argument, `projections`. The syntax is the same as MongoDB: `{ a: 1, b: 1 }` to return only the `a` and `b` fields, `{ a: 0, b: 0 }` to omit these two fields. You cannot use both modes at the time, except for `_id` which is by default always returned and which you can choose to omit. You can project on nested documents.\n\n```javascript\n// Same database as above\n\n// Keeping only the given fields\ndb.find({ planet: 'Mars' }, { planet: 1, system: 1 }, function (err, docs) {\n  // docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }]\n});\n\n// Keeping only the given fields but removing _id\ndb.find({ planet: 'Mars' }, { planet: 1, system: 1, _id: 0 }, function (err, docs) {\n  // docs is [{ planet: 'Mars', system: 'solar' }]\n});\n\n// Omitting only the given fields and removing _id\ndb.find({ planet: 'Mars' }, { planet: 0, system: 0, _id: 0 }, function (err, docs) {\n  // docs is [{ inhabited: false, satellites: ['Phobos', 'Deimos'] }]\n});\n\n// Failure: using both modes at the same time\ndb.find({ planet: 'Mars' }, { planet: 0, system: 1 }, function (err, docs) {\n  // err is the error message, docs is undefined\n});\n\n// You can also use it in a Cursor way but this syntax is not compatible with MongoDB\ndb.find({ planet: 'Mars' }).projection({ planet: 1, system: 1 }).exec(function (err, docs) {\n  // docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }]\n});\n\n// Project on a nested document\ndb.findOne({ planet: 'Earth' }).projection({ planet: 1, 'humans.genders': 1 }).exec(function (err, doc) {\n  // doc is { planet: 'Earth', _id: 'id2', humans: { genders: 2 } }\n});\n```\n\n\n\n### Counting documents\nYou can use `count` to count documents. It has the same syntax as `find`. For example:\n\n```javascript\n// Count all planets in the solar system\ndb.count({ system: 'solar' }, function (err, count) {\n  // count equals to 3\n});\n\n// Count all documents in the datastore\ndb.count({}, function (err, count) {\n  // count equals to 4\n});\n```\n\n\n### Updating documents\n`db.update(query, update, options, callback)` will update all documents matching `query` according to the `update` rules:  \n* `query` is the same kind of finding query you use with `find` and `findOne`\n* `update` specifies how the documents should be modified. It is either a new document or a set of modifiers (you cannot use both together, it doesn't make sense!)\n  * A new document will replace the matched docs\n  * The modifiers create the fields they need to modify if they don't exist, and you can apply them to subdocs. Available field modifiers are `$set` to change a field's value, `$unset` to delete a field, `$inc` to increment a field's value and `$min`/`$max` to change field's value, only if provided value is less/greater than current value. To work on arrays, you have `$push`, `$pop`, `$addToSet`, `$pull`, and the special `$each` and `$slice`. See examples below for the syntax.\n* `options` is an object with two possible parameters\n  * `multi` (defaults to `false`) which allows the modification of several documents if set to true\n  * `upsert` (defaults to `false`) if you want to insert a new document corresponding to the `update` rules if your `query` doesn't match anything. If your `update` is a simple object with no modifiers, it is the inserted document. In the other case, the `query` is stripped from all operator recursively, and the `update` is applied to it.\n  * `returnUpdatedDocs` (defaults to `false`, not MongoDB-compatible) if set to true and update is not an upsert, will return the array of documents matched by the find query and updated. Updated documents will be returned even if the update did not actually modify them.\n* `callback` (optional) signature: `(err, numAffected, affectedDocuments, upsert)`. **Warning**: the API was changed between v1.7.4 and v1.8. Please refer to the <a href=\"https://github.com/louischatriot/nedb/wiki/Change-log\" target=\"_blank\">change log</a> to see the change.\n  * For an upsert, `affectedDocuments` contains the inserted document and the `upsert` flag is set to `true`.\n  * For a standard update with `returnUpdatedDocs` flag set to `false`, `affectedDocuments` is not set.\n  * For a standard update with `returnUpdatedDocs` flag set to `true` and `multi` to `false`, `affectedDocuments` is the updated document.\n  * For a standard update with `returnUpdatedDocs` flag set to `true` and `multi` to `true`, `affectedDocuments` is the array of updated documents.\n\n**Note**: you can't change a document's _id.\n\n```javascript\n// Let's use the same example collection as in the \"finding document\" part\n// { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false }\n// { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true }\n// { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false }\n// { _id: 'id4', planet: 'Omicron Persia 8', system: 'futurama', inhabited: true }\n\n// Replace a document by another\ndb.update({ planet: 'Jupiter' }, { planet: 'Pluton'}, {}, function (err, numReplaced) {\n  // numReplaced = 1\n  // The doc #3 has been replaced by { _id: 'id3', planet: 'Pluton' }\n  // Note that the _id is kept unchanged, and the document has been replaced\n  // (the 'system' and inhabited fields are not here anymore)\n});\n\n// Set an existing field's value\ndb.update({ system: 'solar' }, { $set: { system: 'solar system' } }, { multi: true }, function (err, numReplaced) {\n  // numReplaced = 3\n  // Field 'system' on Mars, Earth, Jupiter now has value 'solar system'\n});\n\n// Setting the value of a non-existing field in a subdocument by using the dot-notation\ndb.update({ planet: 'Mars' }, { $set: { \"data.satellites\": 2, \"data.red\": true } }, {}, function () {\n  // Mars document now is { _id: 'id1', system: 'solar', inhabited: false\n  //                      , data: { satellites: 2, red: true }\n  //                      }\n  // Not that to set fields in subdocuments, you HAVE to use dot-notation\n  // Using object-notation will just replace the top-level field\n  db.update({ planet: 'Mars' }, { $set: { data: { satellites: 3 } } }, {}, function () {\n    // Mars document now is { _id: 'id1', system: 'solar', inhabited: false\n    //                      , data: { satellites: 3 }\n    //                      }\n    // You lost the \"data.red\" field which is probably not the intended behavior\n  });\n});\n\n// Deleting a field\ndb.update({ planet: 'Mars' }, { $unset: { planet: true } }, {}, function () {\n  // Now the document for Mars doesn't contain the planet field\n  // You can unset nested fields with the dot notation of course\n});\n\n// Upserting a document\ndb.update({ planet: 'Pluton' }, { planet: 'Pluton', inhabited: false }, { upsert: true }, function (err, numReplaced, upsert) {\n  // numReplaced = 1, upsert = { _id: 'id5', planet: 'Pluton', inhabited: false }\n  // A new document { _id: 'id5', planet: 'Pluton', inhabited: false } has been added to the collection\n});\n\n// If you upsert with a modifier, the upserted doc is the query modified by the modifier\n// This is simpler than it sounds :)\ndb.update({ planet: 'Pluton' }, { $inc: { distance: 38 } }, { upsert: true }, function () {\n  // A new document { _id: 'id5', planet: 'Pluton', distance: 38 } has been added to the collection  \n});\n\n// If we insert a new document { _id: 'id6', fruits: ['apple', 'orange', 'pear'] } in the collection,\n// let's see how we can modify the array field atomically\n\n// $push inserts new elements at the end of the array\ndb.update({ _id: 'id6' }, { $push: { fruits: 'banana' } }, {}, function () {\n  // Now the fruits array is ['apple', 'orange', 'pear', 'banana']\n});\n\n// $pop removes an element from the end (if used with 1) or the front (if used with -1) of the array\ndb.update({ _id: 'id6' }, { $pop: { fruits: 1 } }, {}, function () {\n  // Now the fruits array is ['apple', 'orange']\n  // With { $pop: { fruits: -1 } }, it would have been ['orange', 'pear']\n});\n\n// $addToSet adds an element to an array only if it isn't already in it\n// Equality is deep-checked (i.e. $addToSet will not insert an object in an array already containing the same object)\n// Note that it doesn't check whether the array contained duplicates before or not\ndb.update({ _id: 'id6' }, { $addToSet: { fruits: 'apple' } }, {}, function () {\n  // The fruits array didn't change\n  // If we had used a fruit not in the array, e.g. 'banana', it would have been added to the array\n});\n\n// $pull removes all values matching a value or even any NeDB query from the array\ndb.update({ _id: 'id6' }, { $pull: { fruits: 'apple' } }, {}, function () {\n  // Now the fruits array is ['orange', 'pear']\n});\ndb.update({ _id: 'id6' }, { $pull: { fruits: $in: ['apple', 'pear'] } }, {}, function () {\n  // Now the fruits array is ['orange']\n});\n\n// $each can be used to $push or $addToSet multiple values at once\n// This example works the same way with $addToSet\ndb.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana', 'orange'] } } }, {}, function () {\n  // Now the fruits array is ['apple', 'orange', 'pear', 'banana', 'orange']\n});\n\n// $slice can be used in cunjunction with $push and $each to limit the size of the resulting array.\n// A value of 0 will update the array to an empty array. A positive value n will keep only the n first elements\n// A negative value -n will keep only the last n elements.\n// If $slice is specified but not $each, $each is set to []\ndb.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana'], $slice: 2 } } }, {}, function () {\n  // Now the fruits array is ['apple', 'orange']\n});\n\n// $min/$max to update only if provided value is less/greater than current value\n// Let's say the database contains this document\n// doc = { _id: 'id', name: 'Name', value: 5 }\ndb.update({ _id: 'id1' }, { $min: { value: 2 } }, {}, function () {\n  // The document will be updated to { _id: 'id', name: 'Name', value: 2 }\n});\n\ndb.update({ _id: 'id1' }, { $min: { value: 8 } }, {}, function () {\n  // The document will not be modified\n});\n```\n\n### Removing documents\n`db.remove(query, options, callback)` will remove all documents matching `query` according to `options`  \n* `query` is the same as the ones used for finding and updating\n* `options` only one option for now: `multi` which allows the removal of multiple documents if set to true. Default is false\n* `callback` is optional, signature: err, numRemoved\n\n```javascript\n// Let's use the same example collection as in the \"finding document\" part\n// { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false }\n// { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true }\n// { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false }\n// { _id: 'id4', planet: 'Omicron Persia 8', system: 'futurama', inhabited: true }\n\n// Remove one document from the collection\n// options set to {} since the default for multi is false\ndb.remove({ _id: 'id2' }, {}, function (err, numRemoved) {\n  // numRemoved = 1\n});\n\n// Remove multiple documents\ndb.remove({ system: 'solar' }, { multi: true }, function (err, numRemoved) {\n  // numRemoved = 3\n  // All planets from the solar system were removed\n});\n\n// Removing all documents with the 'match-all' query\ndb.remove({}, { multi: true }, function (err, numRemoved) {\n});\n```\n\n### Indexing\nNeDB supports indexing. It gives a very nice speed boost and can be used to enforce a unique constraint on a field. You can index any field, including fields in nested documents using the dot notation. For now, indexes are only used to speed up basic queries and queries using `$in`, `$lt`, `$lte`, `$gt` and `$gte`. The indexed values cannot be of type array of object.\n\nTo create an index, use `datastore.ensureIndex(options, cb)`, where callback is optional and get passed an error if any (usually a unique constraint that was violated). `ensureIndex` can be called when you want, even after some data was inserted, though it's best to call it at application startup. The options are:  \n\n* **fieldName** (required): name of the field to index. Use the dot notation to index a field in a nested document.\n* **unique** (optional, defaults to `false`): enforce field uniqueness. Note that a unique index will raise an error if you try to index two documents for which the field is not defined.\n* **sparse** (optional, defaults to `false`): don't index documents for which the field is not defined. Use this option along with \"unique\" if you want to accept multiple documents for which it is not defined.\n* **expireAfterSeconds** (number of seconds, optional): if set, the created index is a TTL (time to live) index, that will automatically remove documents when the system date becomes larger than the date on the indexed field plus `expireAfterSeconds`. Documents where the indexed field is not specified or not a `Date` object are ignored\n\nNote: the `_id` is automatically indexed with a unique constraint, no need to call `ensureIndex` on it.\n\nYou can remove a previously created index with `datastore.removeIndex(fieldName, cb)`.\n\nIf your datastore is persistent, the indexes you created are persisted in the datafile, when you load the database a second time they are automatically created for you. No need to remove any `ensureIndex` though, if it is called on a database that already has the index, nothing happens.\n\n```javascript\ndb.ensureIndex({ fieldName: 'somefield' }, function (err) {\n  // If there was an error, err is not null\n});\n\n// Using a unique constraint with the index\ndb.ensureIndex({ fieldName: 'somefield', unique: true }, function (err) {\n});\n\n// Using a sparse unique index\ndb.ensureIndex({ fieldName: 'somefield', unique: true, sparse: true }, function (err) {\n});\n\n\n// Format of the error message when the unique constraint is not met\ndb.insert({ somefield: 'nedb' }, function (err) {\n  // err is null\n  db.insert({ somefield: 'nedb' }, function (err) {\n    // err is { errorType: 'uniqueViolated'\n    //        , key: 'name'\n    //        , message: 'Unique constraint violated for key name' }\n  });\n});\n\n// Remove index on field somefield\ndb.removeIndex('somefield', function (err) {\n});\n\n// Example of using expireAfterSeconds to remove documents 1 hour\n// after their creation (db's timestampData option is true here)\ndb.ensureIndex({ fieldName: 'createdAt', expireAfterSeconds: 3600 }, function (err) {\n});\n\n// You can also use the option to set an expiration date like so\ndb.ensureIndex({ fieldName: 'expirationDate', expireAfterSeconds: 0 }, function (err) {\n  // Now all documents will expire when system time reaches the date in their\n  // expirationDate field\n});\n\n```\n\n**Note:** the `ensureIndex` function creates the index synchronously, so it's best to use it at application startup. It's quite fast so it doesn't increase startup time much (35 ms for a collection containing 10,000 documents).\n\n\n## Browser version\nThe browser version and its minified counterpart are in the `browser-version/out` directory. You only need to require `nedb.js` or `nedb.min.js` in your HTML file and the global object `Nedb` can be used right away, with the same API as the server version:\n\n```\n<script src=\"nedb.min.js\"></script>\n<script>\n  var db = new Nedb();   // Create an in-memory only datastore\n  \n  db.insert({ planet: 'Earth' }, function (err) {\n   db.find({}, function (err, docs) {\n     // docs contains the two planets Earth and Mars\n   });\n  });\n</script>\n```\n\nIf you specify a `filename`, the database will be persistent, and automatically select the best storage method available (IndexedDB, WebSQL or localStorage) depending on the browser. In most cases that means a lot of data can be stored, typically in hundreds of MB. **WARNING**: the storage system changed between v1.3 and v1.4 and is NOT back-compatible! Your application needs to resync client-side when you upgrade NeDB.\n\nNeDB is compatible with all major browsers: Chrome, Safari, Firefox, IE9+. Tests are in the `browser-version/test` directory (files `index.html` and `testPersistence.html`).\n\nIf you fork and modify nedb, you can build the browser version from the sources, the build script is `browser-version/build.js`.\n\n\n## Performance\n### Speed\nNeDB is not intended to be a replacement of large-scale databases such as MongoDB, and as such was not designed for speed. That said, it is still pretty fast on the expected datasets, especially if you use indexing. On a typical, not-so-fast dev machine, for a collection containing 10,000 documents, with indexing:  \n* Insert: **10,680 ops/s**\n* Find: **43,290 ops/s**\n* Update: **8,000 ops/s**\n* Remove: **11,750 ops/s**  \n\nYou can run these simple benchmarks by executing the scripts in the `benchmarks` folder. Run them with the `--help` flag to see how they work.\n\n### Memory footprint\nA copy of the whole database is kept in memory. This is not much on the\nexpected kind of datasets (20MB for 10,000 2KB documents).\n\n## Use in other services\n* <a href=\"https://github.com/louischatriot/connect-nedb-session\"\n  target=\"_blank\">connect-nedb-session</a> is a session store for\nConnect and Express, backed by nedb\n* If you mostly use NeDB for logging purposes and don't want the memory footprint of your application to grow too large, you can use <a href=\"https://github.com/louischatriot/nedb-logger\" target=\"_blank\">NeDB Logger</a> to insert documents in a NeDB-readable database\n* If you've outgrown NeDB, switching to MongoDB won't be too hard as it is the same API. Use <a href=\"https://github.com/louischatriot/nedb-to-mongodb\" target=\"_blank\">this utility</a> to transfer the data from a NeDB database to a MongoDB collection\n* An ODM for NeDB: <a href=\"https://github.com/scottwrobinson/camo\" target=\"_blank\">Camo</a>\n\n## Pull requests\n**Important: I consider NeDB to be feature-complete, i.e. it does everything I think it should and nothing more. As a general rule I will not accept pull requests anymore, except for bugfixes (of course) or if I get convinced I overlook a strong usecase. Please make sure to open an issue before spending time on any PR.**\n\nIf you submit a pull request, thanks! There are a couple rules to follow though to make it manageable:\n* The pull request should be atomic, i.e. contain only one feature. If it contains more, please submit multiple pull requests. Reviewing massive, 1000 loc+ pull requests is extremely hard.\n* Likewise, if for one unique feature the pull request grows too large (more than 200 loc tests not included), please get in touch first.\n* Please stick to the current coding style. It's important that the code uses a coherent style for readability.\n* Do not include sylistic improvements (\"housekeeping\"). If you think one part deserves lots of housekeeping, use a separate pull request so as not to pollute the code.\n* Don't forget tests for your new feature. Also don't forget to run the whole test suite before submitting to make sure you didn't introduce regressions.\n* Do not build the browser version in your branch, I'll take care of it once the code is merged.\n* Update the readme accordingly.\n* Last but not least: keep in mind what NeDB's mindset is! The goal is not to be a replacement for MongoDB, but to have a pure JS database, easy to use, cross platform, fast and expressive enough for the target projects (small and self contained apps on server/desktop/browser/mobile). Sometimes it's better to shoot for simplicity than for API completeness with regards to MongoDB.\n\n## Bug reporting guidelines\nIf you report a bug, thank you! That said for the process to be manageable please strictly adhere to the following guidelines. I'll not be able to handle bug reports that don't:\n* Your bug report should be a self-containing gist complete with a package.json for any dependencies you need. I need to run through a simple `git clone gist; npm install; node bugreport.js`, nothing more.\n* It should use assertions to showcase the expected vs actual behavior and be hysteresis-proof. It's quite simple in fact, see this example: https://gist.github.com/louischatriot/220cf6bd29c7de06a486\n* Simplify as much as you can. Strip all your application-specific code. Most of the time you will see that there is no bug but an error in your code :)\n* 50 lines max. If you need more, read the above point and rework your bug report. If you're **really** convinced you need more, please explain precisely in the issue.\n* The code should be Javascript, not Coffeescript.\n\n### Bitcoins\nYou don't have time? You can support NeDB by sending bitcoins to this address: 1dDZLnWpBbodPiN8sizzYrgaz5iahFyb1\n\n\n## License \n\nSee [License](LICENSE)\n"
  },
  {
    "path": "benchmarks/commonUtilities.js",
    "content": "/**\n * Functions that are used in several benchmark tests\n */\n\nvar customUtils = require('../lib/customUtils')\n  , fs = require('fs')\n  , path = require('path')\n  , Datastore = require('../lib/datastore')\n  , Persistence = require('../lib/persistence')\n  , executeAsap   // process.nextTick or setImmediate depending on your Node version\n  ;\n\ntry {\n  executeAsap = setImmediate;\n} catch (e) {\n  executeAsap = process.nextTick;\n}\n\n\n/**\n * Configure the benchmark\n */\nmodule.exports.getConfiguration = function (benchDb) {\n  var d, n\n    , program = require('commander')\n    ;\n\n  program\n    .option('-n --number [number]', 'Size of the collection to test on', parseInt)\n    .option('-i --with-index', 'Use an index')\n    .option('-m --in-memory', 'Test with an in-memory only store')\n    .parse(process.argv);\n\n  n = program.number || 10000;\n\n  console.log(\"----------------------------\");\n  console.log(\"Test with \" + n + \" documents\");\n  console.log(program.withIndex ? \"Use an index\" : \"Don't use an index\");\n  console.log(program.inMemory ? \"Use an in-memory datastore\" : \"Use a persistent datastore\");\n  console.log(\"----------------------------\");\n\n  d = new Datastore({ filename: benchDb\n                    , inMemoryOnly: program.inMemory\n                    });\n\n  return { n: n, d: d, program: program };\n};\n\n\n/**\n * Ensure the workspace exists and the db datafile is empty\n */\nmodule.exports.prepareDb = function (filename, cb) {\n  Persistence.ensureDirectoryExists(path.dirname(filename), function () {\n    fs.exists(filename, function (exists) {\n      if (exists) {\n        fs.unlink(filename, cb);\n      } else { return cb(); }\n    });\n  });\n};\n\n\n/**\n * Return an array with the numbers from 0 to n-1, in a random order\n * Uses Fisher Yates algorithm\n * Useful to get fair tests\n */\nfunction getRandomArray (n) {\n  var res = []\n    , i, j, temp\n    ;\n\n  for (i = 0; i < n; i += 1) { res[i] = i; }\n\n  for (i = n - 1; i >= 1; i -= 1) {\n    j = Math.floor((i + 1) * Math.random());\n    temp = res[i];\n    res[i] = res[j];\n    res[j] = temp;\n  }\n\n  return res;\n};\nmodule.exports.getRandomArray = getRandomArray;\n\n\n/**\n * Insert a certain number of documents for testing\n */\nmodule.exports.insertDocs = function (d, n, profiler, cb) {\n  var beg = new Date()\n    , order = getRandomArray(n)\n    ;\n\n  profiler.step('Begin inserting ' + n + ' docs');\n\n  function runFrom(i) {\n    if (i === n) {   // Finished\n      var opsPerSecond = Math.floor(1000* n / profiler.elapsedSinceLastStep());\n      console.log(\"===== RESULT (insert) ===== \" + opsPerSecond + \" ops/s\");\n      profiler.step('Finished inserting ' + n + ' docs');\n      profiler.insertOpsPerSecond = opsPerSecond;\n      return cb();\n    }\n\n    d.insert({ docNumber: order[i] }, function (err) {\n      executeAsap(function () {\n        runFrom(i + 1);\n      });\n    });\n  }\n  runFrom(0);\n};\n\n\n/**\n * Find documents with find\n */\nmodule.exports.findDocs = function (d, n, profiler, cb) {\n  var beg = new Date()\n    , order = getRandomArray(n)\n    ;\n\n  profiler.step(\"Finding \" + n + \" documents\");\n\n  function runFrom(i) {\n    if (i === n) {   // Finished\n      console.log(\"===== RESULT (find) ===== \" + Math.floor(1000* n / profiler.elapsedSinceLastStep()) + \" ops/s\");\n      profiler.step('Finished finding ' + n + ' docs');\n      return cb();\n    }\n\n    d.find({ docNumber: order[i] }, function (err, docs) {\n      if (docs.length !== 1 || docs[0].docNumber !== order[i]) { return cb('One find didnt work'); }\n      executeAsap(function () {\n        runFrom(i + 1);\n      });\n    });\n  }\n  runFrom(0);\n};\n\n\n/**\n * Find documents with find and the $in operator\n */\nmodule.exports.findDocsWithIn = function (d, n, profiler, cb) {\n  var beg = new Date()\n    , order = getRandomArray(n)\n    , ins = [], i, j\n    , arraySize = Math.min(10, n)   // The array for $in needs to be smaller than n (inclusive)\n    ;\n\n  // Preparing all the $in arrays, will take some time\n  for (i = 0; i < n; i += 1) {\n    ins[i] = [];\n\n    for (j = 0; j < arraySize; j += 1) {\n      ins[i].push((i + j) % n);\n    }\n  }\n\n  profiler.step(\"Finding \" + n + \" documents WITH $IN OPERATOR\");\n\n  function runFrom(i) {\n    if (i === n) {   // Finished\n      console.log(\"===== RESULT (find with in selector) ===== \" + Math.floor(1000* n / profiler.elapsedSinceLastStep()) + \" ops/s\");\n      profiler.step('Finished finding ' + n + ' docs');\n      return cb();\n    }\n\n    d.find({ docNumber: { $in: ins[i] } }, function (err, docs) {\n      if (docs.length !== arraySize) { return cb('One find didnt work'); }\n      executeAsap(function () {\n        runFrom(i + 1);\n      });\n    });\n  }\n  runFrom(0);\n};\n\n\n/**\n * Find documents with findOne\n */\nmodule.exports.findOneDocs = function (d, n, profiler, cb) {\n  var beg = new Date()\n    , order = getRandomArray(n)\n    ;\n\n  profiler.step(\"FindingOne \" + n + \" documents\");\n\n  function runFrom(i) {\n    if (i === n) {   // Finished\n      console.log(\"===== RESULT (findOne) ===== \" + Math.floor(1000* n / profiler.elapsedSinceLastStep()) + \" ops/s\");\n      profiler.step('Finished finding ' + n + ' docs');\n      return cb();\n    }\n\n    d.findOne({ docNumber: order[i] }, function (err, doc) {\n      if (!doc || doc.docNumber !== order[i]) { return cb('One find didnt work'); }\n      executeAsap(function () {\n        runFrom(i + 1);\n      });\n    });\n  }\n  runFrom(0);\n};\n\n\n/**\n * Update documents\n * options is the same as the options object for update\n */\nmodule.exports.updateDocs = function (options, d, n, profiler, cb) {\n  var beg = new Date()\n    , order = getRandomArray(n)\n    ;\n\n  profiler.step(\"Updating \" + n + \" documents\");\n\n  function runFrom(i) {\n    if (i === n) {   // Finished\n      console.log(\"===== RESULT (update) ===== \" + Math.floor(1000* n / profiler.elapsedSinceLastStep()) + \" ops/s\");\n      profiler.step('Finished updating ' + n + ' docs');\n      return cb();\n    }\n\n    // Will not actually modify the document but will take the same time\n    d.update({ docNumber: order[i] }, { docNumber: order[i] }, options, function (err, nr) {\n      if (err) { return cb(err); }\n      if (nr !== 1) { return cb('One update didnt work'); }\n      executeAsap(function () {\n        runFrom(i + 1);\n      });\n    });\n  }\n  runFrom(0);\n};\n\n\n/**\n * Remove documents\n * options is the same as the options object for update\n */\nmodule.exports.removeDocs = function (options, d, n, profiler, cb) {\n  var beg = new Date()\n    , order = getRandomArray(n)\n    ;\n\n  profiler.step(\"Removing \" + n + \" documents\");\n\n  function runFrom(i) {\n    if (i === n) {   // Finished\n      // opsPerSecond corresponds to 1 insert + 1 remove, needed to keep collection size at 10,000\n      // We need to subtract the time taken by one insert to get the time actually taken by one remove\n      var opsPerSecond = Math.floor(1000 * n / profiler.elapsedSinceLastStep());\n      var removeOpsPerSecond = Math.floor(1 / ((1 / opsPerSecond) - (1 / profiler.insertOpsPerSecond)))\n      console.log(\"===== RESULT (remove) ===== \" + removeOpsPerSecond + \" ops/s\");\n      profiler.step('Finished removing ' + n + ' docs');\n      return cb();\n    }\n\n    d.remove({ docNumber: order[i] }, options, function (err, nr) {\n      if (err) { return cb(err); }\n      if (nr !== 1) { return cb('One remove didnt work'); }\n      d.insert({ docNumber: order[i] }, function (err) {   // We need to reinsert the doc so that we keep the collection's size at n\n                                                           // So actually we're calculating the average time taken by one insert + one remove\n        executeAsap(function () {\n          runFrom(i + 1);\n        });\n      });\n    });\n  }\n  runFrom(0);\n};\n\n\n/**\n * Load database\n */\nmodule.exports.loadDatabase = function (d, n, profiler, cb) {\n  var beg = new Date()\n    , order = getRandomArray(n)\n    ;\n\n  profiler.step(\"Loading the database \" + n + \" times\");\n\n  function runFrom(i) {\n    if (i === n) {   // Finished\n      console.log(\"===== RESULT ===== \" + Math.floor(1000* n / profiler.elapsedSinceLastStep()) + \" ops/s\");\n      profiler.step('Finished loading a database' + n + ' times');\n      return cb();\n    }\n\n    d.loadDatabase(function (err) {\n      executeAsap(function () {\n        runFrom(i + 1);\n      });\n    });\n  }\n  runFrom(0);\n};\n\n\n\n\n"
  },
  {
    "path": "benchmarks/ensureIndex.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/insert.bench.db'\n  , async = require('async')\n  , commonUtilities = require('./commonUtilities')\n  , execTime = require('exec-time')\n  , profiler = new execTime('INSERT BENCH')\n  , d = new Datastore(benchDb)\n  , program = require('commander')\n  , n\n  ;\n\nprogram\n  .option('-n --number [number]', 'Size of the collection to test on', parseInt)\n  .option('-i --with-index', 'Test with an index')\n  .parse(process.argv);\n\nn = program.number || 10000;\n\nconsole.log(\"----------------------------\");\nconsole.log(\"Test with \" + n + \" documents\");\nconsole.log(\"----------------------------\");\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(function (err) {\n      if (err) { return cb(err); }\n      cb();\n    });\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n, function (cb) {\n    var i;\n\n    profiler.step('Begin calling ensureIndex ' + n + ' times');\n\n    for (i = 0; i < n; i += 1) {\n      d.ensureIndex({ fieldName: 'docNumber' });\n      delete d.indexes.docNumber;\n    }\n\n    console.log(\"Average time for one ensureIndex: \" + (profiler.elapsedSinceLastStep() / n) + \"ms\");\n    profiler.step('Finished calling ensureIndex ' + n + ' times');\n  }\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n\n"
  },
  {
    "path": "benchmarks/find.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/find.bench.db'\n  , fs = require('fs')\n  , path = require('path')\n  , async = require('async')\n  , execTime = require('exec-time')\n  , profiler = new execTime('FIND BENCH')\n  , commonUtilities = require('./commonUtilities')\n  , config = commonUtilities.getConfiguration(benchDb)\n  , d = config.d\n  , n = config.n\n  ;\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(function (err) {\n      if (err) { return cb(err); }\n      if (config.program.withIndex) { d.ensureIndex({ fieldName: 'docNumber' }); }\n      cb();\n    });\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n, async.apply(commonUtilities.findDocs, d, n, profiler)\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n"
  },
  {
    "path": "benchmarks/findOne.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/findOne.bench.db'\n  , fs = require('fs')\n  , path = require('path')\n  , async = require('async')\n  , execTime = require('exec-time')\n  , profiler = new execTime('FINDONE BENCH')\n  , commonUtilities = require('./commonUtilities')\n  , config = commonUtilities.getConfiguration(benchDb)\n  , d = config.d\n  , n = config.n\n  ;\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(function (err) {\n      if (err) { return cb(err); }\n      if (config.program.withIndex) { d.ensureIndex({ fieldName: 'docNumber' }); }\n      cb();\n    });\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n, function (cb) { setTimeout(function () {cb();}, 500); }\n, async.apply(commonUtilities.findOneDocs, d, n, profiler)\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n"
  },
  {
    "path": "benchmarks/findWithIn.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/find.bench.db'\n  , fs = require('fs')\n  , path = require('path')\n  , async = require('async')\n  , execTime = require('exec-time')\n  , profiler = new execTime('FIND BENCH')\n  , commonUtilities = require('./commonUtilities')\n  , config = commonUtilities.getConfiguration(benchDb)\n  , d = config.d\n  , n = config.n\n  ;\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(function (err) {\n      if (err) { return cb(err); }\n      if (config.program.withIndex) { d.ensureIndex({ fieldName: 'docNumber' }); }\n      cb();\n    });\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n, async.apply(commonUtilities.findDocsWithIn, d, n, profiler)\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n"
  },
  {
    "path": "benchmarks/insert.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/insert.bench.db'\n  , async = require('async')\n  , execTime = require('exec-time')\n  , profiler = new execTime('INSERT BENCH')\n  , commonUtilities = require('./commonUtilities')\n  , config = commonUtilities.getConfiguration(benchDb)\n  , d = config.d\n  , n = config.n\n  ;\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(function (err) {\n      if (err) { return cb(err); }\n      if (config.program.withIndex) {\n        d.ensureIndex({ fieldName: 'docNumber' });\n        n = 2 * n;   // We will actually insert twice as many documents\n                     // because the index is slower when the collection is already\n                     // big. So the result given by the algorithm will be a bit worse than\n                     // actual performance\n      }\n      cb();\n    });\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n"
  },
  {
    "path": "benchmarks/loadDatabase.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/loaddb.bench.db'\n  , fs = require('fs')\n  , path = require('path')\n  , async = require('async')\n  , commonUtilities = require('./commonUtilities')\n  , execTime = require('exec-time')\n  , profiler = new execTime('LOADDB BENCH')\n  , d = new Datastore(benchDb)\n  , program = require('commander')\n  , n\n  ;\n\nprogram\n  .option('-n --number [number]', 'Size of the collection to test on', parseInt)\n  .option('-i --with-index', 'Test with an index')\n  .parse(process.argv);\n\nn = program.number || 10000;\n\nconsole.log(\"----------------------------\");\nconsole.log(\"Test with \" + n + \" documents\");\nconsole.log(program.withIndex ? \"Use an index\" : \"Don't use an index\");\nconsole.log(\"----------------------------\");\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(cb);\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n, async.apply(commonUtilities.loadDatabase, d, n, profiler)\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n"
  },
  {
    "path": "benchmarks/remove.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/remove.bench.db'\n  , fs = require('fs')\n  , path = require('path')\n  , async = require('async')\n  , execTime = require('exec-time')\n  , profiler = new execTime('REMOVE BENCH')\n  , commonUtilities = require('./commonUtilities')\n  , config = commonUtilities.getConfiguration(benchDb)\n  , d = config.d\n  , n = config.n\n  ;\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(function (err) {\n      if (err) { return cb(err); }\n      if (config.program.withIndex) { d.ensureIndex({ fieldName: 'docNumber' }); }\n      cb();\n    });\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n\n// Test with remove only one document\n, function (cb) { profiler.step('MULTI: FALSE'); return cb(); }\n, async.apply(commonUtilities.removeDocs, { multi: false }, d, n, profiler)\n// Test with multiple documents\n, function (cb) { d.remove({}, { multi: true }, function () { return cb(); }); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n, function (cb) { profiler.step('MULTI: TRUE'); return cb(); }\n, async.apply(commonUtilities.removeDocs, { multi: true }, d, n, profiler)\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n"
  },
  {
    "path": "benchmarks/update.js",
    "content": "var Datastore = require('../lib/datastore')\n  , benchDb = 'workspace/update.bench.db'\n  , fs = require('fs')\n  , path = require('path')\n  , async = require('async')\n  , execTime = require('exec-time')\n  , profiler = new execTime('UPDATE BENCH')\n  , commonUtilities = require('./commonUtilities')\n  , config = commonUtilities.getConfiguration(benchDb)\n  , d = config.d\n  , n = config.n\n  ;\n\nasync.waterfall([\n  async.apply(commonUtilities.prepareDb, benchDb)\n, function (cb) {\n    d.loadDatabase(function (err) {\n      if (err) { return cb(err); }\n      if (config.program.withIndex) { d.ensureIndex({ fieldName: 'docNumber' }); }\n      cb();\n    });\n  }\n, function (cb) { profiler.beginProfiling(); return cb(); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n\n// Test with update only one document\n, function (cb) { profiler.step('MULTI: FALSE'); return cb(); }\n, async.apply(commonUtilities.updateDocs, { multi: false }, d, n, profiler)\n\n// Test with multiple documents\n, function (cb) { d.remove({}, { multi: true }, function (err) { return cb(); }); }\n, async.apply(commonUtilities.insertDocs, d, n, profiler)\n, function (cb) { profiler.step('MULTI: TRUE'); return cb(); }\n, async.apply(commonUtilities.updateDocs, { multi: true }, d, n, profiler)\n], function (err) {\n  profiler.step(\"Benchmark finished\");\n\n  if (err) { return console.log(\"An error was encountered: \", err); }\n});\n"
  },
  {
    "path": "bower.json",
    "content": "{\n\"name\": \"nedb\",\n\"description\": \"The Javascript Database for Node, nwjs, Electron and the browser\",\n\"ignore\": [\"benchmarks\", \"lib\", \"test\", \"test_lac\"],\n\"main\": [\"browser-version/nedb.js\", \"browser-version/nedb.min.js\"]\n}\n"
  },
  {
    "path": "browser-version/browser-specific/lib/customUtils.js",
    "content": "/**\n * Specific customUtils for the browser, where we don't have access to the Crypto and Buffer modules\n */\n\n/**\n * Taken from the crypto-browserify module\n * https://github.com/dominictarr/crypto-browserify\n * NOTE: Math.random() does not guarantee \"cryptographic quality\" but we actually don't need it\n */\nfunction randomBytes (size) {\n  var bytes = new Array(size);\n  var r;\n\n  for (var i = 0, r; i < size; i++) {\n    if ((i & 0x03) == 0) r = Math.random() * 0x100000000;\n    bytes[i] = r >>> ((i & 0x03) << 3) & 0xff;\n  }\n\n  return bytes;\n}\n\n\n/**\n * Taken from the base64-js module\n * https://github.com/beatgammit/base64-js/\n */\nfunction byteArrayToBase64 (uint8) {\n  var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n    , extraBytes = uint8.length % 3   // if we have 1 byte left, pad 2 bytes\n    , output = \"\"\n    , temp, length, i;\n\n  function tripletToBase64 (num) {\n    return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];\n  };\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n    temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);\n    output += tripletToBase64(temp);\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  switch (extraBytes) {\n    case 1:\n      temp = uint8[uint8.length - 1];\n      output += lookup[temp >> 2];\n      output += lookup[(temp << 4) & 0x3F];\n      output += '==';\n      break;\n    case 2:\n      temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);\n      output += lookup[temp >> 10];\n      output += lookup[(temp >> 4) & 0x3F];\n      output += lookup[(temp << 2) & 0x3F];\n      output += '=';\n      break;\n  }\n\n  return output;\n}\n\n\n/**\n * Return a random alphanumerical string of length len\n * There is a very small probability (less than 1/1,000,000) for the length to be less than len\n * (il the base64 conversion yields too many pluses and slashes) but\n * that's not an issue here\n * The probability of a collision is extremely small (need 3*10^12 documents to have one chance in a million of a collision)\n * See http://en.wikipedia.org/wiki/Birthday_problem\n */\nfunction uid (len) {\n  return byteArrayToBase64(randomBytes(Math.ceil(Math.max(8, len * 2)))).replace(/[+\\/]/g, '').slice(0, len);\n}\n\n\n\nmodule.exports.uid = uid;\n"
  },
  {
    "path": "browser-version/browser-specific/lib/storage.js",
    "content": "/**\n * Way data is stored for this database\n * For a Node.js/Node Webkit database it's the file system\n * For a browser-side database it's localforage, which uses the best backend available (IndexedDB then WebSQL then localStorage)\n *\n * This version is the browser version\n */\n\nvar localforage = require('localforage')\n\n// Configure localforage to display NeDB name for now. Would be a good idea to let user use his own app name\nlocalforage.config({\n  name: 'NeDB'\n, storeName: 'nedbdata'\n});\n\n\nfunction exists (filename, callback) {\n  localforage.getItem(filename, function (err, value) {\n    if (value !== null) {   // Even if value is undefined, localforage returns null\n      return callback(true);\n    } else {\n      return callback(false);\n    }\n  });\n}\n\n\nfunction rename (filename, newFilename, callback) {\n  localforage.getItem(filename, function (err, value) {\n    if (value === null) {\n      localforage.removeItem(newFilename, function () { return callback(); });\n    } else {\n      localforage.setItem(newFilename, value, function () {\n        localforage.removeItem(filename, function () { return callback(); });\n      });\n    }\n  });\n}\n\n\nfunction writeFile (filename, contents, options, callback) {\n  // Options do not matter in browser setup\n  if (typeof options === 'function') { callback = options; }\n  localforage.setItem(filename, contents, function () { return callback(); });\n}\n\n\nfunction appendFile (filename, toAppend, options, callback) {\n  // Options do not matter in browser setup\n  if (typeof options === 'function') { callback = options; }\n\n  localforage.getItem(filename, function (err, contents) {\n    contents = contents || '';\n    contents += toAppend;\n    localforage.setItem(filename, contents, function () { return callback(); });\n  });\n}\n\n\nfunction readFile (filename, options, callback) {\n  // Options do not matter in browser setup\n  if (typeof options === 'function') { callback = options; }\n  localforage.getItem(filename, function (err, contents) { return callback(null, contents || ''); });\n}\n\n\nfunction unlink (filename, callback) {\n  localforage.removeItem(filename, function () { return callback(); });\n}\n\n\n// Nothing to do, no directories will be used on the browser\nfunction mkdirp (dir, callback) {\n  return callback();\n}\n\n\n// Nothing to do, no data corruption possible in the brower\nfunction ensureDatafileIntegrity (filename, callback) {\n  return callback(null);\n}\n\n\n// Interface\nmodule.exports.exists = exists;\nmodule.exports.rename = rename;\nmodule.exports.writeFile = writeFile;\nmodule.exports.crashSafeWriteFile = writeFile;   // No need for a crash safe function in the browser\nmodule.exports.appendFile = appendFile;\nmodule.exports.readFile = readFile;\nmodule.exports.unlink = unlink;\nmodule.exports.mkdirp = mkdirp;\nmodule.exports.ensureDatafileIntegrity = ensureDatafileIntegrity;\n\n"
  },
  {
    "path": "browser-version/build.js",
    "content": "/**\n * Build the browser version of nedb\n */\n\nvar fs = require('fs')\n  , path = require('path')\n  , child_process = require('child_process')\n  , toCopy = ['lib', 'node_modules']\n  , async, browserify, uglify\n  ;\n\n// Ensuring both node_modules (the source one and build one), src and out directories exist\nfunction ensureDirExists (name) {\n  try {\n    fs.mkdirSync(path.join(__dirname, name));\n  } catch (e) {\n    if (e.code !== 'EEXIST') {\n      console.log(\"Error ensuring that node_modules exists\");\n      process.exit(1);\n    }\n  }\n}\nensureDirExists('../node_modules');\nensureDirExists('node_modules');\nensureDirExists('out');\nensureDirExists('src');\n\n\n// Installing build dependencies and require them\nconsole.log(\"Installing build dependencies\");\nchild_process.exec('npm install', { cwd: __dirname }, function (err, stdout, stderr) {\n  if (err) { console.log(\"Error reinstalling dependencies\"); process.exit(1); }\n\n  fs = require('fs-extra');\n  async = require('async');\n  browserify = require('browserify');\n  uglify = require('uglify-js');\n\n  async.waterfall([\n  function (cb) {\n    console.log(\"Installing source dependencies if needed\");\n\n    child_process.exec('npm install', { cwd: path.join(__dirname, '..') }, function (err) { return cb(err); });\n  }\n  , function (cb) {\n    console.log(\"Removing contents of the src directory\");\n\n    async.eachSeries(fs.readdirSync(path.join(__dirname, 'src')), function (item, _cb) {\n      fs.remove(path.join(__dirname, 'src', item), _cb);\n    }, cb);\n  }\n  , function (cb) {\n    console.log(\"Copying source files\");\n\n    async.eachSeries(toCopy, function (item, _cb) {\n      fs.copy(path.join(__dirname, '..', item), path.join(__dirname, 'src', item), _cb);\n    }, cb);\n  }\n  , function (cb) {\n    console.log(\"Copying browser specific files to replace their server-specific counterparts\");\n\n    async.eachSeries(fs.readdirSync(path.join(__dirname, 'browser-specific')), function (item, _cb) {\n      fs.copy(path.join(__dirname, 'browser-specific', item), path.join(__dirname, 'src', item), _cb);\n    }, cb);\n  }\n  , function (cb) {\n    console.log(\"Browserifying the code\");\n\n    var b = browserify()\n      , srcPath = path.join(__dirname, 'src/lib/datastore.js');\n\n    b.add(srcPath);\n    b.bundle({ standalone: 'Nedb' }, function (err, out) {\n      if (err) { return cb(err); }\n      fs.writeFile(path.join(__dirname, 'out/nedb.js'), out, 'utf8', function (err) {\n        if (err) {\n          return cb(err);\n        } else {\n          return cb(null, out);\n        }\n      });\n    });\n  }\n  , function (out, cb) {\n      console.log(\"Creating the minified version\");\n\n      var compressedCode = uglify.minify(out, { fromString: true });\n      fs.writeFile(path.join(__dirname, 'out/nedb.min.js'), compressedCode.code, 'utf8', cb);\n  }\n  ], function (err) {\n    if (err) {\n      console.log(\"Error during build\");\n      console.log(err);\n    } else {\n      console.log(\"Build finished with success\");\n    }\n  });\n});\n\n\n\n"
  },
  {
    "path": "browser-version/out/nedb.js",
    "content": "(function(e){if(\"function\"==typeof bootstrap)bootstrap(\"nedb\",e);else if(\"object\"==typeof exports)module.exports=e();else if(\"function\"==typeof define&&define.amd)define(e);else if(\"undefined\"!=typeof ses){if(!ses.ok())return;ses.makeNedb=e}else\"undefined\"!=typeof window?window.Nedb=e():global.Nedb=e()})(function(){var define,ses,bootstrap,module,exports;\nreturn (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require==\"function\"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error(\"Cannot find module '\"+n+\"'\")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require==\"function\"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){\nvar process=require(\"__browserify_process\");if (!process.EventEmitter) process.EventEmitter = function () {};\n\nvar EventEmitter = exports.EventEmitter = process.EventEmitter;\nvar isArray = typeof Array.isArray === 'function'\n    ? Array.isArray\n    : function (xs) {\n        return Object.prototype.toString.call(xs) === '[object Array]'\n    }\n;\nfunction indexOf (xs, x) {\n    if (xs.indexOf) return xs.indexOf(x);\n    for (var i = 0; i < xs.length; i++) {\n        if (x === xs[i]) return i;\n    }\n    return -1;\n}\n\n// By default EventEmitters will print a warning if more than\n// 10 listeners are added to it. This is a useful default which\n// helps finding memory leaks.\n//\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nvar defaultMaxListeners = 10;\nEventEmitter.prototype.setMaxListeners = function(n) {\n  if (!this._events) this._events = {};\n  this._events.maxListeners = n;\n};\n\n\nEventEmitter.prototype.emit = function(type) {\n  // If there is no 'error' event listener then throw.\n  if (type === 'error') {\n    if (!this._events || !this._events.error ||\n        (isArray(this._events.error) && !this._events.error.length))\n    {\n      if (arguments[1] instanceof Error) {\n        throw arguments[1]; // Unhandled 'error' event\n      } else {\n        throw new Error(\"Uncaught, unspecified 'error' event.\");\n      }\n      return false;\n    }\n  }\n\n  if (!this._events) return false;\n  var handler = this._events[type];\n  if (!handler) return false;\n\n  if (typeof handler == 'function') {\n    switch (arguments.length) {\n      // fast cases\n      case 1:\n        handler.call(this);\n        break;\n      case 2:\n        handler.call(this, arguments[1]);\n        break;\n      case 3:\n        handler.call(this, arguments[1], arguments[2]);\n        break;\n      // slower\n      default:\n        var args = Array.prototype.slice.call(arguments, 1);\n        handler.apply(this, args);\n    }\n    return true;\n\n  } else if (isArray(handler)) {\n    var args = Array.prototype.slice.call(arguments, 1);\n\n    var listeners = handler.slice();\n    for (var i = 0, l = listeners.length; i < l; i++) {\n      listeners[i].apply(this, args);\n    }\n    return true;\n\n  } else {\n    return false;\n  }\n};\n\n// EventEmitter is defined in src/node_events.cc\n// EventEmitter.prototype.emit() is also defined there.\nEventEmitter.prototype.addListener = function(type, listener) {\n  if ('function' !== typeof listener) {\n    throw new Error('addListener only takes instances of Function');\n  }\n\n  if (!this._events) this._events = {};\n\n  // To avoid recursion in the case that type == \"newListeners\"! Before\n  // adding it to the listeners, first emit \"newListeners\".\n  this.emit('newListener', type, listener);\n\n  if (!this._events[type]) {\n    // Optimize the case of one listener. Don't need the extra array object.\n    this._events[type] = listener;\n  } else if (isArray(this._events[type])) {\n\n    // Check for listener leak\n    if (!this._events[type].warned) {\n      var m;\n      if (this._events.maxListeners !== undefined) {\n        m = this._events.maxListeners;\n      } else {\n        m = defaultMaxListeners;\n      }\n\n      if (m && m > 0 && this._events[type].length > m) {\n        this._events[type].warned = true;\n        console.error('(node) warning: possible EventEmitter memory ' +\n                      'leak detected. %d listeners added. ' +\n                      'Use emitter.setMaxListeners() to increase limit.',\n                      this._events[type].length);\n        console.trace();\n      }\n    }\n\n    // If we've already got an array, just append.\n    this._events[type].push(listener);\n  } else {\n    // Adding the second element, need to change to array.\n    this._events[type] = [this._events[type], listener];\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n  var self = this;\n  self.on(type, function g() {\n    self.removeListener(type, g);\n    listener.apply(this, arguments);\n  });\n\n  return this;\n};\n\nEventEmitter.prototype.removeListener = function(type, listener) {\n  if ('function' !== typeof listener) {\n    throw new Error('removeListener only takes instances of Function');\n  }\n\n  // does not use listeners(), so no side effect of creating _events[type]\n  if (!this._events || !this._events[type]) return this;\n\n  var list = this._events[type];\n\n  if (isArray(list)) {\n    var i = indexOf(list, listener);\n    if (i < 0) return this;\n    list.splice(i, 1);\n    if (list.length == 0)\n      delete this._events[type];\n  } else if (this._events[type] === listener) {\n    delete this._events[type];\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n  if (arguments.length === 0) {\n    this._events = {};\n    return this;\n  }\n\n  // does not use listeners(), so no side effect of creating _events[type]\n  if (type && this._events && this._events[type]) this._events[type] = null;\n  return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n  if (!this._events) this._events = {};\n  if (!this._events[type]) this._events[type] = [];\n  if (!isArray(this._events[type])) {\n    this._events[type] = [this._events[type]];\n  }\n  return this._events[type];\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  var ret;\n  if (!emitter._events || !emitter._events[type])\n    ret = 0;\n  else if (typeof emitter._events[type] === 'function')\n    ret = 1;\n  else\n    ret = emitter._events[type].length;\n  return ret;\n};\n\n},{\"__browserify_process\":4}],2:[function(require,module,exports){\nvar process=require(\"__browserify_process\");function filter (xs, fn) {\n    var res = [];\n    for (var i = 0; i < xs.length; i++) {\n        if (fn(xs[i], i, xs)) res.push(xs[i]);\n    }\n    return res;\n}\n\n// resolves . and .. elements in a path array with directory names there\n// must be no slashes, empty elements, or device names (c:\\) in the array\n// (so also no leading and trailing slashes - it does not distinguish\n// relative and absolute paths)\nfunction normalizeArray(parts, allowAboveRoot) {\n  // if the path tries to go above the root, `up` ends up > 0\n  var up = 0;\n  for (var i = parts.length; i >= 0; i--) {\n    var last = parts[i];\n    if (last == '.') {\n      parts.splice(i, 1);\n    } else if (last === '..') {\n      parts.splice(i, 1);\n      up++;\n    } else if (up) {\n      parts.splice(i, 1);\n      up--;\n    }\n  }\n\n  // if the path is allowed to go above the root, restore leading ..s\n  if (allowAboveRoot) {\n    for (; up--; up) {\n      parts.unshift('..');\n    }\n  }\n\n  return parts;\n}\n\n// Regex to split a filename into [*, dir, basename, ext]\n// posix version\nvar splitPathRe = /^(.+\\/(?!$)|\\/)?((?:.+?)?(\\.[^.]*)?)$/;\n\n// path.resolve([from ...], to)\n// posix version\nexports.resolve = function() {\nvar resolvedPath = '',\n    resolvedAbsolute = false;\n\nfor (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) {\n  var path = (i >= 0)\n      ? arguments[i]\n      : process.cwd();\n\n  // Skip empty and invalid entries\n  if (typeof path !== 'string' || !path) {\n    continue;\n  }\n\n  resolvedPath = path + '/' + resolvedPath;\n  resolvedAbsolute = path.charAt(0) === '/';\n}\n\n// At this point the path should be resolved to a full absolute path, but\n// handle relative paths to be safe (might happen when process.cwd() fails)\n\n// Normalize the path\nresolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {\n    return !!p;\n  }), !resolvedAbsolute).join('/');\n\n  return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';\n};\n\n// path.normalize(path)\n// posix version\nexports.normalize = function(path) {\nvar isAbsolute = path.charAt(0) === '/',\n    trailingSlash = path.slice(-1) === '/';\n\n// Normalize the path\npath = normalizeArray(filter(path.split('/'), function(p) {\n    return !!p;\n  }), !isAbsolute).join('/');\n\n  if (!path && !isAbsolute) {\n    path = '.';\n  }\n  if (path && trailingSlash) {\n    path += '/';\n  }\n  \n  return (isAbsolute ? '/' : '') + path;\n};\n\n\n// posix version\nexports.join = function() {\n  var paths = Array.prototype.slice.call(arguments, 0);\n  return exports.normalize(filter(paths, function(p, index) {\n    return p && typeof p === 'string';\n  }).join('/'));\n};\n\n\nexports.dirname = function(path) {\n  var dir = splitPathRe.exec(path)[1] || '';\n  var isWindows = false;\n  if (!dir) {\n    // No dirname\n    return '.';\n  } else if (dir.length === 1 ||\n      (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) {\n    // It is just a slash or a drive letter with a slash\n    return dir;\n  } else {\n    // It is a full dirname, strip trailing slash\n    return dir.substring(0, dir.length - 1);\n  }\n};\n\n\nexports.basename = function(path, ext) {\n  var f = splitPathRe.exec(path)[2] || '';\n  // TODO: make this comparison case-insensitive on windows?\n  if (ext && f.substr(-1 * ext.length) === ext) {\n    f = f.substr(0, f.length - ext.length);\n  }\n  return f;\n};\n\n\nexports.extname = function(path) {\n  return splitPathRe.exec(path)[3] || '';\n};\n\nexports.relative = function(from, to) {\n  from = exports.resolve(from).substr(1);\n  to = exports.resolve(to).substr(1);\n\n  function trim(arr) {\n    var start = 0;\n    for (; start < arr.length; start++) {\n      if (arr[start] !== '') break;\n    }\n\n    var end = arr.length - 1;\n    for (; end >= 0; end--) {\n      if (arr[end] !== '') break;\n    }\n\n    if (start > end) return [];\n    return arr.slice(start, end - start + 1);\n  }\n\n  var fromParts = trim(from.split('/'));\n  var toParts = trim(to.split('/'));\n\n  var length = Math.min(fromParts.length, toParts.length);\n  var samePartsLength = length;\n  for (var i = 0; i < length; i++) {\n    if (fromParts[i] !== toParts[i]) {\n      samePartsLength = i;\n      break;\n    }\n  }\n\n  var outputParts = [];\n  for (var i = samePartsLength; i < fromParts.length; i++) {\n    outputParts.push('..');\n  }\n\n  outputParts = outputParts.concat(toParts.slice(samePartsLength));\n\n  return outputParts.join('/');\n};\n\nexports.sep = '/';\n\n},{\"__browserify_process\":4}],3:[function(require,module,exports){\nvar events = require('events');\n\nexports.isArray = isArray;\nexports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'};\nexports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'};\n\n\nexports.print = function () {};\nexports.puts = function () {};\nexports.debug = function() {};\n\nexports.inspect = function(obj, showHidden, depth, colors) {\n  var seen = [];\n\n  var stylize = function(str, styleType) {\n    // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics\n    var styles =\n        { 'bold' : [1, 22],\n          'italic' : [3, 23],\n          'underline' : [4, 24],\n          'inverse' : [7, 27],\n          'white' : [37, 39],\n          'grey' : [90, 39],\n          'black' : [30, 39],\n          'blue' : [34, 39],\n          'cyan' : [36, 39],\n          'green' : [32, 39],\n          'magenta' : [35, 39],\n          'red' : [31, 39],\n          'yellow' : [33, 39] };\n\n    var style =\n        { 'special': 'cyan',\n          'number': 'blue',\n          'boolean': 'yellow',\n          'undefined': 'grey',\n          'null': 'bold',\n          'string': 'green',\n          'date': 'magenta',\n          // \"name\": intentionally not styling\n          'regexp': 'red' }[styleType];\n\n    if (style) {\n      return '\\u001b[' + styles[style][0] + 'm' + str +\n             '\\u001b[' + styles[style][1] + 'm';\n    } else {\n      return str;\n    }\n  };\n  if (! colors) {\n    stylize = function(str, styleType) { return str; };\n  }\n\n  function format(value, recurseTimes) {\n    // Provide a hook for user-specified inspect functions.\n    // Check that value is an object with an inspect function on it\n    if (value && typeof value.inspect === 'function' &&\n        // Filter out the util module, it's inspect function is special\n        value !== exports &&\n        // Also filter out any prototype objects using the circular check.\n        !(value.constructor && value.constructor.prototype === value)) {\n      return value.inspect(recurseTimes);\n    }\n\n    // Primitive types cannot have properties\n    switch (typeof value) {\n      case 'undefined':\n        return stylize('undefined', 'undefined');\n\n      case 'string':\n        var simple = '\\'' + JSON.stringify(value).replace(/^\"|\"$/g, '')\n                                                 .replace(/'/g, \"\\\\'\")\n                                                 .replace(/\\\\\"/g, '\"') + '\\'';\n        return stylize(simple, 'string');\n\n      case 'number':\n        return stylize('' + value, 'number');\n\n      case 'boolean':\n        return stylize('' + value, 'boolean');\n    }\n    // For some reason typeof null is \"object\", so special case here.\n    if (value === null) {\n      return stylize('null', 'null');\n    }\n\n    // Look up the keys of the object.\n    var visible_keys = Object_keys(value);\n    var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys;\n\n    // Functions without properties can be shortcutted.\n    if (typeof value === 'function' && keys.length === 0) {\n      if (isRegExp(value)) {\n        return stylize('' + value, 'regexp');\n      } else {\n        var name = value.name ? ': ' + value.name : '';\n        return stylize('[Function' + name + ']', 'special');\n      }\n    }\n\n    // Dates without properties can be shortcutted\n    if (isDate(value) && keys.length === 0) {\n      return stylize(value.toUTCString(), 'date');\n    }\n\n    var base, type, braces;\n    // Determine the object type\n    if (isArray(value)) {\n      type = 'Array';\n      braces = ['[', ']'];\n    } else {\n      type = 'Object';\n      braces = ['{', '}'];\n    }\n\n    // Make functions say that they are functions\n    if (typeof value === 'function') {\n      var n = value.name ? ': ' + value.name : '';\n      base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']';\n    } else {\n      base = '';\n    }\n\n    // Make dates with properties first say the date\n    if (isDate(value)) {\n      base = ' ' + value.toUTCString();\n    }\n\n    if (keys.length === 0) {\n      return braces[0] + base + braces[1];\n    }\n\n    if (recurseTimes < 0) {\n      if (isRegExp(value)) {\n        return stylize('' + value, 'regexp');\n      } else {\n        return stylize('[Object]', 'special');\n      }\n    }\n\n    seen.push(value);\n\n    var output = keys.map(function(key) {\n      var name, str;\n      if (value.__lookupGetter__) {\n        if (value.__lookupGetter__(key)) {\n          if (value.__lookupSetter__(key)) {\n            str = stylize('[Getter/Setter]', 'special');\n          } else {\n            str = stylize('[Getter]', 'special');\n          }\n        } else {\n          if (value.__lookupSetter__(key)) {\n            str = stylize('[Setter]', 'special');\n          }\n        }\n      }\n      if (visible_keys.indexOf(key) < 0) {\n        name = '[' + key + ']';\n      }\n      if (!str) {\n        if (seen.indexOf(value[key]) < 0) {\n          if (recurseTimes === null) {\n            str = format(value[key]);\n          } else {\n            str = format(value[key], recurseTimes - 1);\n          }\n          if (str.indexOf('\\n') > -1) {\n            if (isArray(value)) {\n              str = str.split('\\n').map(function(line) {\n                return '  ' + line;\n              }).join('\\n').substr(2);\n            } else {\n              str = '\\n' + str.split('\\n').map(function(line) {\n                return '   ' + line;\n              }).join('\\n');\n            }\n          }\n        } else {\n          str = stylize('[Circular]', 'special');\n        }\n      }\n      if (typeof name === 'undefined') {\n        if (type === 'Array' && key.match(/^\\d+$/)) {\n          return str;\n        }\n        name = JSON.stringify('' + key);\n        if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n          name = name.substr(1, name.length - 2);\n          name = stylize(name, 'name');\n        } else {\n          name = name.replace(/'/g, \"\\\\'\")\n                     .replace(/\\\\\"/g, '\"')\n                     .replace(/(^\"|\"$)/g, \"'\");\n          name = stylize(name, 'string');\n        }\n      }\n\n      return name + ': ' + str;\n    });\n\n    seen.pop();\n\n    var numLinesEst = 0;\n    var length = output.reduce(function(prev, cur) {\n      numLinesEst++;\n      if (cur.indexOf('\\n') >= 0) numLinesEst++;\n      return prev + cur.length + 1;\n    }, 0);\n\n    if (length > 50) {\n      output = braces[0] +\n               (base === '' ? '' : base + '\\n ') +\n               ' ' +\n               output.join(',\\n  ') +\n               ' ' +\n               braces[1];\n\n    } else {\n      output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n    }\n\n    return output;\n  }\n  return format(obj, (typeof depth === 'undefined' ? 2 : depth));\n};\n\n\nfunction isArray(ar) {\n  return Array.isArray(ar) ||\n         (typeof ar === 'object' && Object.prototype.toString.call(ar) === '[object Array]');\n}\n\n\nfunction isRegExp(re) {\n  typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]';\n}\n\n\nfunction isDate(d) {\n  return typeof d === 'object' && Object.prototype.toString.call(d) === '[object Date]';\n}\n\nfunction pad(n) {\n  return n < 10 ? '0' + n.toString(10) : n.toString(10);\n}\n\nvar months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',\n              'Oct', 'Nov', 'Dec'];\n\n// 26 Feb 16:19:34\nfunction timestamp() {\n  var d = new Date();\n  var time = [pad(d.getHours()),\n              pad(d.getMinutes()),\n              pad(d.getSeconds())].join(':');\n  return [d.getDate(), months[d.getMonth()], time].join(' ');\n}\n\nexports.log = function (msg) {};\n\nexports.pump = null;\n\nvar Object_keys = Object.keys || function (obj) {\n    var res = [];\n    for (var key in obj) res.push(key);\n    return res;\n};\n\nvar Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) {\n    var res = [];\n    for (var key in obj) {\n        if (Object.hasOwnProperty.call(obj, key)) res.push(key);\n    }\n    return res;\n};\n\nvar Object_create = Object.create || function (prototype, properties) {\n    // from es5-shim\n    var object;\n    if (prototype === null) {\n        object = { '__proto__' : null };\n    }\n    else {\n        if (typeof prototype !== 'object') {\n            throw new TypeError(\n                'typeof prototype[' + (typeof prototype) + '] != \\'object\\''\n            );\n        }\n        var Type = function () {};\n        Type.prototype = prototype;\n        object = new Type();\n        object.__proto__ = prototype;\n    }\n    if (typeof properties !== 'undefined' && Object.defineProperties) {\n        Object.defineProperties(object, properties);\n    }\n    return object;\n};\n\nexports.inherits = function(ctor, superCtor) {\n  ctor.super_ = superCtor;\n  ctor.prototype = Object_create(superCtor.prototype, {\n    constructor: {\n      value: ctor,\n      enumerable: false,\n      writable: true,\n      configurable: true\n    }\n  });\n};\n\nvar formatRegExp = /%[sdj%]/g;\nexports.format = function(f) {\n  if (typeof f !== 'string') {\n    var objects = [];\n    for (var i = 0; i < arguments.length; i++) {\n      objects.push(exports.inspect(arguments[i]));\n    }\n    return objects.join(' ');\n  }\n\n  var i = 1;\n  var args = arguments;\n  var len = args.length;\n  var str = String(f).replace(formatRegExp, function(x) {\n    if (x === '%%') return '%';\n    if (i >= len) return x;\n    switch (x) {\n      case '%s': return String(args[i++]);\n      case '%d': return Number(args[i++]);\n      case '%j': return JSON.stringify(args[i++]);\n      default:\n        return x;\n    }\n  });\n  for(var x = args[i]; i < len; x = args[++i]){\n    if (x === null || typeof x !== 'object') {\n      str += ' ' + x;\n    } else {\n      str += ' ' + exports.inspect(x);\n    }\n  }\n  return str;\n};\n\n},{\"events\":1}],4:[function(require,module,exports){\n// shim for using process in browser\n\nvar process = module.exports = {};\n\nprocess.nextTick = (function () {\n    var canSetImmediate = typeof window !== 'undefined'\n    && window.setImmediate;\n    var canPost = typeof window !== 'undefined'\n    && window.postMessage && window.addEventListener\n    ;\n\n    if (canSetImmediate) {\n        return function (f) { return window.setImmediate(f) };\n    }\n\n    if (canPost) {\n        var queue = [];\n        window.addEventListener('message', function (ev) {\n            var source = ev.source;\n            if ((source === window || source === null) && ev.data === 'process-tick') {\n                ev.stopPropagation();\n                if (queue.length > 0) {\n                    var fn = queue.shift();\n                    fn();\n                }\n            }\n        }, true);\n\n        return function nextTick(fn) {\n            queue.push(fn);\n            window.postMessage('process-tick', '*');\n        };\n    }\n\n    return function nextTick(fn) {\n        setTimeout(fn, 0);\n    };\n})();\n\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\n\nprocess.binding = function (name) {\n    throw new Error('process.binding is not supported');\n}\n\n// TODO(shtylman)\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n    throw new Error('process.chdir is not supported');\n};\n\n},{}],5:[function(require,module,exports){\n/**\n * Manage access to data, be it to find, update or remove it\n */\nvar model = require('./model')\n  , _ = require('underscore')\n  ;\n\n\n\n/**\n * Create a new cursor for this collection\n * @param {Datastore} db - The datastore this cursor is bound to\n * @param {Query} query - The query this cursor will operate on\n * @param {Function} execFn - Handler to be executed after cursor has found the results and before the callback passed to find/findOne/update/remove\n */\nfunction Cursor (db, query, execFn) {\n  this.db = db;\n  this.query = query || {};\n  if (execFn) { this.execFn = execFn; }\n}\n\n\n/**\n * Set a limit to the number of results\n */\nCursor.prototype.limit = function(limit) {\n  this._limit = limit;\n  return this;\n};\n\n\n/**\n * Skip a the number of results\n */\nCursor.prototype.skip = function(skip) {\n  this._skip = skip;\n  return this;\n};\n\n\n/**\n * Sort results of the query\n * @param {SortQuery} sortQuery - SortQuery is { field: order }, field can use the dot-notation, order is 1 for ascending and -1 for descending\n */\nCursor.prototype.sort = function(sortQuery) {\n  this._sort = sortQuery;\n  return this;\n};\n\n\n/**\n * Add the use of a projection\n * @param {Object} projection - MongoDB-style projection. {} means take all fields. Then it's { key1: 1, key2: 1 } to take only key1 and key2\n *                              { key1: 0, key2: 0 } to omit only key1 and key2. Except _id, you can't mix takes and omits\n */\nCursor.prototype.projection = function(projection) {\n  this._projection = projection;\n  return this;\n};\n\n\n/**\n * Apply the projection\n */\nCursor.prototype.project = function (candidates) {\n  var res = [], self = this\n    , keepId, action, keys\n    ;\n\n  if (this._projection === undefined || Object.keys(this._projection).length === 0) {\n    return candidates;\n  }\n\n  keepId = this._projection._id === 0 ? false : true;\n  this._projection = _.omit(this._projection, '_id');\n\n  // Check for consistency\n  keys = Object.keys(this._projection);\n  keys.forEach(function (k) {\n    if (action !== undefined && self._projection[k] !== action) { throw new Error(\"Can't both keep and omit fields except for _id\"); }\n    action = self._projection[k];\n  });\n\n  // Do the actual projection\n  candidates.forEach(function (candidate) {\n    var toPush;\n    if (action === 1) {   // pick-type projection\n      toPush = { $set: {} };\n      keys.forEach(function (k) {\n        toPush.$set[k] = model.getDotValue(candidate, k);\n        if (toPush.$set[k] === undefined) { delete toPush.$set[k]; }\n      });\n      toPush = model.modify({}, toPush);\n    } else {   // omit-type projection\n      toPush = { $unset: {} };\n      keys.forEach(function (k) { toPush.$unset[k] = true });\n      toPush = model.modify(candidate, toPush);\n    }\n    if (keepId) {\n      toPush._id = candidate._id;\n    } else {\n      delete toPush._id;\n    }\n    res.push(toPush);\n  });\n\n  return res;\n};\n\n\n/**\n * Get all matching elements\n * Will return pointers to matched elements (shallow copies), returning full copies is the role of find or findOne\n * This is an internal function, use exec which uses the executor\n *\n * @param {Function} callback - Signature: err, results\n */\nCursor.prototype._exec = function(_callback) {\n  var res = [], added = 0, skipped = 0, self = this\n    , error = null\n    , i, keys, key\n    ;\n\n  function callback (error, res) {\n    if (self.execFn) {\n      return self.execFn(error, res, _callback);\n    } else {\n      return _callback(error, res);\n    }\n  }\n\n  this.db.getCandidates(this.query, function (err, candidates) {\n    if (err) { return callback(err); }\n\n    try {\n      for (i = 0; i < candidates.length; i += 1) {\n        if (model.match(candidates[i], self.query)) {\n          // If a sort is defined, wait for the results to be sorted before applying limit and skip\n          if (!self._sort) {\n            if (self._skip && self._skip > skipped) {\n              skipped += 1;\n            } else {\n              res.push(candidates[i]);\n              added += 1;\n              if (self._limit && self._limit <= added) { break; }\n            }\n          } else {\n            res.push(candidates[i]);\n          }\n        }\n      }\n    } catch (err) {\n      return callback(err);\n    }\n\n    // Apply all sorts\n    if (self._sort) {\n      keys = Object.keys(self._sort);\n\n      // Sorting\n      var criteria = [];\n      for (i = 0; i < keys.length; i++) {\n        key = keys[i];\n        criteria.push({ key: key, direction: self._sort[key] });\n      }\n      res.sort(function(a, b) {\n        var criterion, compare, i;\n        for (i = 0; i < criteria.length; i++) {\n          criterion = criteria[i];\n          compare = criterion.direction * model.compareThings(model.getDotValue(a, criterion.key), model.getDotValue(b, criterion.key), self.db.compareStrings);\n          if (compare !== 0) {\n            return compare;\n          }\n        }\n        return 0;\n      });\n\n      // Applying limit and skip\n      var limit = self._limit || res.length\n        , skip = self._skip || 0;\n\n      res = res.slice(skip, skip + limit);\n    }\n\n    // Apply projection\n    try {\n      res = self.project(res);\n    } catch (e) {\n      error = e;\n      res = undefined;\n    }\n\n    return callback(error, res);\n  });\n};\n\nCursor.prototype.exec = function () {\n  this.db.executor.push({ this: this, fn: this._exec, arguments: arguments });\n};\n\n\n\n// Interface\nmodule.exports = Cursor;\n\n},{\"./model\":10,\"underscore\":19}],6:[function(require,module,exports){\n/**\n * Specific customUtils for the browser, where we don't have access to the Crypto and Buffer modules\n */\n\n/**\n * Taken from the crypto-browserify module\n * https://github.com/dominictarr/crypto-browserify\n * NOTE: Math.random() does not guarantee \"cryptographic quality\" but we actually don't need it\n */\nfunction randomBytes (size) {\n  var bytes = new Array(size);\n  var r;\n\n  for (var i = 0, r; i < size; i++) {\n    if ((i & 0x03) == 0) r = Math.random() * 0x100000000;\n    bytes[i] = r >>> ((i & 0x03) << 3) & 0xff;\n  }\n\n  return bytes;\n}\n\n\n/**\n * Taken from the base64-js module\n * https://github.com/beatgammit/base64-js/\n */\nfunction byteArrayToBase64 (uint8) {\n  var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n    , extraBytes = uint8.length % 3   // if we have 1 byte left, pad 2 bytes\n    , output = \"\"\n    , temp, length, i;\n\n  function tripletToBase64 (num) {\n    return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];\n  };\n\n  // go through the array every three bytes, we'll deal with trailing stuff later\n  for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {\n    temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]);\n    output += tripletToBase64(temp);\n  }\n\n  // pad the end with zeros, but make sure to not forget the extra bytes\n  switch (extraBytes) {\n    case 1:\n      temp = uint8[uint8.length - 1];\n      output += lookup[temp >> 2];\n      output += lookup[(temp << 4) & 0x3F];\n      output += '==';\n      break;\n    case 2:\n      temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]);\n      output += lookup[temp >> 10];\n      output += lookup[(temp >> 4) & 0x3F];\n      output += lookup[(temp << 2) & 0x3F];\n      output += '=';\n      break;\n  }\n\n  return output;\n}\n\n\n/**\n * Return a random alphanumerical string of length len\n * There is a very small probability (less than 1/1,000,000) for the length to be less than len\n * (il the base64 conversion yields too many pluses and slashes) but\n * that's not an issue here\n * The probability of a collision is extremely small (need 3*10^12 documents to have one chance in a million of a collision)\n * See http://en.wikipedia.org/wiki/Birthday_problem\n */\nfunction uid (len) {\n  return byteArrayToBase64(randomBytes(Math.ceil(Math.max(8, len * 2)))).replace(/[+\\/]/g, '').slice(0, len);\n}\n\n\n\nmodule.exports.uid = uid;\n\n},{}],7:[function(require,module,exports){\nvar customUtils = require('./customUtils')\n  , model = require('./model')\n  , async = require('async')\n  , Executor = require('./executor')\n  , Index = require('./indexes')\n  , util = require('util')\n  , _ = require('underscore')\n  , Persistence = require('./persistence')\n  , Cursor = require('./cursor')\n  ;\n\n\n/**\n * Create a new collection\n * @param {String} options.filename Optional, datastore will be in-memory only if not provided\n * @param {Boolean} options.timestampData Optional, defaults to false. If set to true, createdAt and updatedAt will be created and populated automatically (if not specified by user)\n * @param {Boolean} options.inMemoryOnly Optional, defaults to false\n * @param {String} options.nodeWebkitAppName Optional, specify the name of your NW app if you want options.filename to be relative to the directory where\n *                                            Node Webkit stores application data such as cookies and local storage (the best place to store data in my opinion)\n * @param {Boolean} options.autoload Optional, defaults to false\n * @param {Function} options.onload Optional, if autoload is used this will be called after the load database with the error object as parameter. If you don't pass it the error will be thrown\n * @param {Function} options.afterSerialization/options.beforeDeserialization Optional, serialization hooks\n * @param {Number} options.corruptAlertThreshold Optional, threshold after which an alert is thrown if too much data is corrupt\n * @param {Function} options.compareStrings Optional, string comparison function that overrides default for sorting\n *\n * Event Emitter - Events\n * * compaction.done - Fired whenever a compaction operation was finished\n */\nfunction Datastore (options) {\n  var filename;\n\n  // Retrocompatibility with v0.6 and before\n  if (typeof options === 'string') {\n    filename = options;\n    this.inMemoryOnly = false;   // Default\n  } else {\n    options = options || {};\n    filename = options.filename;\n    this.inMemoryOnly = options.inMemoryOnly || false;\n    this.autoload = options.autoload || false;\n    this.timestampData = options.timestampData || false;\n  }\n\n  // Determine whether in memory or persistent\n  if (!filename || typeof filename !== 'string' || filename.length === 0) {\n    this.filename = null;\n    this.inMemoryOnly = true;\n  } else {\n    this.filename = filename;\n  }\n\n  // String comparison function\n  this.compareStrings = options.compareStrings;\n\n  // Persistence handling\n  this.persistence = new Persistence({ db: this, nodeWebkitAppName: options.nodeWebkitAppName\n                                      , afterSerialization: options.afterSerialization\n                                      , beforeDeserialization: options.beforeDeserialization\n                                      , corruptAlertThreshold: options.corruptAlertThreshold\n                                      });\n\n  // This new executor is ready if we don't use persistence\n  // If we do, it will only be ready once loadDatabase is called\n  this.executor = new Executor();\n  if (this.inMemoryOnly) { this.executor.ready = true; }\n\n  // Indexed by field name, dot notation can be used\n  // _id is always indexed and since _ids are generated randomly the underlying\n  // binary is always well-balanced\n  this.indexes = {};\n  this.indexes._id = new Index({ fieldName: '_id', unique: true });\n  this.ttlIndexes = {};\n\n  // Queue a load of the database right away and call the onload handler\n  // By default (no onload handler), if there is an error there, no operation will be possible so warn the user by throwing an exception\n  if (this.autoload) { this.loadDatabase(options.onload || function (err) {\n    if (err) { throw err; }\n  }); }\n}\n\nutil.inherits(Datastore, require('events').EventEmitter);\n\n\n/**\n * Load the database from the datafile, and trigger the execution of buffered commands if any\n */\nDatastore.prototype.loadDatabase = function () {\n  this.executor.push({ this: this.persistence, fn: this.persistence.loadDatabase, arguments: arguments }, true);\n};\n\n\n/**\n * Get an array of all the data in the database\n */\nDatastore.prototype.getAllData = function () {\n  return this.indexes._id.getAll();\n};\n\n\n/**\n * Reset all currently defined indexes\n */\nDatastore.prototype.resetIndexes = function (newData) {\n  var self = this;\n\n  Object.keys(this.indexes).forEach(function (i) {\n    self.indexes[i].reset(newData);\n  });\n};\n\n\n/**\n * Ensure an index is kept for this field. Same parameters as lib/indexes\n * For now this function is synchronous, we need to test how much time it takes\n * We use an async API for consistency with the rest of the code\n * @param {String} options.fieldName\n * @param {Boolean} options.unique\n * @param {Boolean} options.sparse\n * @param {Number} options.expireAfterSeconds - Optional, if set this index becomes a TTL index (only works on Date fields, not arrays of Date)\n * @param {Function} cb Optional callback, signature: err\n */\nDatastore.prototype.ensureIndex = function (options, cb) {\n  var err\n    , callback = cb || function () {};\n\n  options = options || {};\n\n  if (!options.fieldName) {\n    err = new Error(\"Cannot create an index without a fieldName\");\n    err.missingFieldName = true;\n    return callback(err);\n  }\n  if (this.indexes[options.fieldName]) { return callback(null); }\n\n  this.indexes[options.fieldName] = new Index(options);\n  if (options.expireAfterSeconds !== undefined) { this.ttlIndexes[options.fieldName] = options.expireAfterSeconds; }   // With this implementation index creation is not necessary to ensure TTL but we stick with MongoDB's API here\n\n  try {\n    this.indexes[options.fieldName].insert(this.getAllData());\n  } catch (e) {\n    delete this.indexes[options.fieldName];\n    return callback(e);\n  }\n\n  // We may want to force all options to be persisted including defaults, not just the ones passed the index creation function\n  this.persistence.persistNewState([{ $$indexCreated: options }], function (err) {\n    if (err) { return callback(err); }\n    return callback(null);\n  });\n};\n\n\n/**\n * Remove an index\n * @param {String} fieldName\n * @param {Function} cb Optional callback, signature: err\n */\nDatastore.prototype.removeIndex = function (fieldName, cb) {\n  var callback = cb || function () {};\n\n  delete this.indexes[fieldName];\n\n  this.persistence.persistNewState([{ $$indexRemoved: fieldName }], function (err) {\n    if (err) { return callback(err); }\n    return callback(null);\n  });\n};\n\n\n/**\n * Add one or several document(s) to all indexes\n */\nDatastore.prototype.addToIndexes = function (doc) {\n  var i, failingIndex, error\n    , keys = Object.keys(this.indexes)\n    ;\n\n  for (i = 0; i < keys.length; i += 1) {\n    try {\n      this.indexes[keys[i]].insert(doc);\n    } catch (e) {\n      failingIndex = i;\n      error = e;\n      break;\n    }\n  }\n\n  // If an error happened, we need to rollback the insert on all other indexes\n  if (error) {\n    for (i = 0; i < failingIndex; i += 1) {\n      this.indexes[keys[i]].remove(doc);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Remove one or several document(s) from all indexes\n */\nDatastore.prototype.removeFromIndexes = function (doc) {\n  var self = this;\n\n  Object.keys(this.indexes).forEach(function (i) {\n    self.indexes[i].remove(doc);\n  });\n};\n\n\n/**\n * Update one or several documents in all indexes\n * To update multiple documents, oldDoc must be an array of { oldDoc, newDoc } pairs\n * If one update violates a constraint, all changes are rolled back\n */\nDatastore.prototype.updateIndexes = function (oldDoc, newDoc) {\n  var i, failingIndex, error\n    , keys = Object.keys(this.indexes)\n    ;\n\n  for (i = 0; i < keys.length; i += 1) {\n    try {\n      this.indexes[keys[i]].update(oldDoc, newDoc);\n    } catch (e) {\n      failingIndex = i;\n      error = e;\n      break;\n    }\n  }\n\n  // If an error happened, we need to rollback the update on all other indexes\n  if (error) {\n    for (i = 0; i < failingIndex; i += 1) {\n      this.indexes[keys[i]].revertUpdate(oldDoc, newDoc);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Return the list of candidates for a given query\n * Crude implementation for now, we return the candidates given by the first usable index if any\n * We try the following query types, in this order: basic match, $in match, comparison match\n * One way to make it better would be to enable the use of multiple indexes if the first usable index\n * returns too much data. I may do it in the future.\n *\n * Returned candidates will be scanned to find and remove all expired documents\n *\n * @param {Query} query\n * @param {Boolean} dontExpireStaleDocs Optional, defaults to false, if true don't remove stale docs. Useful for the remove function which shouldn't be impacted by expirations\n * @param {Function} callback Signature err, candidates\n */\nDatastore.prototype.getCandidates = function (query, dontExpireStaleDocs, callback) {\n  var indexNames = Object.keys(this.indexes)\n    , self = this\n    , usableQueryKeys;\n\n  if (typeof dontExpireStaleDocs === 'function') {\n    callback = dontExpireStaleDocs;\n    dontExpireStaleDocs = false;\n  }\n\n\n  async.waterfall([\n  // STEP 1: get candidates list by checking indexes from most to least frequent usecase\n  function (cb) {\n    // For a basic match\n    usableQueryKeys = [];\n    Object.keys(query).forEach(function (k) {\n      if (typeof query[k] === 'string' || typeof query[k] === 'number' || typeof query[k] === 'boolean' || util.isDate(query[k]) || query[k] === null) {\n        usableQueryKeys.push(k);\n      }\n    });\n    usableQueryKeys = _.intersection(usableQueryKeys, indexNames);\n    if (usableQueryKeys.length > 0) {\n      return cb(null, self.indexes[usableQueryKeys[0]].getMatching(query[usableQueryKeys[0]]));\n    }\n\n    // For a $in match\n    usableQueryKeys = [];\n    Object.keys(query).forEach(function (k) {\n      if (query[k] && query[k].hasOwnProperty('$in')) {\n        usableQueryKeys.push(k);\n      }\n    });\n    usableQueryKeys = _.intersection(usableQueryKeys, indexNames);\n    if (usableQueryKeys.length > 0) {\n      return cb(null, self.indexes[usableQueryKeys[0]].getMatching(query[usableQueryKeys[0]].$in));\n    }\n\n    // For a comparison match\n    usableQueryKeys = [];\n    Object.keys(query).forEach(function (k) {\n      if (query[k] && (query[k].hasOwnProperty('$lt') || query[k].hasOwnProperty('$lte') || query[k].hasOwnProperty('$gt') || query[k].hasOwnProperty('$gte'))) {\n        usableQueryKeys.push(k);\n      }\n    });\n    usableQueryKeys = _.intersection(usableQueryKeys, indexNames);\n    if (usableQueryKeys.length > 0) {\n      return cb(null, self.indexes[usableQueryKeys[0]].getBetweenBounds(query[usableQueryKeys[0]]));\n    }\n\n    // By default, return all the DB data\n    return cb(null, self.getAllData());\n  }\n  // STEP 2: remove all expired documents\n  , function (docs) {\n    if (dontExpireStaleDocs) { return callback(null, docs); }\n\n    var expiredDocsIds = [], validDocs = [], ttlIndexesFieldNames = Object.keys(self.ttlIndexes);\n\n    docs.forEach(function (doc) {\n      var valid = true;\n      ttlIndexesFieldNames.forEach(function (i) {\n        if (doc[i] !== undefined && util.isDate(doc[i]) && Date.now() > doc[i].getTime() + self.ttlIndexes[i] * 1000) {\n          valid = false;\n        }\n      });\n      if (valid) { validDocs.push(doc); } else { expiredDocsIds.push(doc._id); }\n    });\n\n    async.eachSeries(expiredDocsIds, function (_id, cb) {\n      self._remove({ _id: _id }, {}, function (err) {\n        if (err) { return callback(err); }\n        return cb();\n      });\n    }, function (err) {\n      return callback(null, validDocs);\n    });\n  }]);\n};\n\n\n/**\n * Insert a new document\n * @param {Function} cb Optional callback, signature: err, insertedDoc\n *\n * @api private Use Datastore.insert which has the same signature\n */\nDatastore.prototype._insert = function (newDoc, cb) {\n  var callback = cb || function () {}\n    , preparedDoc\n    ;\n\n  try {\n    preparedDoc = this.prepareDocumentForInsertion(newDoc)\n    this._insertInCache(preparedDoc);\n  } catch (e) {\n    return callback(e);\n  }\n\n  this.persistence.persistNewState(util.isArray(preparedDoc) ? preparedDoc : [preparedDoc], function (err) {\n    if (err) { return callback(err); }\n    return callback(null, model.deepCopy(preparedDoc));\n  });\n};\n\n/**\n * Create a new _id that's not already in use\n */\nDatastore.prototype.createNewId = function () {\n  var tentativeId = customUtils.uid(16);\n  // Try as many times as needed to get an unused _id. As explained in customUtils, the probability of this ever happening is extremely small, so this is O(1)\n  if (this.indexes._id.getMatching(tentativeId).length > 0) {\n    tentativeId = this.createNewId();\n  }\n  return tentativeId;\n};\n\n/**\n * Prepare a document (or array of documents) to be inserted in a database\n * Meaning adds _id and timestamps if necessary on a copy of newDoc to avoid any side effect on user input\n * @api private\n */\nDatastore.prototype.prepareDocumentForInsertion = function (newDoc) {\n  var preparedDoc, self = this;\n\n  if (util.isArray(newDoc)) {\n    preparedDoc = [];\n    newDoc.forEach(function (doc) { preparedDoc.push(self.prepareDocumentForInsertion(doc)); });\n  } else {\n    preparedDoc = model.deepCopy(newDoc);\n    if (preparedDoc._id === undefined) { preparedDoc._id = this.createNewId(); }\n    var now = new Date();\n    if (this.timestampData && preparedDoc.createdAt === undefined) { preparedDoc.createdAt = now; }\n    if (this.timestampData && preparedDoc.updatedAt === undefined) { preparedDoc.updatedAt = now; }\n    model.checkObject(preparedDoc);\n  }\n\n  return preparedDoc;\n};\n\n/**\n * If newDoc is an array of documents, this will insert all documents in the cache\n * @api private\n */\nDatastore.prototype._insertInCache = function (preparedDoc) {\n  if (util.isArray(preparedDoc)) {\n    this._insertMultipleDocsInCache(preparedDoc);\n  } else {\n    this.addToIndexes(preparedDoc);\n  }\n};\n\n/**\n * If one insertion fails (e.g. because of a unique constraint), roll back all previous\n * inserts and throws the error\n * @api private\n */\nDatastore.prototype._insertMultipleDocsInCache = function (preparedDocs) {\n  var i, failingI, error;\n\n  for (i = 0; i < preparedDocs.length; i += 1) {\n    try {\n      this.addToIndexes(preparedDocs[i]);\n    } catch (e) {\n      error = e;\n      failingI = i;\n      break;\n    }\n  }\n\n  if (error) {\n    for (i = 0; i < failingI; i += 1) {\n      this.removeFromIndexes(preparedDocs[i]);\n    }\n\n    throw error;\n  }\n};\n\nDatastore.prototype.insert = function () {\n  this.executor.push({ this: this, fn: this._insert, arguments: arguments });\n};\n\n\n/**\n * Count all documents matching the query\n * @param {Object} query MongoDB-style query\n */\nDatastore.prototype.count = function(query, callback) {\n  var cursor = new Cursor(this, query, function(err, docs, callback) {\n    if (err) { return callback(err); }\n    return callback(null, docs.length);\n  });\n\n  if (typeof callback === 'function') {\n    cursor.exec(callback);\n  } else {\n    return cursor;\n  }\n};\n\n\n/**\n * Find all documents matching the query\n * If no callback is passed, we return the cursor so that user can limit, skip and finally exec\n * @param {Object} query MongoDB-style query\n * @param {Object} projection MongoDB-style projection\n */\nDatastore.prototype.find = function (query, projection, callback) {\n  switch (arguments.length) {\n    case 1:\n      projection = {};\n      // callback is undefined, will return a cursor\n      break;\n    case 2:\n      if (typeof projection === 'function') {\n        callback = projection;\n        projection = {};\n      }   // If not assume projection is an object and callback undefined\n      break;\n  }\n\n  var cursor = new Cursor(this, query, function(err, docs, callback) {\n    var res = [], i;\n\n    if (err) { return callback(err); }\n\n    for (i = 0; i < docs.length; i += 1) {\n      res.push(model.deepCopy(docs[i]));\n    }\n    return callback(null, res);\n  });\n\n  cursor.projection(projection);\n  if (typeof callback === 'function') {\n    cursor.exec(callback);\n  } else {\n    return cursor;\n  }\n};\n\n\n/**\n * Find one document matching the query\n * @param {Object} query MongoDB-style query\n * @param {Object} projection MongoDB-style projection\n */\nDatastore.prototype.findOne = function (query, projection, callback) {\n  switch (arguments.length) {\n    case 1:\n      projection = {};\n      // callback is undefined, will return a cursor\n      break;\n    case 2:\n      if (typeof projection === 'function') {\n        callback = projection;\n        projection = {};\n      }   // If not assume projection is an object and callback undefined\n      break;\n  }\n\n  var cursor = new Cursor(this, query, function(err, docs, callback) {\n    if (err) { return callback(err); }\n    if (docs.length === 1) {\n      return callback(null, model.deepCopy(docs[0]));\n    } else {\n      return callback(null, null);\n    }\n  });\n\n  cursor.projection(projection).limit(1);\n  if (typeof callback === 'function') {\n    cursor.exec(callback);\n  } else {\n    return cursor;\n  }\n};\n\n\n/**\n * Update all docs matching query\n * @param {Object} query\n * @param {Object} updateQuery\n * @param {Object} options Optional options\n *                 options.multi If true, can update multiple documents (defaults to false)\n *                 options.upsert If true, document is inserted if the query doesn't match anything\n *                 options.returnUpdatedDocs Defaults to false, if true return as third argument the array of updated matched documents (even if no change actually took place)\n * @param {Function} cb Optional callback, signature: (err, numAffected, affectedDocuments, upsert)\n *                      If update was an upsert, upsert flag is set to true\n *                      affectedDocuments can be one of the following:\n *                        * For an upsert, the upserted document\n *                        * For an update with returnUpdatedDocs option false, null\n *                        * For an update with returnUpdatedDocs true and multi false, the updated document\n *                        * For an update with returnUpdatedDocs true and multi true, the array of updated documents\n *\n * WARNING: The API was changed between v1.7.4 and v1.8, for consistency and readability reasons. Prior and including to v1.7.4,\n *          the callback signature was (err, numAffected, updated) where updated was the updated document in case of an upsert\n *          or the array of updated documents for an update if the returnUpdatedDocs option was true. That meant that the type of\n *          affectedDocuments in a non multi update depended on whether there was an upsert or not, leaving only two ways for the\n *          user to check whether an upsert had occured: checking the type of affectedDocuments or running another find query on\n *          the whole dataset to check its size. Both options being ugly, the breaking change was necessary.\n *\n * @api private Use Datastore.update which has the same signature\n */\nDatastore.prototype._update = function (query, updateQuery, options, cb) {\n  var callback\n    , self = this\n    , numReplaced = 0\n    , multi, upsert\n    , i\n    ;\n\n  if (typeof options === 'function') { cb = options; options = {}; }\n  callback = cb || function () {};\n  multi = options.multi !== undefined ? options.multi : false;\n  upsert = options.upsert !== undefined ? options.upsert : false;\n\n  async.waterfall([\n  function (cb) {   // If upsert option is set, check whether we need to insert the doc\n    if (!upsert) { return cb(); }\n\n    // Need to use an internal function not tied to the executor to avoid deadlock\n    var cursor = new Cursor(self, query);\n    cursor.limit(1)._exec(function (err, docs) {\n      if (err) { return callback(err); }\n      if (docs.length === 1) {\n        return cb();\n      } else {\n        var toBeInserted;\n\n        try {\n          model.checkObject(updateQuery);\n          // updateQuery is a simple object with no modifier, use it as the document to insert\n          toBeInserted = updateQuery;\n        } catch (e) {\n          // updateQuery contains modifiers, use the find query as the base,\n          // strip it from all operators and update it according to updateQuery\n          try {\n            toBeInserted = model.modify(model.deepCopy(query, true), updateQuery);\n          } catch (err) {\n            return callback(err);\n          }\n        }\n\n        return self._insert(toBeInserted, function (err, newDoc) {\n          if (err) { return callback(err); }\n          return callback(null, 1, newDoc, true);\n        });\n      }\n    });\n  }\n  , function () {   // Perform the update\n    var modifiedDoc , modifications = [], createdAt;\n\n    self.getCandidates(query, function (err, candidates) {\n      if (err) { return callback(err); }\n\n      // Preparing update (if an error is thrown here neither the datafile nor\n      // the in-memory indexes are affected)\n      try {\n        for (i = 0; i < candidates.length; i += 1) {\n          if (model.match(candidates[i], query) && (multi || numReplaced === 0)) {\n            numReplaced += 1;\n            if (self.timestampData) { createdAt = candidates[i].createdAt; }\n            modifiedDoc = model.modify(candidates[i], updateQuery);\n            if (self.timestampData) {\n              modifiedDoc.createdAt = createdAt;\n              modifiedDoc.updatedAt = new Date();\n            }\n            modifications.push({ oldDoc: candidates[i], newDoc: modifiedDoc });\n          }\n        }\n      } catch (err) {\n        return callback(err);\n      }\n\n      // Change the docs in memory\n      try {\n        self.updateIndexes(modifications);\n      } catch (err) {\n        return callback(err);\n      }\n\n      // Update the datafile\n      var updatedDocs = _.pluck(modifications, 'newDoc');\n      self.persistence.persistNewState(updatedDocs, function (err) {\n        if (err) { return callback(err); }\n        if (!options.returnUpdatedDocs) {\n          return callback(null, numReplaced);\n        } else {\n          var updatedDocsDC = [];\n          updatedDocs.forEach(function (doc) { updatedDocsDC.push(model.deepCopy(doc)); });\n          if (! multi) { updatedDocsDC = updatedDocsDC[0]; }\n          return callback(null, numReplaced, updatedDocsDC);\n        }\n      });\n    });\n  }]);\n};\n\nDatastore.prototype.update = function () {\n  this.executor.push({ this: this, fn: this._update, arguments: arguments });\n};\n\n\n/**\n * Remove all docs matching the query\n * For now very naive implementation (similar to update)\n * @param {Object} query\n * @param {Object} options Optional options\n *                 options.multi If true, can update multiple documents (defaults to false)\n * @param {Function} cb Optional callback, signature: err, numRemoved\n *\n * @api private Use Datastore.remove which has the same signature\n */\nDatastore.prototype._remove = function (query, options, cb) {\n  var callback\n    , self = this, numRemoved = 0, removedDocs = [], multi\n    ;\n\n  if (typeof options === 'function') { cb = options; options = {}; }\n  callback = cb || function () {};\n  multi = options.multi !== undefined ? options.multi : false;\n\n  this.getCandidates(query, true, function (err, candidates) {\n    if (err) { return callback(err); }\n\n    try {\n      candidates.forEach(function (d) {\n        if (model.match(d, query) && (multi || numRemoved === 0)) {\n          numRemoved += 1;\n          removedDocs.push({ $$deleted: true, _id: d._id });\n          self.removeFromIndexes(d);\n        }\n      });\n    } catch (err) { return callback(err); }\n\n    self.persistence.persistNewState(removedDocs, function (err) {\n      if (err) { return callback(err); }\n      return callback(null, numRemoved);\n    });\n  });\n};\n\nDatastore.prototype.remove = function () {\n  this.executor.push({ this: this, fn: this._remove, arguments: arguments });\n};\n\n\n\nmodule.exports = Datastore;\n\n},{\"./cursor\":5,\"./customUtils\":6,\"./executor\":8,\"./indexes\":9,\"./model\":10,\"./persistence\":11,\"async\":13,\"events\":1,\"underscore\":19,\"util\":3}],8:[function(require,module,exports){\nvar process=require(\"__browserify_process\");/**\n * Responsible for sequentially executing actions on the database\n */\n\nvar async = require('async')\n  ;\n\nfunction Executor () {\n  this.buffer = [];\n  this.ready = false;\n\n  // This queue will execute all commands, one-by-one in order\n  this.queue = async.queue(function (task, cb) {\n    var newArguments = [];\n\n    // task.arguments is an array-like object on which adding a new field doesn't work, so we transform it into a real array\n    for (var i = 0; i < task.arguments.length; i += 1) { newArguments.push(task.arguments[i]); }\n    var lastArg = task.arguments[task.arguments.length - 1];\n\n    // Always tell the queue task is complete. Execute callback if any was given.\n    if (typeof lastArg === 'function') {\n      // Callback was supplied\n      newArguments[newArguments.length - 1] = function () {\n        if (typeof setImmediate === 'function') {\n           setImmediate(cb);\n        } else {\n          process.nextTick(cb);\n        }\n        lastArg.apply(null, arguments);\n      };\n    } else if (!lastArg && task.arguments.length !== 0) {\n      // false/undefined/null supplied as callbback\n      newArguments[newArguments.length - 1] = function () { cb(); };\n    } else {\n      // Nothing supplied as callback\n      newArguments.push(function () { cb(); });\n    }\n\n\n    task.fn.apply(task.this, newArguments);\n  }, 1);\n}\n\n\n/**\n * If executor is ready, queue task (and process it immediately if executor was idle)\n * If not, buffer task for later processing\n * @param {Object} task\n *                 task.this - Object to use as this\n *                 task.fn - Function to execute\n *                 task.arguments - Array of arguments, IMPORTANT: only the last argument may be a function (the callback)\n *                                                                 and the last argument cannot be false/undefined/null\n * @param {Boolean} forceQueuing Optional (defaults to false) force executor to queue task even if it is not ready\n */\nExecutor.prototype.push = function (task, forceQueuing) {\n  if (this.ready || forceQueuing) {\n    this.queue.push(task);\n  } else {\n    this.buffer.push(task);\n  }\n};\n\n\n/**\n * Queue all tasks in buffer (in the same order they came in)\n * Automatically sets executor as ready\n */\nExecutor.prototype.processBuffer = function () {\n  var i;\n  this.ready = true;\n  for (i = 0; i < this.buffer.length; i += 1) { this.queue.push(this.buffer[i]); }\n  this.buffer = [];\n};\n\n\n\n// Interface\nmodule.exports = Executor;\n\n},{\"__browserify_process\":4,\"async\":13}],9:[function(require,module,exports){\nvar BinarySearchTree = require('binary-search-tree').AVLTree\n  , model = require('./model')\n  , _ = require('underscore')\n  , util = require('util')\n  ;\n\n/**\n * Two indexed pointers are equal iif they point to the same place\n */\nfunction checkValueEquality (a, b) {\n  return a === b;\n}\n\n/**\n * Type-aware projection\n */\nfunction projectForUnique (elt) {\n  if (elt === null) { return '$null'; }\n  if (typeof elt === 'string') { return '$string' + elt; }\n  if (typeof elt === 'boolean') { return '$boolean' + elt; }\n  if (typeof elt === 'number') { return '$number' + elt; }\n  if (util.isArray(elt)) { return '$date' + elt.getTime(); }\n\n  return elt;   // Arrays and objects, will check for pointer equality\n}\n\n\n/**\n * Create a new index\n * All methods on an index guarantee that either the whole operation was successful and the index changed\n * or the operation was unsuccessful and an error is thrown while the index is unchanged\n * @param {String} options.fieldName On which field should the index apply (can use dot notation to index on sub fields)\n * @param {Boolean} options.unique Optional, enforce a unique constraint (default: false)\n * @param {Boolean} options.sparse Optional, allow a sparse index (we can have documents for which fieldName is undefined) (default: false)\n */\nfunction Index (options) {\n  this.fieldName = options.fieldName;\n  this.unique = options.unique || false;\n  this.sparse = options.sparse || false;\n\n  this.treeOptions = { unique: this.unique, compareKeys: model.compareThings, checkValueEquality: checkValueEquality };\n\n  this.reset();   // No data in the beginning\n}\n\n\n/**\n * Reset an index\n * @param {Document or Array of documents} newData Optional, data to initialize the index with\n *                                                 If an error is thrown during insertion, the index is not modified\n */\nIndex.prototype.reset = function (newData) {\n  this.tree = new BinarySearchTree(this.treeOptions);\n\n  if (newData) { this.insert(newData); }\n};\n\n\n/**\n * Insert a new document in the index\n * If an array is passed, we insert all its elements (if one insertion fails the index is not modified)\n * O(log(n))\n */\nIndex.prototype.insert = function (doc) {\n  var key, self = this\n    , keys, i, failingI, error\n    ;\n\n  if (util.isArray(doc)) { this.insertMultipleDocs(doc); return; }\n\n  key = model.getDotValue(doc, this.fieldName);\n\n  // We don't index documents that don't contain the field if the index is sparse\n  if (key === undefined && this.sparse) { return; }\n\n  if (!util.isArray(key)) {\n    this.tree.insert(key, doc);\n  } else {\n    // If an insert fails due to a unique constraint, roll back all inserts before it\n    keys = _.uniq(key, projectForUnique);\n\n    for (i = 0; i < keys.length; i += 1) {\n      try {\n        this.tree.insert(keys[i], doc);\n      } catch (e) {\n        error = e;\n        failingI = i;\n        break;\n      }\n    }\n\n    if (error) {\n      for (i = 0; i < failingI; i += 1) {\n        this.tree.delete(keys[i], doc);\n      }\n\n      throw error;\n    }\n  }\n};\n\n\n/**\n * Insert an array of documents in the index\n * If a constraint is violated, the changes should be rolled back and an error thrown\n *\n * @API private\n */\nIndex.prototype.insertMultipleDocs = function (docs) {\n  var i, error, failingI;\n\n  for (i = 0; i < docs.length; i += 1) {\n    try {\n      this.insert(docs[i]);\n    } catch (e) {\n      error = e;\n      failingI = i;\n      break;\n    }\n  }\n\n  if (error) {\n    for (i = 0; i < failingI; i += 1) {\n      this.remove(docs[i]);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Remove a document from the index\n * If an array is passed, we remove all its elements\n * The remove operation is safe with regards to the 'unique' constraint\n * O(log(n))\n */\nIndex.prototype.remove = function (doc) {\n  var key, self = this;\n\n  if (util.isArray(doc)) { doc.forEach(function (d) { self.remove(d); }); return; }\n\n  key = model.getDotValue(doc, this.fieldName);\n\n  if (key === undefined && this.sparse) { return; }\n\n  if (!util.isArray(key)) {\n    this.tree.delete(key, doc);\n  } else {\n    _.uniq(key, projectForUnique).forEach(function (_key) {\n      self.tree.delete(_key, doc);\n    });\n  }\n};\n\n\n/**\n * Update a document in the index\n * If a constraint is violated, changes are rolled back and an error thrown\n * Naive implementation, still in O(log(n))\n */\nIndex.prototype.update = function (oldDoc, newDoc) {\n  if (util.isArray(oldDoc)) { this.updateMultipleDocs(oldDoc); return; }\n\n  this.remove(oldDoc);\n\n  try {\n    this.insert(newDoc);\n  } catch (e) {\n    this.insert(oldDoc);\n    throw e;\n  }\n};\n\n\n/**\n * Update multiple documents in the index\n * If a constraint is violated, the changes need to be rolled back\n * and an error thrown\n * @param {Array of oldDoc, newDoc pairs} pairs\n *\n * @API private\n */\nIndex.prototype.updateMultipleDocs = function (pairs) {\n  var i, failingI, error;\n\n  for (i = 0; i < pairs.length; i += 1) {\n    this.remove(pairs[i].oldDoc);\n  }\n\n  for (i = 0; i < pairs.length; i += 1) {\n    try {\n      this.insert(pairs[i].newDoc);\n    } catch (e) {\n      error = e;\n      failingI = i;\n      break;\n    }\n  }\n\n  // If an error was raised, roll back changes in the inverse order\n  if (error) {\n    for (i = 0; i < failingI; i += 1) {\n      this.remove(pairs[i].newDoc);\n    }\n\n    for (i = 0; i < pairs.length; i += 1) {\n      this.insert(pairs[i].oldDoc);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Revert an update\n */\nIndex.prototype.revertUpdate = function (oldDoc, newDoc) {\n  var revert = [];\n\n  if (!util.isArray(oldDoc)) {\n    this.update(newDoc, oldDoc);\n  } else {\n    oldDoc.forEach(function (pair) {\n      revert.push({ oldDoc: pair.newDoc, newDoc: pair.oldDoc });\n    });\n    this.update(revert);\n  }\n};\n\n\n/**\n * Get all documents in index whose key match value (if it is a Thing) or one of the elements of value (if it is an array of Things)\n * @param {Thing} value Value to match the key against\n * @return {Array of documents}\n */\nIndex.prototype.getMatching = function (value) {\n  var self = this;\n\n  if (!util.isArray(value)) {\n    return self.tree.search(value);\n  } else {\n    var _res = {}, res = [];\n\n    value.forEach(function (v) {\n      self.getMatching(v).forEach(function (doc) {\n        _res[doc._id] = doc;\n      });\n    });\n\n    Object.keys(_res).forEach(function (_id) {\n      res.push(_res[_id]);\n    });\n\n    return res;\n  }\n};\n\n\n/**\n * Get all documents in index whose key is between bounds are they are defined by query\n * Documents are sorted by key\n * @param {Query} query\n * @return {Array of documents}\n */\nIndex.prototype.getBetweenBounds = function (query) {\n  return this.tree.betweenBounds(query);\n};\n\n\n/**\n * Get all elements in the index\n * @return {Array of documents}\n */\nIndex.prototype.getAll = function () {\n  var res = [];\n\n  this.tree.executeOnEveryNode(function (node) {\n    var i;\n\n    for (i = 0; i < node.data.length; i += 1) {\n      res.push(node.data[i]);\n    }\n  });\n\n  return res;\n};\n\n\n\n\n// Interface\nmodule.exports = Index;\n\n},{\"./model\":10,\"binary-search-tree\":14,\"underscore\":19,\"util\":3}],10:[function(require,module,exports){\n/**\n * Handle models (i.e. docs)\n * Serialization/deserialization\n * Copying\n * Querying, update\n */\n\nvar util = require('util')\n  , _ = require('underscore')\n  , modifierFunctions = {}\n  , lastStepModifierFunctions = {}\n  , comparisonFunctions = {}\n  , logicalOperators = {}\n  , arrayComparisonFunctions = {}\n  ;\n\n\n/**\n * Check a key, throw an error if the key is non valid\n * @param {String} k key\n * @param {Model} v value, needed to treat the Date edge case\n * Non-treatable edge cases here: if part of the object if of the form { $$date: number } or { $$deleted: true }\n * Its serialized-then-deserialized version it will transformed into a Date object\n * But you really need to want it to trigger such behaviour, even when warned not to use '$' at the beginning of the field names...\n */\nfunction checkKey (k, v) {\n  if (typeof k === 'number') {\n    k = k.toString();\n  }\n\n  if (k[0] === '$' && !(k === '$$date' && typeof v === 'number') && !(k === '$$deleted' && v === true) && !(k === '$$indexCreated') && !(k === '$$indexRemoved')) {\n    throw new Error('Field names cannot begin with the $ character');\n  }\n\n  if (k.indexOf('.') !== -1) {\n    throw new Error('Field names cannot contain a .');\n  }\n}\n\n\n/**\n * Check a DB object and throw an error if it's not valid\n * Works by applying the above checkKey function to all fields recursively\n */\nfunction checkObject (obj) {\n  if (util.isArray(obj)) {\n    obj.forEach(function (o) {\n      checkObject(o);\n    });\n  }\n\n  if (typeof obj === 'object' && obj !== null) {\n    Object.keys(obj).forEach(function (k) {\n      checkKey(k, obj[k]);\n      checkObject(obj[k]);\n    });\n  }\n}\n\n\n/**\n * Serialize an object to be persisted to a one-line string\n * For serialization/deserialization, we use the native JSON parser and not eval or Function\n * That gives us less freedom but data entered in the database may come from users\n * so eval and the like are not safe\n * Accepted primitive types: Number, String, Boolean, Date, null\n * Accepted secondary types: Objects, Arrays\n */\nfunction serialize (obj) {\n  var res;\n\n  res = JSON.stringify(obj, function (k, v) {\n    checkKey(k, v);\n\n    if (v === undefined) { return undefined; }\n    if (v === null) { return null; }\n\n    // Hackish way of checking if object is Date (this way it works between execution contexts in node-webkit).\n    // We can't use value directly because for dates it is already string in this function (date.toJSON was already called), so we use this\n    if (typeof this[k].getTime === 'function') { return { $$date: this[k].getTime() }; }\n\n    return v;\n  });\n\n  return res;\n}\n\n\n/**\n * From a one-line representation of an object generate by the serialize function\n * Return the object itself\n */\nfunction deserialize (rawData) {\n  return JSON.parse(rawData, function (k, v) {\n    if (k === '$$date') { return new Date(v); }\n    if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || v === null) { return v; }\n    if (v && v.$$date) { return v.$$date; }\n\n    return v;\n  });\n}\n\n\n/**\n * Deep copy a DB object\n * The optional strictKeys flag (defaulting to false) indicates whether to copy everything or only fields\n * where the keys are valid, i.e. don't begin with $ and don't contain a .\n */\nfunction deepCopy (obj, strictKeys) {\n  var res;\n\n  if ( typeof obj === 'boolean' ||\n       typeof obj === 'number' ||\n       typeof obj === 'string' ||\n       obj === null ||\n       (util.isDate(obj)) ) {\n    return obj;\n  }\n\n  if (util.isArray(obj)) {\n    res = [];\n    obj.forEach(function (o) { res.push(deepCopy(o, strictKeys)); });\n    return res;\n  }\n\n  if (typeof obj === 'object') {\n    res = {};\n    Object.keys(obj).forEach(function (k) {\n      if (!strictKeys || (k[0] !== '$' && k.indexOf('.') === -1)) {\n        res[k] = deepCopy(obj[k], strictKeys);\n      }\n    });\n    return res;\n  }\n\n  return undefined;   // For now everything else is undefined. We should probably throw an error instead\n}\n\n\n/**\n * Tells if an object is a primitive type or a \"real\" object\n * Arrays are considered primitive\n */\nfunction isPrimitiveType (obj) {\n  return ( typeof obj === 'boolean' ||\n       typeof obj === 'number' ||\n       typeof obj === 'string' ||\n       obj === null ||\n       util.isDate(obj) ||\n       util.isArray(obj));\n}\n\n\n/**\n * Utility functions for comparing things\n * Assumes type checking was already done (a and b already have the same type)\n * compareNSB works for numbers, strings and booleans\n */\nfunction compareNSB (a, b) {\n  if (a < b) { return -1; }\n  if (a > b) { return 1; }\n  return 0;\n}\n\nfunction compareArrays (a, b) {\n  var i, comp;\n\n  for (i = 0; i < Math.min(a.length, b.length); i += 1) {\n    comp = compareThings(a[i], b[i]);\n\n    if (comp !== 0) { return comp; }\n  }\n\n  // Common section was identical, longest one wins\n  return compareNSB(a.length, b.length);\n}\n\n\n/**\n * Compare { things U undefined }\n * Things are defined as any native types (string, number, boolean, null, date) and objects\n * We need to compare with undefined as it will be used in indexes\n * In the case of objects and arrays, we deep-compare\n * If two objects dont have the same type, the (arbitrary) type hierarchy is: undefined, null, number, strings, boolean, dates, arrays, objects\n * Return -1 if a < b, 1 if a > b and 0 if a = b (note that equality here is NOT the same as defined in areThingsEqual!)\n *\n * @param {Function} _compareStrings String comparing function, returning -1, 0 or 1, overriding default string comparison (useful for languages with accented letters)\n */\nfunction compareThings (a, b, _compareStrings) {\n  var aKeys, bKeys, comp, i\n    , compareStrings = _compareStrings || compareNSB;\n\n  // undefined\n  if (a === undefined) { return b === undefined ? 0 : -1; }\n  if (b === undefined) { return a === undefined ? 0 : 1; }\n\n  // null\n  if (a === null) { return b === null ? 0 : -1; }\n  if (b === null) { return a === null ? 0 : 1; }\n\n  // Numbers\n  if (typeof a === 'number') { return typeof b === 'number' ? compareNSB(a, b) : -1; }\n  if (typeof b === 'number') { return typeof a === 'number' ? compareNSB(a, b) : 1; }\n\n  // Strings\n  if (typeof a === 'string') { return typeof b === 'string' ? compareStrings(a, b) : -1; }\n  if (typeof b === 'string') { return typeof a === 'string' ? compareStrings(a, b) : 1; }\n\n  // Booleans\n  if (typeof a === 'boolean') { return typeof b === 'boolean' ? compareNSB(a, b) : -1; }\n  if (typeof b === 'boolean') { return typeof a === 'boolean' ? compareNSB(a, b) : 1; }\n\n  // Dates\n  if (util.isDate(a)) { return util.isDate(b) ? compareNSB(a.getTime(), b.getTime()) : -1; }\n  if (util.isDate(b)) { return util.isDate(a) ? compareNSB(a.getTime(), b.getTime()) : 1; }\n\n  // Arrays (first element is most significant and so on)\n  if (util.isArray(a)) { return util.isArray(b) ? compareArrays(a, b) : -1; }\n  if (util.isArray(b)) { return util.isArray(a) ? compareArrays(a, b) : 1; }\n\n  // Objects\n  aKeys = Object.keys(a).sort();\n  bKeys = Object.keys(b).sort();\n\n  for (i = 0; i < Math.min(aKeys.length, bKeys.length); i += 1) {\n    comp = compareThings(a[aKeys[i]], b[bKeys[i]]);\n\n    if (comp !== 0) { return comp; }\n  }\n\n  return compareNSB(aKeys.length, bKeys.length);\n}\n\n\n\n// ==============================================================\n// Updating documents\n// ==============================================================\n\n/**\n * The signature of modifier functions is as follows\n * Their structure is always the same: recursively follow the dot notation while creating\n * the nested documents if needed, then apply the \"last step modifier\"\n * @param {Object} obj The model to modify\n * @param {String} field Can contain dots, in that case that means we will set a subfield recursively\n * @param {Model} value\n */\n\n/**\n * Set a field to a new value\n */\nlastStepModifierFunctions.$set = function (obj, field, value) {\n  obj[field] = value;\n};\n\n\n/**\n * Unset a field\n */\nlastStepModifierFunctions.$unset = function (obj, field, value) {\n  delete obj[field];\n};\n\n\n/**\n * Push an element to the end of an array field\n * Optional modifier $each instead of value to push several values\n * Optional modifier $slice to slice the resulting array, see https://docs.mongodb.org/manual/reference/operator/update/slice/\n * Différeence with MongoDB: if $slice is specified and not $each, we act as if value is an empty array\n */\nlastStepModifierFunctions.$push = function (obj, field, value) {\n  // Create the array if it doesn't exist\n  if (!obj.hasOwnProperty(field)) { obj[field] = []; }\n\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $push an element on non-array values\"); }\n\n  if (value !== null && typeof value === 'object' && value.$slice && value.$each === undefined) {\n    value.$each = [];\n  }\n\n  if (value !== null && typeof value === 'object' && value.$each) {\n    if (Object.keys(value).length >= 3 || (Object.keys(value).length === 2 && value.$slice === undefined)) { throw new Error(\"Can only use $slice in cunjunction with $each when $push to array\"); }\n    if (!util.isArray(value.$each)) { throw new Error(\"$each requires an array value\"); }\n\n    value.$each.forEach(function (v) {\n      obj[field].push(v);\n    });\n\n    if (value.$slice === undefined || typeof value.$slice !== 'number') { return; }\n\n    if (value.$slice === 0) {\n      obj[field] = [];\n    } else {\n      var start, end, n = obj[field].length;\n      if (value.$slice < 0) {\n        start = Math.max(0, n + value.$slice);\n        end = n;\n      } else if (value.$slice > 0) {\n        start = 0;\n        end = Math.min(n, value.$slice);\n      }\n      obj[field] = obj[field].slice(start, end);\n    }\n  } else {\n    obj[field].push(value);\n  }\n};\n\n\n/**\n * Add an element to an array field only if it is not already in it\n * No modification if the element is already in the array\n * Note that it doesn't check whether the original array contains duplicates\n */\nlastStepModifierFunctions.$addToSet = function (obj, field, value) {\n  var addToSet = true;\n\n  // Create the array if it doesn't exist\n  if (!obj.hasOwnProperty(field)) { obj[field] = []; }\n\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $addToSet an element on non-array values\"); }\n\n  if (value !== null && typeof value === 'object' && value.$each) {\n    if (Object.keys(value).length > 1) { throw new Error(\"Can't use another field in conjunction with $each\"); }\n    if (!util.isArray(value.$each)) { throw new Error(\"$each requires an array value\"); }\n\n    value.$each.forEach(function (v) {\n      lastStepModifierFunctions.$addToSet(obj, field, v);\n    });\n  } else {\n    obj[field].forEach(function (v) {\n      if (compareThings(v, value) === 0) { addToSet = false; }\n    });\n    if (addToSet) { obj[field].push(value); }\n  }\n};\n\n\n/**\n * Remove the first or last element of an array\n */\nlastStepModifierFunctions.$pop = function (obj, field, value) {\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $pop an element from non-array values\"); }\n  if (typeof value !== 'number') { throw new Error(value + \" isn't an integer, can't use it with $pop\"); }\n  if (value === 0) { return; }\n\n  if (value > 0) {\n    obj[field] = obj[field].slice(0, obj[field].length - 1);\n  } else {\n    obj[field] = obj[field].slice(1);\n  }\n};\n\n\n/**\n * Removes all instances of a value from an existing array\n */\nlastStepModifierFunctions.$pull = function (obj, field, value) {\n  var arr, i;\n\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $pull an element from non-array values\"); }\n\n  arr = obj[field];\n  for (i = arr.length - 1; i >= 0; i -= 1) {\n    if (match(arr[i], value)) {\n      arr.splice(i, 1);\n    }\n  }\n};\n\n\n/**\n * Increment a numeric field's value\n */\nlastStepModifierFunctions.$inc = function (obj, field, value) {\n  if (typeof value !== 'number') { throw new Error(value + \" must be a number\"); }\n\n  if (typeof obj[field] !== 'number') {\n    if (!_.has(obj, field)) {\n      obj[field] = value;\n    } else {\n      throw new Error(\"Don't use the $inc modifier on non-number fields\");\n    }\n  } else {\n    obj[field] += value;\n  }\n};\n\n/**\n * Updates the value of the field, only if specified field is greater than the current value of the field\n */\nlastStepModifierFunctions.$max = function (obj, field, value) {\n  if (typeof obj[field] === 'undefined') {\n    obj[field] = value;\n  } else if (value > obj[field]) {\n    obj[field] = value;\n  }\n};\n\n/**\n * Updates the value of the field, only if specified field is smaller than the current value of the field\n */\nlastStepModifierFunctions.$min = function (obj, field, value) {\n  if (typeof obj[field] === 'undefined') { \n    obj[field] = value;\n  } else if (value < obj[field]) {\n    obj[field] = value;\n  }\n};\n\n// Given its name, create the complete modifier function\nfunction createModifierFunction (modifier) {\n  return function (obj, field, value) {\n    var fieldParts = typeof field === 'string' ? field.split('.') : field;\n\n    if (fieldParts.length === 1) {\n      lastStepModifierFunctions[modifier](obj, field, value);\n    } else {\n      if (obj[fieldParts[0]] === undefined) {\n        if (modifier === '$unset') { return; }   // Bad looking specific fix, needs to be generalized modifiers that behave like $unset are implemented\n        obj[fieldParts[0]] = {};\n      }\n      modifierFunctions[modifier](obj[fieldParts[0]], fieldParts.slice(1), value);\n    }\n  };\n}\n\n// Actually create all modifier functions\nObject.keys(lastStepModifierFunctions).forEach(function (modifier) {\n  modifierFunctions[modifier] = createModifierFunction(modifier);\n});\n\n\n/**\n * Modify a DB object according to an update query\n */\nfunction modify (obj, updateQuery) {\n  var keys = Object.keys(updateQuery)\n    , firstChars = _.map(keys, function (item) { return item[0]; })\n    , dollarFirstChars = _.filter(firstChars, function (c) { return c === '$'; })\n    , newDoc, modifiers\n    ;\n\n  if (keys.indexOf('_id') !== -1 && updateQuery._id !== obj._id) { throw new Error(\"You cannot change a document's _id\"); }\n\n  if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) {\n    throw new Error(\"You cannot mix modifiers and normal fields\");\n  }\n\n  if (dollarFirstChars.length === 0) {\n    // Simply replace the object with the update query contents\n    newDoc = deepCopy(updateQuery);\n    newDoc._id = obj._id;\n  } else {\n    // Apply modifiers\n    modifiers = _.uniq(keys);\n    newDoc = deepCopy(obj);\n    modifiers.forEach(function (m) {\n      var keys;\n\n      if (!modifierFunctions[m]) { throw new Error(\"Unknown modifier \" + m); }\n\n      // Can't rely on Object.keys throwing on non objects since ES6\n      // Not 100% satisfying as non objects can be interpreted as objects but no false negatives so we can live with it\n      if (typeof updateQuery[m] !== 'object') {\n        throw new Error(\"Modifier \" + m + \"'s argument must be an object\");\n      }\n\n      keys = Object.keys(updateQuery[m]);\n      keys.forEach(function (k) {\n        modifierFunctions[m](newDoc, k, updateQuery[m][k]);\n      });\n    });\n  }\n\n  // Check result is valid and return it\n  checkObject(newDoc);\n\n  if (obj._id !== newDoc._id) { throw new Error(\"You can't change a document's _id\"); }\n  return newDoc;\n};\n\n\n// ==============================================================\n// Finding documents\n// ==============================================================\n\n/**\n * Get a value from object with dot notation\n * @param {Object} obj\n * @param {String} field\n */\nfunction getDotValue (obj, field) {\n  var fieldParts = typeof field === 'string' ? field.split('.') : field\n    , i, objs;\n\n  if (!obj) { return undefined; }   // field cannot be empty so that means we should return undefined so that nothing can match\n\n  if (fieldParts.length === 0) { return obj; }\n\n  if (fieldParts.length === 1) { return obj[fieldParts[0]]; }\n\n  if (util.isArray(obj[fieldParts[0]])) {\n    // If the next field is an integer, return only this item of the array\n    i = parseInt(fieldParts[1], 10);\n    if (typeof i === 'number' && !isNaN(i)) {\n      return getDotValue(obj[fieldParts[0]][i], fieldParts.slice(2))\n    }\n\n    // Return the array of values\n    objs = new Array();\n    for (i = 0; i < obj[fieldParts[0]].length; i += 1) {\n       objs.push(getDotValue(obj[fieldParts[0]][i], fieldParts.slice(1)));\n    }\n    return objs;\n  } else {\n    return getDotValue(obj[fieldParts[0]], fieldParts.slice(1));\n  }\n}\n\n\n/**\n * Check whether 'things' are equal\n * Things are defined as any native types (string, number, boolean, null, date) and objects\n * In the case of object, we check deep equality\n * Returns true if they are, false otherwise\n */\nfunction areThingsEqual (a, b) {\n  var aKeys , bKeys , i;\n\n  // Strings, booleans, numbers, null\n  if (a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' ||\n      b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; }\n\n  // Dates\n  if (util.isDate(a) || util.isDate(b)) { return util.isDate(a) && util.isDate(b) && a.getTime() === b.getTime(); }\n\n  // Arrays (no match since arrays are used as a $in)\n  // undefined (no match since they mean field doesn't exist and can't be serialized)\n  if ((!(util.isArray(a) && util.isArray(b)) && (util.isArray(a) || util.isArray(b))) || a === undefined || b === undefined) { return false; }\n\n  // General objects (check for deep equality)\n  // a and b should be objects at this point\n  try {\n    aKeys = Object.keys(a);\n    bKeys = Object.keys(b);\n  } catch (e) {\n    return false;\n  }\n\n  if (aKeys.length !== bKeys.length) { return false; }\n  for (i = 0; i < aKeys.length; i += 1) {\n    if (bKeys.indexOf(aKeys[i]) === -1) { return false; }\n    if (!areThingsEqual(a[aKeys[i]], b[aKeys[i]])) { return false; }\n  }\n  return true;\n}\n\n\n/**\n * Check that two values are comparable\n */\nfunction areComparable (a, b) {\n  if (typeof a !== 'string' && typeof a !== 'number' && !util.isDate(a) &&\n      typeof b !== 'string' && typeof b !== 'number' && !util.isDate(b)) {\n    return false;\n  }\n\n  if (typeof a !== typeof b) { return false; }\n\n  return true;\n}\n\n\n/**\n * Arithmetic and comparison operators\n * @param {Native value} a Value in the object\n * @param {Native value} b Value in the query\n */\ncomparisonFunctions.$lt = function (a, b) {\n  return areComparable(a, b) && a < b;\n};\n\ncomparisonFunctions.$lte = function (a, b) {\n  return areComparable(a, b) && a <= b;\n};\n\ncomparisonFunctions.$gt = function (a, b) {\n  return areComparable(a, b) && a > b;\n};\n\ncomparisonFunctions.$gte = function (a, b) {\n  return areComparable(a, b) && a >= b;\n};\n\ncomparisonFunctions.$ne = function (a, b) {\n  if (a === undefined) { return true; }\n  return !areThingsEqual(a, b);\n};\n\ncomparisonFunctions.$in = function (a, b) {\n  var i;\n\n  if (!util.isArray(b)) { throw new Error(\"$in operator called with a non-array\"); }\n\n  for (i = 0; i < b.length; i += 1) {\n    if (areThingsEqual(a, b[i])) { return true; }\n  }\n\n  return false;\n};\n\ncomparisonFunctions.$nin = function (a, b) {\n  if (!util.isArray(b)) { throw new Error(\"$nin operator called with a non-array\"); }\n\n  return !comparisonFunctions.$in(a, b);\n};\n\ncomparisonFunctions.$regex = function (a, b) {\n  if (!util.isRegExp(b)) { throw new Error(\"$regex operator called with non regular expression\"); }\n\n  if (typeof a !== 'string') {\n    return false\n  } else {\n    return b.test(a);\n  }\n};\n\ncomparisonFunctions.$exists = function (value, exists) {\n  if (exists || exists === '') {   // This will be true for all values of exists except false, null, undefined and 0\n    exists = true;                 // That's strange behaviour (we should only use true/false) but that's the way Mongo does it...\n  } else {\n    exists = false;\n  }\n\n  if (value === undefined) {\n    return !exists\n  } else {\n    return exists;\n  }\n};\n\n// Specific to arrays\ncomparisonFunctions.$size = function (obj, value) {\n    if (!util.isArray(obj)) { return false; }\n    if (value % 1 !== 0) { throw new Error(\"$size operator called without an integer\"); }\n\n    return (obj.length == value);\n};\ncomparisonFunctions.$elemMatch = function (obj, value) {\n  if (!util.isArray(obj)) { return false; }\n  var i = obj.length;\n  var result = false;   // Initialize result\n  while (i--) {\n    if (match(obj[i], value)) {   // If match for array element, return true\n      result = true;\n      break;\n    }\n  }\n  return result;\n};\narrayComparisonFunctions.$size = true;\narrayComparisonFunctions.$elemMatch = true;\n\n\n/**\n * Match any of the subqueries\n * @param {Model} obj\n * @param {Array of Queries} query\n */\nlogicalOperators.$or = function (obj, query) {\n  var i;\n\n  if (!util.isArray(query)) { throw new Error(\"$or operator used without an array\"); }\n\n  for (i = 0; i < query.length; i += 1) {\n    if (match(obj, query[i])) { return true; }\n  }\n\n  return false;\n};\n\n\n/**\n * Match all of the subqueries\n * @param {Model} obj\n * @param {Array of Queries} query\n */\nlogicalOperators.$and = function (obj, query) {\n  var i;\n\n  if (!util.isArray(query)) { throw new Error(\"$and operator used without an array\"); }\n\n  for (i = 0; i < query.length; i += 1) {\n    if (!match(obj, query[i])) { return false; }\n  }\n\n  return true;\n};\n\n\n/**\n * Inverted match of the query\n * @param {Model} obj\n * @param {Query} query\n */\nlogicalOperators.$not = function (obj, query) {\n  return !match(obj, query);\n};\n\n\n/**\n * Use a function to match\n * @param {Model} obj\n * @param {Query} query\n */\nlogicalOperators.$where = function (obj, fn) {\n  var result;\n\n  if (!_.isFunction(fn)) { throw new Error(\"$where operator used without a function\"); }\n\n  result = fn.call(obj);\n  if (!_.isBoolean(result)) { throw new Error(\"$where function must return boolean\"); }\n\n  return result;\n};\n\n\n/**\n * Tell if a given document matches a query\n * @param {Object} obj Document to check\n * @param {Object} query\n */\nfunction match (obj, query) {\n  var queryKeys, queryKey, queryValue, i;\n\n  // Primitive query against a primitive type\n  // This is a bit of a hack since we construct an object with an arbitrary key only to dereference it later\n  // But I don't have time for a cleaner implementation now\n  if (isPrimitiveType(obj) || isPrimitiveType(query)) {\n    return matchQueryPart({ needAKey: obj }, 'needAKey', query);\n  }\n\n  // Normal query\n  queryKeys = Object.keys(query);\n  for (i = 0; i < queryKeys.length; i += 1) {\n    queryKey = queryKeys[i];\n    queryValue = query[queryKey];\n\n    if (queryKey[0] === '$') {\n      if (!logicalOperators[queryKey]) { throw new Error(\"Unknown logical operator \" + queryKey); }\n      if (!logicalOperators[queryKey](obj, queryValue)) { return false; }\n    } else {\n      if (!matchQueryPart(obj, queryKey, queryValue)) { return false; }\n    }\n  }\n\n  return true;\n};\n\n\n/**\n * Match an object against a specific { key: value } part of a query\n * if the treatObjAsValue flag is set, don't try to match every part separately, but the array as a whole\n */\nfunction matchQueryPart (obj, queryKey, queryValue, treatObjAsValue) {\n  var objValue = getDotValue(obj, queryKey)\n    , i, keys, firstChars, dollarFirstChars;\n\n  // Check if the value is an array if we don't force a treatment as value\n  if (util.isArray(objValue) && !treatObjAsValue) {\n    // If the queryValue is an array, try to perform an exact match\n    if (util.isArray(queryValue)) {\n      return matchQueryPart(obj, queryKey, queryValue, true);\n    }\n\n    // Check if we are using an array-specific comparison function\n    if (queryValue !== null && typeof queryValue === 'object' && !util.isRegExp(queryValue)) {\n      keys = Object.keys(queryValue);\n      for (i = 0; i < keys.length; i += 1) {\n        if (arrayComparisonFunctions[keys[i]]) { return matchQueryPart(obj, queryKey, queryValue, true); }\n      }\n    }\n\n    // If not, treat it as an array of { obj, query } where there needs to be at least one match\n    for (i = 0; i < objValue.length; i += 1) {\n      if (matchQueryPart({ k: objValue[i] }, 'k', queryValue)) { return true; }   // k here could be any string\n    }\n    return false;\n  }\n\n  // queryValue is an actual object. Determine whether it contains comparison operators\n  // or only normal fields. Mixed objects are not allowed\n  if (queryValue !== null && typeof queryValue === 'object' && !util.isRegExp(queryValue) && !util.isArray(queryValue)) {\n    keys = Object.keys(queryValue);\n    firstChars = _.map(keys, function (item) { return item[0]; });\n    dollarFirstChars = _.filter(firstChars, function (c) { return c === '$'; });\n\n    if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) {\n      throw new Error(\"You cannot mix operators and normal fields\");\n    }\n\n    // queryValue is an object of this form: { $comparisonOperator1: value1, ... }\n    if (dollarFirstChars.length > 0) {\n      for (i = 0; i < keys.length; i += 1) {\n        if (!comparisonFunctions[keys[i]]) { throw new Error(\"Unknown comparison function \" + keys[i]); }\n\n        if (!comparisonFunctions[keys[i]](objValue, queryValue[keys[i]])) { return false; }\n      }\n      return true;\n    }\n  }\n\n  // Using regular expressions with basic querying\n  if (util.isRegExp(queryValue)) { return comparisonFunctions.$regex(objValue, queryValue); }\n\n  // queryValue is either a native value or a normal object\n  // Basic matching is possible\n  if (!areThingsEqual(objValue, queryValue)) { return false; }\n\n  return true;\n}\n\n\n// Interface\nmodule.exports.serialize = serialize;\nmodule.exports.deserialize = deserialize;\nmodule.exports.deepCopy = deepCopy;\nmodule.exports.checkObject = checkObject;\nmodule.exports.isPrimitiveType = isPrimitiveType;\nmodule.exports.modify = modify;\nmodule.exports.getDotValue = getDotValue;\nmodule.exports.match = match;\nmodule.exports.areThingsEqual = areThingsEqual;\nmodule.exports.compareThings = compareThings;\n\n},{\"underscore\":19,\"util\":3}],11:[function(require,module,exports){\nvar process=require(\"__browserify_process\");/**\n * Handle every persistence-related task\n * The interface Datastore expects to be implemented is\n * * Persistence.loadDatabase(callback) and callback has signature err\n * * Persistence.persistNewState(newDocs, callback) where newDocs is an array of documents and callback has signature err\n */\n\nvar storage = require('./storage')\n  , path = require('path')\n  , model = require('./model')\n  , async = require('async')\n  , customUtils = require('./customUtils')\n  , Index = require('./indexes')\n  ;\n\n\n/**\n * Create a new Persistence object for database options.db\n * @param {Datastore} options.db\n * @param {Boolean} options.nodeWebkitAppName Optional, specify the name of your NW app if you want options.filename to be relative to the directory where\n *                                            Node Webkit stores application data such as cookies and local storage (the best place to store data in my opinion)\n */\nfunction Persistence (options) {\n  var i, j, randomString;\n\n  this.db = options.db;\n  this.inMemoryOnly = this.db.inMemoryOnly;\n  this.filename = this.db.filename;\n  this.corruptAlertThreshold = options.corruptAlertThreshold !== undefined ? options.corruptAlertThreshold : 0.1;\n\n  if (!this.inMemoryOnly && this.filename && this.filename.charAt(this.filename.length - 1) === '~') {\n    throw new Error(\"The datafile name can't end with a ~, which is reserved for crash safe backup files\");\n  }\n\n  // After serialization and before deserialization hooks with some basic sanity checks\n  if (options.afterSerialization && !options.beforeDeserialization) {\n    throw new Error(\"Serialization hook defined but deserialization hook undefined, cautiously refusing to start NeDB to prevent dataloss\");\n  }\n  if (!options.afterSerialization && options.beforeDeserialization) {\n    throw new Error(\"Serialization hook undefined but deserialization hook defined, cautiously refusing to start NeDB to prevent dataloss\");\n  }\n  this.afterSerialization = options.afterSerialization || function (s) { return s; };\n  this.beforeDeserialization = options.beforeDeserialization || function (s) { return s; };\n  for (i = 1; i < 30; i += 1) {\n    for (j = 0; j < 10; j += 1) {\n      randomString = customUtils.uid(i);\n      if (this.beforeDeserialization(this.afterSerialization(randomString)) !== randomString) {\n        throw new Error(\"beforeDeserialization is not the reverse of afterSerialization, cautiously refusing to start NeDB to prevent dataloss\");\n      }\n    }\n  }\n\n  // For NW apps, store data in the same directory where NW stores application data\n  if (this.filename && options.nodeWebkitAppName) {\n    console.log(\"==================================================================\");\n    console.log(\"WARNING: The nodeWebkitAppName option is deprecated\");\n    console.log(\"To get the path to the directory where Node Webkit stores the data\");\n    console.log(\"for your app, use the internal nw.gui module like this\");\n    console.log(\"require('nw.gui').App.dataPath\");\n    console.log(\"See https://github.com/rogerwang/node-webkit/issues/500\");\n    console.log(\"==================================================================\");\n    this.filename = Persistence.getNWAppFilename(options.nodeWebkitAppName, this.filename);\n  }\n};\n\n\n/**\n * Check if a directory exists and create it on the fly if it is not the case\n * cb is optional, signature: err\n */\nPersistence.ensureDirectoryExists = function (dir, cb) {\n  var callback = cb || function () {}\n    ;\n\n  storage.mkdirp(dir, function (err) { return callback(err); });\n};\n\n\n\n\n/**\n * Return the path the datafile if the given filename is relative to the directory where Node Webkit stores\n * data for this application. Probably the best place to store data\n */\nPersistence.getNWAppFilename = function (appName, relativeFilename) {\n  var home;\n\n  switch (process.platform) {\n    case 'win32':\n    case 'win64':\n      home = process.env.LOCALAPPDATA || process.env.APPDATA;\n      if (!home) { throw new Error(\"Couldn't find the base application data folder\"); }\n      home = path.join(home, appName);\n      break;\n    case 'darwin':\n      home = process.env.HOME;\n      if (!home) { throw new Error(\"Couldn't find the base application data directory\"); }\n      home = path.join(home, 'Library', 'Application Support', appName);\n      break;\n    case 'linux':\n      home = process.env.HOME;\n      if (!home) { throw new Error(\"Couldn't find the base application data directory\"); }\n      home = path.join(home, '.config', appName);\n      break;\n    default:\n      throw new Error(\"Can't use the Node Webkit relative path for platform \" + process.platform);\n      break;\n  }\n\n  return path.join(home, 'nedb-data', relativeFilename);\n}\n\n\n/**\n * Persist cached database\n * This serves as a compaction function since the cache always contains only the number of documents in the collection\n * while the data file is append-only so it may grow larger\n * @param {Function} cb Optional callback, signature: err\n */\nPersistence.prototype.persistCachedDatabase = function (cb) {\n  var callback = cb || function () {}\n    , toPersist = ''\n    , self = this\n    ;\n\n  if (this.inMemoryOnly) { return callback(null); }\n\n  this.db.getAllData().forEach(function (doc) {\n    toPersist += self.afterSerialization(model.serialize(doc)) + '\\n';\n  });\n  Object.keys(this.db.indexes).forEach(function (fieldName) {\n    if (fieldName != \"_id\") {   // The special _id index is managed by datastore.js, the others need to be persisted\n      toPersist += self.afterSerialization(model.serialize({ $$indexCreated: { fieldName: fieldName, unique: self.db.indexes[fieldName].unique, sparse: self.db.indexes[fieldName].sparse }})) + '\\n';\n    }\n  });\n\n  storage.crashSafeWriteFile(this.filename, toPersist, function (err) {\n    if (err) { return callback(err); }\n    self.db.emit('compaction.done');\n    return callback(null);\n  });\n};\n\n\n/**\n * Queue a rewrite of the datafile\n */\nPersistence.prototype.compactDatafile = function () {\n  this.db.executor.push({ this: this, fn: this.persistCachedDatabase, arguments: [] });\n};\n\n\n/**\n * Set automatic compaction every interval ms\n * @param {Number} interval in milliseconds, with an enforced minimum of 5 seconds\n */\nPersistence.prototype.setAutocompactionInterval = function (interval) {\n  var self = this\n    , minInterval = 5000\n    , realInterval = Math.max(interval || 0, minInterval)\n    ;\n\n  this.stopAutocompaction();\n\n  this.autocompactionIntervalId = setInterval(function () {\n    self.compactDatafile();\n  }, realInterval);\n};\n\n\n/**\n * Stop autocompaction (do nothing if autocompaction was not running)\n */\nPersistence.prototype.stopAutocompaction = function () {\n  if (this.autocompactionIntervalId) { clearInterval(this.autocompactionIntervalId); }\n};\n\n\n/**\n * Persist new state for the given newDocs (can be insertion, update or removal)\n * Use an append-only format\n * @param {Array} newDocs Can be empty if no doc was updated/removed\n * @param {Function} cb Optional, signature: err\n */\nPersistence.prototype.persistNewState = function (newDocs, cb) {\n  var self = this\n    , toPersist = ''\n    , callback = cb || function () {}\n    ;\n\n  // In-memory only datastore\n  if (self.inMemoryOnly) { return callback(null); }\n\n  newDocs.forEach(function (doc) {\n    toPersist += self.afterSerialization(model.serialize(doc)) + '\\n';\n  });\n\n  if (toPersist.length === 0) { return callback(null); }\n\n  storage.appendFile(self.filename, toPersist, 'utf8', function (err) {\n    return callback(err);\n  });\n};\n\n\n/**\n * From a database's raw data, return the corresponding\n * machine understandable collection\n */\nPersistence.prototype.treatRawData = function (rawData) {\n  var data = rawData.split('\\n')\n    , dataById = {}\n    , tdata = []\n    , i\n    , indexes = {}\n    , corruptItems = -1   // Last line of every data file is usually blank so not really corrupt\n    ;\n\n  for (i = 0; i < data.length; i += 1) {\n    var doc;\n\n    try {\n      doc = model.deserialize(this.beforeDeserialization(data[i]));\n      if (doc._id) {\n        if (doc.$$deleted === true) {\n          delete dataById[doc._id];\n        } else {\n          dataById[doc._id] = doc;\n        }\n      } else if (doc.$$indexCreated && doc.$$indexCreated.fieldName != undefined) {\n        indexes[doc.$$indexCreated.fieldName] = doc.$$indexCreated;\n      } else if (typeof doc.$$indexRemoved === \"string\") {\n        delete indexes[doc.$$indexRemoved];\n      }\n    } catch (e) {\n      corruptItems += 1;\n    }\n  }\n\n  // A bit lenient on corruption\n  if (data.length > 0 && corruptItems / data.length > this.corruptAlertThreshold) {\n    throw new Error(\"More than \" + Math.floor(100 * this.corruptAlertThreshold) + \"% of the data file is corrupt, the wrong beforeDeserialization hook may be used. Cautiously refusing to start NeDB to prevent dataloss\");\n  }\n\n  Object.keys(dataById).forEach(function (k) {\n    tdata.push(dataById[k]);\n  });\n\n  return { data: tdata, indexes: indexes };\n};\n\n\n/**\n * Load the database\n * 1) Create all indexes\n * 2) Insert all data\n * 3) Compact the database\n * This means pulling data out of the data file or creating it if it doesn't exist\n * Also, all data is persisted right away, which has the effect of compacting the database file\n * This operation is very quick at startup for a big collection (60ms for ~10k docs)\n * @param {Function} cb Optional callback, signature: err\n */\nPersistence.prototype.loadDatabase = function (cb) {\n  var callback = cb || function () {}\n    , self = this\n    ;\n\n  self.db.resetIndexes();\n\n  // In-memory only datastore\n  if (self.inMemoryOnly) { return callback(null); }\n\n  async.waterfall([\n    function (cb) {\n      Persistence.ensureDirectoryExists(path.dirname(self.filename), function (err) {\n        storage.ensureDatafileIntegrity(self.filename, function (err) {\n          storage.readFile(self.filename, 'utf8', function (err, rawData) {\n            if (err) { return cb(err); }\n\n            try {\n              var treatedData = self.treatRawData(rawData);\n            } catch (e) {\n              return cb(e);\n            }\n\n            // Recreate all indexes in the datafile\n            Object.keys(treatedData.indexes).forEach(function (key) {\n              self.db.indexes[key] = new Index(treatedData.indexes[key]);\n            });\n\n            // Fill cached database (i.e. all indexes) with data\n            try {\n              self.db.resetIndexes(treatedData.data);\n            } catch (e) {\n              self.db.resetIndexes();   // Rollback any index which didn't fail\n              return cb(e);\n            }\n\n            self.db.persistence.persistCachedDatabase(cb);\n          });\n        });\n      });\n    }\n  ], function (err) {\n       if (err) { return callback(err); }\n\n       self.db.executor.processBuffer();\n       return callback(null);\n     });\n};\n\n\n// Interface\nmodule.exports = Persistence;\n\n},{\"./customUtils\":6,\"./indexes\":9,\"./model\":10,\"./storage\":12,\"__browserify_process\":4,\"async\":13,\"path\":2}],12:[function(require,module,exports){\n/**\n * Way data is stored for this database\n * For a Node.js/Node Webkit database it's the file system\n * For a browser-side database it's localforage, which uses the best backend available (IndexedDB then WebSQL then localStorage)\n *\n * This version is the browser version\n */\n\nvar localforage = require('localforage')\n\n// Configure localforage to display NeDB name for now. Would be a good idea to let user use his own app name\nlocalforage.config({\n  name: 'NeDB'\n, storeName: 'nedbdata'\n});\n\n\nfunction exists (filename, callback) {\n  localforage.getItem(filename, function (err, value) {\n    if (value !== null) {   // Even if value is undefined, localforage returns null\n      return callback(true);\n    } else {\n      return callback(false);\n    }\n  });\n}\n\n\nfunction rename (filename, newFilename, callback) {\n  localforage.getItem(filename, function (err, value) {\n    if (value === null) {\n      localforage.removeItem(newFilename, function () { return callback(); });\n    } else {\n      localforage.setItem(newFilename, value, function () {\n        localforage.removeItem(filename, function () { return callback(); });\n      });\n    }\n  });\n}\n\n\nfunction writeFile (filename, contents, options, callback) {\n  // Options do not matter in browser setup\n  if (typeof options === 'function') { callback = options; }\n  localforage.setItem(filename, contents, function () { return callback(); });\n}\n\n\nfunction appendFile (filename, toAppend, options, callback) {\n  // Options do not matter in browser setup\n  if (typeof options === 'function') { callback = options; }\n\n  localforage.getItem(filename, function (err, contents) {\n    contents = contents || '';\n    contents += toAppend;\n    localforage.setItem(filename, contents, function () { return callback(); });\n  });\n}\n\n\nfunction readFile (filename, options, callback) {\n  // Options do not matter in browser setup\n  if (typeof options === 'function') { callback = options; }\n  localforage.getItem(filename, function (err, contents) { return callback(null, contents || ''); });\n}\n\n\nfunction unlink (filename, callback) {\n  localforage.removeItem(filename, function () { return callback(); });\n}\n\n\n// Nothing to do, no directories will be used on the browser\nfunction mkdirp (dir, callback) {\n  return callback();\n}\n\n\n// Nothing to do, no data corruption possible in the brower\nfunction ensureDatafileIntegrity (filename, callback) {\n  return callback(null);\n}\n\n\n// Interface\nmodule.exports.exists = exists;\nmodule.exports.rename = rename;\nmodule.exports.writeFile = writeFile;\nmodule.exports.crashSafeWriteFile = writeFile;   // No need for a crash safe function in the browser\nmodule.exports.appendFile = appendFile;\nmodule.exports.readFile = readFile;\nmodule.exports.unlink = unlink;\nmodule.exports.mkdirp = mkdirp;\nmodule.exports.ensureDatafileIntegrity = ensureDatafileIntegrity;\n\n\n},{\"localforage\":18}],13:[function(require,module,exports){\nvar process=require(\"__browserify_process\");/*global setImmediate: false, setTimeout: false, console: false */\n(function () {\n\n    var async = {};\n\n    // global on the server, window in the browser\n    var root, previous_async;\n\n    root = this;\n    if (root != null) {\n      previous_async = root.async;\n    }\n\n    async.noConflict = function () {\n        root.async = previous_async;\n        return async;\n    };\n\n    function only_once(fn) {\n        var called = false;\n        return function() {\n            if (called) throw new Error(\"Callback was already called.\");\n            called = true;\n            fn.apply(root, arguments);\n        }\n    }\n\n    //// cross-browser compatiblity functions ////\n\n    var _each = function (arr, iterator) {\n        if (arr.forEach) {\n            return arr.forEach(iterator);\n        }\n        for (var i = 0; i < arr.length; i += 1) {\n            iterator(arr[i], i, arr);\n        }\n    };\n\n    var _map = function (arr, iterator) {\n        if (arr.map) {\n            return arr.map(iterator);\n        }\n        var results = [];\n        _each(arr, function (x, i, a) {\n            results.push(iterator(x, i, a));\n        });\n        return results;\n    };\n\n    var _reduce = function (arr, iterator, memo) {\n        if (arr.reduce) {\n            return arr.reduce(iterator, memo);\n        }\n        _each(arr, function (x, i, a) {\n            memo = iterator(memo, x, i, a);\n        });\n        return memo;\n    };\n\n    var _keys = function (obj) {\n        if (Object.keys) {\n            return Object.keys(obj);\n        }\n        var keys = [];\n        for (var k in obj) {\n            if (obj.hasOwnProperty(k)) {\n                keys.push(k);\n            }\n        }\n        return keys;\n    };\n\n    //// exported async module functions ////\n\n    //// nextTick implementation with browser-compatible fallback ////\n    if (typeof process === 'undefined' || !(process.nextTick)) {\n        if (typeof setImmediate === 'function') {\n            async.nextTick = function (fn) {\n                // not a direct alias for IE10 compatibility\n                setImmediate(fn);\n            };\n            async.setImmediate = async.nextTick;\n        }\n        else {\n            async.nextTick = function (fn) {\n                setTimeout(fn, 0);\n            };\n            async.setImmediate = async.nextTick;\n        }\n    }\n    else {\n        async.nextTick = process.nextTick;\n        if (typeof setImmediate !== 'undefined') {\n            async.setImmediate = function (fn) {\n              // not a direct alias for IE10 compatibility\n              setImmediate(fn);\n            };\n        }\n        else {\n            async.setImmediate = async.nextTick;\n        }\n    }\n\n    async.each = function (arr, iterator, callback) {\n        callback = callback || function () {};\n        if (!arr.length) {\n            return callback();\n        }\n        var completed = 0;\n        _each(arr, function (x) {\n            iterator(x, only_once(function (err) {\n                if (err) {\n                    callback(err);\n                    callback = function () {};\n                }\n                else {\n                    completed += 1;\n                    if (completed >= arr.length) {\n                        callback(null);\n                    }\n                }\n            }));\n        });\n    };\n    async.forEach = async.each;\n\n    async.eachSeries = function (arr, iterator, callback) {\n        callback = callback || function () {};\n        if (!arr.length) {\n            return callback();\n        }\n        var completed = 0;\n        var iterate = function () {\n            iterator(arr[completed], function (err) {\n                if (err) {\n                    callback(err);\n                    callback = function () {};\n                }\n                else {\n                    completed += 1;\n                    if (completed >= arr.length) {\n                        callback(null);\n                    }\n                    else {\n                        iterate();\n                    }\n                }\n            });\n        };\n        iterate();\n    };\n    async.forEachSeries = async.eachSeries;\n\n    async.eachLimit = function (arr, limit, iterator, callback) {\n        var fn = _eachLimit(limit);\n        fn.apply(null, [arr, iterator, callback]);\n    };\n    async.forEachLimit = async.eachLimit;\n\n    var _eachLimit = function (limit) {\n\n        return function (arr, iterator, callback) {\n            callback = callback || function () {};\n            if (!arr.length || limit <= 0) {\n                return callback();\n            }\n            var completed = 0;\n            var started = 0;\n            var running = 0;\n\n            (function replenish () {\n                if (completed >= arr.length) {\n                    return callback();\n                }\n\n                while (running < limit && started < arr.length) {\n                    started += 1;\n                    running += 1;\n                    iterator(arr[started - 1], function (err) {\n                        if (err) {\n                            callback(err);\n                            callback = function () {};\n                        }\n                        else {\n                            completed += 1;\n                            running -= 1;\n                            if (completed >= arr.length) {\n                                callback();\n                            }\n                            else {\n                                replenish();\n                            }\n                        }\n                    });\n                }\n            })();\n        };\n    };\n\n\n    var doParallel = function (fn) {\n        return function () {\n            var args = Array.prototype.slice.call(arguments);\n            return fn.apply(null, [async.each].concat(args));\n        };\n    };\n    var doParallelLimit = function(limit, fn) {\n        return function () {\n            var args = Array.prototype.slice.call(arguments);\n            return fn.apply(null, [_eachLimit(limit)].concat(args));\n        };\n    };\n    var doSeries = function (fn) {\n        return function () {\n            var args = Array.prototype.slice.call(arguments);\n            return fn.apply(null, [async.eachSeries].concat(args));\n        };\n    };\n\n\n    var _asyncMap = function (eachfn, arr, iterator, callback) {\n        var results = [];\n        arr = _map(arr, function (x, i) {\n            return {index: i, value: x};\n        });\n        eachfn(arr, function (x, callback) {\n            iterator(x.value, function (err, v) {\n                results[x.index] = v;\n                callback(err);\n            });\n        }, function (err) {\n            callback(err, results);\n        });\n    };\n    async.map = doParallel(_asyncMap);\n    async.mapSeries = doSeries(_asyncMap);\n    async.mapLimit = function (arr, limit, iterator, callback) {\n        return _mapLimit(limit)(arr, iterator, callback);\n    };\n\n    var _mapLimit = function(limit) {\n        return doParallelLimit(limit, _asyncMap);\n    };\n\n    // reduce only has a series version, as doing reduce in parallel won't\n    // work in many situations.\n    async.reduce = function (arr, memo, iterator, callback) {\n        async.eachSeries(arr, function (x, callback) {\n            iterator(memo, x, function (err, v) {\n                memo = v;\n                callback(err);\n            });\n        }, function (err) {\n            callback(err, memo);\n        });\n    };\n    // inject alias\n    async.inject = async.reduce;\n    // foldl alias\n    async.foldl = async.reduce;\n\n    async.reduceRight = function (arr, memo, iterator, callback) {\n        var reversed = _map(arr, function (x) {\n            return x;\n        }).reverse();\n        async.reduce(reversed, memo, iterator, callback);\n    };\n    // foldr alias\n    async.foldr = async.reduceRight;\n\n    var _filter = function (eachfn, arr, iterator, callback) {\n        var results = [];\n        arr = _map(arr, function (x, i) {\n            return {index: i, value: x};\n        });\n        eachfn(arr, function (x, callback) {\n            iterator(x.value, function (v) {\n                if (v) {\n                    results.push(x);\n                }\n                callback();\n            });\n        }, function (err) {\n            callback(_map(results.sort(function (a, b) {\n                return a.index - b.index;\n            }), function (x) {\n                return x.value;\n            }));\n        });\n    };\n    async.filter = doParallel(_filter);\n    async.filterSeries = doSeries(_filter);\n    // select alias\n    async.select = async.filter;\n    async.selectSeries = async.filterSeries;\n\n    var _reject = function (eachfn, arr, iterator, callback) {\n        var results = [];\n        arr = _map(arr, function (x, i) {\n            return {index: i, value: x};\n        });\n        eachfn(arr, function (x, callback) {\n            iterator(x.value, function (v) {\n                if (!v) {\n                    results.push(x);\n                }\n                callback();\n            });\n        }, function (err) {\n            callback(_map(results.sort(function (a, b) {\n                return a.index - b.index;\n            }), function (x) {\n                return x.value;\n            }));\n        });\n    };\n    async.reject = doParallel(_reject);\n    async.rejectSeries = doSeries(_reject);\n\n    var _detect = function (eachfn, arr, iterator, main_callback) {\n        eachfn(arr, function (x, callback) {\n            iterator(x, function (result) {\n                if (result) {\n                    main_callback(x);\n                    main_callback = function () {};\n                }\n                else {\n                    callback();\n                }\n            });\n        }, function (err) {\n            main_callback();\n        });\n    };\n    async.detect = doParallel(_detect);\n    async.detectSeries = doSeries(_detect);\n\n    async.some = function (arr, iterator, main_callback) {\n        async.each(arr, function (x, callback) {\n            iterator(x, function (v) {\n                if (v) {\n                    main_callback(true);\n                    main_callback = function () {};\n                }\n                callback();\n            });\n        }, function (err) {\n            main_callback(false);\n        });\n    };\n    // any alias\n    async.any = async.some;\n\n    async.every = function (arr, iterator, main_callback) {\n        async.each(arr, function (x, callback) {\n            iterator(x, function (v) {\n                if (!v) {\n                    main_callback(false);\n                    main_callback = function () {};\n                }\n                callback();\n            });\n        }, function (err) {\n            main_callback(true);\n        });\n    };\n    // all alias\n    async.all = async.every;\n\n    async.sortBy = function (arr, iterator, callback) {\n        async.map(arr, function (x, callback) {\n            iterator(x, function (err, criteria) {\n                if (err) {\n                    callback(err);\n                }\n                else {\n                    callback(null, {value: x, criteria: criteria});\n                }\n            });\n        }, function (err, results) {\n            if (err) {\n                return callback(err);\n            }\n            else {\n                var fn = function (left, right) {\n                    var a = left.criteria, b = right.criteria;\n                    return a < b ? -1 : a > b ? 1 : 0;\n                };\n                callback(null, _map(results.sort(fn), function (x) {\n                    return x.value;\n                }));\n            }\n        });\n    };\n\n    async.auto = function (tasks, callback) {\n        callback = callback || function () {};\n        var keys = _keys(tasks);\n        if (!keys.length) {\n            return callback(null);\n        }\n\n        var results = {};\n\n        var listeners = [];\n        var addListener = function (fn) {\n            listeners.unshift(fn);\n        };\n        var removeListener = function (fn) {\n            for (var i = 0; i < listeners.length; i += 1) {\n                if (listeners[i] === fn) {\n                    listeners.splice(i, 1);\n                    return;\n                }\n            }\n        };\n        var taskComplete = function () {\n            _each(listeners.slice(0), function (fn) {\n                fn();\n            });\n        };\n\n        addListener(function () {\n            if (_keys(results).length === keys.length) {\n                callback(null, results);\n                callback = function () {};\n            }\n        });\n\n        _each(keys, function (k) {\n            var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];\n            var taskCallback = function (err) {\n                var args = Array.prototype.slice.call(arguments, 1);\n                if (args.length <= 1) {\n                    args = args[0];\n                }\n                if (err) {\n                    var safeResults = {};\n                    _each(_keys(results), function(rkey) {\n                        safeResults[rkey] = results[rkey];\n                    });\n                    safeResults[k] = args;\n                    callback(err, safeResults);\n                    // stop subsequent errors hitting callback multiple times\n                    callback = function () {};\n                }\n                else {\n                    results[k] = args;\n                    async.setImmediate(taskComplete);\n                }\n            };\n            var requires = task.slice(0, Math.abs(task.length - 1)) || [];\n            var ready = function () {\n                return _reduce(requires, function (a, x) {\n                    return (a && results.hasOwnProperty(x));\n                }, true) && !results.hasOwnProperty(k);\n            };\n            if (ready()) {\n                task[task.length - 1](taskCallback, results);\n            }\n            else {\n                var listener = function () {\n                    if (ready()) {\n                        removeListener(listener);\n                        task[task.length - 1](taskCallback, results);\n                    }\n                };\n                addListener(listener);\n            }\n        });\n    };\n\n    async.waterfall = function (tasks, callback) {\n        callback = callback || function () {};\n        if (tasks.constructor !== Array) {\n          var err = new Error('First argument to waterfall must be an array of functions');\n          return callback(err);\n        }\n        if (!tasks.length) {\n            return callback();\n        }\n        var wrapIterator = function (iterator) {\n            return function (err) {\n                if (err) {\n                    callback.apply(null, arguments);\n                    callback = function () {};\n                }\n                else {\n                    var args = Array.prototype.slice.call(arguments, 1);\n                    var next = iterator.next();\n                    if (next) {\n                        args.push(wrapIterator(next));\n                    }\n                    else {\n                        args.push(callback);\n                    }\n                    async.setImmediate(function () {\n                        iterator.apply(null, args);\n                    });\n                }\n            };\n        };\n        wrapIterator(async.iterator(tasks))();\n    };\n\n    var _parallel = function(eachfn, tasks, callback) {\n        callback = callback || function () {};\n        if (tasks.constructor === Array) {\n            eachfn.map(tasks, function (fn, callback) {\n                if (fn) {\n                    fn(function (err) {\n                        var args = Array.prototype.slice.call(arguments, 1);\n                        if (args.length <= 1) {\n                            args = args[0];\n                        }\n                        callback.call(null, err, args);\n                    });\n                }\n            }, callback);\n        }\n        else {\n            var results = {};\n            eachfn.each(_keys(tasks), function (k, callback) {\n                tasks[k](function (err) {\n                    var args = Array.prototype.slice.call(arguments, 1);\n                    if (args.length <= 1) {\n                        args = args[0];\n                    }\n                    results[k] = args;\n                    callback(err);\n                });\n            }, function (err) {\n                callback(err, results);\n            });\n        }\n    };\n\n    async.parallel = function (tasks, callback) {\n        _parallel({ map: async.map, each: async.each }, tasks, callback);\n    };\n\n    async.parallelLimit = function(tasks, limit, callback) {\n        _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback);\n    };\n\n    async.series = function (tasks, callback) {\n        callback = callback || function () {};\n        if (tasks.constructor === Array) {\n            async.mapSeries(tasks, function (fn, callback) {\n                if (fn) {\n                    fn(function (err) {\n                        var args = Array.prototype.slice.call(arguments, 1);\n                        if (args.length <= 1) {\n                            args = args[0];\n                        }\n                        callback.call(null, err, args);\n                    });\n                }\n            }, callback);\n        }\n        else {\n            var results = {};\n            async.eachSeries(_keys(tasks), function (k, callback) {\n                tasks[k](function (err) {\n                    var args = Array.prototype.slice.call(arguments, 1);\n                    if (args.length <= 1) {\n                        args = args[0];\n                    }\n                    results[k] = args;\n                    callback(err);\n                });\n            }, function (err) {\n                callback(err, results);\n            });\n        }\n    };\n\n    async.iterator = function (tasks) {\n        var makeCallback = function (index) {\n            var fn = function () {\n                if (tasks.length) {\n                    tasks[index].apply(null, arguments);\n                }\n                return fn.next();\n            };\n            fn.next = function () {\n                return (index < tasks.length - 1) ? makeCallback(index + 1): null;\n            };\n            return fn;\n        };\n        return makeCallback(0);\n    };\n\n    async.apply = function (fn) {\n        var args = Array.prototype.slice.call(arguments, 1);\n        return function () {\n            return fn.apply(\n                null, args.concat(Array.prototype.slice.call(arguments))\n            );\n        };\n    };\n\n    var _concat = function (eachfn, arr, fn, callback) {\n        var r = [];\n        eachfn(arr, function (x, cb) {\n            fn(x, function (err, y) {\n                r = r.concat(y || []);\n                cb(err);\n            });\n        }, function (err) {\n            callback(err, r);\n        });\n    };\n    async.concat = doParallel(_concat);\n    async.concatSeries = doSeries(_concat);\n\n    async.whilst = function (test, iterator, callback) {\n        if (test()) {\n            iterator(function (err) {\n                if (err) {\n                    return callback(err);\n                }\n                async.whilst(test, iterator, callback);\n            });\n        }\n        else {\n            callback();\n        }\n    };\n\n    async.doWhilst = function (iterator, test, callback) {\n        iterator(function (err) {\n            if (err) {\n                return callback(err);\n            }\n            if (test()) {\n                async.doWhilst(iterator, test, callback);\n            }\n            else {\n                callback();\n            }\n        });\n    };\n\n    async.until = function (test, iterator, callback) {\n        if (!test()) {\n            iterator(function (err) {\n                if (err) {\n                    return callback(err);\n                }\n                async.until(test, iterator, callback);\n            });\n        }\n        else {\n            callback();\n        }\n    };\n\n    async.doUntil = function (iterator, test, callback) {\n        iterator(function (err) {\n            if (err) {\n                return callback(err);\n            }\n            if (!test()) {\n                async.doUntil(iterator, test, callback);\n            }\n            else {\n                callback();\n            }\n        });\n    };\n\n    async.queue = function (worker, concurrency) {\n        if (concurrency === undefined) {\n            concurrency = 1;\n        }\n        function _insert(q, data, pos, callback) {\n          if(data.constructor !== Array) {\n              data = [data];\n          }\n          _each(data, function(task) {\n              var item = {\n                  data: task,\n                  callback: typeof callback === 'function' ? callback : null\n              };\n\n              if (pos) {\n                q.tasks.unshift(item);\n              } else {\n                q.tasks.push(item);\n              }\n\n              if (q.saturated && q.tasks.length === concurrency) {\n                  q.saturated();\n              }\n              async.setImmediate(q.process);\n          });\n        }\n\n        var workers = 0;\n        var q = {\n            tasks: [],\n            concurrency: concurrency,\n            saturated: null,\n            empty: null,\n            drain: null,\n            push: function (data, callback) {\n              _insert(q, data, false, callback);\n            },\n            unshift: function (data, callback) {\n              _insert(q, data, true, callback);\n            },\n            process: function () {\n                if (workers < q.concurrency && q.tasks.length) {\n                    var task = q.tasks.shift();\n                    if (q.empty && q.tasks.length === 0) {\n                        q.empty();\n                    }\n                    workers += 1;\n                    var next = function () {\n                        workers -= 1;\n                        if (task.callback) {\n                            task.callback.apply(task, arguments);\n                        }\n                        if (q.drain && q.tasks.length + workers === 0) {\n                            q.drain();\n                        }\n                        q.process();\n                    };\n                    var cb = only_once(next);\n                    worker(task.data, cb);\n                }\n            },\n            length: function () {\n                return q.tasks.length;\n            },\n            running: function () {\n                return workers;\n            }\n        };\n        return q;\n    };\n\n    async.cargo = function (worker, payload) {\n        var working     = false,\n            tasks       = [];\n\n        var cargo = {\n            tasks: tasks,\n            payload: payload,\n            saturated: null,\n            empty: null,\n            drain: null,\n            push: function (data, callback) {\n                if(data.constructor !== Array) {\n                    data = [data];\n                }\n                _each(data, function(task) {\n                    tasks.push({\n                        data: task,\n                        callback: typeof callback === 'function' ? callback : null\n                    });\n                    if (cargo.saturated && tasks.length === payload) {\n                        cargo.saturated();\n                    }\n                });\n                async.setImmediate(cargo.process);\n            },\n            process: function process() {\n                if (working) return;\n                if (tasks.length === 0) {\n                    if(cargo.drain) cargo.drain();\n                    return;\n                }\n\n                var ts = typeof payload === 'number'\n                            ? tasks.splice(0, payload)\n                            : tasks.splice(0);\n\n                var ds = _map(ts, function (task) {\n                    return task.data;\n                });\n\n                if(cargo.empty) cargo.empty();\n                working = true;\n                worker(ds, function () {\n                    working = false;\n\n                    var args = arguments;\n                    _each(ts, function (data) {\n                        if (data.callback) {\n                            data.callback.apply(null, args);\n                        }\n                    });\n\n                    process();\n                });\n            },\n            length: function () {\n                return tasks.length;\n            },\n            running: function () {\n                return working;\n            }\n        };\n        return cargo;\n    };\n\n    var _console_fn = function (name) {\n        return function (fn) {\n            var args = Array.prototype.slice.call(arguments, 1);\n            fn.apply(null, args.concat([function (err) {\n                var args = Array.prototype.slice.call(arguments, 1);\n                if (typeof console !== 'undefined') {\n                    if (err) {\n                        if (console.error) {\n                            console.error(err);\n                        }\n                    }\n                    else if (console[name]) {\n                        _each(args, function (x) {\n                            console[name](x);\n                        });\n                    }\n                }\n            }]));\n        };\n    };\n    async.log = _console_fn('log');\n    async.dir = _console_fn('dir');\n    /*async.info = _console_fn('info');\n    async.warn = _console_fn('warn');\n    async.error = _console_fn('error');*/\n\n    async.memoize = function (fn, hasher) {\n        var memo = {};\n        var queues = {};\n        hasher = hasher || function (x) {\n            return x;\n        };\n        var memoized = function () {\n            var args = Array.prototype.slice.call(arguments);\n            var callback = args.pop();\n            var key = hasher.apply(null, args);\n            if (key in memo) {\n                callback.apply(null, memo[key]);\n            }\n            else if (key in queues) {\n                queues[key].push(callback);\n            }\n            else {\n                queues[key] = [callback];\n                fn.apply(null, args.concat([function () {\n                    memo[key] = arguments;\n                    var q = queues[key];\n                    delete queues[key];\n                    for (var i = 0, l = q.length; i < l; i++) {\n                      q[i].apply(null, arguments);\n                    }\n                }]));\n            }\n        };\n        memoized.memo = memo;\n        memoized.unmemoized = fn;\n        return memoized;\n    };\n\n    async.unmemoize = function (fn) {\n      return function () {\n        return (fn.unmemoized || fn).apply(null, arguments);\n      };\n    };\n\n    async.times = function (count, iterator, callback) {\n        var counter = [];\n        for (var i = 0; i < count; i++) {\n            counter.push(i);\n        }\n        return async.map(counter, iterator, callback);\n    };\n\n    async.timesSeries = function (count, iterator, callback) {\n        var counter = [];\n        for (var i = 0; i < count; i++) {\n            counter.push(i);\n        }\n        return async.mapSeries(counter, iterator, callback);\n    };\n\n    async.compose = function (/* functions... */) {\n        var fns = Array.prototype.reverse.call(arguments);\n        return function () {\n            var that = this;\n            var args = Array.prototype.slice.call(arguments);\n            var callback = args.pop();\n            async.reduce(fns, args, function (newargs, fn, cb) {\n                fn.apply(that, newargs.concat([function () {\n                    var err = arguments[0];\n                    var nextargs = Array.prototype.slice.call(arguments, 1);\n                    cb(err, nextargs);\n                }]))\n            },\n            function (err, results) {\n                callback.apply(that, [err].concat(results));\n            });\n        };\n    };\n\n    var _applyEach = function (eachfn, fns /*args...*/) {\n        var go = function () {\n            var that = this;\n            var args = Array.prototype.slice.call(arguments);\n            var callback = args.pop();\n            return eachfn(fns, function (fn, cb) {\n                fn.apply(that, args.concat([cb]));\n            },\n            callback);\n        };\n        if (arguments.length > 2) {\n            var args = Array.prototype.slice.call(arguments, 2);\n            return go.apply(this, args);\n        }\n        else {\n            return go;\n        }\n    };\n    async.applyEach = doParallel(_applyEach);\n    async.applyEachSeries = doSeries(_applyEach);\n\n    async.forever = function (fn, callback) {\n        function next(err) {\n            if (err) {\n                if (callback) {\n                    return callback(err);\n                }\n                throw err;\n            }\n            fn(next);\n        }\n        next();\n    };\n\n    // AMD / RequireJS\n    if (typeof define !== 'undefined' && define.amd) {\n        define([], function () {\n            return async;\n        });\n    }\n    // Node.js\n    else if (typeof module !== 'undefined' && module.exports) {\n        module.exports = async;\n    }\n    // included directly via <script> tag\n    else {\n        root.async = async;\n    }\n\n}());\n\n},{\"__browserify_process\":4}],14:[function(require,module,exports){\nmodule.exports.BinarySearchTree = require('./lib/bst');\nmodule.exports.AVLTree = require('./lib/avltree');\n\n},{\"./lib/avltree\":15,\"./lib/bst\":16}],15:[function(require,module,exports){\n/**\n * Self-balancing binary search tree using the AVL implementation\n */\nvar BinarySearchTree = require('./bst')\n  , customUtils = require('./customUtils')\n  , util = require('util')\n  , _ = require('underscore')\n  ;\n\n\n/**\n * Constructor\n * We can't use a direct pointer to the root node (as in the simple binary search tree)\n * as the root will change during tree rotations\n * @param {Boolean}  options.unique Whether to enforce a 'unique' constraint on the key or not\n * @param {Function} options.compareKeys Initialize this BST's compareKeys\n */\nfunction AVLTree (options) {\n  this.tree = new _AVLTree(options);\n}\n\n\n/**\n * Constructor of the internal AVLTree\n * @param {Object} options Optional\n * @param {Boolean}  options.unique Whether to enforce a 'unique' constraint on the key or not\n * @param {Key}      options.key Initialize this BST's key with key\n * @param {Value}    options.value Initialize this BST's data with [value]\n * @param {Function} options.compareKeys Initialize this BST's compareKeys\n */\nfunction _AVLTree (options) {\n  options = options || {};\n\n  this.left = null;\n  this.right = null;\n  this.parent = options.parent !== undefined ? options.parent : null;\n  if (options.hasOwnProperty('key')) { this.key = options.key; }\n  this.data = options.hasOwnProperty('value') ? [options.value] : [];\n  this.unique = options.unique || false;\n\n  this.compareKeys = options.compareKeys || customUtils.defaultCompareKeysFunction;\n  this.checkValueEquality = options.checkValueEquality || customUtils.defaultCheckValueEquality;\n}\n\n\n/**\n * Inherit basic functions from the basic binary search tree\n */\nutil.inherits(_AVLTree, BinarySearchTree);\n\n/**\n * Keep a pointer to the internal tree constructor for testing purposes\n */\nAVLTree._AVLTree = _AVLTree;\n\n\n/**\n * Check the recorded height is correct for every node\n * Throws if one height doesn't match\n */\n_AVLTree.prototype.checkHeightCorrect = function () {\n  var leftH, rightH;\n\n  if (!this.hasOwnProperty('key')) { return; }   // Empty tree\n\n  if (this.left && this.left.height === undefined) { throw new Error(\"Undefined height for node \" + this.left.key); }\n  if (this.right && this.right.height === undefined) { throw new Error(\"Undefined height for node \" + this.right.key); }\n  if (this.height === undefined) { throw new Error(\"Undefined height for node \" + this.key); }\n\n  leftH = this.left ? this.left.height : 0;\n  rightH = this.right ? this.right.height : 0;\n\n  if (this.height !== 1 + Math.max(leftH, rightH)) { throw new Error(\"Height constraint failed for node \" + this.key); }\n  if (this.left) { this.left.checkHeightCorrect(); }\n  if (this.right) { this.right.checkHeightCorrect(); }\n};\n\n\n/**\n * Return the balance factor\n */\n_AVLTree.prototype.balanceFactor = function () {\n  var leftH = this.left ? this.left.height : 0\n    , rightH = this.right ? this.right.height : 0\n    ;\n  return leftH - rightH;\n};\n\n\n/**\n * Check that the balance factors are all between -1 and 1\n */\n_AVLTree.prototype.checkBalanceFactors = function () {\n  if (Math.abs(this.balanceFactor()) > 1) { throw new Error('Tree is unbalanced at node ' + this.key); }\n\n  if (this.left) { this.left.checkBalanceFactors(); }\n  if (this.right) { this.right.checkBalanceFactors(); }\n};\n\n\n/**\n * When checking if the BST conditions are met, also check that the heights are correct\n * and the tree is balanced\n */\n_AVLTree.prototype.checkIsAVLT = function () {\n  _AVLTree.super_.prototype.checkIsBST.call(this);\n  this.checkHeightCorrect();\n  this.checkBalanceFactors();\n};\nAVLTree.prototype.checkIsAVLT = function () { this.tree.checkIsAVLT(); };\n\n\n/**\n * Perform a right rotation of the tree if possible\n * and return the root of the resulting tree\n * The resulting tree's nodes' heights are also updated\n */\n_AVLTree.prototype.rightRotation = function () {\n  var q = this\n    , p = this.left\n    , b\n    , ah, bh, ch;\n\n  if (!p) { return this; }   // No change\n\n  b = p.right;\n\n  // Alter tree structure\n  if (q.parent) {\n    p.parent = q.parent;\n    if (q.parent.left === q) { q.parent.left = p; } else { q.parent.right = p; }\n  } else {\n    p.parent = null;\n  }\n  p.right = q;\n  q.parent = p;\n  q.left = b;\n  if (b) { b.parent = q; }\n\n  // Update heights\n  ah = p.left ? p.left.height : 0;\n  bh = b ? b.height : 0;\n  ch = q.right ? q.right.height : 0;\n  q.height = Math.max(bh, ch) + 1;\n  p.height = Math.max(ah, q.height) + 1;\n\n  return p;\n};\n\n\n/**\n * Perform a left rotation of the tree if possible\n * and return the root of the resulting tree\n * The resulting tree's nodes' heights are also updated\n */\n_AVLTree.prototype.leftRotation = function () {\n  var p = this\n    , q = this.right\n    , b\n    , ah, bh, ch;\n\n  if (!q) { return this; }   // No change\n\n  b = q.left;\n\n  // Alter tree structure\n  if (p.parent) {\n    q.parent = p.parent;\n    if (p.parent.left === p) { p.parent.left = q; } else { p.parent.right = q; }\n  } else {\n    q.parent = null;\n  }\n  q.left = p;\n  p.parent = q;\n  p.right = b;\n  if (b) { b.parent = p; }\n\n  // Update heights\n  ah = p.left ? p.left.height : 0;\n  bh = b ? b.height : 0;\n  ch = q.right ? q.right.height : 0;\n  p.height = Math.max(ah, bh) + 1;\n  q.height = Math.max(ch, p.height) + 1;\n\n  return q;\n};\n\n\n/**\n * Modify the tree if its right subtree is too small compared to the left\n * Return the new root if any\n */\n_AVLTree.prototype.rightTooSmall = function () {\n  if (this.balanceFactor() <= 1) { return this; }   // Right is not too small, don't change\n\n  if (this.left.balanceFactor() < 0) {\n    this.left.leftRotation();\n  }\n\n  return this.rightRotation();\n};\n\n\n/**\n * Modify the tree if its left subtree is too small compared to the right\n * Return the new root if any\n */\n_AVLTree.prototype.leftTooSmall = function () {\n  if (this.balanceFactor() >= -1) { return this; }   // Left is not too small, don't change\n\n  if (this.right.balanceFactor() > 0) {\n    this.right.rightRotation();\n  }\n\n  return this.leftRotation();\n};\n\n\n/**\n * Rebalance the tree along the given path. The path is given reversed (as he was calculated\n * in the insert and delete functions).\n * Returns the new root of the tree\n * Of course, the first element of the path must be the root of the tree\n */\n_AVLTree.prototype.rebalanceAlongPath = function (path) {\n  var newRoot = this\n    , rotated\n    , i;\n\n  if (!this.hasOwnProperty('key')) { delete this.height; return this; }   // Empty tree\n\n  // Rebalance the tree and update all heights\n  for (i = path.length - 1; i >= 0; i -= 1) {\n    path[i].height = 1 + Math.max(path[i].left ? path[i].left.height : 0, path[i].right ? path[i].right.height : 0);\n\n    if (path[i].balanceFactor() > 1) {\n      rotated = path[i].rightTooSmall();\n      if (i === 0) { newRoot = rotated; }\n    }\n\n    if (path[i].balanceFactor() < -1) {\n      rotated = path[i].leftTooSmall();\n      if (i === 0) { newRoot = rotated; }\n    }\n  }\n\n  return newRoot;\n};\n\n\n/**\n * Insert a key, value pair in the tree while maintaining the AVL tree height constraint\n * Return a pointer to the root node, which may have changed\n */\n_AVLTree.prototype.insert = function (key, value) {\n  var insertPath = []\n    , currentNode = this\n    ;\n\n  // Empty tree, insert as root\n  if (!this.hasOwnProperty('key')) {\n    this.key = key;\n    this.data.push(value);\n    this.height = 1;\n    return this;\n  }\n\n  // Insert new leaf at the right place\n  while (true) {\n    // Same key: no change in the tree structure\n    if (currentNode.compareKeys(currentNode.key, key) === 0) {\n      if (currentNode.unique) {\n        var err = new Error(\"Can't insert key \" + key + \", it violates the unique constraint\");\n        err.key = key;\n        err.errorType = 'uniqueViolated';\n        throw err;\n      } else {\n        currentNode.data.push(value);\n      }\n      return this;\n    }\n\n    insertPath.push(currentNode);\n\n    if (currentNode.compareKeys(key, currentNode.key) < 0) {\n      if (!currentNode.left) {\n        insertPath.push(currentNode.createLeftChild({ key: key, value: value }));\n        break;\n      } else {\n        currentNode = currentNode.left;\n      }\n    } else {\n      if (!currentNode.right) {\n        insertPath.push(currentNode.createRightChild({ key: key, value: value }));\n        break;\n      } else {\n        currentNode = currentNode.right;\n      }\n    }\n  }\n\n  return this.rebalanceAlongPath(insertPath);\n};\n\n// Insert in the internal tree, update the pointer to the root if needed\nAVLTree.prototype.insert = function (key, value) {\n  var newTree = this.tree.insert(key, value);\n\n  // If newTree is undefined, that means its structure was not modified\n  if (newTree) { this.tree = newTree; }\n};\n\n\n/**\n * Delete a key or just a value and return the new root of the tree\n * @param {Key} key\n * @param {Value} value Optional. If not set, the whole key is deleted. If set, only this value is deleted\n */\n_AVLTree.prototype.delete = function (key, value) {\n  var newData = [], replaceWith\n    , self = this\n    , currentNode = this\n    , deletePath = []\n    ;\n\n  if (!this.hasOwnProperty('key')) { return this; }   // Empty tree\n\n  // Either no match is found and the function will return from within the loop\n  // Or a match is found and deletePath will contain the path from the root to the node to delete after the loop\n  while (true) {\n    if (currentNode.compareKeys(key, currentNode.key) === 0) { break; }\n\n    deletePath.push(currentNode);\n\n    if (currentNode.compareKeys(key, currentNode.key) < 0) {\n      if (currentNode.left) {\n        currentNode = currentNode.left;\n      } else {\n        return this;   // Key not found, no modification\n      }\n    } else {\n      // currentNode.compareKeys(key, currentNode.key) is > 0\n      if (currentNode.right) {\n        currentNode = currentNode.right;\n      } else {\n        return this;   // Key not found, no modification\n      }\n    }\n  }\n\n  // Delete only a value (no tree modification)\n  if (currentNode.data.length > 1 && value) {\n    currentNode.data.forEach(function (d) {\n      if (!currentNode.checkValueEquality(d, value)) { newData.push(d); }\n    });\n    currentNode.data = newData;\n    return this;\n  }\n\n  // Delete a whole node\n\n  // Leaf\n  if (!currentNode.left && !currentNode.right) {\n    if (currentNode === this) {   // This leaf is also the root\n      delete currentNode.key;\n      currentNode.data = [];\n      delete currentNode.height;\n      return this;\n    } else {\n      if (currentNode.parent.left === currentNode) {\n        currentNode.parent.left = null;\n      } else {\n        currentNode.parent.right = null;\n      }\n      return this.rebalanceAlongPath(deletePath);\n    }\n  }\n\n\n  // Node with only one child\n  if (!currentNode.left || !currentNode.right) {\n    replaceWith = currentNode.left ? currentNode.left : currentNode.right;\n\n    if (currentNode === this) {   // This node is also the root\n      replaceWith.parent = null;\n      return replaceWith;   // height of replaceWith is necessarily 1 because the tree was balanced before deletion\n    } else {\n      if (currentNode.parent.left === currentNode) {\n        currentNode.parent.left = replaceWith;\n        replaceWith.parent = currentNode.parent;\n      } else {\n        currentNode.parent.right = replaceWith;\n        replaceWith.parent = currentNode.parent;\n      }\n\n      return this.rebalanceAlongPath(deletePath);\n    }\n  }\n\n\n  // Node with two children\n  // Use the in-order predecessor (no need to randomize since we actively rebalance)\n  deletePath.push(currentNode);\n  replaceWith = currentNode.left;\n\n  // Special case: the in-order predecessor is right below the node to delete\n  if (!replaceWith.right) {\n    currentNode.key = replaceWith.key;\n    currentNode.data = replaceWith.data;\n    currentNode.left = replaceWith.left;\n    if (replaceWith.left) { replaceWith.left.parent = currentNode; }\n    return this.rebalanceAlongPath(deletePath);\n  }\n\n  // After this loop, replaceWith is the right-most leaf in the left subtree\n  // and deletePath the path from the root (inclusive) to replaceWith (exclusive)\n  while (true) {\n    if (replaceWith.right) {\n      deletePath.push(replaceWith);\n      replaceWith = replaceWith.right;\n    } else {\n      break;\n    }\n  }\n\n  currentNode.key = replaceWith.key;\n  currentNode.data = replaceWith.data;\n\n  replaceWith.parent.right = replaceWith.left;\n  if (replaceWith.left) { replaceWith.left.parent = replaceWith.parent; }\n\n  return this.rebalanceAlongPath(deletePath);\n};\n\n// Delete a value\nAVLTree.prototype.delete = function (key, value) {\n  var newTree = this.tree.delete(key, value);\n\n  // If newTree is undefined, that means its structure was not modified\n  if (newTree) { this.tree = newTree; }\n};\n\n\n/**\n * Other functions we want to use on an AVLTree as if it were the internal _AVLTree\n */\n['getNumberOfKeys', 'search', 'betweenBounds', 'prettyPrint', 'executeOnEveryNode'].forEach(function (fn) {\n  AVLTree.prototype[fn] = function () {\n    return this.tree[fn].apply(this.tree, arguments);\n  };\n});\n\n\n// Interface\nmodule.exports = AVLTree;\n\n},{\"./bst\":16,\"./customUtils\":17,\"underscore\":19,\"util\":3}],16:[function(require,module,exports){\n/**\n * Simple binary search tree\n */\nvar customUtils = require('./customUtils');\n\n\n/**\n * Constructor\n * @param {Object} options Optional\n * @param {Boolean}  options.unique Whether to enforce a 'unique' constraint on the key or not\n * @param {Key}      options.key Initialize this BST's key with key\n * @param {Value}    options.value Initialize this BST's data with [value]\n * @param {Function} options.compareKeys Initialize this BST's compareKeys\n */\nfunction BinarySearchTree (options) {\n  options = options || {};\n\n  this.left = null;\n  this.right = null;\n  this.parent = options.parent !== undefined ? options.parent : null;\n  if (options.hasOwnProperty('key')) { this.key = options.key; }\n  this.data = options.hasOwnProperty('value') ? [options.value] : [];\n  this.unique = options.unique || false;\n\n  this.compareKeys = options.compareKeys || customUtils.defaultCompareKeysFunction;\n  this.checkValueEquality = options.checkValueEquality || customUtils.defaultCheckValueEquality;\n}\n\n\n// ================================\n// Methods used to test the tree\n// ================================\n\n\n/**\n * Get the descendant with max key\n */\nBinarySearchTree.prototype.getMaxKeyDescendant = function () {\n  if (this.right) {\n    return this.right.getMaxKeyDescendant();\n  } else {\n    return this;\n  }\n};\n\n\n/**\n * Get the maximum key\n */\nBinarySearchTree.prototype.getMaxKey = function () {\n  return this.getMaxKeyDescendant().key;\n};\n\n\n/**\n * Get the descendant with min key\n */\nBinarySearchTree.prototype.getMinKeyDescendant = function () {\n  if (this.left) {\n    return this.left.getMinKeyDescendant()\n  } else {\n    return this;\n  }\n};\n\n\n/**\n * Get the minimum key\n */\nBinarySearchTree.prototype.getMinKey = function () {\n  return this.getMinKeyDescendant().key;\n};\n\n\n/**\n * Check that all nodes (incl. leaves) fullfil condition given by fn\n * test is a function passed every (key, data) and which throws if the condition is not met\n */\nBinarySearchTree.prototype.checkAllNodesFullfillCondition = function (test) {\n  if (!this.hasOwnProperty('key')) { return; }\n\n  test(this.key, this.data);\n  if (this.left) { this.left.checkAllNodesFullfillCondition(test); }\n  if (this.right) { this.right.checkAllNodesFullfillCondition(test); }\n};\n\n\n/**\n * Check that the core BST properties on node ordering are verified\n * Throw if they aren't\n */\nBinarySearchTree.prototype.checkNodeOrdering = function () {\n  var self = this;\n\n  if (!this.hasOwnProperty('key')) { return; }\n\n  if (this.left) {\n    this.left.checkAllNodesFullfillCondition(function (k) {\n      if (self.compareKeys(k, self.key) >= 0) {\n        throw new Error('Tree with root ' + self.key + ' is not a binary search tree');\n      }\n    });\n    this.left.checkNodeOrdering();\n  }\n\n  if (this.right) {\n    this.right.checkAllNodesFullfillCondition(function (k) {\n      if (self.compareKeys(k, self.key) <= 0) {\n        throw new Error('Tree with root ' + self.key + ' is not a binary search tree');\n      }\n    });\n    this.right.checkNodeOrdering();\n  }\n};\n\n\n/**\n * Check that all pointers are coherent in this tree\n */\nBinarySearchTree.prototype.checkInternalPointers = function () {\n  if (this.left) {\n    if (this.left.parent !== this) { throw new Error('Parent pointer broken for key ' + this.key); }\n    this.left.checkInternalPointers();\n  }\n\n  if (this.right) {\n    if (this.right.parent !== this) { throw new Error('Parent pointer broken for key ' + this.key); }\n    this.right.checkInternalPointers();\n  }\n};\n\n\n/**\n * Check that a tree is a BST as defined here (node ordering and pointer references)\n */\nBinarySearchTree.prototype.checkIsBST = function () {\n  this.checkNodeOrdering();\n  this.checkInternalPointers();\n  if (this.parent) { throw new Error(\"The root shouldn't have a parent\"); }\n};\n\n\n/**\n * Get number of keys inserted\n */\nBinarySearchTree.prototype.getNumberOfKeys = function () {\n  var res;\n\n  if (!this.hasOwnProperty('key')) { return 0; }\n\n  res = 1;\n  if (this.left) { res += this.left.getNumberOfKeys(); }\n  if (this.right) { res += this.right.getNumberOfKeys(); }\n\n  return res;\n};\n\n\n\n// ============================================\n// Methods used to actually work on the tree\n// ============================================\n\n/**\n * Create a BST similar (i.e. same options except for key and value) to the current one\n * Use the same constructor (i.e. BinarySearchTree, AVLTree etc)\n * @param {Object} options see constructor\n */\nBinarySearchTree.prototype.createSimilar = function (options) {\n  options = options || {};\n  options.unique = this.unique;\n  options.compareKeys = this.compareKeys;\n  options.checkValueEquality = this.checkValueEquality;\n\n  return new this.constructor(options);\n};\n\n\n/**\n * Create the left child of this BST and return it\n */\nBinarySearchTree.prototype.createLeftChild = function (options) {\n  var leftChild = this.createSimilar(options);\n  leftChild.parent = this;\n  this.left = leftChild;\n\n  return leftChild;\n};\n\n\n/**\n * Create the right child of this BST and return it\n */\nBinarySearchTree.prototype.createRightChild = function (options) {\n  var rightChild = this.createSimilar(options);\n  rightChild.parent = this;\n  this.right = rightChild;\n\n  return rightChild;\n};\n\n\n/**\n * Insert a new element\n */\nBinarySearchTree.prototype.insert = function (key, value) {\n  // Empty tree, insert as root\n  if (!this.hasOwnProperty('key')) {\n    this.key = key;\n    this.data.push(value);\n    return;\n  }\n\n  // Same key as root\n  if (this.compareKeys(this.key, key) === 0) {\n    if (this.unique) {\n      var err = new Error(\"Can't insert key \" + key + \", it violates the unique constraint\");\n      err.key = key;\n      err.errorType = 'uniqueViolated';\n      throw err;\n    } else {\n      this.data.push(value);\n    }\n    return;\n  }\n\n  if (this.compareKeys(key, this.key) < 0) {\n    // Insert in left subtree\n    if (this.left) {\n      this.left.insert(key, value);\n    } else {\n      this.createLeftChild({ key: key, value: value });\n    }\n  } else {\n    // Insert in right subtree\n    if (this.right) {\n      this.right.insert(key, value);\n    } else {\n      this.createRightChild({ key: key, value: value });\n    }\n  }\n};\n\n\n/**\n * Search for all data corresponding to a key\n */\nBinarySearchTree.prototype.search = function (key) {\n  if (!this.hasOwnProperty('key')) { return []; }\n\n  if (this.compareKeys(this.key, key) === 0) { return this.data; }\n\n  if (this.compareKeys(key, this.key) < 0) {\n    if (this.left) {\n      return this.left.search(key);\n    } else {\n      return [];\n    }\n  } else {\n    if (this.right) {\n      return this.right.search(key);\n    } else {\n      return [];\n    }\n  }\n};\n\n\n/**\n * Return a function that tells whether a given key matches a lower bound\n */\nBinarySearchTree.prototype.getLowerBoundMatcher = function (query) {\n  var self = this;\n\n  // No lower bound\n  if (!query.hasOwnProperty('$gt') && !query.hasOwnProperty('$gte')) {\n    return function () { return true; };\n  }\n\n  if (query.hasOwnProperty('$gt') && query.hasOwnProperty('$gte')) {\n    if (self.compareKeys(query.$gte, query.$gt) === 0) {\n      return function (key) { return self.compareKeys(key, query.$gt) > 0; };\n    }\n\n    if (self.compareKeys(query.$gte, query.$gt) > 0) {\n      return function (key) { return self.compareKeys(key, query.$gte) >= 0; };\n    } else {\n      return function (key) { return self.compareKeys(key, query.$gt) > 0; };\n    }\n  }\n\n  if (query.hasOwnProperty('$gt')) {\n    return function (key) { return self.compareKeys(key, query.$gt) > 0; };\n  } else {\n    return function (key) { return self.compareKeys(key, query.$gte) >= 0; };\n  }\n};\n\n\n/**\n * Return a function that tells whether a given key matches an upper bound\n */\nBinarySearchTree.prototype.getUpperBoundMatcher = function (query) {\n  var self = this;\n\n  // No lower bound\n  if (!query.hasOwnProperty('$lt') && !query.hasOwnProperty('$lte')) {\n    return function () { return true; };\n  }\n\n  if (query.hasOwnProperty('$lt') && query.hasOwnProperty('$lte')) {\n    if (self.compareKeys(query.$lte, query.$lt) === 0) {\n      return function (key) { return self.compareKeys(key, query.$lt) < 0; };\n    }\n\n    if (self.compareKeys(query.$lte, query.$lt) < 0) {\n      return function (key) { return self.compareKeys(key, query.$lte) <= 0; };\n    } else {\n      return function (key) { return self.compareKeys(key, query.$lt) < 0; };\n    }\n  }\n\n  if (query.hasOwnProperty('$lt')) {\n    return function (key) { return self.compareKeys(key, query.$lt) < 0; };\n  } else {\n    return function (key) { return self.compareKeys(key, query.$lte) <= 0; };\n  }\n};\n\n\n// Append all elements in toAppend to array\nfunction append (array, toAppend) {\n  var i;\n\n  for (i = 0; i < toAppend.length; i += 1) {\n    array.push(toAppend[i]);\n  }\n}\n\n\n/**\n * Get all data for a key between bounds\n * Return it in key order\n * @param {Object} query Mongo-style query where keys are $lt, $lte, $gt or $gte (other keys are not considered)\n * @param {Functions} lbm/ubm matching functions calculated at the first recursive step\n */\nBinarySearchTree.prototype.betweenBounds = function (query, lbm, ubm) {\n  var res = [];\n\n  if (!this.hasOwnProperty('key')) { return []; }   // Empty tree\n\n  lbm = lbm || this.getLowerBoundMatcher(query);\n  ubm = ubm || this.getUpperBoundMatcher(query);\n\n  if (lbm(this.key) && this.left) { append(res, this.left.betweenBounds(query, lbm, ubm)); }\n  if (lbm(this.key) && ubm(this.key)) { append(res, this.data); }\n  if (ubm(this.key) && this.right) { append(res, this.right.betweenBounds(query, lbm, ubm)); }\n\n  return res;\n};\n\n\n/**\n * Delete the current node if it is a leaf\n * Return true if it was deleted\n */\nBinarySearchTree.prototype.deleteIfLeaf = function () {\n  if (this.left || this.right) { return false; }\n\n  // The leaf is itself a root\n  if (!this.parent) {\n    delete this.key;\n    this.data = [];\n    return true;\n  }\n\n  if (this.parent.left === this) {\n    this.parent.left = null;\n  } else {\n    this.parent.right = null;\n  }\n\n  return true;\n};\n\n\n/**\n * Delete the current node if it has only one child\n * Return true if it was deleted\n */\nBinarySearchTree.prototype.deleteIfOnlyOneChild = function () {\n  var child;\n\n  if (this.left && !this.right) { child = this.left; }\n  if (!this.left && this.right) { child = this.right; }\n  if (!child) { return false; }\n\n  // Root\n  if (!this.parent) {\n    this.key = child.key;\n    this.data = child.data;\n\n    this.left = null;\n    if (child.left) {\n      this.left = child.left;\n      child.left.parent = this;\n    }\n\n    this.right = null;\n    if (child.right) {\n      this.right = child.right;\n      child.right.parent = this;\n    }\n\n    return true;\n  }\n\n  if (this.parent.left === this) {\n    this.parent.left = child;\n    child.parent = this.parent;\n  } else {\n    this.parent.right = child;\n    child.parent = this.parent;\n  }\n\n  return true;\n};\n\n\n/**\n * Delete a key or just a value\n * @param {Key} key\n * @param {Value} value Optional. If not set, the whole key is deleted. If set, only this value is deleted\n */\nBinarySearchTree.prototype.delete = function (key, value) {\n  var newData = [], replaceWith\n    , self = this\n    ;\n\n  if (!this.hasOwnProperty('key')) { return; }\n\n  if (this.compareKeys(key, this.key) < 0) {\n    if (this.left) { this.left.delete(key, value); }\n    return;\n  }\n\n  if (this.compareKeys(key, this.key) > 0) {\n    if (this.right) { this.right.delete(key, value); }\n    return;\n  }\n\n  if (!this.compareKeys(key, this.key) === 0) { return; }\n\n  // Delete only a value\n  if (this.data.length > 1 && value !== undefined) {\n    this.data.forEach(function (d) {\n      if (!self.checkValueEquality(d, value)) { newData.push(d); }\n    });\n    self.data = newData;\n    return;\n  }\n\n  // Delete the whole node\n  if (this.deleteIfLeaf()) {\n    return;\n  }\n  if (this.deleteIfOnlyOneChild()) {\n    return;\n  }\n\n  // We are in the case where the node to delete has two children\n  if (Math.random() >= 0.5) {   // Randomize replacement to avoid unbalancing the tree too much\n    // Use the in-order predecessor\n    replaceWith = this.left.getMaxKeyDescendant();\n\n    this.key = replaceWith.key;\n    this.data = replaceWith.data;\n\n    if (this === replaceWith.parent) {   // Special case\n      this.left = replaceWith.left;\n      if (replaceWith.left) { replaceWith.left.parent = replaceWith.parent; }\n    } else {\n      replaceWith.parent.right = replaceWith.left;\n      if (replaceWith.left) { replaceWith.left.parent = replaceWith.parent; }\n    }\n  } else {\n    // Use the in-order successor\n    replaceWith = this.right.getMinKeyDescendant();\n\n    this.key = replaceWith.key;\n    this.data = replaceWith.data;\n\n    if (this === replaceWith.parent) {   // Special case\n      this.right = replaceWith.right;\n      if (replaceWith.right) { replaceWith.right.parent = replaceWith.parent; }\n    } else {\n      replaceWith.parent.left = replaceWith.right;\n      if (replaceWith.right) { replaceWith.right.parent = replaceWith.parent; }\n    }\n  }\n};\n\n\n/**\n * Execute a function on every node of the tree, in key order\n * @param {Function} fn Signature: node. Most useful will probably be node.key and node.data\n */\nBinarySearchTree.prototype.executeOnEveryNode = function (fn) {\n  if (this.left) { this.left.executeOnEveryNode(fn); }\n  fn(this);\n  if (this.right) { this.right.executeOnEveryNode(fn); }\n};\n\n\n/**\n * Pretty print a tree\n * @param {Boolean} printData To print the nodes' data along with the key\n */\nBinarySearchTree.prototype.prettyPrint = function (printData, spacing) {\n  spacing = spacing || \"\";\n\n  console.log(spacing + \"* \" + this.key);\n  if (printData) { console.log(spacing + \"* \" + this.data); }\n\n  if (!this.left && !this.right) { return; }\n\n  if (this.left) {\n    this.left.prettyPrint(printData, spacing + \"  \");\n  } else {\n    console.log(spacing + \"  *\");\n  }\n  if (this.right) {\n    this.right.prettyPrint(printData, spacing + \"  \");\n  } else {\n    console.log(spacing + \"  *\");\n  }\n};\n\n\n\n\n// Interface\nmodule.exports = BinarySearchTree;\n\n},{\"./customUtils\":17}],17:[function(require,module,exports){\n/**\n * Return an array with the numbers from 0 to n-1, in a random order\n */\nfunction getRandomArray (n) {\n  var res, next;\n\n  if (n === 0) { return []; }\n  if (n === 1) { return [0]; }\n\n  res = getRandomArray(n - 1);\n  next = Math.floor(Math.random() * n);\n  res.splice(next, 0, n - 1);   // Add n-1 at a random position in the array\n\n  return res;\n};\nmodule.exports.getRandomArray = getRandomArray;\n\n\n/*\n * Default compareKeys function will work for numbers, strings and dates\n */\nfunction defaultCompareKeysFunction (a, b) {\n  if (a < b) { return -1; }\n  if (a > b) { return 1; }\n  if (a === b) { return 0; }\n\n  var err = new Error(\"Couldn't compare elements\");\n  err.a = a;\n  err.b = b;\n  throw err;\n}\nmodule.exports.defaultCompareKeysFunction = defaultCompareKeysFunction;\n\n\n/**\n * Check whether two values are equal (used in non-unique deletion)\n */\nfunction defaultCheckValueEquality (a, b) {\n  return a === b;\n}\nmodule.exports.defaultCheckValueEquality = defaultCheckValueEquality;\n\n},{}],18:[function(require,module,exports){\nvar process=require(\"__browserify_process\"),global=self;/*!\n    localForage -- Offline Storage, Improved\n    Version 1.3.0\n    https://mozilla.github.io/localForage\n    (c) 2013-2015 Mozilla, Apache License 2.0\n*/\n(function() {\nvar define, requireModule, require, requirejs;\n\n(function() {\n  var registry = {}, seen = {};\n\n  define = function(name, deps, callback) {\n    registry[name] = { deps: deps, callback: callback };\n  };\n\n  requirejs = require = requireModule = function(name) {\n  requirejs._eak_seen = registry;\n\n    if (seen[name]) { return seen[name]; }\n    seen[name] = {};\n\n    if (!registry[name]) {\n      throw new Error(\"Could not find module \" + name);\n    }\n\n    var mod = registry[name],\n        deps = mod.deps,\n        callback = mod.callback,\n        reified = [],\n        exports;\n\n    for (var i=0, l=deps.length; i<l; i++) {\n      if (deps[i] === 'exports') {\n        reified.push(exports = {});\n      } else {\n        reified.push(requireModule(resolve(deps[i])));\n      }\n    }\n\n    var value = callback.apply(this, reified);\n    return seen[name] = exports || value;\n\n    function resolve(child) {\n      if (child.charAt(0) !== '.') { return child; }\n      var parts = child.split(\"/\");\n      var parentBase = name.split(\"/\").slice(0, -1);\n\n      for (var i=0, l=parts.length; i<l; i++) {\n        var part = parts[i];\n\n        if (part === '..') { parentBase.pop(); }\n        else if (part === '.') { continue; }\n        else { parentBase.push(part); }\n      }\n\n      return parentBase.join(\"/\");\n    }\n  };\n})();\n\ndefine(\"promise/all\", \n  [\"./utils\",\"exports\"],\n  function(__dependency1__, __exports__) {\n    \"use strict\";\n    /* global toString */\n\n    var isArray = __dependency1__.isArray;\n    var isFunction = __dependency1__.isFunction;\n\n    /**\n      Returns a promise that is fulfilled when all the given promises have been\n      fulfilled, or rejected if any of them become rejected. The return promise\n      is fulfilled with an array that gives all the values in the order they were\n      passed in the `promises` array argument.\n\n      Example:\n\n      ```javascript\n      var promise1 = RSVP.resolve(1);\n      var promise2 = RSVP.resolve(2);\n      var promise3 = RSVP.resolve(3);\n      var promises = [ promise1, promise2, promise3 ];\n\n      RSVP.all(promises).then(function(array){\n        // The array here would be [ 1, 2, 3 ];\n      });\n      ```\n\n      If any of the `promises` given to `RSVP.all` are rejected, the first promise\n      that is rejected will be given as an argument to the returned promises's\n      rejection handler. For example:\n\n      Example:\n\n      ```javascript\n      var promise1 = RSVP.resolve(1);\n      var promise2 = RSVP.reject(new Error(\"2\"));\n      var promise3 = RSVP.reject(new Error(\"3\"));\n      var promises = [ promise1, promise2, promise3 ];\n\n      RSVP.all(promises).then(function(array){\n        // Code here never runs because there are rejected promises!\n      }, function(error) {\n        // error.message === \"2\"\n      });\n      ```\n\n      @method all\n      @for RSVP\n      @param {Array} promises\n      @param {String} label\n      @return {Promise} promise that is fulfilled when all `promises` have been\n      fulfilled, or rejected if any of them become rejected.\n    */\n    function all(promises) {\n      /*jshint validthis:true */\n      var Promise = this;\n\n      if (!isArray(promises)) {\n        throw new TypeError('You must pass an array to all.');\n      }\n\n      return new Promise(function(resolve, reject) {\n        var results = [], remaining = promises.length,\n        promise;\n\n        if (remaining === 0) {\n          resolve([]);\n        }\n\n        function resolver(index) {\n          return function(value) {\n            resolveAll(index, value);\n          };\n        }\n\n        function resolveAll(index, value) {\n          results[index] = value;\n          if (--remaining === 0) {\n            resolve(results);\n          }\n        }\n\n        for (var i = 0; i < promises.length; i++) {\n          promise = promises[i];\n\n          if (promise && isFunction(promise.then)) {\n            promise.then(resolver(i), reject);\n          } else {\n            resolveAll(i, promise);\n          }\n        }\n      });\n    }\n\n    __exports__.all = all;\n  });\ndefine(\"promise/asap\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    var browserGlobal = (typeof window !== 'undefined') ? window : {};\n    var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;\n    var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this);\n\n    // node\n    function useNextTick() {\n      return function() {\n        process.nextTick(flush);\n      };\n    }\n\n    function useMutationObserver() {\n      var iterations = 0;\n      var observer = new BrowserMutationObserver(flush);\n      var node = document.createTextNode('');\n      observer.observe(node, { characterData: true });\n\n      return function() {\n        node.data = (iterations = ++iterations % 2);\n      };\n    }\n\n    function useSetTimeout() {\n      return function() {\n        local.setTimeout(flush, 1);\n      };\n    }\n\n    var queue = [];\n    function flush() {\n      for (var i = 0; i < queue.length; i++) {\n        var tuple = queue[i];\n        var callback = tuple[0], arg = tuple[1];\n        callback(arg);\n      }\n      queue = [];\n    }\n\n    var scheduleFlush;\n\n    // Decide what async method to use to triggering processing of queued callbacks:\n    if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {\n      scheduleFlush = useNextTick();\n    } else if (BrowserMutationObserver) {\n      scheduleFlush = useMutationObserver();\n    } else {\n      scheduleFlush = useSetTimeout();\n    }\n\n    function asap(callback, arg) {\n      var length = queue.push([callback, arg]);\n      if (length === 1) {\n        // If length is 1, that means that we need to schedule an async flush.\n        // If additional callbacks are queued before the queue is flushed, they\n        // will be processed by this flush that we are scheduling.\n        scheduleFlush();\n      }\n    }\n\n    __exports__.asap = asap;\n  });\ndefine(\"promise/config\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    var config = {\n      instrument: false\n    };\n\n    function configure(name, value) {\n      if (arguments.length === 2) {\n        config[name] = value;\n      } else {\n        return config[name];\n      }\n    }\n\n    __exports__.config = config;\n    __exports__.configure = configure;\n  });\ndefine(\"promise/polyfill\", \n  [\"./promise\",\"./utils\",\"exports\"],\n  function(__dependency1__, __dependency2__, __exports__) {\n    \"use strict\";\n    /*global self*/\n    var RSVPPromise = __dependency1__.Promise;\n    var isFunction = __dependency2__.isFunction;\n\n    function polyfill() {\n      var local;\n\n      if (typeof global !== 'undefined') {\n        local = global;\n      } else if (typeof window !== 'undefined' && window.document) {\n        local = window;\n      } else {\n        local = self;\n      }\n\n      var es6PromiseSupport = \n        \"Promise\" in local &&\n        // Some of these methods are missing from\n        // Firefox/Chrome experimental implementations\n        \"resolve\" in local.Promise &&\n        \"reject\" in local.Promise &&\n        \"all\" in local.Promise &&\n        \"race\" in local.Promise &&\n        // Older version of the spec had a resolver object\n        // as the arg rather than a function\n        (function() {\n          var resolve;\n          new local.Promise(function(r) { resolve = r; });\n          return isFunction(resolve);\n        }());\n\n      if (!es6PromiseSupport) {\n        local.Promise = RSVPPromise;\n      }\n    }\n\n    __exports__.polyfill = polyfill;\n  });\ndefine(\"promise/promise\", \n  [\"./config\",\"./utils\",\"./all\",\"./race\",\"./resolve\",\"./reject\",\"./asap\",\"exports\"],\n  function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {\n    \"use strict\";\n    var config = __dependency1__.config;\n    var configure = __dependency1__.configure;\n    var objectOrFunction = __dependency2__.objectOrFunction;\n    var isFunction = __dependency2__.isFunction;\n    var now = __dependency2__.now;\n    var all = __dependency3__.all;\n    var race = __dependency4__.race;\n    var staticResolve = __dependency5__.resolve;\n    var staticReject = __dependency6__.reject;\n    var asap = __dependency7__.asap;\n\n    var counter = 0;\n\n    config.async = asap; // default async is asap;\n\n    function Promise(resolver) {\n      if (!isFunction(resolver)) {\n        throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');\n      }\n\n      if (!(this instanceof Promise)) {\n        throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\");\n      }\n\n      this._subscribers = [];\n\n      invokeResolver(resolver, this);\n    }\n\n    function invokeResolver(resolver, promise) {\n      function resolvePromise(value) {\n        resolve(promise, value);\n      }\n\n      function rejectPromise(reason) {\n        reject(promise, reason);\n      }\n\n      try {\n        resolver(resolvePromise, rejectPromise);\n      } catch(e) {\n        rejectPromise(e);\n      }\n    }\n\n    function invokeCallback(settled, promise, callback, detail) {\n      var hasCallback = isFunction(callback),\n          value, error, succeeded, failed;\n\n      if (hasCallback) {\n        try {\n          value = callback(detail);\n          succeeded = true;\n        } catch(e) {\n          failed = true;\n          error = e;\n        }\n      } else {\n        value = detail;\n        succeeded = true;\n      }\n\n      if (handleThenable(promise, value)) {\n        return;\n      } else if (hasCallback && succeeded) {\n        resolve(promise, value);\n      } else if (failed) {\n        reject(promise, error);\n      } else if (settled === FULFILLED) {\n        resolve(promise, value);\n      } else if (settled === REJECTED) {\n        reject(promise, value);\n      }\n    }\n\n    var PENDING   = void 0;\n    var SEALED    = 0;\n    var FULFILLED = 1;\n    var REJECTED  = 2;\n\n    function subscribe(parent, child, onFulfillment, onRejection) {\n      var subscribers = parent._subscribers;\n      var length = subscribers.length;\n\n      subscribers[length] = child;\n      subscribers[length + FULFILLED] = onFulfillment;\n      subscribers[length + REJECTED]  = onRejection;\n    }\n\n    function publish(promise, settled) {\n      var child, callback, subscribers = promise._subscribers, detail = promise._detail;\n\n      for (var i = 0; i < subscribers.length; i += 3) {\n        child = subscribers[i];\n        callback = subscribers[i + settled];\n\n        invokeCallback(settled, child, callback, detail);\n      }\n\n      promise._subscribers = null;\n    }\n\n    Promise.prototype = {\n      constructor: Promise,\n\n      _state: undefined,\n      _detail: undefined,\n      _subscribers: undefined,\n\n      then: function(onFulfillment, onRejection) {\n        var promise = this;\n\n        var thenPromise = new this.constructor(function() {});\n\n        if (this._state) {\n          var callbacks = arguments;\n          config.async(function invokePromiseCallback() {\n            invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);\n          });\n        } else {\n          subscribe(this, thenPromise, onFulfillment, onRejection);\n        }\n\n        return thenPromise;\n      },\n\n      'catch': function(onRejection) {\n        return this.then(null, onRejection);\n      }\n    };\n\n    Promise.all = all;\n    Promise.race = race;\n    Promise.resolve = staticResolve;\n    Promise.reject = staticReject;\n\n    function handleThenable(promise, value) {\n      var then = null,\n      resolved;\n\n      try {\n        if (promise === value) {\n          throw new TypeError(\"A promises callback cannot return that same promise.\");\n        }\n\n        if (objectOrFunction(value)) {\n          then = value.then;\n\n          if (isFunction(then)) {\n            then.call(value, function(val) {\n              if (resolved) { return true; }\n              resolved = true;\n\n              if (value !== val) {\n                resolve(promise, val);\n              } else {\n                fulfill(promise, val);\n              }\n            }, function(val) {\n              if (resolved) { return true; }\n              resolved = true;\n\n              reject(promise, val);\n            });\n\n            return true;\n          }\n        }\n      } catch (error) {\n        if (resolved) { return true; }\n        reject(promise, error);\n        return true;\n      }\n\n      return false;\n    }\n\n    function resolve(promise, value) {\n      if (promise === value) {\n        fulfill(promise, value);\n      } else if (!handleThenable(promise, value)) {\n        fulfill(promise, value);\n      }\n    }\n\n    function fulfill(promise, value) {\n      if (promise._state !== PENDING) { return; }\n      promise._state = SEALED;\n      promise._detail = value;\n\n      config.async(publishFulfillment, promise);\n    }\n\n    function reject(promise, reason) {\n      if (promise._state !== PENDING) { return; }\n      promise._state = SEALED;\n      promise._detail = reason;\n\n      config.async(publishRejection, promise);\n    }\n\n    function publishFulfillment(promise) {\n      publish(promise, promise._state = FULFILLED);\n    }\n\n    function publishRejection(promise) {\n      publish(promise, promise._state = REJECTED);\n    }\n\n    __exports__.Promise = Promise;\n  });\ndefine(\"promise/race\", \n  [\"./utils\",\"exports\"],\n  function(__dependency1__, __exports__) {\n    \"use strict\";\n    /* global toString */\n    var isArray = __dependency1__.isArray;\n\n    /**\n      `RSVP.race` allows you to watch a series of promises and act as soon as the\n      first promise given to the `promises` argument fulfills or rejects.\n\n      Example:\n\n      ```javascript\n      var promise1 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          resolve(\"promise 1\");\n        }, 200);\n      });\n\n      var promise2 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          resolve(\"promise 2\");\n        }, 100);\n      });\n\n      RSVP.race([promise1, promise2]).then(function(result){\n        // result === \"promise 2\" because it was resolved before promise1\n        // was resolved.\n      });\n      ```\n\n      `RSVP.race` is deterministic in that only the state of the first completed\n      promise matters. For example, even if other promises given to the `promises`\n      array argument are resolved, but the first completed promise has become\n      rejected before the other promises became fulfilled, the returned promise\n      will become rejected:\n\n      ```javascript\n      var promise1 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          resolve(\"promise 1\");\n        }, 200);\n      });\n\n      var promise2 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          reject(new Error(\"promise 2\"));\n        }, 100);\n      });\n\n      RSVP.race([promise1, promise2]).then(function(result){\n        // Code here never runs because there are rejected promises!\n      }, function(reason){\n        // reason.message === \"promise2\" because promise 2 became rejected before\n        // promise 1 became fulfilled\n      });\n      ```\n\n      @method race\n      @for RSVP\n      @param {Array} promises array of promises to observe\n      @param {String} label optional string for describing the promise returned.\n      Useful for tooling.\n      @return {Promise} a promise that becomes fulfilled with the value the first\n      completed promises is resolved with if the first completed promise was\n      fulfilled, or rejected with the reason that the first completed promise\n      was rejected with.\n    */\n    function race(promises) {\n      /*jshint validthis:true */\n      var Promise = this;\n\n      if (!isArray(promises)) {\n        throw new TypeError('You must pass an array to race.');\n      }\n      return new Promise(function(resolve, reject) {\n        var results = [], promise;\n\n        for (var i = 0; i < promises.length; i++) {\n          promise = promises[i];\n\n          if (promise && typeof promise.then === 'function') {\n            promise.then(resolve, reject);\n          } else {\n            resolve(promise);\n          }\n        }\n      });\n    }\n\n    __exports__.race = race;\n  });\ndefine(\"promise/reject\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    /**\n      `RSVP.reject` returns a promise that will become rejected with the passed\n      `reason`. `RSVP.reject` is essentially shorthand for the following:\n\n      ```javascript\n      var promise = new RSVP.Promise(function(resolve, reject){\n        reject(new Error('WHOOPS'));\n      });\n\n      promise.then(function(value){\n        // Code here doesn't run because the promise is rejected!\n      }, function(reason){\n        // reason.message === 'WHOOPS'\n      });\n      ```\n\n      Instead of writing the above, your code now simply becomes the following:\n\n      ```javascript\n      var promise = RSVP.reject(new Error('WHOOPS'));\n\n      promise.then(function(value){\n        // Code here doesn't run because the promise is rejected!\n      }, function(reason){\n        // reason.message === 'WHOOPS'\n      });\n      ```\n\n      @method reject\n      @for RSVP\n      @param {Any} reason value that the returned promise will be rejected with.\n      @param {String} label optional string for identifying the returned promise.\n      Useful for tooling.\n      @return {Promise} a promise that will become rejected with the given\n      `reason`.\n    */\n    function reject(reason) {\n      /*jshint validthis:true */\n      var Promise = this;\n\n      return new Promise(function (resolve, reject) {\n        reject(reason);\n      });\n    }\n\n    __exports__.reject = reject;\n  });\ndefine(\"promise/resolve\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    function resolve(value) {\n      /*jshint validthis:true */\n      if (value && typeof value === 'object' && value.constructor === this) {\n        return value;\n      }\n\n      var Promise = this;\n\n      return new Promise(function(resolve) {\n        resolve(value);\n      });\n    }\n\n    __exports__.resolve = resolve;\n  });\ndefine(\"promise/utils\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    function objectOrFunction(x) {\n      return isFunction(x) || (typeof x === \"object\" && x !== null);\n    }\n\n    function isFunction(x) {\n      return typeof x === \"function\";\n    }\n\n    function isArray(x) {\n      return Object.prototype.toString.call(x) === \"[object Array]\";\n    }\n\n    // Date.now is not available in browsers < IE9\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility\n    var now = Date.now || function() { return new Date().getTime(); };\n\n\n    __exports__.objectOrFunction = objectOrFunction;\n    __exports__.isFunction = isFunction;\n    __exports__.isArray = isArray;\n    __exports__.now = now;\n  });\nrequireModule('promise/polyfill').polyfill();\n}());(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"localforage\"] = factory();\n\telse\n\t\troot[\"localforage\"] = factory();\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }\n\n\t(function () {\n\t    'use strict';\n\n\t    // Custom drivers are stored here when `defineDriver()` is called.\n\t    // They are shared across all instances of localForage.\n\t    var CustomDrivers = {};\n\n\t    var DriverType = {\n\t        INDEXEDDB: 'asyncStorage',\n\t        LOCALSTORAGE: 'localStorageWrapper',\n\t        WEBSQL: 'webSQLStorage'\n\t    };\n\n\t    var DefaultDriverOrder = [DriverType.INDEXEDDB, DriverType.WEBSQL, DriverType.LOCALSTORAGE];\n\n\t    var LibraryMethods = ['clear', 'getItem', 'iterate', 'key', 'keys', 'length', 'removeItem', 'setItem'];\n\n\t    var DefaultConfig = {\n\t        description: '',\n\t        driver: DefaultDriverOrder.slice(),\n\t        name: 'localforage',\n\t        // Default DB size is _JUST UNDER_ 5MB, as it's the highest size\n\t        // we can use without a prompt.\n\t        size: 4980736,\n\t        storeName: 'keyvaluepairs',\n\t        version: 1.0\n\t    };\n\n\t    // Check to see if IndexedDB is available and if it is the latest\n\t    // implementation; it's our preferred backend library. We use \"_spec_test\"\n\t    // as the name of the database because it's not the one we'll operate on,\n\t    // but it's useful to make sure its using the right spec.\n\t    // See: https://github.com/mozilla/localForage/issues/128\n\t    var driverSupport = (function (self) {\n\t        // Initialize IndexedDB; fall back to vendor-prefixed versions\n\t        // if needed.\n\t        var indexedDB = indexedDB || self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.OIndexedDB || self.msIndexedDB;\n\n\t        var result = {};\n\n\t        result[DriverType.WEBSQL] = !!self.openDatabase;\n\t        result[DriverType.INDEXEDDB] = !!(function () {\n\t            // We mimic PouchDB here; just UA test for Safari (which, as of\n\t            // iOS 8/Yosemite, doesn't properly support IndexedDB).\n\t            // IndexedDB support is broken and different from Blink's.\n\t            // This is faster than the test case (and it's sync), so we just\n\t            // do this. *SIGH*\n\t            // http://bl.ocks.org/nolanlawson/raw/c83e9039edf2278047e9/\n\t            //\n\t            // We test for openDatabase because IE Mobile identifies itself\n\t            // as Safari. Oh the lulz...\n\t            if (typeof self.openDatabase !== 'undefined' && self.navigator && self.navigator.userAgent && /Safari/.test(self.navigator.userAgent) && !/Chrome/.test(self.navigator.userAgent)) {\n\t                return false;\n\t            }\n\t            try {\n\t                return indexedDB && typeof indexedDB.open === 'function' &&\n\t                // Some Samsung/HTC Android 4.0-4.3 devices\n\t                // have older IndexedDB specs; if this isn't available\n\t                // their IndexedDB is too old for us to use.\n\t                // (Replaces the onupgradeneeded test.)\n\t                typeof self.IDBKeyRange !== 'undefined';\n\t            } catch (e) {\n\t                return false;\n\t            }\n\t        })();\n\n\t        result[DriverType.LOCALSTORAGE] = !!(function () {\n\t            try {\n\t                return self.localStorage && 'setItem' in self.localStorage && self.localStorage.setItem;\n\t            } catch (e) {\n\t                return false;\n\t            }\n\t        })();\n\n\t        return result;\n\t    })(this);\n\n\t    var isArray = Array.isArray || function (arg) {\n\t        return Object.prototype.toString.call(arg) === '[object Array]';\n\t    };\n\n\t    function callWhenReady(localForageInstance, libraryMethod) {\n\t        localForageInstance[libraryMethod] = function () {\n\t            var _args = arguments;\n\t            return localForageInstance.ready().then(function () {\n\t                return localForageInstance[libraryMethod].apply(localForageInstance, _args);\n\t            });\n\t        };\n\t    }\n\n\t    function extend() {\n\t        for (var i = 1; i < arguments.length; i++) {\n\t            var arg = arguments[i];\n\n\t            if (arg) {\n\t                for (var key in arg) {\n\t                    if (arg.hasOwnProperty(key)) {\n\t                        if (isArray(arg[key])) {\n\t                            arguments[0][key] = arg[key].slice();\n\t                        } else {\n\t                            arguments[0][key] = arg[key];\n\t                        }\n\t                    }\n\t                }\n\t            }\n\t        }\n\n\t        return arguments[0];\n\t    }\n\n\t    function isLibraryDriver(driverName) {\n\t        for (var driver in DriverType) {\n\t            if (DriverType.hasOwnProperty(driver) && DriverType[driver] === driverName) {\n\t                return true;\n\t            }\n\t        }\n\n\t        return false;\n\t    }\n\n\t    var LocalForage = (function () {\n\t        function LocalForage(options) {\n\t            _classCallCheck(this, LocalForage);\n\n\t            this.INDEXEDDB = DriverType.INDEXEDDB;\n\t            this.LOCALSTORAGE = DriverType.LOCALSTORAGE;\n\t            this.WEBSQL = DriverType.WEBSQL;\n\n\t            this._defaultConfig = extend({}, DefaultConfig);\n\t            this._config = extend({}, this._defaultConfig, options);\n\t            this._driverSet = null;\n\t            this._initDriver = null;\n\t            this._ready = false;\n\t            this._dbInfo = null;\n\n\t            this._wrapLibraryMethodsWithReady();\n\t            this.setDriver(this._config.driver);\n\t        }\n\n\t        // The actual localForage object that we expose as a module or via a\n\t        // global. It's extended by pulling in one of our other libraries.\n\n\t        // Set any config values for localForage; can be called anytime before\n\t        // the first API call (e.g. `getItem`, `setItem`).\n\t        // We loop through options so we don't overwrite existing config\n\t        // values.\n\n\t        LocalForage.prototype.config = function config(options) {\n\t            // If the options argument is an object, we use it to set values.\n\t            // Otherwise, we return either a specified config value or all\n\t            // config values.\n\t            if (typeof options === 'object') {\n\t                // If localforage is ready and fully initialized, we can't set\n\t                // any new configuration values. Instead, we return an error.\n\t                if (this._ready) {\n\t                    return new Error(\"Can't call config() after localforage \" + 'has been used.');\n\t                }\n\n\t                for (var i in options) {\n\t                    if (i === 'storeName') {\n\t                        options[i] = options[i].replace(/\\W/g, '_');\n\t                    }\n\n\t                    this._config[i] = options[i];\n\t                }\n\n\t                // after all config options are set and\n\t                // the driver option is used, try setting it\n\t                if ('driver' in options && options.driver) {\n\t                    this.setDriver(this._config.driver);\n\t                }\n\n\t                return true;\n\t            } else if (typeof options === 'string') {\n\t                return this._config[options];\n\t            } else {\n\t                return this._config;\n\t            }\n\t        };\n\n\t        // Used to define a custom driver, shared across all instances of\n\t        // localForage.\n\n\t        LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) {\n\t            var promise = new Promise(function (resolve, reject) {\n\t                try {\n\t                    var driverName = driverObject._driver;\n\t                    var complianceError = new Error('Custom driver not compliant; see ' + 'https://mozilla.github.io/localForage/#definedriver');\n\t                    var namingError = new Error('Custom driver name already in use: ' + driverObject._driver);\n\n\t                    // A driver name should be defined and not overlap with the\n\t                    // library-defined, default drivers.\n\t                    if (!driverObject._driver) {\n\t                        reject(complianceError);\n\t                        return;\n\t                    }\n\t                    if (isLibraryDriver(driverObject._driver)) {\n\t                        reject(namingError);\n\t                        return;\n\t                    }\n\n\t                    var customDriverMethods = LibraryMethods.concat('_initStorage');\n\t                    for (var i = 0; i < customDriverMethods.length; i++) {\n\t                        var customDriverMethod = customDriverMethods[i];\n\t                        if (!customDriverMethod || !driverObject[customDriverMethod] || typeof driverObject[customDriverMethod] !== 'function') {\n\t                            reject(complianceError);\n\t                            return;\n\t                        }\n\t                    }\n\n\t                    var supportPromise = Promise.resolve(true);\n\t                    if ('_support' in driverObject) {\n\t                        if (driverObject._support && typeof driverObject._support === 'function') {\n\t                            supportPromise = driverObject._support();\n\t                        } else {\n\t                            supportPromise = Promise.resolve(!!driverObject._support);\n\t                        }\n\t                    }\n\n\t                    supportPromise.then(function (supportResult) {\n\t                        driverSupport[driverName] = supportResult;\n\t                        CustomDrivers[driverName] = driverObject;\n\t                        resolve();\n\t                    }, reject);\n\t                } catch (e) {\n\t                    reject(e);\n\t                }\n\t            });\n\n\t            promise.then(callback, errorCallback);\n\t            return promise;\n\t        };\n\n\t        LocalForage.prototype.driver = function driver() {\n\t            return this._driver || null;\n\t        };\n\n\t        LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) {\n\t            var self = this;\n\t            var getDriverPromise = (function () {\n\t                if (isLibraryDriver(driverName)) {\n\t                    switch (driverName) {\n\t                        case self.INDEXEDDB:\n\t                            return new Promise(function (resolve, reject) {\n\t                                resolve(__webpack_require__(1));\n\t                            });\n\t                        case self.LOCALSTORAGE:\n\t                            return new Promise(function (resolve, reject) {\n\t                                resolve(__webpack_require__(2));\n\t                            });\n\t                        case self.WEBSQL:\n\t                            return new Promise(function (resolve, reject) {\n\t                                resolve(__webpack_require__(4));\n\t                            });\n\t                    }\n\t                } else if (CustomDrivers[driverName]) {\n\t                    return Promise.resolve(CustomDrivers[driverName]);\n\t                }\n\n\t                return Promise.reject(new Error('Driver not found.'));\n\t            })();\n\n\t            getDriverPromise.then(callback, errorCallback);\n\t            return getDriverPromise;\n\t        };\n\n\t        LocalForage.prototype.getSerializer = function getSerializer(callback) {\n\t            var serializerPromise = new Promise(function (resolve, reject) {\n\t                resolve(__webpack_require__(3));\n\t            });\n\t            if (callback && typeof callback === 'function') {\n\t                serializerPromise.then(function (result) {\n\t                    callback(result);\n\t                });\n\t            }\n\t            return serializerPromise;\n\t        };\n\n\t        LocalForage.prototype.ready = function ready(callback) {\n\t            var self = this;\n\n\t            var promise = self._driverSet.then(function () {\n\t                if (self._ready === null) {\n\t                    self._ready = self._initDriver();\n\t                }\n\n\t                return self._ready;\n\t            });\n\n\t            promise.then(callback, callback);\n\t            return promise;\n\t        };\n\n\t        LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) {\n\t            var self = this;\n\n\t            if (!isArray(drivers)) {\n\t                drivers = [drivers];\n\t            }\n\n\t            var supportedDrivers = this._getSupportedDrivers(drivers);\n\n\t            function setDriverToConfig() {\n\t                self._config.driver = self.driver();\n\t            }\n\n\t            function initDriver(supportedDrivers) {\n\t                return function () {\n\t                    var currentDriverIndex = 0;\n\n\t                    function driverPromiseLoop() {\n\t                        while (currentDriverIndex < supportedDrivers.length) {\n\t                            var driverName = supportedDrivers[currentDriverIndex];\n\t                            currentDriverIndex++;\n\n\t                            self._dbInfo = null;\n\t                            self._ready = null;\n\n\t                            return self.getDriver(driverName).then(function (driver) {\n\t                                self._extend(driver);\n\t                                setDriverToConfig();\n\n\t                                self._ready = self._initStorage(self._config);\n\t                                return self._ready;\n\t                            })['catch'](driverPromiseLoop);\n\t                        }\n\n\t                        setDriverToConfig();\n\t                        var error = new Error('No available storage method found.');\n\t                        self._driverSet = Promise.reject(error);\n\t                        return self._driverSet;\n\t                    }\n\n\t                    return driverPromiseLoop();\n\t                };\n\t            }\n\n\t            // There might be a driver initialization in progress\n\t            // so wait for it to finish in order to avoid a possible\n\t            // race condition to set _dbInfo\n\t            var oldDriverSetDone = this._driverSet !== null ? this._driverSet['catch'](function () {\n\t                return Promise.resolve();\n\t            }) : Promise.resolve();\n\n\t            this._driverSet = oldDriverSetDone.then(function () {\n\t                var driverName = supportedDrivers[0];\n\t                self._dbInfo = null;\n\t                self._ready = null;\n\n\t                return self.getDriver(driverName).then(function (driver) {\n\t                    self._driver = driver._driver;\n\t                    setDriverToConfig();\n\t                    self._wrapLibraryMethodsWithReady();\n\t                    self._initDriver = initDriver(supportedDrivers);\n\t                });\n\t            })['catch'](function () {\n\t                setDriverToConfig();\n\t                var error = new Error('No available storage method found.');\n\t                self._driverSet = Promise.reject(error);\n\t                return self._driverSet;\n\t            });\n\n\t            this._driverSet.then(callback, errorCallback);\n\t            return this._driverSet;\n\t        };\n\n\t        LocalForage.prototype.supports = function supports(driverName) {\n\t            return !!driverSupport[driverName];\n\t        };\n\n\t        LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) {\n\t            extend(this, libraryMethodsAndProperties);\n\t        };\n\n\t        LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) {\n\t            var supportedDrivers = [];\n\t            for (var i = 0, len = drivers.length; i < len; i++) {\n\t                var driverName = drivers[i];\n\t                if (this.supports(driverName)) {\n\t                    supportedDrivers.push(driverName);\n\t                }\n\t            }\n\t            return supportedDrivers;\n\t        };\n\n\t        LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() {\n\t            // Add a stub for each driver API method that delays the call to the\n\t            // corresponding driver method until localForage is ready. These stubs\n\t            // will be replaced by the driver methods as soon as the driver is\n\t            // loaded, so there is no performance impact.\n\t            for (var i = 0; i < LibraryMethods.length; i++) {\n\t                callWhenReady(this, LibraryMethods[i]);\n\t            }\n\t        };\n\n\t        LocalForage.prototype.createInstance = function createInstance(options) {\n\t            return new LocalForage(options);\n\t        };\n\n\t        return LocalForage;\n\t    })();\n\n\t    var localForage = new LocalForage();\n\n\t    exports['default'] = localForage;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t// Some code originally from async_storage.js in\n\t// [Gaia](https://github.com/mozilla-b2g/gaia).\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    var globalObject = this;\n\t    // Initialize IndexedDB; fall back to vendor-prefixed versions if needed.\n\t    var indexedDB = indexedDB || this.indexedDB || this.webkitIndexedDB || this.mozIndexedDB || this.OIndexedDB || this.msIndexedDB;\n\n\t    // If IndexedDB isn't available, we get outta here!\n\t    if (!indexedDB) {\n\t        return;\n\t    }\n\n\t    var DETECT_BLOB_SUPPORT_STORE = 'local-forage-detect-blob-support';\n\t    var supportsBlobs;\n\t    var dbContexts;\n\n\t    // Abstracts constructing a Blob object, so it also works in older\n\t    // browsers that don't support the native Blob constructor. (i.e.\n\t    // old QtWebKit versions, at least).\n\t    function _createBlob(parts, properties) {\n\t        parts = parts || [];\n\t        properties = properties || {};\n\t        try {\n\t            return new Blob(parts, properties);\n\t        } catch (e) {\n\t            if (e.name !== 'TypeError') {\n\t                throw e;\n\t            }\n\t            var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;\n\t            var builder = new BlobBuilder();\n\t            for (var i = 0; i < parts.length; i += 1) {\n\t                builder.append(parts[i]);\n\t            }\n\t            return builder.getBlob(properties.type);\n\t        }\n\t    }\n\n\t    // Transform a binary string to an array buffer, because otherwise\n\t    // weird stuff happens when you try to work with the binary string directly.\n\t    // It is known.\n\t    // From http://stackoverflow.com/questions/14967647/ (continues on next line)\n\t    // encode-decode-image-with-base64-breaks-image (2013-04-21)\n\t    function _binStringToArrayBuffer(bin) {\n\t        var length = bin.length;\n\t        var buf = new ArrayBuffer(length);\n\t        var arr = new Uint8Array(buf);\n\t        for (var i = 0; i < length; i++) {\n\t            arr[i] = bin.charCodeAt(i);\n\t        }\n\t        return buf;\n\t    }\n\n\t    // Fetch a blob using ajax. This reveals bugs in Chrome < 43.\n\t    // For details on all this junk:\n\t    // https://github.com/nolanlawson/state-of-binary-data-in-the-browser#readme\n\t    function _blobAjax(url) {\n\t        return new Promise(function (resolve, reject) {\n\t            var xhr = new XMLHttpRequest();\n\t            xhr.open('GET', url);\n\t            xhr.withCredentials = true;\n\t            xhr.responseType = 'arraybuffer';\n\n\t            xhr.onreadystatechange = function () {\n\t                if (xhr.readyState !== 4) {\n\t                    return;\n\t                }\n\t                if (xhr.status === 200) {\n\t                    return resolve({\n\t                        response: xhr.response,\n\t                        type: xhr.getResponseHeader('Content-Type')\n\t                    });\n\t                }\n\t                reject({ status: xhr.status, response: xhr.response });\n\t            };\n\t            xhr.send();\n\t        });\n\t    }\n\n\t    //\n\t    // Detect blob support. Chrome didn't support it until version 38.\n\t    // In version 37 they had a broken version where PNGs (and possibly\n\t    // other binary types) aren't stored correctly, because when you fetch\n\t    // them, the content type is always null.\n\t    //\n\t    // Furthermore, they have some outstanding bugs where blobs occasionally\n\t    // are read by FileReader as null, or by ajax as 404s.\n\t    //\n\t    // Sadly we use the 404 bug to detect the FileReader bug, so if they\n\t    // get fixed independently and released in different versions of Chrome,\n\t    // then the bug could come back. So it's worthwhile to watch these issues:\n\t    // 404 bug: https://code.google.com/p/chromium/issues/detail?id=447916\n\t    // FileReader bug: https://code.google.com/p/chromium/issues/detail?id=447836\n\t    //\n\t    function _checkBlobSupportWithoutCaching(idb) {\n\t        return new Promise(function (resolve, reject) {\n\t            var blob = _createBlob([''], { type: 'image/png' });\n\t            var txn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');\n\t            txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key');\n\t            txn.oncomplete = function () {\n\t                // have to do it in a separate transaction, else the correct\n\t                // content type is always returned\n\t                var blobTxn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');\n\t                var getBlobReq = blobTxn.objectStore(DETECT_BLOB_SUPPORT_STORE).get('key');\n\t                getBlobReq.onerror = reject;\n\t                getBlobReq.onsuccess = function (e) {\n\n\t                    var storedBlob = e.target.result;\n\t                    var url = URL.createObjectURL(storedBlob);\n\n\t                    _blobAjax(url).then(function (res) {\n\t                        resolve(!!(res && res.type === 'image/png'));\n\t                    }, function () {\n\t                        resolve(false);\n\t                    }).then(function () {\n\t                        URL.revokeObjectURL(url);\n\t                    });\n\t                };\n\t            };\n\t        })['catch'](function () {\n\t            return false; // error, so assume unsupported\n\t        });\n\t    }\n\n\t    function _checkBlobSupport(idb) {\n\t        if (typeof supportsBlobs === 'boolean') {\n\t            return Promise.resolve(supportsBlobs);\n\t        }\n\t        return _checkBlobSupportWithoutCaching(idb).then(function (value) {\n\t            supportsBlobs = value;\n\t            return supportsBlobs;\n\t        });\n\t    }\n\n\t    // encode a blob for indexeddb engines that don't support blobs\n\t    function _encodeBlob(blob) {\n\t        return new Promise(function (resolve, reject) {\n\t            var reader = new FileReader();\n\t            reader.onerror = reject;\n\t            reader.onloadend = function (e) {\n\t                var base64 = btoa(e.target.result || '');\n\t                resolve({\n\t                    __local_forage_encoded_blob: true,\n\t                    data: base64,\n\t                    type: blob.type\n\t                });\n\t            };\n\t            reader.readAsBinaryString(blob);\n\t        });\n\t    }\n\n\t    // decode an encoded blob\n\t    function _decodeBlob(encodedBlob) {\n\t        var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));\n\t        return _createBlob([arrayBuff], { type: encodedBlob.type });\n\t    }\n\n\t    // is this one of our fancy encoded blobs?\n\t    function _isEncodedBlob(value) {\n\t        return value && value.__local_forage_encoded_blob;\n\t    }\n\n\t    // Open the IndexedDB database (automatically creates one if one didn't\n\t    // previously exist), using any options set in the config.\n\t    function _initStorage(options) {\n\t        var self = this;\n\t        var dbInfo = {\n\t            db: null\n\t        };\n\n\t        if (options) {\n\t            for (var i in options) {\n\t                dbInfo[i] = options[i];\n\t            }\n\t        }\n\n\t        // Initialize a singleton container for all running localForages.\n\t        if (!dbContexts) {\n\t            dbContexts = {};\n\t        }\n\n\t        // Get the current context of the database;\n\t        var dbContext = dbContexts[dbInfo.name];\n\n\t        // ...or create a new context.\n\t        if (!dbContext) {\n\t            dbContext = {\n\t                // Running localForages sharing a database.\n\t                forages: [],\n\t                // Shared database.\n\t                db: null\n\t            };\n\t            // Register the new context in the global container.\n\t            dbContexts[dbInfo.name] = dbContext;\n\t        }\n\n\t        // Register itself as a running localForage in the current context.\n\t        dbContext.forages.push(this);\n\n\t        // Create an array of readiness of the related localForages.\n\t        var readyPromises = [];\n\n\t        function ignoreErrors() {\n\t            // Don't handle errors here,\n\t            // just makes sure related localForages aren't pending.\n\t            return Promise.resolve();\n\t        }\n\n\t        for (var j = 0; j < dbContext.forages.length; j++) {\n\t            var forage = dbContext.forages[j];\n\t            if (forage !== this) {\n\t                // Don't wait for itself...\n\t                readyPromises.push(forage.ready()['catch'](ignoreErrors));\n\t            }\n\t        }\n\n\t        // Take a snapshot of the related localForages.\n\t        var forages = dbContext.forages.slice(0);\n\n\t        // Initialize the connection process only when\n\t        // all the related localForages aren't pending.\n\t        return Promise.all(readyPromises).then(function () {\n\t            dbInfo.db = dbContext.db;\n\t            // Get the connection or open a new one without upgrade.\n\t            return _getOriginalConnection(dbInfo);\n\t        }).then(function (db) {\n\t            dbInfo.db = db;\n\t            if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) {\n\t                // Reopen the database for upgrading.\n\t                return _getUpgradedConnection(dbInfo);\n\t            }\n\t            return db;\n\t        }).then(function (db) {\n\t            dbInfo.db = dbContext.db = db;\n\t            self._dbInfo = dbInfo;\n\t            // Share the final connection amongst related localForages.\n\t            for (var k in forages) {\n\t                var forage = forages[k];\n\t                if (forage !== self) {\n\t                    // Self is already up-to-date.\n\t                    forage._dbInfo.db = dbInfo.db;\n\t                    forage._dbInfo.version = dbInfo.version;\n\t                }\n\t            }\n\t        });\n\t    }\n\n\t    function _getOriginalConnection(dbInfo) {\n\t        return _getConnection(dbInfo, false);\n\t    }\n\n\t    function _getUpgradedConnection(dbInfo) {\n\t        return _getConnection(dbInfo, true);\n\t    }\n\n\t    function _getConnection(dbInfo, upgradeNeeded) {\n\t        return new Promise(function (resolve, reject) {\n\t            if (dbInfo.db) {\n\t                if (upgradeNeeded) {\n\t                    dbInfo.db.close();\n\t                } else {\n\t                    return resolve(dbInfo.db);\n\t                }\n\t            }\n\n\t            var dbArgs = [dbInfo.name];\n\n\t            if (upgradeNeeded) {\n\t                dbArgs.push(dbInfo.version);\n\t            }\n\n\t            var openreq = indexedDB.open.apply(indexedDB, dbArgs);\n\n\t            if (upgradeNeeded) {\n\t                openreq.onupgradeneeded = function (e) {\n\t                    var db = openreq.result;\n\t                    try {\n\t                        db.createObjectStore(dbInfo.storeName);\n\t                        if (e.oldVersion <= 1) {\n\t                            // Added when support for blob shims was added\n\t                            db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);\n\t                        }\n\t                    } catch (ex) {\n\t                        if (ex.name === 'ConstraintError') {\n\t                            globalObject.console.warn('The database \"' + dbInfo.name + '\"' + ' has been upgraded from version ' + e.oldVersion + ' to version ' + e.newVersion + ', but the storage \"' + dbInfo.storeName + '\" already exists.');\n\t                        } else {\n\t                            throw ex;\n\t                        }\n\t                    }\n\t                };\n\t            }\n\n\t            openreq.onerror = function () {\n\t                reject(openreq.error);\n\t            };\n\n\t            openreq.onsuccess = function () {\n\t                resolve(openreq.result);\n\t            };\n\t        });\n\t    }\n\n\t    function _isUpgradeNeeded(dbInfo, defaultVersion) {\n\t        if (!dbInfo.db) {\n\t            return true;\n\t        }\n\n\t        var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);\n\t        var isDowngrade = dbInfo.version < dbInfo.db.version;\n\t        var isUpgrade = dbInfo.version > dbInfo.db.version;\n\n\t        if (isDowngrade) {\n\t            // If the version is not the default one\n\t            // then warn for impossible downgrade.\n\t            if (dbInfo.version !== defaultVersion) {\n\t                globalObject.console.warn('The database \"' + dbInfo.name + '\"' + ' can\\'t be downgraded from version ' + dbInfo.db.version + ' to version ' + dbInfo.version + '.');\n\t            }\n\t            // Align the versions to prevent errors.\n\t            dbInfo.version = dbInfo.db.version;\n\t        }\n\n\t        if (isUpgrade || isNewStore) {\n\t            // If the store is new then increment the version (if needed).\n\t            // This will trigger an \"upgradeneeded\" event which is required\n\t            // for creating a store.\n\t            if (isNewStore) {\n\t                var incVersion = dbInfo.db.version + 1;\n\t                if (incVersion > dbInfo.version) {\n\t                    dbInfo.version = incVersion;\n\t                }\n\t            }\n\n\t            return true;\n\t        }\n\n\t        return false;\n\t    }\n\n\t    function getItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\t                var req = store.get(key);\n\n\t                req.onsuccess = function () {\n\t                    var value = req.result;\n\t                    if (value === undefined) {\n\t                        value = null;\n\t                    }\n\t                    if (_isEncodedBlob(value)) {\n\t                        value = _decodeBlob(value);\n\t                    }\n\t                    resolve(value);\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Iterate over all items stored in database.\n\t    function iterate(iterator, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\n\t                var req = store.openCursor();\n\t                var iterationNumber = 1;\n\n\t                req.onsuccess = function () {\n\t                    var cursor = req.result;\n\n\t                    if (cursor) {\n\t                        var value = cursor.value;\n\t                        if (_isEncodedBlob(value)) {\n\t                            value = _decodeBlob(value);\n\t                        }\n\t                        var result = iterator(value, cursor.key, iterationNumber++);\n\n\t                        if (result !== void 0) {\n\t                            resolve(result);\n\t                        } else {\n\t                            cursor['continue']();\n\t                        }\n\t                    } else {\n\t                        resolve();\n\t                    }\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\n\t        return promise;\n\t    }\n\n\t    function setItem(key, value, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            var dbInfo;\n\t            self.ready().then(function () {\n\t                dbInfo = self._dbInfo;\n\t                return _checkBlobSupport(dbInfo.db);\n\t            }).then(function (blobSupport) {\n\t                if (!blobSupport && value instanceof Blob) {\n\t                    return _encodeBlob(value);\n\t                }\n\t                return value;\n\t            }).then(function (value) {\n\t                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');\n\t                var store = transaction.objectStore(dbInfo.storeName);\n\n\t                // The reason we don't _save_ null is because IE 10 does\n\t                // not support saving the `null` type in IndexedDB. How\n\t                // ironic, given the bug below!\n\t                // See: https://github.com/mozilla/localForage/issues/161\n\t                if (value === null) {\n\t                    value = undefined;\n\t                }\n\n\t                var req = store.put(value, key);\n\t                transaction.oncomplete = function () {\n\t                    // Cast to undefined so the value passed to\n\t                    // callback/promise is the same as what one would get out\n\t                    // of `getItem()` later. This leads to some weirdness\n\t                    // (setItem('foo', undefined) will return `null`), but\n\t                    // it's not my fault localStorage is our baseline and that\n\t                    // it's weird.\n\t                    if (value === undefined) {\n\t                        value = null;\n\t                    }\n\n\t                    resolve(value);\n\t                };\n\t                transaction.onabort = transaction.onerror = function () {\n\t                    var err = req.error ? req.error : req.transaction.error;\n\t                    reject(err);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function removeItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');\n\t                var store = transaction.objectStore(dbInfo.storeName);\n\n\t                // We use a Grunt task to make this safe for IE and some\n\t                // versions of Android (including those used by Cordova).\n\t                // Normally IE won't like `.delete()` and will insist on\n\t                // using `['delete']()`, but we have a build step that\n\t                // fixes this for us now.\n\t                var req = store['delete'](key);\n\t                transaction.oncomplete = function () {\n\t                    resolve();\n\t                };\n\n\t                transaction.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\n\t                // The request will be also be aborted if we've exceeded our storage\n\t                // space.\n\t                transaction.onabort = function () {\n\t                    var err = req.error ? req.error : req.transaction.error;\n\t                    reject(err);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function clear(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');\n\t                var store = transaction.objectStore(dbInfo.storeName);\n\t                var req = store.clear();\n\n\t                transaction.oncomplete = function () {\n\t                    resolve();\n\t                };\n\n\t                transaction.onabort = transaction.onerror = function () {\n\t                    var err = req.error ? req.error : req.transaction.error;\n\t                    reject(err);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function length(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\t                var req = store.count();\n\n\t                req.onsuccess = function () {\n\t                    resolve(req.result);\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function key(n, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            if (n < 0) {\n\t                resolve(null);\n\n\t                return;\n\t            }\n\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\n\t                var advanced = false;\n\t                var req = store.openCursor();\n\t                req.onsuccess = function () {\n\t                    var cursor = req.result;\n\t                    if (!cursor) {\n\t                        // this means there weren't enough keys\n\t                        resolve(null);\n\n\t                        return;\n\t                    }\n\n\t                    if (n === 0) {\n\t                        // We have the first key, return it if that's what they\n\t                        // wanted.\n\t                        resolve(cursor.key);\n\t                    } else {\n\t                        if (!advanced) {\n\t                            // Otherwise, ask the cursor to skip ahead n\n\t                            // records.\n\t                            advanced = true;\n\t                            cursor.advance(n);\n\t                        } else {\n\t                            // When we get here, we've got the nth key.\n\t                            resolve(cursor.key);\n\t                        }\n\t                    }\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function keys(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\n\t                var req = store.openCursor();\n\t                var keys = [];\n\n\t                req.onsuccess = function () {\n\t                    var cursor = req.result;\n\n\t                    if (!cursor) {\n\t                        resolve(keys);\n\t                        return;\n\t                    }\n\n\t                    keys.push(cursor.key);\n\t                    cursor['continue']();\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function executeCallback(promise, callback) {\n\t        if (callback) {\n\t            promise.then(function (result) {\n\t                callback(null, result);\n\t            }, function (error) {\n\t                callback(error);\n\t            });\n\t        }\n\t    }\n\n\t    var asyncStorage = {\n\t        _driver: 'asyncStorage',\n\t        _initStorage: _initStorage,\n\t        iterate: iterate,\n\t        getItem: getItem,\n\t        setItem: setItem,\n\t        removeItem: removeItem,\n\t        clear: clear,\n\t        length: length,\n\t        key: key,\n\t        keys: keys\n\t    };\n\n\t    exports['default'] = asyncStorage;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 2 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t// If IndexedDB isn't available, we'll fall back to localStorage.\n\t// Note that this will have considerable performance and storage\n\t// side-effects (all data will be serialized on save and only data that\n\t// can be converted to a string via `JSON.stringify()` will be saved).\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    var globalObject = this;\n\t    var localStorage = null;\n\n\t    // If the app is running inside a Google Chrome packaged webapp, or some\n\t    // other context where localStorage isn't available, we don't use\n\t    // localStorage. This feature detection is preferred over the old\n\t    // `if (window.chrome && window.chrome.runtime)` code.\n\t    // See: https://github.com/mozilla/localForage/issues/68\n\t    try {\n\t        // If localStorage isn't available, we get outta here!\n\t        // This should be inside a try catch\n\t        if (!this.localStorage || !('setItem' in this.localStorage)) {\n\t            return;\n\t        }\n\t        // Initialize localStorage and create a variable to use throughout\n\t        // the code.\n\t        localStorage = this.localStorage;\n\t    } catch (e) {\n\t        return;\n\t    }\n\n\t    // Config the localStorage backend, using options set in the config.\n\t    function _initStorage(options) {\n\t        var self = this;\n\t        var dbInfo = {};\n\t        if (options) {\n\t            for (var i in options) {\n\t                dbInfo[i] = options[i];\n\t            }\n\t        }\n\n\t        dbInfo.keyPrefix = dbInfo.name + '/';\n\n\t        if (dbInfo.storeName !== self._defaultConfig.storeName) {\n\t            dbInfo.keyPrefix += dbInfo.storeName + '/';\n\t        }\n\n\t        self._dbInfo = dbInfo;\n\n\t        return new Promise(function (resolve, reject) {\n\t            resolve(__webpack_require__(3));\n\t        }).then(function (lib) {\n\t            dbInfo.serializer = lib;\n\t            return Promise.resolve();\n\t        });\n\t    }\n\n\t    // Remove all keys from the datastore, effectively destroying all data in\n\t    // the app's key/value store!\n\t    function clear(callback) {\n\t        var self = this;\n\t        var promise = self.ready().then(function () {\n\t            var keyPrefix = self._dbInfo.keyPrefix;\n\n\t            for (var i = localStorage.length - 1; i >= 0; i--) {\n\t                var key = localStorage.key(i);\n\n\t                if (key.indexOf(keyPrefix) === 0) {\n\t                    localStorage.removeItem(key);\n\t                }\n\t            }\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Retrieve an item from the store. Unlike the original async_storage\n\t    // library in Gaia, we don't modify return values at all. If a key's value\n\t    // is `undefined`, we pass that value to the callback function.\n\t    function getItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var result = localStorage.getItem(dbInfo.keyPrefix + key);\n\n\t            // If a result was found, parse it from the serialized\n\t            // string into a JS object. If result isn't truthy, the key\n\t            // is likely undefined and we'll pass it straight to the\n\t            // callback.\n\t            if (result) {\n\t                result = dbInfo.serializer.deserialize(result);\n\t            }\n\n\t            return result;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Iterate over all items in the store.\n\t    function iterate(iterator, callback) {\n\t        var self = this;\n\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var keyPrefix = dbInfo.keyPrefix;\n\t            var keyPrefixLength = keyPrefix.length;\n\t            var length = localStorage.length;\n\n\t            // We use a dedicated iterator instead of the `i` variable below\n\t            // so other keys we fetch in localStorage aren't counted in\n\t            // the `iterationNumber` argument passed to the `iterate()`\n\t            // callback.\n\t            //\n\t            // See: github.com/mozilla/localForage/pull/435#discussion_r38061530\n\t            var iterationNumber = 1;\n\n\t            for (var i = 0; i < length; i++) {\n\t                var key = localStorage.key(i);\n\t                if (key.indexOf(keyPrefix) !== 0) {\n\t                    continue;\n\t                }\n\t                var value = localStorage.getItem(key);\n\n\t                // If a result was found, parse it from the serialized\n\t                // string into a JS object. If result isn't truthy, the\n\t                // key is likely undefined and we'll pass it straight\n\t                // to the iterator.\n\t                if (value) {\n\t                    value = dbInfo.serializer.deserialize(value);\n\t                }\n\n\t                value = iterator(value, key.substring(keyPrefixLength), iterationNumber++);\n\n\t                if (value !== void 0) {\n\t                    return value;\n\t                }\n\t            }\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Same as localStorage's key() method, except takes a callback.\n\t    function key(n, callback) {\n\t        var self = this;\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var result;\n\t            try {\n\t                result = localStorage.key(n);\n\t            } catch (error) {\n\t                result = null;\n\t            }\n\n\t            // Remove the prefix from the key, if a key is found.\n\t            if (result) {\n\t                result = result.substring(dbInfo.keyPrefix.length);\n\t            }\n\n\t            return result;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function keys(callback) {\n\t        var self = this;\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var length = localStorage.length;\n\t            var keys = [];\n\n\t            for (var i = 0; i < length; i++) {\n\t                if (localStorage.key(i).indexOf(dbInfo.keyPrefix) === 0) {\n\t                    keys.push(localStorage.key(i).substring(dbInfo.keyPrefix.length));\n\t                }\n\t            }\n\n\t            return keys;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Supply the number of keys in the datastore to the callback function.\n\t    function length(callback) {\n\t        var self = this;\n\t        var promise = self.keys().then(function (keys) {\n\t            return keys.length;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Remove an item from the store, nice and simple.\n\t    function removeItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            localStorage.removeItem(dbInfo.keyPrefix + key);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Set a key's value and run an optional callback once the value is set.\n\t    // Unlike Gaia's implementation, the callback function is passed the value,\n\t    // in case you want to operate on that value only after you're sure it\n\t    // saved, or something like that.\n\t    function setItem(key, value, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = self.ready().then(function () {\n\t            // Convert undefined values to null.\n\t            // https://github.com/mozilla/localForage/pull/42\n\t            if (value === undefined) {\n\t                value = null;\n\t            }\n\n\t            // Save the original value to pass to the callback.\n\t            var originalValue = value;\n\n\t            return new Promise(function (resolve, reject) {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.serializer.serialize(value, function (value, error) {\n\t                    if (error) {\n\t                        reject(error);\n\t                    } else {\n\t                        try {\n\t                            localStorage.setItem(dbInfo.keyPrefix + key, value);\n\t                            resolve(originalValue);\n\t                        } catch (e) {\n\t                            // localStorage capacity exceeded.\n\t                            // TODO: Make this a specific error/event.\n\t                            if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {\n\t                                reject(e);\n\t                            }\n\t                            reject(e);\n\t                        }\n\t                    }\n\t                });\n\t            });\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function executeCallback(promise, callback) {\n\t        if (callback) {\n\t            promise.then(function (result) {\n\t                callback(null, result);\n\t            }, function (error) {\n\t                callback(error);\n\t            });\n\t        }\n\t    }\n\n\t    var localStorageWrapper = {\n\t        _driver: 'localStorageWrapper',\n\t        _initStorage: _initStorage,\n\t        // Default API, from Gaia/localStorage.\n\t        iterate: iterate,\n\t        getItem: getItem,\n\t        setItem: setItem,\n\t        removeItem: removeItem,\n\t        clear: clear,\n\t        length: length,\n\t        key: key,\n\t        keys: keys\n\t    };\n\n\t    exports['default'] = localStorageWrapper;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    // Sadly, the best way to save binary data in WebSQL/localStorage is serializing\n\t    // it to Base64, so this is how we store it to prevent very strange errors with less\n\t    // verbose ways of binary <-> string data storage.\n\t    var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n\t    var BLOB_TYPE_PREFIX = '~~local_forage_type~';\n\t    var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;\n\n\t    var SERIALIZED_MARKER = '__lfsc__:';\n\t    var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;\n\n\t    // OMG the serializations!\n\t    var TYPE_ARRAYBUFFER = 'arbf';\n\t    var TYPE_BLOB = 'blob';\n\t    var TYPE_INT8ARRAY = 'si08';\n\t    var TYPE_UINT8ARRAY = 'ui08';\n\t    var TYPE_UINT8CLAMPEDARRAY = 'uic8';\n\t    var TYPE_INT16ARRAY = 'si16';\n\t    var TYPE_INT32ARRAY = 'si32';\n\t    var TYPE_UINT16ARRAY = 'ur16';\n\t    var TYPE_UINT32ARRAY = 'ui32';\n\t    var TYPE_FLOAT32ARRAY = 'fl32';\n\t    var TYPE_FLOAT64ARRAY = 'fl64';\n\t    var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;\n\n\t    // Get out of our habit of using `window` inline, at least.\n\t    var globalObject = this;\n\n\t    // Abstracts constructing a Blob object, so it also works in older\n\t    // browsers that don't support the native Blob constructor. (i.e.\n\t    // old QtWebKit versions, at least).\n\t    function _createBlob(parts, properties) {\n\t        parts = parts || [];\n\t        properties = properties || {};\n\n\t        try {\n\t            return new Blob(parts, properties);\n\t        } catch (err) {\n\t            if (err.name !== 'TypeError') {\n\t                throw err;\n\t            }\n\n\t            var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;\n\n\t            var builder = new BlobBuilder();\n\t            for (var i = 0; i < parts.length; i += 1) {\n\t                builder.append(parts[i]);\n\t            }\n\n\t            return builder.getBlob(properties.type);\n\t        }\n\t    }\n\n\t    // Serialize a value, afterwards executing a callback (which usually\n\t    // instructs the `setItem()` callback/promise to be executed). This is how\n\t    // we store binary data with localStorage.\n\t    function serialize(value, callback) {\n\t        var valueString = '';\n\t        if (value) {\n\t            valueString = value.toString();\n\t        }\n\n\t        // Cannot use `value instanceof ArrayBuffer` or such here, as these\n\t        // checks fail when running the tests using casper.js...\n\t        //\n\t        // TODO: See why those tests fail and use a better solution.\n\t        if (value && (value.toString() === '[object ArrayBuffer]' || value.buffer && value.buffer.toString() === '[object ArrayBuffer]')) {\n\t            // Convert binary arrays to a string and prefix the string with\n\t            // a special marker.\n\t            var buffer;\n\t            var marker = SERIALIZED_MARKER;\n\n\t            if (value instanceof ArrayBuffer) {\n\t                buffer = value;\n\t                marker += TYPE_ARRAYBUFFER;\n\t            } else {\n\t                buffer = value.buffer;\n\n\t                if (valueString === '[object Int8Array]') {\n\t                    marker += TYPE_INT8ARRAY;\n\t                } else if (valueString === '[object Uint8Array]') {\n\t                    marker += TYPE_UINT8ARRAY;\n\t                } else if (valueString === '[object Uint8ClampedArray]') {\n\t                    marker += TYPE_UINT8CLAMPEDARRAY;\n\t                } else if (valueString === '[object Int16Array]') {\n\t                    marker += TYPE_INT16ARRAY;\n\t                } else if (valueString === '[object Uint16Array]') {\n\t                    marker += TYPE_UINT16ARRAY;\n\t                } else if (valueString === '[object Int32Array]') {\n\t                    marker += TYPE_INT32ARRAY;\n\t                } else if (valueString === '[object Uint32Array]') {\n\t                    marker += TYPE_UINT32ARRAY;\n\t                } else if (valueString === '[object Float32Array]') {\n\t                    marker += TYPE_FLOAT32ARRAY;\n\t                } else if (valueString === '[object Float64Array]') {\n\t                    marker += TYPE_FLOAT64ARRAY;\n\t                } else {\n\t                    callback(new Error('Failed to get type for BinaryArray'));\n\t                }\n\t            }\n\n\t            callback(marker + bufferToString(buffer));\n\t        } else if (valueString === '[object Blob]') {\n\t            // Conver the blob to a binaryArray and then to a string.\n\t            var fileReader = new FileReader();\n\n\t            fileReader.onload = function () {\n\t                // Backwards-compatible prefix for the blob type.\n\t                var str = BLOB_TYPE_PREFIX + value.type + '~' + bufferToString(this.result);\n\n\t                callback(SERIALIZED_MARKER + TYPE_BLOB + str);\n\t            };\n\n\t            fileReader.readAsArrayBuffer(value);\n\t        } else {\n\t            try {\n\t                callback(JSON.stringify(value));\n\t            } catch (e) {\n\t                console.error(\"Couldn't convert value into a JSON string: \", value);\n\n\t                callback(null, e);\n\t            }\n\t        }\n\t    }\n\n\t    // Deserialize data we've inserted into a value column/field. We place\n\t    // special markers into our strings to mark them as encoded; this isn't\n\t    // as nice as a meta field, but it's the only sane thing we can do whilst\n\t    // keeping localStorage support intact.\n\t    //\n\t    // Oftentimes this will just deserialize JSON content, but if we have a\n\t    // special marker (SERIALIZED_MARKER, defined above), we will extract\n\t    // some kind of arraybuffer/binary data/typed array out of the string.\n\t    function deserialize(value) {\n\t        // If we haven't marked this string as being specially serialized (i.e.\n\t        // something other than serialized JSON), we can just return it and be\n\t        // done with it.\n\t        if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {\n\t            return JSON.parse(value);\n\t        }\n\n\t        // The following code deals with deserializing some kind of Blob or\n\t        // TypedArray. First we separate out the type of data we're dealing\n\t        // with from the data itself.\n\t        var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);\n\t        var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);\n\n\t        var blobType;\n\t        // Backwards-compatible blob type serialization strategy.\n\t        // DBs created with older versions of localForage will simply not have the blob type.\n\t        if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {\n\t            var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);\n\t            blobType = matcher[1];\n\t            serializedString = serializedString.substring(matcher[0].length);\n\t        }\n\t        var buffer = stringToBuffer(serializedString);\n\n\t        // Return the right type based on the code/type set during\n\t        // serialization.\n\t        switch (type) {\n\t            case TYPE_ARRAYBUFFER:\n\t                return buffer;\n\t            case TYPE_BLOB:\n\t                return _createBlob([buffer], { type: blobType });\n\t            case TYPE_INT8ARRAY:\n\t                return new Int8Array(buffer);\n\t            case TYPE_UINT8ARRAY:\n\t                return new Uint8Array(buffer);\n\t            case TYPE_UINT8CLAMPEDARRAY:\n\t                return new Uint8ClampedArray(buffer);\n\t            case TYPE_INT16ARRAY:\n\t                return new Int16Array(buffer);\n\t            case TYPE_UINT16ARRAY:\n\t                return new Uint16Array(buffer);\n\t            case TYPE_INT32ARRAY:\n\t                return new Int32Array(buffer);\n\t            case TYPE_UINT32ARRAY:\n\t                return new Uint32Array(buffer);\n\t            case TYPE_FLOAT32ARRAY:\n\t                return new Float32Array(buffer);\n\t            case TYPE_FLOAT64ARRAY:\n\t                return new Float64Array(buffer);\n\t            default:\n\t                throw new Error('Unkown type: ' + type);\n\t        }\n\t    }\n\n\t    function stringToBuffer(serializedString) {\n\t        // Fill the string into a ArrayBuffer.\n\t        var bufferLength = serializedString.length * 0.75;\n\t        var len = serializedString.length;\n\t        var i;\n\t        var p = 0;\n\t        var encoded1, encoded2, encoded3, encoded4;\n\n\t        if (serializedString[serializedString.length - 1] === '=') {\n\t            bufferLength--;\n\t            if (serializedString[serializedString.length - 2] === '=') {\n\t                bufferLength--;\n\t            }\n\t        }\n\n\t        var buffer = new ArrayBuffer(bufferLength);\n\t        var bytes = new Uint8Array(buffer);\n\n\t        for (i = 0; i < len; i += 4) {\n\t            encoded1 = BASE_CHARS.indexOf(serializedString[i]);\n\t            encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);\n\t            encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);\n\t            encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);\n\n\t            /*jslint bitwise: true */\n\t            bytes[p++] = encoded1 << 2 | encoded2 >> 4;\n\t            bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;\n\t            bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;\n\t        }\n\t        return buffer;\n\t    }\n\n\t    // Converts a buffer to a string to store, serialized, in the backend\n\t    // storage library.\n\t    function bufferToString(buffer) {\n\t        // base64-arraybuffer\n\t        var bytes = new Uint8Array(buffer);\n\t        var base64String = '';\n\t        var i;\n\n\t        for (i = 0; i < bytes.length; i += 3) {\n\t            /*jslint bitwise: true */\n\t            base64String += BASE_CHARS[bytes[i] >> 2];\n\t            base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];\n\t            base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];\n\t            base64String += BASE_CHARS[bytes[i + 2] & 63];\n\t        }\n\n\t        if (bytes.length % 3 === 2) {\n\t            base64String = base64String.substring(0, base64String.length - 1) + '=';\n\t        } else if (bytes.length % 3 === 1) {\n\t            base64String = base64String.substring(0, base64String.length - 2) + '==';\n\t        }\n\n\t        return base64String;\n\t    }\n\n\t    var localforageSerializer = {\n\t        serialize: serialize,\n\t        deserialize: deserialize,\n\t        stringToBuffer: stringToBuffer,\n\t        bufferToString: bufferToString\n\t    };\n\n\t    exports['default'] = localforageSerializer;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 4 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t/*\n\t * Includes code from:\n\t *\n\t * base64-arraybuffer\n\t * https://github.com/niklasvh/base64-arraybuffer\n\t *\n\t * Copyright (c) 2012 Niklas von Hertzen\n\t * Licensed under the MIT license.\n\t */\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    var globalObject = this;\n\t    var openDatabase = this.openDatabase;\n\n\t    // If WebSQL methods aren't available, we can stop now.\n\t    if (!openDatabase) {\n\t        return;\n\t    }\n\n\t    // Open the WebSQL database (automatically creates one if one didn't\n\t    // previously exist), using any options set in the config.\n\t    function _initStorage(options) {\n\t        var self = this;\n\t        var dbInfo = {\n\t            db: null\n\t        };\n\n\t        if (options) {\n\t            for (var i in options) {\n\t                dbInfo[i] = typeof options[i] !== 'string' ? options[i].toString() : options[i];\n\t            }\n\t        }\n\n\t        var dbInfoPromise = new Promise(function (resolve, reject) {\n\t            // Open the database; the openDatabase API will automatically\n\t            // create it for us if it doesn't exist.\n\t            try {\n\t                dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size);\n\t            } catch (e) {\n\t                return self.setDriver(self.LOCALSTORAGE).then(function () {\n\t                    return self._initStorage(options);\n\t                }).then(resolve)['catch'](reject);\n\t            }\n\n\t            // Create our key/value table if it doesn't exist.\n\t            dbInfo.db.transaction(function (t) {\n\t                t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName + ' (id INTEGER PRIMARY KEY, key unique, value)', [], function () {\n\t                    self._dbInfo = dbInfo;\n\t                    resolve();\n\t                }, function (t, error) {\n\t                    reject(error);\n\t                });\n\t            });\n\t        });\n\n\t        return new Promise(function (resolve, reject) {\n\t            resolve(__webpack_require__(3));\n\t        }).then(function (lib) {\n\t            dbInfo.serializer = lib;\n\t            return dbInfoPromise;\n\t        });\n\t    }\n\n\t    function getItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT * FROM ' + dbInfo.storeName + ' WHERE key = ? LIMIT 1', [key], function (t, results) {\n\t                        var result = results.rows.length ? results.rows.item(0).value : null;\n\n\t                        // Check to see if this is serialized content we need to\n\t                        // unpack.\n\t                        if (result) {\n\t                            result = dbInfo.serializer.deserialize(result);\n\t                        }\n\n\t                        resolve(result);\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function iterate(iterator, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT * FROM ' + dbInfo.storeName, [], function (t, results) {\n\t                        var rows = results.rows;\n\t                        var length = rows.length;\n\n\t                        for (var i = 0; i < length; i++) {\n\t                            var item = rows.item(i);\n\t                            var result = item.value;\n\n\t                            // Check to see if this is serialized content\n\t                            // we need to unpack.\n\t                            if (result) {\n\t                                result = dbInfo.serializer.deserialize(result);\n\t                            }\n\n\t                            result = iterator(result, item.key, i + 1);\n\n\t                            // void(0) prevents problems with redefinition\n\t                            // of `undefined`.\n\t                            if (result !== void 0) {\n\t                                resolve(result);\n\t                                return;\n\t                            }\n\t                        }\n\n\t                        resolve();\n\t                    }, function (t, error) {\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function setItem(key, value, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                // The localStorage API doesn't return undefined values in an\n\t                // \"expected\" way, so undefined is always cast to null in all\n\t                // drivers. See: https://github.com/mozilla/localForage/pull/42\n\t                if (value === undefined) {\n\t                    value = null;\n\t                }\n\n\t                // Save the original value to pass to the callback.\n\t                var originalValue = value;\n\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.serializer.serialize(value, function (value, error) {\n\t                    if (error) {\n\t                        reject(error);\n\t                    } else {\n\t                        dbInfo.db.transaction(function (t) {\n\t                            t.executeSql('INSERT OR REPLACE INTO ' + dbInfo.storeName + ' (key, value) VALUES (?, ?)', [key, value], function () {\n\t                                resolve(originalValue);\n\t                            }, function (t, error) {\n\t                                reject(error);\n\t                            });\n\t                        }, function (sqlError) {\n\t                            // The transaction failed; check\n\t                            // to see if it's a quota error.\n\t                            if (sqlError.code === sqlError.QUOTA_ERR) {\n\t                                // We reject the callback outright for now, but\n\t                                // it's worth trying to re-run the transaction.\n\t                                // Even if the user accepts the prompt to use\n\t                                // more storage on Safari, this error will\n\t                                // be called.\n\t                                //\n\t                                // TODO: Try to re-run the transaction.\n\t                                reject(sqlError);\n\t                            }\n\t                        });\n\t                    }\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function removeItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('DELETE FROM ' + dbInfo.storeName + ' WHERE key = ?', [key], function () {\n\t                        resolve();\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Deletes every item in the table.\n\t    // TODO: Find out if this resets the AUTO_INCREMENT number.\n\t    function clear(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('DELETE FROM ' + dbInfo.storeName, [], function () {\n\t                        resolve();\n\t                    }, function (t, error) {\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Does a simple `COUNT(key)` to get the number of items stored in\n\t    // localForage.\n\t    function length(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    // Ahhh, SQL makes this one soooooo easy.\n\t                    t.executeSql('SELECT COUNT(key) as c FROM ' + dbInfo.storeName, [], function (t, results) {\n\t                        var result = results.rows.item(0).c;\n\n\t                        resolve(result);\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Return the key located at key index X; essentially gets the key from a\n\t    // `WHERE id = ?`. This is the most efficient way I can think to implement\n\t    // this rarely-used (in my experience) part of the API, but it can seem\n\t    // inconsistent, because we do `INSERT OR REPLACE INTO` on `setItem()`, so\n\t    // the ID of each key will change every time it's updated. Perhaps a stored\n\t    // procedure for the `setItem()` SQL would solve this problem?\n\t    // TODO: Don't change ID on `setItem()`.\n\t    function key(n, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT key FROM ' + dbInfo.storeName + ' WHERE id = ? LIMIT 1', [n + 1], function (t, results) {\n\t                        var result = results.rows.length ? results.rows.item(0).key : null;\n\t                        resolve(result);\n\t                    }, function (t, error) {\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function keys(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT key FROM ' + dbInfo.storeName, [], function (t, results) {\n\t                        var keys = [];\n\n\t                        for (var i = 0; i < results.rows.length; i++) {\n\t                            keys.push(results.rows.item(i).key);\n\t                        }\n\n\t                        resolve(keys);\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function executeCallback(promise, callback) {\n\t        if (callback) {\n\t            promise.then(function (result) {\n\t                callback(null, result);\n\t            }, function (error) {\n\t                callback(error);\n\t            });\n\t        }\n\t    }\n\n\t    var webSQLStorage = {\n\t        _driver: 'webSQLStorage',\n\t        _initStorage: _initStorage,\n\t        iterate: iterate,\n\t        getItem: getItem,\n\t        setItem: setItem,\n\t        removeItem: removeItem,\n\t        clear: clear,\n\t        length: length,\n\t        key: key,\n\t        keys: keys\n\t    };\n\n\t    exports['default'] = webSQLStorage;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ }\n/******/ ])\n});\n;\n},{\"__browserify_process\":4}],19:[function(require,module,exports){\n//     Underscore.js 1.4.4\n//     http://underscorejs.org\n//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.\n//     Underscore may be freely distributed under the MIT license.\n\n(function() {\n\n  // Baseline setup\n  // --------------\n\n  // Establish the root object, `window` in the browser, or `global` on the server.\n  var root = this;\n\n  // Save the previous value of the `_` variable.\n  var previousUnderscore = root._;\n\n  // Establish the object that gets returned to break out of a loop iteration.\n  var breaker = {};\n\n  // Save bytes in the minified (but not gzipped) version:\n  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;\n\n  // Create quick reference variables for speed access to core prototypes.\n  var push             = ArrayProto.push,\n      slice            = ArrayProto.slice,\n      concat           = ArrayProto.concat,\n      toString         = ObjProto.toString,\n      hasOwnProperty   = ObjProto.hasOwnProperty;\n\n  // All **ECMAScript 5** native function implementations that we hope to use\n  // are declared here.\n  var\n    nativeForEach      = ArrayProto.forEach,\n    nativeMap          = ArrayProto.map,\n    nativeReduce       = ArrayProto.reduce,\n    nativeReduceRight  = ArrayProto.reduceRight,\n    nativeFilter       = ArrayProto.filter,\n    nativeEvery        = ArrayProto.every,\n    nativeSome         = ArrayProto.some,\n    nativeIndexOf      = ArrayProto.indexOf,\n    nativeLastIndexOf  = ArrayProto.lastIndexOf,\n    nativeIsArray      = Array.isArray,\n    nativeKeys         = Object.keys,\n    nativeBind         = FuncProto.bind;\n\n  // Create a safe reference to the Underscore object for use below.\n  var _ = function(obj) {\n    if (obj instanceof _) return obj;\n    if (!(this instanceof _)) return new _(obj);\n    this._wrapped = obj;\n  };\n\n  // Export the Underscore object for **Node.js**, with\n  // backwards-compatibility for the old `require()` API. If we're in\n  // the browser, add `_` as a global object via a string identifier,\n  // for Closure Compiler \"advanced\" mode.\n  if (typeof exports !== 'undefined') {\n    if (typeof module !== 'undefined' && module.exports) {\n      exports = module.exports = _;\n    }\n    exports._ = _;\n  } else {\n    root._ = _;\n  }\n\n  // Current version.\n  _.VERSION = '1.4.4';\n\n  // Collection Functions\n  // --------------------\n\n  // The cornerstone, an `each` implementation, aka `forEach`.\n  // Handles objects with the built-in `forEach`, arrays, and raw objects.\n  // Delegates to **ECMAScript 5**'s native `forEach` if available.\n  var each = _.each = _.forEach = function(obj, iterator, context) {\n    if (obj == null) return;\n    if (nativeForEach && obj.forEach === nativeForEach) {\n      obj.forEach(iterator, context);\n    } else if (obj.length === +obj.length) {\n      for (var i = 0, l = obj.length; i < l; i++) {\n        if (iterator.call(context, obj[i], i, obj) === breaker) return;\n      }\n    } else {\n      for (var key in obj) {\n        if (_.has(obj, key)) {\n          if (iterator.call(context, obj[key], key, obj) === breaker) return;\n        }\n      }\n    }\n  };\n\n  // Return the results of applying the iterator to each element.\n  // Delegates to **ECMAScript 5**'s native `map` if available.\n  _.map = _.collect = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n    each(obj, function(value, index, list) {\n      results[results.length] = iterator.call(context, value, index, list);\n    });\n    return results;\n  };\n\n  var reduceError = 'Reduce of empty array with no initial value';\n\n  // **Reduce** builds up a single result from a list of values, aka `inject`,\n  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.\n  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduce && obj.reduce === nativeReduce) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n    }\n    each(obj, function(value, index, list) {\n      if (!initial) {\n        memo = value;\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, value, index, list);\n      }\n    });\n    if (!initial) throw new TypeError(reduceError);\n    return memo;\n  };\n\n  // The right-associative version of reduce, also known as `foldr`.\n  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n    var initial = arguments.length > 2;\n    if (obj == null) obj = [];\n    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n      if (context) iterator = _.bind(iterator, context);\n      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n    }\n    var length = obj.length;\n    if (length !== +length) {\n      var keys = _.keys(obj);\n      length = keys.length;\n    }\n    each(obj, function(value, index, list) {\n      index = keys ? keys[--length] : --length;\n      if (!initial) {\n        memo = obj[index];\n        initial = true;\n      } else {\n        memo = iterator.call(context, memo, obj[index], index, list);\n      }\n    });\n    if (!initial) throw new TypeError(reduceError);\n    return memo;\n  };\n\n  // Return the first value which passes a truth test. Aliased as `detect`.\n  _.find = _.detect = function(obj, iterator, context) {\n    var result;\n    any(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) {\n        result = value;\n        return true;\n      }\n    });\n    return result;\n  };\n\n  // Return all the elements that pass a truth test.\n  // Delegates to **ECMAScript 5**'s native `filter` if available.\n  // Aliased as `select`.\n  _.filter = _.select = function(obj, iterator, context) {\n    var results = [];\n    if (obj == null) return results;\n    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n    each(obj, function(value, index, list) {\n      if (iterator.call(context, value, index, list)) results[results.length] = value;\n    });\n    return results;\n  };\n\n  // Return all the elements for which a truth test fails.\n  _.reject = function(obj, iterator, context) {\n    return _.filter(obj, function(value, index, list) {\n      return !iterator.call(context, value, index, list);\n    }, context);\n  };\n\n  // Determine whether all of the elements match a truth test.\n  // Delegates to **ECMAScript 5**'s native `every` if available.\n  // Aliased as `all`.\n  _.every = _.all = function(obj, iterator, context) {\n    iterator || (iterator = _.identity);\n    var result = true;\n    if (obj == null) return result;\n    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n    each(obj, function(value, index, list) {\n      if (!(result = result && iterator.call(context, value, index, list))) return breaker;\n    });\n    return !!result;\n  };\n\n  // Determine if at least one element in the object matches a truth test.\n  // Delegates to **ECMAScript 5**'s native `some` if available.\n  // Aliased as `any`.\n  var any = _.some = _.any = function(obj, iterator, context) {\n    iterator || (iterator = _.identity);\n    var result = false;\n    if (obj == null) return result;\n    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n    each(obj, function(value, index, list) {\n      if (result || (result = iterator.call(context, value, index, list))) return breaker;\n    });\n    return !!result;\n  };\n\n  // Determine if the array or object contains a given value (using `===`).\n  // Aliased as `include`.\n  _.contains = _.include = function(obj, target) {\n    if (obj == null) return false;\n    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n    return any(obj, function(value) {\n      return value === target;\n    });\n  };\n\n  // Invoke a method (with arguments) on every item in a collection.\n  _.invoke = function(obj, method) {\n    var args = slice.call(arguments, 2);\n    var isFunc = _.isFunction(method);\n    return _.map(obj, function(value) {\n      return (isFunc ? method : value[method]).apply(value, args);\n    });\n  };\n\n  // Convenience version of a common use case of `map`: fetching a property.\n  _.pluck = function(obj, key) {\n    return _.map(obj, function(value){ return value[key]; });\n  };\n\n  // Convenience version of a common use case of `filter`: selecting only objects\n  // containing specific `key:value` pairs.\n  _.where = function(obj, attrs, first) {\n    if (_.isEmpty(attrs)) return first ? null : [];\n    return _[first ? 'find' : 'filter'](obj, function(value) {\n      for (var key in attrs) {\n        if (attrs[key] !== value[key]) return false;\n      }\n      return true;\n    });\n  };\n\n  // Convenience version of a common use case of `find`: getting the first object\n  // containing specific `key:value` pairs.\n  _.findWhere = function(obj, attrs) {\n    return _.where(obj, attrs, true);\n  };\n\n  // Return the maximum element or (element-based computation).\n  // Can't optimize arrays of integers longer than 65,535 elements.\n  // See: https://bugs.webkit.org/show_bug.cgi?id=80797\n  _.max = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n      return Math.max.apply(Math, obj);\n    }\n    if (!iterator && _.isEmpty(obj)) return -Infinity;\n    var result = {computed : -Infinity, value: -Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed >= result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Return the minimum element (or element-based computation).\n  _.min = function(obj, iterator, context) {\n    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n      return Math.min.apply(Math, obj);\n    }\n    if (!iterator && _.isEmpty(obj)) return Infinity;\n    var result = {computed : Infinity, value: Infinity};\n    each(obj, function(value, index, list) {\n      var computed = iterator ? iterator.call(context, value, index, list) : value;\n      computed < result.computed && (result = {value : value, computed : computed});\n    });\n    return result.value;\n  };\n\n  // Shuffle an array.\n  _.shuffle = function(obj) {\n    var rand;\n    var index = 0;\n    var shuffled = [];\n    each(obj, function(value) {\n      rand = _.random(index++);\n      shuffled[index - 1] = shuffled[rand];\n      shuffled[rand] = value;\n    });\n    return shuffled;\n  };\n\n  // An internal function to generate lookup iterators.\n  var lookupIterator = function(value) {\n    return _.isFunction(value) ? value : function(obj){ return obj[value]; };\n  };\n\n  // Sort the object's values by a criterion produced by an iterator.\n  _.sortBy = function(obj, value, context) {\n    var iterator = lookupIterator(value);\n    return _.pluck(_.map(obj, function(value, index, list) {\n      return {\n        value : value,\n        index : index,\n        criteria : iterator.call(context, value, index, list)\n      };\n    }).sort(function(left, right) {\n      var a = left.criteria;\n      var b = right.criteria;\n      if (a !== b) {\n        if (a > b || a === void 0) return 1;\n        if (a < b || b === void 0) return -1;\n      }\n      return left.index < right.index ? -1 : 1;\n    }), 'value');\n  };\n\n  // An internal function used for aggregate \"group by\" operations.\n  var group = function(obj, value, context, behavior) {\n    var result = {};\n    var iterator = lookupIterator(value || _.identity);\n    each(obj, function(value, index) {\n      var key = iterator.call(context, value, index, obj);\n      behavior(result, key, value);\n    });\n    return result;\n  };\n\n  // Groups the object's values by a criterion. Pass either a string attribute\n  // to group by, or a function that returns the criterion.\n  _.groupBy = function(obj, value, context) {\n    return group(obj, value, context, function(result, key, value) {\n      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);\n    });\n  };\n\n  // Counts instances of an object that group by a certain criterion. Pass\n  // either a string attribute to count by, or a function that returns the\n  // criterion.\n  _.countBy = function(obj, value, context) {\n    return group(obj, value, context, function(result, key) {\n      if (!_.has(result, key)) result[key] = 0;\n      result[key]++;\n    });\n  };\n\n  // Use a comparator function to figure out the smallest index at which\n  // an object should be inserted so as to maintain order. Uses binary search.\n  _.sortedIndex = function(array, obj, iterator, context) {\n    iterator = iterator == null ? _.identity : lookupIterator(iterator);\n    var value = iterator.call(context, obj);\n    var low = 0, high = array.length;\n    while (low < high) {\n      var mid = (low + high) >>> 1;\n      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;\n    }\n    return low;\n  };\n\n  // Safely convert anything iterable into a real, live array.\n  _.toArray = function(obj) {\n    if (!obj) return [];\n    if (_.isArray(obj)) return slice.call(obj);\n    if (obj.length === +obj.length) return _.map(obj, _.identity);\n    return _.values(obj);\n  };\n\n  // Return the number of elements in an object.\n  _.size = function(obj) {\n    if (obj == null) return 0;\n    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;\n  };\n\n  // Array Functions\n  // ---------------\n\n  // Get the first element of an array. Passing **n** will return the first N\n  // values in the array. Aliased as `head` and `take`. The **guard** check\n  // allows it to work with `_.map`.\n  _.first = _.head = _.take = function(array, n, guard) {\n    if (array == null) return void 0;\n    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];\n  };\n\n  // Returns everything but the last entry of the array. Especially useful on\n  // the arguments object. Passing **n** will return all the values in\n  // the array, excluding the last N. The **guard** check allows it to work with\n  // `_.map`.\n  _.initial = function(array, n, guard) {\n    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));\n  };\n\n  // Get the last element of an array. Passing **n** will return the last N\n  // values in the array. The **guard** check allows it to work with `_.map`.\n  _.last = function(array, n, guard) {\n    if (array == null) return void 0;\n    if ((n != null) && !guard) {\n      return slice.call(array, Math.max(array.length - n, 0));\n    } else {\n      return array[array.length - 1];\n    }\n  };\n\n  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.\n  // Especially useful on the arguments object. Passing an **n** will return\n  // the rest N values in the array. The **guard**\n  // check allows it to work with `_.map`.\n  _.rest = _.tail = _.drop = function(array, n, guard) {\n    return slice.call(array, (n == null) || guard ? 1 : n);\n  };\n\n  // Trim out all falsy values from an array.\n  _.compact = function(array) {\n    return _.filter(array, _.identity);\n  };\n\n  // Internal implementation of a recursive `flatten` function.\n  var flatten = function(input, shallow, output) {\n    each(input, function(value) {\n      if (_.isArray(value)) {\n        shallow ? push.apply(output, value) : flatten(value, shallow, output);\n      } else {\n        output.push(value);\n      }\n    });\n    return output;\n  };\n\n  // Return a completely flattened version of an array.\n  _.flatten = function(array, shallow) {\n    return flatten(array, shallow, []);\n  };\n\n  // Return a version of the array that does not contain the specified value(s).\n  _.without = function(array) {\n    return _.difference(array, slice.call(arguments, 1));\n  };\n\n  // Produce a duplicate-free version of the array. If the array has already\n  // been sorted, you have the option of using a faster algorithm.\n  // Aliased as `unique`.\n  _.uniq = _.unique = function(array, isSorted, iterator, context) {\n    if (_.isFunction(isSorted)) {\n      context = iterator;\n      iterator = isSorted;\n      isSorted = false;\n    }\n    var initial = iterator ? _.map(array, iterator, context) : array;\n    var results = [];\n    var seen = [];\n    each(initial, function(value, index) {\n      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {\n        seen.push(value);\n        results.push(array[index]);\n      }\n    });\n    return results;\n  };\n\n  // Produce an array that contains the union: each distinct element from all of\n  // the passed-in arrays.\n  _.union = function() {\n    return _.uniq(concat.apply(ArrayProto, arguments));\n  };\n\n  // Produce an array that contains every item shared between all the\n  // passed-in arrays.\n  _.intersection = function(array) {\n    var rest = slice.call(arguments, 1);\n    return _.filter(_.uniq(array), function(item) {\n      return _.every(rest, function(other) {\n        return _.indexOf(other, item) >= 0;\n      });\n    });\n  };\n\n  // Take the difference between one array and a number of other arrays.\n  // Only the elements present in just the first array will remain.\n  _.difference = function(array) {\n    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));\n    return _.filter(array, function(value){ return !_.contains(rest, value); });\n  };\n\n  // Zip together multiple lists into a single array -- elements that share\n  // an index go together.\n  _.zip = function() {\n    var args = slice.call(arguments);\n    var length = _.max(_.pluck(args, 'length'));\n    var results = new Array(length);\n    for (var i = 0; i < length; i++) {\n      results[i] = _.pluck(args, \"\" + i);\n    }\n    return results;\n  };\n\n  // Converts lists into objects. Pass either a single array of `[key, value]`\n  // pairs, or two parallel arrays of the same length -- one of keys, and one of\n  // the corresponding values.\n  _.object = function(list, values) {\n    if (list == null) return {};\n    var result = {};\n    for (var i = 0, l = list.length; i < l; i++) {\n      if (values) {\n        result[list[i]] = values[i];\n      } else {\n        result[list[i][0]] = list[i][1];\n      }\n    }\n    return result;\n  };\n\n  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n  // we need this function. Return the position of the first occurrence of an\n  // item in an array, or -1 if the item is not included in the array.\n  // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n  // If the array is large and already in sort order, pass `true`\n  // for **isSorted** to use binary search.\n  _.indexOf = function(array, item, isSorted) {\n    if (array == null) return -1;\n    var i = 0, l = array.length;\n    if (isSorted) {\n      if (typeof isSorted == 'number') {\n        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);\n      } else {\n        i = _.sortedIndex(array, item);\n        return array[i] === item ? i : -1;\n      }\n    }\n    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);\n    for (; i < l; i++) if (array[i] === item) return i;\n    return -1;\n  };\n\n  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n  _.lastIndexOf = function(array, item, from) {\n    if (array == null) return -1;\n    var hasIndex = from != null;\n    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {\n      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);\n    }\n    var i = (hasIndex ? from : array.length);\n    while (i--) if (array[i] === item) return i;\n    return -1;\n  };\n\n  // Generate an integer Array containing an arithmetic progression. A port of\n  // the native Python `range()` function. See\n  // [the Python documentation](http://docs.python.org/library/functions.html#range).\n  _.range = function(start, stop, step) {\n    if (arguments.length <= 1) {\n      stop = start || 0;\n      start = 0;\n    }\n    step = arguments[2] || 1;\n\n    var len = Math.max(Math.ceil((stop - start) / step), 0);\n    var idx = 0;\n    var range = new Array(len);\n\n    while(idx < len) {\n      range[idx++] = start;\n      start += step;\n    }\n\n    return range;\n  };\n\n  // Function (ahem) Functions\n  // ------------------\n\n  // Create a function bound to a given object (assigning `this`, and arguments,\n  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if\n  // available.\n  _.bind = function(func, context) {\n    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n    var args = slice.call(arguments, 2);\n    return function() {\n      return func.apply(context, args.concat(slice.call(arguments)));\n    };\n  };\n\n  // Partially apply a function by creating a version that has had some of its\n  // arguments pre-filled, without changing its dynamic `this` context.\n  _.partial = function(func) {\n    var args = slice.call(arguments, 1);\n    return function() {\n      return func.apply(this, args.concat(slice.call(arguments)));\n    };\n  };\n\n  // Bind all of an object's methods to that object. Useful for ensuring that\n  // all callbacks defined on an object belong to it.\n  _.bindAll = function(obj) {\n    var funcs = slice.call(arguments, 1);\n    if (funcs.length === 0) funcs = _.functions(obj);\n    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n    return obj;\n  };\n\n  // Memoize an expensive function by storing its results.\n  _.memoize = function(func, hasher) {\n    var memo = {};\n    hasher || (hasher = _.identity);\n    return function() {\n      var key = hasher.apply(this, arguments);\n      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));\n    };\n  };\n\n  // Delays a function for the given number of milliseconds, and then calls\n  // it with the arguments supplied.\n  _.delay = function(func, wait) {\n    var args = slice.call(arguments, 2);\n    return setTimeout(function(){ return func.apply(null, args); }, wait);\n  };\n\n  // Defers a function, scheduling it to run after the current call stack has\n  // cleared.\n  _.defer = function(func) {\n    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n  };\n\n  // Returns a function, that, when invoked, will only be triggered at most once\n  // during a given window of time.\n  _.throttle = function(func, wait) {\n    var context, args, timeout, result;\n    var previous = 0;\n    var later = function() {\n      previous = new Date;\n      timeout = null;\n      result = func.apply(context, args);\n    };\n    return function() {\n      var now = new Date;\n      var remaining = wait - (now - previous);\n      context = this;\n      args = arguments;\n      if (remaining <= 0) {\n        clearTimeout(timeout);\n        timeout = null;\n        previous = now;\n        result = func.apply(context, args);\n      } else if (!timeout) {\n        timeout = setTimeout(later, remaining);\n      }\n      return result;\n    };\n  };\n\n  // Returns a function, that, as long as it continues to be invoked, will not\n  // be triggered. The function will be called after it stops being called for\n  // N milliseconds. If `immediate` is passed, trigger the function on the\n  // leading edge, instead of the trailing.\n  _.debounce = function(func, wait, immediate) {\n    var timeout, result;\n    return function() {\n      var context = this, args = arguments;\n      var later = function() {\n        timeout = null;\n        if (!immediate) result = func.apply(context, args);\n      };\n      var callNow = immediate && !timeout;\n      clearTimeout(timeout);\n      timeout = setTimeout(later, wait);\n      if (callNow) result = func.apply(context, args);\n      return result;\n    };\n  };\n\n  // Returns a function that will be executed at most one time, no matter how\n  // often you call it. Useful for lazy initialization.\n  _.once = function(func) {\n    var ran = false, memo;\n    return function() {\n      if (ran) return memo;\n      ran = true;\n      memo = func.apply(this, arguments);\n      func = null;\n      return memo;\n    };\n  };\n\n  // Returns the first function passed as an argument to the second,\n  // allowing you to adjust arguments, run code before and after, and\n  // conditionally execute the original function.\n  _.wrap = function(func, wrapper) {\n    return function() {\n      var args = [func];\n      push.apply(args, arguments);\n      return wrapper.apply(this, args);\n    };\n  };\n\n  // Returns a function that is the composition of a list of functions, each\n  // consuming the return value of the function that follows.\n  _.compose = function() {\n    var funcs = arguments;\n    return function() {\n      var args = arguments;\n      for (var i = funcs.length - 1; i >= 0; i--) {\n        args = [funcs[i].apply(this, args)];\n      }\n      return args[0];\n    };\n  };\n\n  // Returns a function that will only be executed after being called N times.\n  _.after = function(times, func) {\n    if (times <= 0) return func();\n    return function() {\n      if (--times < 1) {\n        return func.apply(this, arguments);\n      }\n    };\n  };\n\n  // Object Functions\n  // ----------------\n\n  // Retrieve the names of an object's properties.\n  // Delegates to **ECMAScript 5**'s native `Object.keys`\n  _.keys = nativeKeys || function(obj) {\n    if (obj !== Object(obj)) throw new TypeError('Invalid object');\n    var keys = [];\n    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;\n    return keys;\n  };\n\n  // Retrieve the values of an object's properties.\n  _.values = function(obj) {\n    var values = [];\n    for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);\n    return values;\n  };\n\n  // Convert an object into a list of `[key, value]` pairs.\n  _.pairs = function(obj) {\n    var pairs = [];\n    for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);\n    return pairs;\n  };\n\n  // Invert the keys and values of an object. The values must be serializable.\n  _.invert = function(obj) {\n    var result = {};\n    for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;\n    return result;\n  };\n\n  // Return a sorted list of the function names available on the object.\n  // Aliased as `methods`\n  _.functions = _.methods = function(obj) {\n    var names = [];\n    for (var key in obj) {\n      if (_.isFunction(obj[key])) names.push(key);\n    }\n    return names.sort();\n  };\n\n  // Extend a given object with all the properties in passed-in object(s).\n  _.extend = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      if (source) {\n        for (var prop in source) {\n          obj[prop] = source[prop];\n        }\n      }\n    });\n    return obj;\n  };\n\n  // Return a copy of the object only containing the whitelisted properties.\n  _.pick = function(obj) {\n    var copy = {};\n    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n    each(keys, function(key) {\n      if (key in obj) copy[key] = obj[key];\n    });\n    return copy;\n  };\n\n   // Return a copy of the object without the blacklisted properties.\n  _.omit = function(obj) {\n    var copy = {};\n    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n    for (var key in obj) {\n      if (!_.contains(keys, key)) copy[key] = obj[key];\n    }\n    return copy;\n  };\n\n  // Fill in a given object with default properties.\n  _.defaults = function(obj) {\n    each(slice.call(arguments, 1), function(source) {\n      if (source) {\n        for (var prop in source) {\n          if (obj[prop] == null) obj[prop] = source[prop];\n        }\n      }\n    });\n    return obj;\n  };\n\n  // Create a (shallow-cloned) duplicate of an object.\n  _.clone = function(obj) {\n    if (!_.isObject(obj)) return obj;\n    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n  };\n\n  // Invokes interceptor with the obj, and then returns obj.\n  // The primary purpose of this method is to \"tap into\" a method chain, in\n  // order to perform operations on intermediate results within the chain.\n  _.tap = function(obj, interceptor) {\n    interceptor(obj);\n    return obj;\n  };\n\n  // Internal recursive comparison function for `isEqual`.\n  var eq = function(a, b, aStack, bStack) {\n    // Identical objects are equal. `0 === -0`, but they aren't identical.\n    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.\n    if (a === b) return a !== 0 || 1 / a == 1 / b;\n    // A strict comparison is necessary because `null == undefined`.\n    if (a == null || b == null) return a === b;\n    // Unwrap any wrapped objects.\n    if (a instanceof _) a = a._wrapped;\n    if (b instanceof _) b = b._wrapped;\n    // Compare `[[Class]]` names.\n    var className = toString.call(a);\n    if (className != toString.call(b)) return false;\n    switch (className) {\n      // Strings, numbers, dates, and booleans are compared by value.\n      case '[object String]':\n        // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n        // equivalent to `new String(\"5\")`.\n        return a == String(b);\n      case '[object Number]':\n        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for\n        // other numeric values.\n        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);\n      case '[object Date]':\n      case '[object Boolean]':\n        // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n        // millisecond representations. Note that invalid dates with millisecond representations\n        // of `NaN` are not equivalent.\n        return +a == +b;\n      // RegExps are compared by their source patterns and flags.\n      case '[object RegExp]':\n        return a.source == b.source &&\n               a.global == b.global &&\n               a.multiline == b.multiline &&\n               a.ignoreCase == b.ignoreCase;\n    }\n    if (typeof a != 'object' || typeof b != 'object') return false;\n    // Assume equality for cyclic structures. The algorithm for detecting cyclic\n    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n    var length = aStack.length;\n    while (length--) {\n      // Linear search. Performance is inversely proportional to the number of\n      // unique nested structures.\n      if (aStack[length] == a) return bStack[length] == b;\n    }\n    // Add the first object to the stack of traversed objects.\n    aStack.push(a);\n    bStack.push(b);\n    var size = 0, result = true;\n    // Recursively compare objects and arrays.\n    if (className == '[object Array]') {\n      // Compare array lengths to determine if a deep comparison is necessary.\n      size = a.length;\n      result = size == b.length;\n      if (result) {\n        // Deep compare the contents, ignoring non-numeric properties.\n        while (size--) {\n          if (!(result = eq(a[size], b[size], aStack, bStack))) break;\n        }\n      }\n    } else {\n      // Objects with different constructors are not equivalent, but `Object`s\n      // from different frames are.\n      var aCtor = a.constructor, bCtor = b.constructor;\n      if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&\n                               _.isFunction(bCtor) && (bCtor instanceof bCtor))) {\n        return false;\n      }\n      // Deep compare objects.\n      for (var key in a) {\n        if (_.has(a, key)) {\n          // Count the expected number of properties.\n          size++;\n          // Deep compare each member.\n          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;\n        }\n      }\n      // Ensure that both objects contain the same number of properties.\n      if (result) {\n        for (key in b) {\n          if (_.has(b, key) && !(size--)) break;\n        }\n        result = !size;\n      }\n    }\n    // Remove the first object from the stack of traversed objects.\n    aStack.pop();\n    bStack.pop();\n    return result;\n  };\n\n  // Perform a deep comparison to check if two objects are equal.\n  _.isEqual = function(a, b) {\n    return eq(a, b, [], []);\n  };\n\n  // Is a given array, string, or object empty?\n  // An \"empty\" object has no enumerable own-properties.\n  _.isEmpty = function(obj) {\n    if (obj == null) return true;\n    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n    for (var key in obj) if (_.has(obj, key)) return false;\n    return true;\n  };\n\n  // Is a given value a DOM element?\n  _.isElement = function(obj) {\n    return !!(obj && obj.nodeType === 1);\n  };\n\n  // Is a given value an array?\n  // Delegates to ECMA5's native Array.isArray\n  _.isArray = nativeIsArray || function(obj) {\n    return toString.call(obj) == '[object Array]';\n  };\n\n  // Is a given variable an object?\n  _.isObject = function(obj) {\n    return obj === Object(obj);\n  };\n\n  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.\n  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {\n    _['is' + name] = function(obj) {\n      return toString.call(obj) == '[object ' + name + ']';\n    };\n  });\n\n  // Define a fallback version of the method in browsers (ahem, IE), where\n  // there isn't any inspectable \"Arguments\" type.\n  if (!_.isArguments(arguments)) {\n    _.isArguments = function(obj) {\n      return !!(obj && _.has(obj, 'callee'));\n    };\n  }\n\n  // Optimize `isFunction` if appropriate.\n  if (typeof (/./) !== 'function') {\n    _.isFunction = function(obj) {\n      return typeof obj === 'function';\n    };\n  }\n\n  // Is a given object a finite number?\n  _.isFinite = function(obj) {\n    return isFinite(obj) && !isNaN(parseFloat(obj));\n  };\n\n  // Is the given value `NaN`? (NaN is the only number which does not equal itself).\n  _.isNaN = function(obj) {\n    return _.isNumber(obj) && obj != +obj;\n  };\n\n  // Is a given value a boolean?\n  _.isBoolean = function(obj) {\n    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';\n  };\n\n  // Is a given value equal to null?\n  _.isNull = function(obj) {\n    return obj === null;\n  };\n\n  // Is a given variable undefined?\n  _.isUndefined = function(obj) {\n    return obj === void 0;\n  };\n\n  // Shortcut function for checking if an object has a given property directly\n  // on itself (in other words, not on a prototype).\n  _.has = function(obj, key) {\n    return hasOwnProperty.call(obj, key);\n  };\n\n  // Utility Functions\n  // -----------------\n\n  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n  // previous owner. Returns a reference to the Underscore object.\n  _.noConflict = function() {\n    root._ = previousUnderscore;\n    return this;\n  };\n\n  // Keep the identity function around for default iterators.\n  _.identity = function(value) {\n    return value;\n  };\n\n  // Run a function **n** times.\n  _.times = function(n, iterator, context) {\n    var accum = Array(n);\n    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);\n    return accum;\n  };\n\n  // Return a random integer between min and max (inclusive).\n  _.random = function(min, max) {\n    if (max == null) {\n      max = min;\n      min = 0;\n    }\n    return min + Math.floor(Math.random() * (max - min + 1));\n  };\n\n  // List of HTML entities for escaping.\n  var entityMap = {\n    escape: {\n      '&': '&amp;',\n      '<': '&lt;',\n      '>': '&gt;',\n      '\"': '&quot;',\n      \"'\": '&#x27;',\n      '/': '&#x2F;'\n    }\n  };\n  entityMap.unescape = _.invert(entityMap.escape);\n\n  // Regexes containing the keys and values listed immediately above.\n  var entityRegexes = {\n    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),\n    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')\n  };\n\n  // Functions for escaping and unescaping strings to/from HTML interpolation.\n  _.each(['escape', 'unescape'], function(method) {\n    _[method] = function(string) {\n      if (string == null) return '';\n      return ('' + string).replace(entityRegexes[method], function(match) {\n        return entityMap[method][match];\n      });\n    };\n  });\n\n  // If the value of the named property is a function then invoke it;\n  // otherwise, return it.\n  _.result = function(object, property) {\n    if (object == null) return null;\n    var value = object[property];\n    return _.isFunction(value) ? value.call(object) : value;\n  };\n\n  // Add your own custom functions to the Underscore object.\n  _.mixin = function(obj) {\n    each(_.functions(obj), function(name){\n      var func = _[name] = obj[name];\n      _.prototype[name] = function() {\n        var args = [this._wrapped];\n        push.apply(args, arguments);\n        return result.call(this, func.apply(_, args));\n      };\n    });\n  };\n\n  // Generate a unique integer id (unique within the entire client session).\n  // Useful for temporary DOM ids.\n  var idCounter = 0;\n  _.uniqueId = function(prefix) {\n    var id = ++idCounter + '';\n    return prefix ? prefix + id : id;\n  };\n\n  // By default, Underscore uses ERB-style template delimiters, change the\n  // following template settings to use alternative delimiters.\n  _.templateSettings = {\n    evaluate    : /<%([\\s\\S]+?)%>/g,\n    interpolate : /<%=([\\s\\S]+?)%>/g,\n    escape      : /<%-([\\s\\S]+?)%>/g\n  };\n\n  // When customizing `templateSettings`, if you don't want to define an\n  // interpolation, evaluation or escaping regex, we need one that is\n  // guaranteed not to match.\n  var noMatch = /(.)^/;\n\n  // Certain characters need to be escaped so that they can be put into a\n  // string literal.\n  var escapes = {\n    \"'\":      \"'\",\n    '\\\\':     '\\\\',\n    '\\r':     'r',\n    '\\n':     'n',\n    '\\t':     't',\n    '\\u2028': 'u2028',\n    '\\u2029': 'u2029'\n  };\n\n  var escaper = /\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;\n\n  // JavaScript micro-templating, similar to John Resig's implementation.\n  // Underscore templating handles arbitrary delimiters, preserves whitespace,\n  // and correctly escapes quotes within interpolated code.\n  _.template = function(text, data, settings) {\n    var render;\n    settings = _.defaults({}, settings, _.templateSettings);\n\n    // Combine delimiters into one regular expression via alternation.\n    var matcher = new RegExp([\n      (settings.escape || noMatch).source,\n      (settings.interpolate || noMatch).source,\n      (settings.evaluate || noMatch).source\n    ].join('|') + '|$', 'g');\n\n    // Compile the template source, escaping string literals appropriately.\n    var index = 0;\n    var source = \"__p+='\";\n    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {\n      source += text.slice(index, offset)\n        .replace(escaper, function(match) { return '\\\\' + escapes[match]; });\n\n      if (escape) {\n        source += \"'+\\n((__t=(\" + escape + \"))==null?'':_.escape(__t))+\\n'\";\n      }\n      if (interpolate) {\n        source += \"'+\\n((__t=(\" + interpolate + \"))==null?'':__t)+\\n'\";\n      }\n      if (evaluate) {\n        source += \"';\\n\" + evaluate + \"\\n__p+='\";\n      }\n      index = offset + match.length;\n      return match;\n    });\n    source += \"';\\n\";\n\n    // If a variable is not specified, place data values in local scope.\n    if (!settings.variable) source = 'with(obj||{}){\\n' + source + '}\\n';\n\n    source = \"var __t,__p='',__j=Array.prototype.join,\" +\n      \"print=function(){__p+=__j.call(arguments,'');};\\n\" +\n      source + \"return __p;\\n\";\n\n    try {\n      render = new Function(settings.variable || 'obj', '_', source);\n    } catch (e) {\n      e.source = source;\n      throw e;\n    }\n\n    if (data) return render(data, _);\n    var template = function(data) {\n      return render.call(this, data, _);\n    };\n\n    // Provide the compiled function source as a convenience for precompilation.\n    template.source = 'function(' + (settings.variable || 'obj') + '){\\n' + source + '}';\n\n    return template;\n  };\n\n  // Add a \"chain\" function, which will delegate to the wrapper.\n  _.chain = function(obj) {\n    return _(obj).chain();\n  };\n\n  // OOP\n  // ---------------\n  // If Underscore is called as a function, it returns a wrapped object that\n  // can be used OO-style. This wrapper holds altered versions of all the\n  // underscore functions. Wrapped objects may be chained.\n\n  // Helper function to continue chaining intermediate results.\n  var result = function(obj) {\n    return this._chain ? _(obj).chain() : obj;\n  };\n\n  // Add all of the Underscore functions to the wrapper object.\n  _.mixin(_);\n\n  // Add all mutator Array functions to the wrapper.\n  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n    var method = ArrayProto[name];\n    _.prototype[name] = function() {\n      var obj = this._wrapped;\n      method.apply(obj, arguments);\n      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];\n      return result.call(this, obj);\n    };\n  });\n\n  // Add all accessor Array functions to the wrapper.\n  each(['concat', 'join', 'slice'], function(name) {\n    var method = ArrayProto[name];\n    _.prototype[name] = function() {\n      return result.call(this, method.apply(this._wrapped, arguments));\n    };\n  });\n\n  _.extend(_.prototype, {\n\n    // Start chaining a wrapped Underscore object.\n    chain: function() {\n      this._chain = true;\n      return this;\n    },\n\n    // Extracts the result from a wrapped and chained object.\n    value: function() {\n      return this._wrapped;\n    }\n\n  });\n\n}).call(this);\n\n},{}]},{},[7])(7)\n});\n;"
  },
  {
    "path": "browser-version/package.json",
    "content": "{\n  \"dependencies\": {\n    \"async\": \"~0.2.9\",\n    \"fs-extra\": \"~0.6.3\",\n    \"uglify-js\": \"~2.3.6\",\n    \"browserify\": \"~2.25.0\"\n  }\n}\n"
  },
  {
    "path": "browser-version/test/async.js",
    "content": "!function(){function n(){}function t(n){return n}function e(n){return!!n}function r(n){return!n}function u(n){return function(){if(null===n)throw new Error(\"Callback was already called.\");n.apply(this,arguments),n=null}}function i(n){return function(){null!==n&&(n.apply(this,arguments),n=null)}}function o(n){return M(n)||\"number\"==typeof n.length&&n.length>=0&&n.length%1===0}function c(n,t){for(var e=-1,r=n.length;++e<r;)t(n[e],e,n)}function a(n,t){for(var e=-1,r=n.length,u=Array(r);++e<r;)u[e]=t(n[e],e,n);return u}function f(n){return a(Array(n),function(n,t){return t})}function l(n,t,e){return c(n,function(n,r,u){e=t(e,n,r,u)}),e}function s(n,t){c(W(n),function(e){t(n[e],e)})}function p(n,t){for(var e=0;e<n.length;e++)if(n[e]===t)return e;return-1}function h(n){var t,e,r=-1;return o(n)?(t=n.length,function(){return r++,t>r?r:null}):(e=W(n),t=e.length,function(){return r++,t>r?e[r]:null})}function m(n,t){return t=null==t?n.length-1:+t,function(){for(var e=Math.max(arguments.length-t,0),r=Array(e),u=0;e>u;u++)r[u]=arguments[u+t];switch(t){case 0:return n.call(this,r);case 1:return n.call(this,arguments[0],r)}}}function y(n){return function(t,e,r){return n(t,r)}}function v(t){return function(e,r,o){o=i(o||n),e=e||[];var c=h(e);if(0>=t)return o(null);var a=!1,f=0,l=!1;!function s(){if(a&&0>=f)return o(null);for(;t>f&&!l;){var n=c();if(null===n)return a=!0,void(0>=f&&o(null));f+=1,r(e[n],n,u(function(n){f-=1,n?(o(n),l=!0):s()}))}}()}}function d(n){return function(t,e,r){return n(C.eachOf,t,e,r)}}function g(n){return function(t,e,r,u){return n(v(e),t,r,u)}}function k(n){return function(t,e,r){return n(C.eachOfSeries,t,e,r)}}function b(t,e,r,u){u=i(u||n),e=e||[];var c=o(e)?[]:{};t(e,function(n,t,e){r(n,function(n,r){c[t]=r,e(n)})},function(n){u(n,c)})}function w(n,t,e,r){var u=[];n(t,function(n,t,r){e(n,function(e){e&&u.push({index:t,value:n}),r()})},function(){r(a(u.sort(function(n,t){return n.index-t.index}),function(n){return n.value}))})}function O(n,t,e,r){w(n,t,function(n,t){e(n,function(n){t(!n)})},r)}function S(n,t,e){return function(r,u,i,o){function c(){o&&o(e(!1,void 0))}function a(n,r,u){return o?void i(n,function(r){o&&t(r)&&(o(e(!0,n)),o=i=!1),u()}):u()}arguments.length>3?n(r,u,a,c):(o=i,i=u,n(r,a,c))}}function E(n,t){return t}function L(t,e,r){r=r||n;var u=o(e)?[]:{};t(e,function(n,t,e){n(m(function(n,r){r.length<=1&&(r=r[0]),u[t]=r,e(n)}))},function(n){r(n,u)})}function I(n,t,e,r){var u=[];n(t,function(n,t,r){e(n,function(n,t){u=u.concat(t||[]),r(n)})},function(n){r(n,u)})}function x(t,e,r){function i(t,e,r,u){if(null!=u&&\"function\"!=typeof u)throw new Error(\"task callback must be a function\");return t.started=!0,M(e)||(e=[e]),0===e.length&&t.idle()?C.setImmediate(function(){t.drain()}):(c(e,function(e){var i={data:e,callback:u||n};r?t.tasks.unshift(i):t.tasks.push(i),t.tasks.length===t.concurrency&&t.saturated()}),void C.setImmediate(t.process))}function o(n,t){return function(){f-=1;var e=!1,r=arguments;c(t,function(n){c(l,function(t,r){t!==n||e||(l.splice(r,1),e=!0)}),n.callback.apply(n,r)}),n.tasks.length+f===0&&n.drain(),n.process()}}if(null==e)e=1;else if(0===e)throw new Error(\"Concurrency must not be zero\");var f=0,l=[],s={tasks:[],concurrency:e,payload:r,saturated:n,empty:n,drain:n,started:!1,paused:!1,push:function(n,t){i(s,n,!1,t)},kill:function(){s.drain=n,s.tasks=[]},unshift:function(n,t){i(s,n,!0,t)},process:function(){if(!s.paused&&f<s.concurrency&&s.tasks.length)for(;f<s.concurrency&&s.tasks.length;){var n=s.payload?s.tasks.splice(0,s.payload):s.tasks.splice(0,s.tasks.length),e=a(n,function(n){return n.data});0===s.tasks.length&&s.empty(),f+=1,l.push(n[0]);var r=u(o(s,n));t(e,r)}},length:function(){return s.tasks.length},running:function(){return f},workersList:function(){return l},idle:function(){return s.tasks.length+f===0},pause:function(){s.paused=!0},resume:function(){if(s.paused!==!1){s.paused=!1;for(var n=Math.min(s.concurrency,s.tasks.length),t=1;n>=t;t++)C.setImmediate(s.process)}}};return s}function j(n){return m(function(t,e){t.apply(null,e.concat([m(function(t,e){\"object\"==typeof console&&(t?console.error&&console.error(t):console[n]&&c(e,function(t){console[n](t)}))})]))})}function A(n){return function(t,e,r){n(f(t),e,r)}}function T(n){return m(function(t,e){var r=m(function(e){var r=this,u=e.pop();return n(t,function(n,t,u){n.apply(r,e.concat([u]))},u)});return e.length?r.apply(this,e):r})}function z(n){return m(function(t){var e=t.pop();t.push(function(){var n=arguments;r?C.setImmediate(function(){e.apply(null,n)}):e.apply(null,n)});var r=!0;n.apply(this,t),r=!1})}var q,C={},P=\"object\"==typeof self&&self.self===self&&self||\"object\"==typeof global&&global.global===global&&global||this;null!=P&&(q=P.async),C.noConflict=function(){return P.async=q,C};var H=Object.prototype.toString,M=Array.isArray||function(n){return\"[object Array]\"===H.call(n)},U=function(n){var t=typeof n;return\"function\"===t||\"object\"===t&&!!n},W=Object.keys||function(n){var t=[];for(var e in n)n.hasOwnProperty(e)&&t.push(e);return t},B=\"function\"==typeof setImmediate&&setImmediate,D=B?function(n){B(n)}:function(n){setTimeout(n,0)};\"object\"==typeof process&&\"function\"==typeof process.nextTick?C.nextTick=process.nextTick:C.nextTick=D,C.setImmediate=B?D:C.nextTick,C.forEach=C.each=function(n,t,e){return C.eachOf(n,y(t),e)},C.forEachSeries=C.eachSeries=function(n,t,e){return C.eachOfSeries(n,y(t),e)},C.forEachLimit=C.eachLimit=function(n,t,e,r){return v(t)(n,y(e),r)},C.forEachOf=C.eachOf=function(t,e,r){function o(n){f--,n?r(n):null===c&&0>=f&&r(null)}r=i(r||n),t=t||[];for(var c,a=h(t),f=0;null!=(c=a());)f+=1,e(t[c],c,u(o));0===f&&r(null)},C.forEachOfSeries=C.eachOfSeries=function(t,e,r){function o(){var n=!0;return null===a?r(null):(e(t[a],a,u(function(t){if(t)r(t);else{if(a=c(),null===a)return r(null);n?C.setImmediate(o):o()}})),void(n=!1))}r=i(r||n),t=t||[];var c=h(t),a=c();o()},C.forEachOfLimit=C.eachOfLimit=function(n,t,e,r){v(t)(n,e,r)},C.map=d(b),C.mapSeries=k(b),C.mapLimit=g(b),C.inject=C.foldl=C.reduce=function(n,t,e,r){C.eachOfSeries(n,function(n,r,u){e(t,n,function(n,e){t=e,u(n)})},function(n){r(n,t)})},C.foldr=C.reduceRight=function(n,e,r,u){var i=a(n,t).reverse();C.reduce(i,e,r,u)},C.transform=function(n,t,e,r){3===arguments.length&&(r=e,e=t,t=M(n)?[]:{}),C.eachOf(n,function(n,r,u){e(t,n,r,u)},function(n){r(n,t)})},C.select=C.filter=d(w),C.selectLimit=C.filterLimit=g(w),C.selectSeries=C.filterSeries=k(w),C.reject=d(O),C.rejectLimit=g(O),C.rejectSeries=k(O),C.any=C.some=S(C.eachOf,e,t),C.someLimit=S(C.eachOfLimit,e,t),C.all=C.every=S(C.eachOf,r,r),C.everyLimit=S(C.eachOfLimit,r,r),C.detect=S(C.eachOf,t,E),C.detectSeries=S(C.eachOfSeries,t,E),C.detectLimit=S(C.eachOfLimit,t,E),C.sortBy=function(n,t,e){function r(n,t){var e=n.criteria,r=t.criteria;return r>e?-1:e>r?1:0}C.map(n,function(n,e){t(n,function(t,r){t?e(t):e(null,{value:n,criteria:r})})},function(n,t){return n?e(n):void e(null,a(t.sort(r),function(n){return n.value}))})},C.auto=function(t,e,r){function u(n){d.unshift(n)}function o(n){var t=p(d,n);t>=0&&d.splice(t,1)}function a(){h--,c(d.slice(0),function(n){n()})}r||(r=e,e=null),r=i(r||n);var f=W(t),h=f.length;if(!h)return r(null);e||(e=h);var y={},v=0,d=[];u(function(){h||r(null,y)}),c(f,function(n){function i(){return e>v&&l(g,function(n,t){return n&&y.hasOwnProperty(t)},!0)&&!y.hasOwnProperty(n)}function c(){i()&&(v++,o(c),h[h.length-1](d,y))}for(var f,h=M(t[n])?t[n]:[t[n]],d=m(function(t,e){if(v--,e.length<=1&&(e=e[0]),t){var u={};s(y,function(n,t){u[t]=n}),u[n]=e,r(t,u)}else y[n]=e,C.setImmediate(a)}),g=h.slice(0,h.length-1),k=g.length;k--;){if(!(f=t[g[k]]))throw new Error(\"Has inexistant dependency\");if(M(f)&&p(f,n)>=0)throw new Error(\"Has cyclic dependencies\")}i()?(v++,h[h.length-1](d,y)):u(c)})},C.retry=function(n,t,e){function r(n,t){if(\"number\"==typeof t)n.times=parseInt(t,10)||i;else{if(\"object\"!=typeof t)throw new Error(\"Unsupported argument type for 'times': \"+typeof t);n.times=parseInt(t.times,10)||i,n.interval=parseInt(t.interval,10)||o}}function u(n,t){function e(n,e){return function(r){n(function(n,t){r(!n||e,{err:n,result:t})},t)}}function r(n){return function(t){setTimeout(function(){t(null)},n)}}for(;a.times;){var u=!(a.times-=1);c.push(e(a.task,u)),!u&&a.interval>0&&c.push(r(a.interval))}C.series(c,function(t,e){e=e[e.length-1],(n||a.callback)(e.err,e.result)})}var i=5,o=0,c=[],a={times:i,interval:o},f=arguments.length;if(1>f||f>3)throw new Error(\"Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)\");return 2>=f&&\"function\"==typeof n&&(e=t,t=n),\"function\"!=typeof n&&r(a,n),a.callback=e,a.task=t,a.callback?u():u},C.waterfall=function(t,e){function r(n){return m(function(t,u){if(t)e.apply(null,[t].concat(u));else{var i=n.next();i?u.push(r(i)):u.push(e),z(n).apply(null,u)}})}if(e=i(e||n),!M(t)){var u=new Error(\"First argument to waterfall must be an array of functions\");return e(u)}return t.length?void r(C.iterator(t))():e()},C.parallel=function(n,t){L(C.eachOf,n,t)},C.parallelLimit=function(n,t,e){L(v(t),n,e)},C.series=function(n,t){L(C.eachOfSeries,n,t)},C.iterator=function(n){function t(e){function r(){return n.length&&n[e].apply(null,arguments),r.next()}return r.next=function(){return e<n.length-1?t(e+1):null},r}return t(0)},C.apply=m(function(n,t){return m(function(e){return n.apply(null,t.concat(e))})}),C.concat=d(I),C.concatSeries=k(I),C.whilst=function(t,e,r){if(r=r||n,t()){var u=m(function(n,i){n?r(n):t.apply(this,i)?e(u):r(null)});e(u)}else r(null)},C.doWhilst=function(n,t,e){var r=0;return C.whilst(function(){return++r<=1||t.apply(this,arguments)},n,e)},C.until=function(n,t,e){return C.whilst(function(){return!n.apply(this,arguments)},t,e)},C.doUntil=function(n,t,e){return C.doWhilst(n,function(){return!t.apply(this,arguments)},e)},C.during=function(t,e,r){r=r||n;var u=m(function(n,e){n?r(n):(e.push(i),t.apply(this,e))}),i=function(n,t){n?r(n):t?e(u):r(null)};t(i)},C.doDuring=function(n,t,e){var r=0;C.during(function(n){r++<1?n(null,!0):t.apply(this,arguments)},n,e)},C.queue=function(n,t){var e=x(function(t,e){n(t[0],e)},t,1);return e},C.priorityQueue=function(t,e){function r(n,t){return n.priority-t.priority}function u(n,t,e){for(var r=-1,u=n.length-1;u>r;){var i=r+(u-r+1>>>1);e(t,n[i])>=0?r=i:u=i-1}return r}function i(t,e,i,o){if(null!=o&&\"function\"!=typeof o)throw new Error(\"task callback must be a function\");return t.started=!0,M(e)||(e=[e]),0===e.length?C.setImmediate(function(){t.drain()}):void c(e,function(e){var c={data:e,priority:i,callback:\"function\"==typeof o?o:n};t.tasks.splice(u(t.tasks,c,r)+1,0,c),t.tasks.length===t.concurrency&&t.saturated(),C.setImmediate(t.process)})}var o=C.queue(t,e);return o.push=function(n,t,e){i(o,n,t,e)},delete o.unshift,o},C.cargo=function(n,t){return x(n,1,t)},C.log=j(\"log\"),C.dir=j(\"dir\"),C.memoize=function(n,e){var r={},u={};e=e||t;var i=m(function(t){var i=t.pop(),o=e.apply(null,t);o in r?C.setImmediate(function(){i.apply(null,r[o])}):o in u?u[o].push(i):(u[o]=[i],n.apply(null,t.concat([m(function(n){r[o]=n;var t=u[o];delete u[o];for(var e=0,i=t.length;i>e;e++)t[e].apply(null,n)})])))});return i.memo=r,i.unmemoized=n,i},C.unmemoize=function(n){return function(){return(n.unmemoized||n).apply(null,arguments)}},C.times=A(C.map),C.timesSeries=A(C.mapSeries),C.timesLimit=function(n,t,e,r){return C.mapLimit(f(n),t,e,r)},C.seq=function(){var t=arguments;return m(function(e){var r=this,u=e[e.length-1];\"function\"==typeof u?e.pop():u=n,C.reduce(t,e,function(n,t,e){t.apply(r,n.concat([m(function(n,t){e(n,t)})]))},function(n,t){u.apply(r,[n].concat(t))})})},C.compose=function(){return C.seq.apply(null,Array.prototype.reverse.call(arguments))},C.applyEach=T(C.eachOf),C.applyEachSeries=T(C.eachOfSeries),C.forever=function(t,e){function r(n){return n?i(n):void o(r)}var i=u(e||n),o=z(t);r()},C.ensureAsync=z,C.constant=m(function(n){var t=[null].concat(n);return function(n){return n.apply(this,t)}}),C.wrapSync=C.asyncify=function(n){return m(function(t){var e,r=t.pop();try{e=n.apply(this,t)}catch(u){return r(u)}U(e)&&\"function\"==typeof e.then?e.then(function(n){r(null,n)})[\"catch\"](function(n){r(n.message?n:new Error(n))}):r(null,e)})},\"object\"==typeof module&&module.exports?module.exports=C:\"function\"==typeof define&&define.amd?define([],function(){return C}):P.async=C}();\n\n"
  },
  {
    "path": "browser-version/test/chai.js",
    "content": "\n;(function(){\n\n/**\n * Require the module at `name`.\n *\n * @param {String} name\n * @return {Object} exports\n * @api public\n */\n\nfunction require(name) {\n  var module = require.modules[name];\n  if (!module) throw new Error('failed to require \"' + name + '\"');\n\n  if (!('exports' in module) && typeof module.definition === 'function') {\n    module.client = module.component = true;\n    module.definition.call(this, module.exports = {}, module);\n    delete module.definition;\n  }\n\n  return module.exports;\n}\n\n/**\n * Meta info, accessible in the global scope unless you use AMD option.\n */\n\nrequire.loader = 'component';\n\n/**\n * Internal helper object, contains a sorting function for semantiv versioning\n */\nrequire.helper = {};\nrequire.helper.semVerSort = function(a, b) {\n  var aArray = a.version.split('.');\n  var bArray = b.version.split('.');\n  for (var i=0; i<aArray.length; ++i) {\n    var aInt = parseInt(aArray[i], 10);\n    var bInt = parseInt(bArray[i], 10);\n    if (aInt === bInt) {\n      var aLex = aArray[i].substr((\"\"+aInt).length);\n      var bLex = bArray[i].substr((\"\"+bInt).length);\n      if (aLex === '' && bLex !== '') return 1;\n      if (aLex !== '' && bLex === '') return -1;\n      if (aLex !== '' && bLex !== '') return aLex > bLex ? 1 : -1;\n      continue;\n    } else if (aInt > bInt) {\n      return 1;\n    } else {\n      return -1;\n    }\n  }\n  return 0;\n}\n\n/**\n * Find and require a module which name starts with the provided name.\n * If multiple modules exists, the highest semver is used. \n * This function can only be used for remote dependencies.\n\n * @param {String} name - module name: `user~repo`\n * @param {Boolean} returnPath - returns the canonical require path if true, \n *                               otherwise it returns the epxorted module\n */\nrequire.latest = function (name, returnPath) {\n  function showError(name) {\n    throw new Error('failed to find latest module of \"' + name + '\"');\n  }\n  // only remotes with semvers, ignore local files conataining a '/'\n  var versionRegexp = /(.*)~(.*)@v?(\\d+\\.\\d+\\.\\d+[^\\/]*)$/;\n  var remoteRegexp = /(.*)~(.*)/;\n  if (!remoteRegexp.test(name)) showError(name);\n  var moduleNames = Object.keys(require.modules);\n  var semVerCandidates = [];\n  var otherCandidates = []; // for instance: name of the git branch\n  for (var i=0; i<moduleNames.length; i++) {\n    var moduleName = moduleNames[i];\n    if (new RegExp(name + '@').test(moduleName)) {\n        var version = moduleName.substr(name.length+1);\n        var semVerMatch = versionRegexp.exec(moduleName);\n        if (semVerMatch != null) {\n          semVerCandidates.push({version: version, name: moduleName});\n        } else {\n          otherCandidates.push({version: version, name: moduleName});\n        } \n    }\n  }\n  if (semVerCandidates.concat(otherCandidates).length === 0) {\n    showError(name);\n  }\n  if (semVerCandidates.length > 0) {\n    var module = semVerCandidates.sort(require.helper.semVerSort).pop().name;\n    if (returnPath === true) {\n      return module;\n    }\n    return require(module);\n  }\n  // if the build contains more than one branch of the same module\n  // you should not use this funciton\n  var module = otherCandidates.sort(function(a, b) {return a.name > b.name})[0].name;\n  if (returnPath === true) {\n    return module;\n  }\n  return require(module);\n}\n\n/**\n * Registered modules.\n */\n\nrequire.modules = {};\n\n/**\n * Register module at `name` with callback `definition`.\n *\n * @param {String} name\n * @param {Function} definition\n * @api private\n */\n\nrequire.register = function (name, definition) {\n  require.modules[name] = {\n    definition: definition\n  };\n};\n\n/**\n * Define a module's exports immediately with `exports`.\n *\n * @param {String} name\n * @param {Generic} exports\n * @api private\n */\n\nrequire.define = function (name, exports) {\n  require.modules[name] = {\n    exports: exports\n  };\n};\nrequire.register(\"chaijs~assertion-error@1.0.0\", function (exports, module) {\n/*!\n * assertion-error\n * Copyright(c) 2013 Jake Luer <jake@qualiancy.com>\n * MIT Licensed\n */\n\n/*!\n * Return a function that will copy properties from\n * one object to another excluding any originally\n * listed. Returned function will create a new `{}`.\n *\n * @param {String} excluded properties ...\n * @return {Function}\n */\n\nfunction exclude () {\n  var excludes = [].slice.call(arguments);\n\n  function excludeProps (res, obj) {\n    Object.keys(obj).forEach(function (key) {\n      if (!~excludes.indexOf(key)) res[key] = obj[key];\n    });\n  }\n\n  return function extendExclude () {\n    var args = [].slice.call(arguments)\n      , i = 0\n      , res = {};\n\n    for (; i < args.length; i++) {\n      excludeProps(res, args[i]);\n    }\n\n    return res;\n  };\n};\n\n/*!\n * Primary Exports\n */\n\nmodule.exports = AssertionError;\n\n/**\n * ### AssertionError\n *\n * An extension of the JavaScript `Error` constructor for\n * assertion and validation scenarios.\n *\n * @param {String} message\n * @param {Object} properties to include (optional)\n * @param {callee} start stack function (optional)\n */\n\nfunction AssertionError (message, _props, ssf) {\n  var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON')\n    , props = extend(_props || {});\n\n  // default values\n  this.message = message || 'Unspecified AssertionError';\n  this.showDiff = false;\n\n  // copy from properties\n  for (var key in props) {\n    this[key] = props[key];\n  }\n\n  // capture stack trace\n  ssf = ssf || arguments.callee;\n  if (ssf && Error.captureStackTrace) {\n    Error.captureStackTrace(this, ssf);\n  }\n}\n\n/*!\n * Inherit from Error.prototype\n */\n\nAssertionError.prototype = Object.create(Error.prototype);\n\n/*!\n * Statically set name\n */\n\nAssertionError.prototype.name = 'AssertionError';\n\n/*!\n * Ensure correct constructor\n */\n\nAssertionError.prototype.constructor = AssertionError;\n\n/**\n * Allow errors to be converted to JSON for static transfer.\n *\n * @param {Boolean} include stack (default: `true`)\n * @return {Object} object that can be `JSON.stringify`\n */\n\nAssertionError.prototype.toJSON = function (stack) {\n  var extend = exclude('constructor', 'toJSON', 'stack')\n    , props = extend({ name: this.name }, this);\n\n  // include stack if exists and not turned off\n  if (false !== stack && this.stack) {\n    props.stack = this.stack;\n  }\n\n  return props;\n};\n\n});\n\nrequire.register(\"chaijs~type-detect@0.1.1\", function (exports, module) {\n/*!\n * type-detect\n * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Primary Exports\n */\n\nvar exports = module.exports = getType;\n\n/*!\n * Detectable javascript natives\n */\n\nvar natives = {\n    '[object Array]': 'array'\n  , '[object RegExp]': 'regexp'\n  , '[object Function]': 'function'\n  , '[object Arguments]': 'arguments'\n  , '[object Date]': 'date'\n};\n\n/**\n * ### typeOf (obj)\n *\n * Use several different techniques to determine\n * the type of object being tested.\n *\n *\n * @param {Mixed} object\n * @return {String} object type\n * @api public\n */\n\nfunction getType (obj) {\n  var str = Object.prototype.toString.call(obj);\n  if (natives[str]) return natives[str];\n  if (obj === null) return 'null';\n  if (obj === undefined) return 'undefined';\n  if (obj === Object(obj)) return 'object';\n  return typeof obj;\n}\n\nexports.Library = Library;\n\n/**\n * ### Library\n *\n * Create a repository for custom type detection.\n *\n * ```js\n * var lib = new type.Library;\n * ```\n *\n */\n\nfunction Library () {\n  this.tests = {};\n}\n\n/**\n * #### .of (obj)\n *\n * Expose replacement `typeof` detection to the library.\n *\n * ```js\n * if ('string' === lib.of('hello world')) {\n *   // ...\n * }\n * ```\n *\n * @param {Mixed} object to test\n * @return {String} type\n */\n\nLibrary.prototype.of = getType;\n\n/**\n * #### .define (type, test)\n *\n * Add a test to for the `.test()` assertion.\n *\n * Can be defined as a regular expression:\n *\n * ```js\n * lib.define('int', /^[0-9]+$/);\n * ```\n *\n * ... or as a function:\n *\n * ```js\n * lib.define('bln', function (obj) {\n *   if ('boolean' === lib.of(obj)) return true;\n *   var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ];\n *   if ('string' === lib.of(obj)) obj = obj.toLowerCase();\n *   return !! ~blns.indexOf(obj);\n * });\n * ```\n *\n * @param {String} type\n * @param {RegExp|Function} test\n * @api public\n */\n\nLibrary.prototype.define = function (type, test) {\n  if (arguments.length === 1) return this.tests[type];\n  this.tests[type] = test;\n  return this;\n};\n\n/**\n * #### .test (obj, test)\n *\n * Assert that an object is of type. Will first\n * check natives, and if that does not pass it will\n * use the user defined custom tests.\n *\n * ```js\n * assert(lib.test('1', 'int'));\n * assert(lib.test('yes', 'bln'));\n * ```\n *\n * @param {Mixed} object\n * @param {String} type\n * @return {Boolean} result\n * @api public\n */\n\nLibrary.prototype.test = function (obj, type) {\n  if (type === getType(obj)) return true;\n  var test = this.tests[type];\n\n  if (test && 'regexp' === getType(test)) {\n    return test.test(obj);\n  } else if (test && 'function' === getType(test)) {\n    return test(obj);\n  } else {\n    throw new ReferenceError('Type test \"' + type + '\" not defined or invalid.');\n  }\n};\n\n});\n\nrequire.register(\"chaijs~deep-eql@0.1.3\", function (exports, module) {\n/*!\n * deep-eql\n * Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar type = require('chaijs~type-detect@0.1.1');\n\n/*!\n * Buffer.isBuffer browser shim\n */\n\nvar Buffer;\ntry { Buffer = require('buffer').Buffer; }\ncatch(ex) {\n  Buffer = {};\n  Buffer.isBuffer = function() { return false; }\n}\n\n/*!\n * Primary Export\n */\n\nmodule.exports = deepEqual;\n\n/**\n * Assert super-strict (egal) equality between\n * two objects of any type.\n *\n * @param {Mixed} a\n * @param {Mixed} b\n * @param {Array} memoised (optional)\n * @return {Boolean} equal match\n */\n\nfunction deepEqual(a, b, m) {\n  if (sameValue(a, b)) {\n    return true;\n  } else if ('date' === type(a)) {\n    return dateEqual(a, b);\n  } else if ('regexp' === type(a)) {\n    return regexpEqual(a, b);\n  } else if (Buffer.isBuffer(a)) {\n    return bufferEqual(a, b);\n  } else if ('arguments' === type(a)) {\n    return argumentsEqual(a, b, m);\n  } else if (!typeEqual(a, b)) {\n    return false;\n  } else if (('object' !== type(a) && 'object' !== type(b))\n  && ('array' !== type(a) && 'array' !== type(b))) {\n    return sameValue(a, b);\n  } else {\n    return objectEqual(a, b, m);\n  }\n}\n\n/*!\n * Strict (egal) equality test. Ensures that NaN always\n * equals NaN and `-0` does not equal `+0`.\n *\n * @param {Mixed} a\n * @param {Mixed} b\n * @return {Boolean} equal match\n */\n\nfunction sameValue(a, b) {\n  if (a === b) return a !== 0 || 1 / a === 1 / b;\n  return a !== a && b !== b;\n}\n\n/*!\n * Compare the types of two given objects and\n * return if they are equal. Note that an Array\n * has a type of `array` (not `object`) and arguments\n * have a type of `arguments` (not `array`/`object`).\n *\n * @param {Mixed} a\n * @param {Mixed} b\n * @return {Boolean} result\n */\n\nfunction typeEqual(a, b) {\n  return type(a) === type(b);\n}\n\n/*!\n * Compare two Date objects by asserting that\n * the time values are equal using `saveValue`.\n *\n * @param {Date} a\n * @param {Date} b\n * @return {Boolean} result\n */\n\nfunction dateEqual(a, b) {\n  if ('date' !== type(b)) return false;\n  return sameValue(a.getTime(), b.getTime());\n}\n\n/*!\n * Compare two regular expressions by converting them\n * to string and checking for `sameValue`.\n *\n * @param {RegExp} a\n * @param {RegExp} b\n * @return {Boolean} result\n */\n\nfunction regexpEqual(a, b) {\n  if ('regexp' !== type(b)) return false;\n  return sameValue(a.toString(), b.toString());\n}\n\n/*!\n * Assert deep equality of two `arguments` objects.\n * Unfortunately, these must be sliced to arrays\n * prior to test to ensure no bad behavior.\n *\n * @param {Arguments} a\n * @param {Arguments} b\n * @param {Array} memoize (optional)\n * @return {Boolean} result\n */\n\nfunction argumentsEqual(a, b, m) {\n  if ('arguments' !== type(b)) return false;\n  a = [].slice.call(a);\n  b = [].slice.call(b);\n  return deepEqual(a, b, m);\n}\n\n/*!\n * Get enumerable properties of a given object.\n *\n * @param {Object} a\n * @return {Array} property names\n */\n\nfunction enumerable(a) {\n  var res = [];\n  for (var key in a) res.push(key);\n  return res;\n}\n\n/*!\n * Simple equality for flat iterable objects\n * such as Arrays or Node.js buffers.\n *\n * @param {Iterable} a\n * @param {Iterable} b\n * @return {Boolean} result\n */\n\nfunction iterableEqual(a, b) {\n  if (a.length !==  b.length) return false;\n\n  var i = 0;\n  var match = true;\n\n  for (; i < a.length; i++) {\n    if (a[i] !== b[i]) {\n      match = false;\n      break;\n    }\n  }\n\n  return match;\n}\n\n/*!\n * Extension to `iterableEqual` specifically\n * for Node.js Buffers.\n *\n * @param {Buffer} a\n * @param {Mixed} b\n * @return {Boolean} result\n */\n\nfunction bufferEqual(a, b) {\n  if (!Buffer.isBuffer(b)) return false;\n  return iterableEqual(a, b);\n}\n\n/*!\n * Block for `objectEqual` ensuring non-existing\n * values don't get in.\n *\n * @param {Mixed} object\n * @return {Boolean} result\n */\n\nfunction isValue(a) {\n  return a !== null && a !== undefined;\n}\n\n/*!\n * Recursively check the equality of two objects.\n * Once basic sameness has been established it will\n * defer to `deepEqual` for each enumerable key\n * in the object.\n *\n * @param {Mixed} a\n * @param {Mixed} b\n * @return {Boolean} result\n */\n\nfunction objectEqual(a, b, m) {\n  if (!isValue(a) || !isValue(b)) {\n    return false;\n  }\n\n  if (a.prototype !== b.prototype) {\n    return false;\n  }\n\n  var i;\n  if (m) {\n    for (i = 0; i < m.length; i++) {\n      if ((m[i][0] === a && m[i][1] === b)\n      ||  (m[i][0] === b && m[i][1] === a)) {\n        return true;\n      }\n    }\n  } else {\n    m = [];\n  }\n\n  try {\n    var ka = enumerable(a);\n    var kb = enumerable(b);\n  } catch (ex) {\n    return false;\n  }\n\n  ka.sort();\n  kb.sort();\n\n  if (!iterableEqual(ka, kb)) {\n    return false;\n  }\n\n  m.push([ a, b ]);\n\n  var key;\n  for (i = ka.length - 1; i >= 0; i--) {\n    key = ka[i];\n    if (!deepEqual(a[key], b[key], m)) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\n});\n\nrequire.register(\"chai\", function (exports, module) {\nmodule.exports = require('chai/lib/chai.js');\n\n});\n\nrequire.register(\"chai/lib/chai.js\", function (exports, module) {\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar used = []\n  , exports = module.exports = {};\n\n/*!\n * Chai version\n */\n\nexports.version = '2.1.0';\n\n/*!\n * Assertion Error\n */\n\nexports.AssertionError = require('chaijs~assertion-error@1.0.0');\n\n/*!\n * Utils for plugins (not exported)\n */\n\nvar util = require('chai/lib/chai/utils/index.js');\n\n/**\n * # .use(function)\n *\n * Provides a way to extend the internals of Chai\n *\n * @param {Function}\n * @returns {this} for chaining\n * @api public\n */\n\nexports.use = function (fn) {\n  if (!~used.indexOf(fn)) {\n    fn(this, util);\n    used.push(fn);\n  }\n\n  return this;\n};\n\n/*!\n * Utility Functions\n */\n\nexports.util = util;\n\n/*!\n * Configuration\n */\n\nvar config = require('chai/lib/chai/config.js');\nexports.config = config;\n\n/*!\n * Primary `Assertion` prototype\n */\n\nvar assertion = require('chai/lib/chai/assertion.js');\nexports.use(assertion);\n\n/*!\n * Core Assertions\n */\n\nvar core = require('chai/lib/chai/core/assertions.js');\nexports.use(core);\n\n/*!\n * Expect interface\n */\n\nvar expect = require('chai/lib/chai/interface/expect.js');\nexports.use(expect);\n\n/*!\n * Should interface\n */\n\nvar should = require('chai/lib/chai/interface/should.js');\nexports.use(should);\n\n/*!\n * Assert interface\n */\n\nvar assert = require('chai/lib/chai/interface/assert.js');\nexports.use(assert);\n\n});\n\nrequire.register(\"chai/lib/chai/assertion.js\", function (exports, module) {\n/*!\n * chai\n * http://chaijs.com\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar config = require('chai/lib/chai/config.js');\n\nmodule.exports = function (_chai, util) {\n  /*!\n   * Module dependencies.\n   */\n\n  var AssertionError = _chai.AssertionError\n    , flag = util.flag;\n\n  /*!\n   * Module export.\n   */\n\n  _chai.Assertion = Assertion;\n\n  /*!\n   * Assertion Constructor\n   *\n   * Creates object for chaining.\n   *\n   * @api private\n   */\n\n  function Assertion (obj, msg, stack) {\n    flag(this, 'ssfi', stack || arguments.callee);\n    flag(this, 'object', obj);\n    flag(this, 'message', msg);\n  }\n\n  Object.defineProperty(Assertion, 'includeStack', {\n    get: function() {\n      console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.');\n      return config.includeStack;\n    },\n    set: function(value) {\n      console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.');\n      config.includeStack = value;\n    }\n  });\n\n  Object.defineProperty(Assertion, 'showDiff', {\n    get: function() {\n      console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.');\n      return config.showDiff;\n    },\n    set: function(value) {\n      console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.');\n      config.showDiff = value;\n    }\n  });\n\n  Assertion.addProperty = function (name, fn) {\n    util.addProperty(this.prototype, name, fn);\n  };\n\n  Assertion.addMethod = function (name, fn) {\n    util.addMethod(this.prototype, name, fn);\n  };\n\n  Assertion.addChainableMethod = function (name, fn, chainingBehavior) {\n    util.addChainableMethod(this.prototype, name, fn, chainingBehavior);\n  };\n\n  Assertion.overwriteProperty = function (name, fn) {\n    util.overwriteProperty(this.prototype, name, fn);\n  };\n\n  Assertion.overwriteMethod = function (name, fn) {\n    util.overwriteMethod(this.prototype, name, fn);\n  };\n\n  Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) {\n    util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior);\n  };\n\n  /*!\n   * ### .assert(expression, message, negateMessage, expected, actual)\n   *\n   * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass.\n   *\n   * @name assert\n   * @param {Philosophical} expression to be tested\n   * @param {String or Function} message or function that returns message to display if fails\n   * @param {String or Function} negatedMessage or function that returns negatedMessage to display if negated expression fails\n   * @param {Mixed} expected value (remember to check for negation)\n   * @param {Mixed} actual (optional) will default to `this.obj`\n   * @api private\n   */\n\n  Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) {\n    var ok = util.test(this, arguments);\n    if (true !== showDiff) showDiff = false;\n    if (true !== config.showDiff) showDiff = false;\n\n    if (!ok) {\n      var msg = util.getMessage(this, arguments)\n        , actual = util.getActual(this, arguments);\n      throw new AssertionError(msg, {\n          actual: actual\n        , expected: expected\n        , showDiff: showDiff\n      }, (config.includeStack) ? this.assert : flag(this, 'ssfi'));\n    }\n  };\n\n  /*!\n   * ### ._obj\n   *\n   * Quick reference to stored `actual` value for plugin developers.\n   *\n   * @api private\n   */\n\n  Object.defineProperty(Assertion.prototype, '_obj',\n    { get: function () {\n        return flag(this, 'object');\n      }\n    , set: function (val) {\n        flag(this, 'object', val);\n      }\n  });\n};\n\n});\n\nrequire.register(\"chai/lib/chai/config.js\", function (exports, module) {\nmodule.exports = {\n\n  /**\n   * ### config.includeStack\n   *\n   * User configurable property, influences whether stack trace\n   * is included in Assertion error message. Default of false\n   * suppresses stack trace in the error message.\n   *\n   *     chai.config.includeStack = true;  // enable stack on error\n   *\n   * @param {Boolean}\n   * @api public\n   */\n\n   includeStack: false,\n\n  /**\n   * ### config.showDiff\n   *\n   * User configurable property, influences whether or not\n   * the `showDiff` flag should be included in the thrown\n   * AssertionErrors. `false` will always be `false`; `true`\n   * will be true when the assertion has requested a diff\n   * be shown.\n   *\n   * @param {Boolean}\n   * @api public\n   */\n\n  showDiff: true,\n\n  /**\n   * ### config.truncateThreshold\n   *\n   * User configurable property, sets length threshold for actual and\n   * expected values in assertion errors. If this threshold is exceeded,\n   * the value is truncated.\n   *\n   * Set it to zero if you want to disable truncating altogether.\n   *\n   *     chai.config.truncateThreshold = 0;  // disable truncating\n   *\n   * @param {Number}\n   * @api public\n   */\n\n  truncateThreshold: 40\n\n};\n\n});\n\nrequire.register(\"chai/lib/chai/core/assertions.js\", function (exports, module) {\n/*!\n * chai\n * http://chaijs.com\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, _) {\n  var Assertion = chai.Assertion\n    , toString = Object.prototype.toString\n    , flag = _.flag;\n\n  /**\n   * ### Language Chains\n   *\n   * The following are provided as chainable getters to\n   * improve the readability of your assertions. They\n   * do not provide testing capabilities unless they\n   * have been overwritten by a plugin.\n   *\n   * **Chains**\n   *\n   * - to\n   * - be\n   * - been\n   * - is\n   * - that\n   * - which\n   * - and\n   * - has\n   * - have\n   * - with\n   * - at\n   * - of\n   * - same\n   *\n   * @name language chains\n   * @api public\n   */\n\n  [ 'to', 'be', 'been'\n  , 'is', 'and', 'has', 'have'\n  , 'with', 'that', 'which', 'at'\n  , 'of', 'same' ].forEach(function (chain) {\n    Assertion.addProperty(chain, function () {\n      return this;\n    });\n  });\n\n  /**\n   * ### .not\n   *\n   * Negates any of assertions following in the chain.\n   *\n   *     expect(foo).to.not.equal('bar');\n   *     expect(goodFn).to.not.throw(Error);\n   *     expect({ foo: 'baz' }).to.have.property('foo')\n   *       .and.not.equal('bar');\n   *\n   * @name not\n   * @api public\n   */\n\n  Assertion.addProperty('not', function () {\n    flag(this, 'negate', true);\n  });\n\n  /**\n   * ### .deep\n   *\n   * Sets the `deep` flag, later used by the `equal` and\n   * `property` assertions.\n   *\n   *     expect(foo).to.deep.equal({ bar: 'baz' });\n   *     expect({ foo: { bar: { baz: 'quux' } } })\n   *       .to.have.deep.property('foo.bar.baz', 'quux');\n   *\n   * @name deep\n   * @api public\n   */\n\n  Assertion.addProperty('deep', function () {\n    flag(this, 'deep', true);\n  });\n\n  /**\n   * ### .any\n   *\n   * Sets the `any` flag, (opposite of the `all` flag)\n   * later used in the `keys` assertion. \n   *\n   *     expect(foo).to.have.any.keys('bar', 'baz');\n   *\n   * @name any\n   * @api public\n   */\n\n  Assertion.addProperty('any', function () {\n    flag(this, 'any', true);\n    flag(this, 'all', false)\n  });\n\n\n  /**\n   * ### .all\n   *\n   * Sets the `all` flag (opposite of the `any` flag) \n   * later used by the `keys` assertion.\n   *\n   *     expect(foo).to.have.all.keys('bar', 'baz');\n   *\n   * @name all\n   * @api public\n   */\n\n  Assertion.addProperty('all', function () {\n    flag(this, 'all', true);\n    flag(this, 'any', false);\n  });\n\n  /**\n   * ### .a(type)\n   *\n   * The `a` and `an` assertions are aliases that can be\n   * used either as language chains or to assert a value's\n   * type.\n   *\n   *     // typeof\n   *     expect('test').to.be.a('string');\n   *     expect({ foo: 'bar' }).to.be.an('object');\n   *     expect(null).to.be.a('null');\n   *     expect(undefined).to.be.an('undefined');\n   *\n   *     // language chain\n   *     expect(foo).to.be.an.instanceof(Foo);\n   *\n   * @name a\n   * @alias an\n   * @param {String} type\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function an (type, msg) {\n    if (msg) flag(this, 'message', msg);\n    type = type.toLowerCase();\n    var obj = flag(this, 'object')\n      , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';\n\n    this.assert(\n        type === _.type(obj)\n      , 'expected #{this} to be ' + article + type\n      , 'expected #{this} not to be ' + article + type\n    );\n  }\n\n  Assertion.addChainableMethod('an', an);\n  Assertion.addChainableMethod('a', an);\n\n  /**\n   * ### .include(value)\n   *\n   * The `include` and `contain` assertions can be used as either property\n   * based language chains or as methods to assert the inclusion of an object\n   * in an array or a substring in a string. When used as language chains,\n   * they toggle the `contains` flag for the `keys` assertion.\n   *\n   *     expect([1,2,3]).to.include(2);\n   *     expect('foobar').to.contain('foo');\n   *     expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');\n   *\n   * @name include\n   * @alias contain\n   * @alias includes\n   * @alias contains\n   * @param {Object|String|Number} obj\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function includeChainingBehavior () {\n    flag(this, 'contains', true);\n  }\n\n  function include (val, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    var expected = false;\n    if (_.type(obj) === 'array' && _.type(val) === 'object') {\n      for (var i in obj) {\n        if (_.eql(obj[i], val)) {\n          expected = true;\n          break;\n        }\n      }\n    } else if (_.type(val) === 'object') {\n      if (!flag(this, 'negate')) {\n        for (var k in val) new Assertion(obj).property(k, val[k]);\n        return;\n      }\n      var subset = {};\n      for (var k in val) subset[k] = obj[k];\n      expected = _.eql(subset, val);\n    } else {\n      expected = obj && ~obj.indexOf(val);\n    }\n    this.assert(\n        expected\n      , 'expected #{this} to include ' + _.inspect(val)\n      , 'expected #{this} to not include ' + _.inspect(val));\n  }\n\n  Assertion.addChainableMethod('include', include, includeChainingBehavior);\n  Assertion.addChainableMethod('contain', include, includeChainingBehavior);\n  Assertion.addChainableMethod('contains', include, includeChainingBehavior);\n  Assertion.addChainableMethod('includes', include, includeChainingBehavior);\n\n  /**\n   * ### .ok\n   *\n   * Asserts that the target is truthy.\n   *\n   *     expect('everthing').to.be.ok;\n   *     expect(1).to.be.ok;\n   *     expect(false).to.not.be.ok;\n   *     expect(undefined).to.not.be.ok;\n   *     expect(null).to.not.be.ok;\n   *\n   * @name ok\n   * @api public\n   */\n\n  Assertion.addProperty('ok', function () {\n    this.assert(\n        flag(this, 'object')\n      , 'expected #{this} to be truthy'\n      , 'expected #{this} to be falsy');\n  });\n\n  /**\n   * ### .true\n   *\n   * Asserts that the target is `true`.\n   *\n   *     expect(true).to.be.true;\n   *     expect(1).to.not.be.true;\n   *\n   * @name true\n   * @api public\n   */\n\n  Assertion.addProperty('true', function () {\n    this.assert(\n        true === flag(this, 'object')\n      , 'expected #{this} to be true'\n      , 'expected #{this} to be false'\n      , this.negate ? false : true\n    );\n  });\n\n  /**\n   * ### .false\n   *\n   * Asserts that the target is `false`.\n   *\n   *     expect(false).to.be.false;\n   *     expect(0).to.not.be.false;\n   *\n   * @name false\n   * @api public\n   */\n\n  Assertion.addProperty('false', function () {\n    this.assert(\n        false === flag(this, 'object')\n      , 'expected #{this} to be false'\n      , 'expected #{this} to be true'\n      , this.negate ? true : false\n    );\n  });\n\n  /**\n   * ### .null\n   *\n   * Asserts that the target is `null`.\n   *\n   *     expect(null).to.be.null;\n   *     expect(undefined).not.to.be.null;\n   *\n   * @name null\n   * @api public\n   */\n\n  Assertion.addProperty('null', function () {\n    this.assert(\n        null === flag(this, 'object')\n      , 'expected #{this} to be null'\n      , 'expected #{this} not to be null'\n    );\n  });\n\n  /**\n   * ### .undefined\n   *\n   * Asserts that the target is `undefined`.\n   *\n   *     expect(undefined).to.be.undefined;\n   *     expect(null).to.not.be.undefined;\n   *\n   * @name undefined\n   * @api public\n   */\n\n  Assertion.addProperty('undefined', function () {\n    this.assert(\n        undefined === flag(this, 'object')\n      , 'expected #{this} to be undefined'\n      , 'expected #{this} not to be undefined'\n    );\n  });\n\n  /**\n   * ### .exist\n   *\n   * Asserts that the target is neither `null` nor `undefined`.\n   *\n   *     var foo = 'hi'\n   *       , bar = null\n   *       , baz;\n   *\n   *     expect(foo).to.exist;\n   *     expect(bar).to.not.exist;\n   *     expect(baz).to.not.exist;\n   *\n   * @name exist\n   * @api public\n   */\n\n  Assertion.addProperty('exist', function () {\n    this.assert(\n        null != flag(this, 'object')\n      , 'expected #{this} to exist'\n      , 'expected #{this} to not exist'\n    );\n  });\n\n\n  /**\n   * ### .empty\n   *\n   * Asserts that the target's length is `0`. For arrays, it checks\n   * the `length` property. For objects, it gets the count of\n   * enumerable keys.\n   *\n   *     expect([]).to.be.empty;\n   *     expect('').to.be.empty;\n   *     expect({}).to.be.empty;\n   *\n   * @name empty\n   * @api public\n   */\n\n  Assertion.addProperty('empty', function () {\n    var obj = flag(this, 'object')\n      , expected = obj;\n\n    if (Array.isArray(obj) || 'string' === typeof object) {\n      expected = obj.length;\n    } else if (typeof obj === 'object') {\n      expected = Object.keys(obj).length;\n    }\n\n    this.assert(\n        !expected\n      , 'expected #{this} to be empty'\n      , 'expected #{this} not to be empty'\n    );\n  });\n\n  /**\n   * ### .arguments\n   *\n   * Asserts that the target is an arguments object.\n   *\n   *     function test () {\n   *       expect(arguments).to.be.arguments;\n   *     }\n   *\n   * @name arguments\n   * @alias Arguments\n   * @api public\n   */\n\n  function checkArguments () {\n    var obj = flag(this, 'object')\n      , type = Object.prototype.toString.call(obj);\n    this.assert(\n        '[object Arguments]' === type\n      , 'expected #{this} to be arguments but got ' + type\n      , 'expected #{this} to not be arguments'\n    );\n  }\n\n  Assertion.addProperty('arguments', checkArguments);\n  Assertion.addProperty('Arguments', checkArguments);\n\n  /**\n   * ### .equal(value)\n   *\n   * Asserts that the target is strictly equal (`===`) to `value`.\n   * Alternately, if the `deep` flag is set, asserts that\n   * the target is deeply equal to `value`.\n   *\n   *     expect('hello').to.equal('hello');\n   *     expect(42).to.equal(42);\n   *     expect(1).to.not.equal(true);\n   *     expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });\n   *     expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });\n   *\n   * @name equal\n   * @alias equals\n   * @alias eq\n   * @alias deep.equal\n   * @param {Mixed} value\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertEqual (val, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    if (flag(this, 'deep')) {\n      return this.eql(val);\n    } else {\n      this.assert(\n          val === obj\n        , 'expected #{this} to equal #{exp}'\n        , 'expected #{this} to not equal #{exp}'\n        , val\n        , this._obj\n        , true\n      );\n    }\n  }\n\n  Assertion.addMethod('equal', assertEqual);\n  Assertion.addMethod('equals', assertEqual);\n  Assertion.addMethod('eq', assertEqual);\n\n  /**\n   * ### .eql(value)\n   *\n   * Asserts that the target is deeply equal to `value`.\n   *\n   *     expect({ foo: 'bar' }).to.eql({ foo: 'bar' });\n   *     expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);\n   *\n   * @name eql\n   * @alias eqls\n   * @param {Mixed} value\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertEql(obj, msg) {\n    if (msg) flag(this, 'message', msg);\n    this.assert(\n        _.eql(obj, flag(this, 'object'))\n      , 'expected #{this} to deeply equal #{exp}'\n      , 'expected #{this} to not deeply equal #{exp}'\n      , obj\n      , this._obj\n      , true\n    );\n  }\n\n  Assertion.addMethod('eql', assertEql);\n  Assertion.addMethod('eqls', assertEql);\n\n  /**\n   * ### .above(value)\n   *\n   * Asserts that the target is greater than `value`.\n   *\n   *     expect(10).to.be.above(5);\n   *\n   * Can also be used in conjunction with `length` to\n   * assert a minimum length. The benefit being a\n   * more informative error message than if the length\n   * was supplied directly.\n   *\n   *     expect('foo').to.have.length.above(2);\n   *     expect([ 1, 2, 3 ]).to.have.length.above(2);\n   *\n   * @name above\n   * @alias gt\n   * @alias greaterThan\n   * @param {Number} value\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertAbove (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    if (flag(this, 'doLength')) {\n      new Assertion(obj, msg).to.have.property('length');\n      var len = obj.length;\n      this.assert(\n          len > n\n        , 'expected #{this} to have a length above #{exp} but got #{act}'\n        , 'expected #{this} to not have a length above #{exp}'\n        , n\n        , len\n      );\n    } else {\n      this.assert(\n          obj > n\n        , 'expected #{this} to be above ' + n\n        , 'expected #{this} to be at most ' + n\n      );\n    }\n  }\n\n  Assertion.addMethod('above', assertAbove);\n  Assertion.addMethod('gt', assertAbove);\n  Assertion.addMethod('greaterThan', assertAbove);\n\n  /**\n   * ### .least(value)\n   *\n   * Asserts that the target is greater than or equal to `value`.\n   *\n   *     expect(10).to.be.at.least(10);\n   *\n   * Can also be used in conjunction with `length` to\n   * assert a minimum length. The benefit being a\n   * more informative error message than if the length\n   * was supplied directly.\n   *\n   *     expect('foo').to.have.length.of.at.least(2);\n   *     expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);\n   *\n   * @name least\n   * @alias gte\n   * @param {Number} value\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertLeast (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    if (flag(this, 'doLength')) {\n      new Assertion(obj, msg).to.have.property('length');\n      var len = obj.length;\n      this.assert(\n          len >= n\n        , 'expected #{this} to have a length at least #{exp} but got #{act}'\n        , 'expected #{this} to have a length below #{exp}'\n        , n\n        , len\n      );\n    } else {\n      this.assert(\n          obj >= n\n        , 'expected #{this} to be at least ' + n\n        , 'expected #{this} to be below ' + n\n      );\n    }\n  }\n\n  Assertion.addMethod('least', assertLeast);\n  Assertion.addMethod('gte', assertLeast);\n\n  /**\n   * ### .below(value)\n   *\n   * Asserts that the target is less than `value`.\n   *\n   *     expect(5).to.be.below(10);\n   *\n   * Can also be used in conjunction with `length` to\n   * assert a maximum length. The benefit being a\n   * more informative error message than if the length\n   * was supplied directly.\n   *\n   *     expect('foo').to.have.length.below(4);\n   *     expect([ 1, 2, 3 ]).to.have.length.below(4);\n   *\n   * @name below\n   * @alias lt\n   * @alias lessThan\n   * @param {Number} value\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertBelow (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    if (flag(this, 'doLength')) {\n      new Assertion(obj, msg).to.have.property('length');\n      var len = obj.length;\n      this.assert(\n          len < n\n        , 'expected #{this} to have a length below #{exp} but got #{act}'\n        , 'expected #{this} to not have a length below #{exp}'\n        , n\n        , len\n      );\n    } else {\n      this.assert(\n          obj < n\n        , 'expected #{this} to be below ' + n\n        , 'expected #{this} to be at least ' + n\n      );\n    }\n  }\n\n  Assertion.addMethod('below', assertBelow);\n  Assertion.addMethod('lt', assertBelow);\n  Assertion.addMethod('lessThan', assertBelow);\n\n  /**\n   * ### .most(value)\n   *\n   * Asserts that the target is less than or equal to `value`.\n   *\n   *     expect(5).to.be.at.most(5);\n   *\n   * Can also be used in conjunction with `length` to\n   * assert a maximum length. The benefit being a\n   * more informative error message than if the length\n   * was supplied directly.\n   *\n   *     expect('foo').to.have.length.of.at.most(4);\n   *     expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);\n   *\n   * @name most\n   * @alias lte\n   * @param {Number} value\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertMost (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    if (flag(this, 'doLength')) {\n      new Assertion(obj, msg).to.have.property('length');\n      var len = obj.length;\n      this.assert(\n          len <= n\n        , 'expected #{this} to have a length at most #{exp} but got #{act}'\n        , 'expected #{this} to have a length above #{exp}'\n        , n\n        , len\n      );\n    } else {\n      this.assert(\n          obj <= n\n        , 'expected #{this} to be at most ' + n\n        , 'expected #{this} to be above ' + n\n      );\n    }\n  }\n\n  Assertion.addMethod('most', assertMost);\n  Assertion.addMethod('lte', assertMost);\n\n  /**\n   * ### .within(start, finish)\n   *\n   * Asserts that the target is within a range.\n   *\n   *     expect(7).to.be.within(5,10);\n   *\n   * Can also be used in conjunction with `length` to\n   * assert a length range. The benefit being a\n   * more informative error message than if the length\n   * was supplied directly.\n   *\n   *     expect('foo').to.have.length.within(2,4);\n   *     expect([ 1, 2, 3 ]).to.have.length.within(2,4);\n   *\n   * @name within\n   * @param {Number} start lowerbound inclusive\n   * @param {Number} finish upperbound inclusive\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  Assertion.addMethod('within', function (start, finish, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , range = start + '..' + finish;\n    if (flag(this, 'doLength')) {\n      new Assertion(obj, msg).to.have.property('length');\n      var len = obj.length;\n      this.assert(\n          len >= start && len <= finish\n        , 'expected #{this} to have a length within ' + range\n        , 'expected #{this} to not have a length within ' + range\n      );\n    } else {\n      this.assert(\n          obj >= start && obj <= finish\n        , 'expected #{this} to be within ' + range\n        , 'expected #{this} to not be within ' + range\n      );\n    }\n  });\n\n  /**\n   * ### .instanceof(constructor)\n   *\n   * Asserts that the target is an instance of `constructor`.\n   *\n   *     var Tea = function (name) { this.name = name; }\n   *       , Chai = new Tea('chai');\n   *\n   *     expect(Chai).to.be.an.instanceof(Tea);\n   *     expect([ 1, 2, 3 ]).to.be.instanceof(Array);\n   *\n   * @name instanceof\n   * @param {Constructor} constructor\n   * @param {String} message _optional_\n   * @alias instanceOf\n   * @api public\n   */\n\n  function assertInstanceOf (constructor, msg) {\n    if (msg) flag(this, 'message', msg);\n    var name = _.getName(constructor);\n    this.assert(\n        flag(this, 'object') instanceof constructor\n      , 'expected #{this} to be an instance of ' + name\n      , 'expected #{this} to not be an instance of ' + name\n    );\n  };\n\n  Assertion.addMethod('instanceof', assertInstanceOf);\n  Assertion.addMethod('instanceOf', assertInstanceOf);\n\n  /**\n   * ### .property(name, [value])\n   *\n   * Asserts that the target has a property `name`, optionally asserting that\n   * the value of that property is strictly equal to  `value`.\n   * If the `deep` flag is set, you can use dot- and bracket-notation for deep\n   * references into objects and arrays.\n   *\n   *     // simple referencing\n   *     var obj = { foo: 'bar' };\n   *     expect(obj).to.have.property('foo');\n   *     expect(obj).to.have.property('foo', 'bar');\n   *\n   *     // deep referencing\n   *     var deepObj = {\n   *         green: { tea: 'matcha' }\n   *       , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]\n   *     };\n\n   *     expect(deepObj).to.have.deep.property('green.tea', 'matcha');\n   *     expect(deepObj).to.have.deep.property('teas[1]', 'matcha');\n   *     expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');\n   *\n   * You can also use an array as the starting point of a `deep.property`\n   * assertion, or traverse nested arrays.\n   *\n   *     var arr = [\n   *         [ 'chai', 'matcha', 'konacha' ]\n   *       , [ { tea: 'chai' }\n   *         , { tea: 'matcha' }\n   *         , { tea: 'konacha' } ]\n   *     ];\n   *\n   *     expect(arr).to.have.deep.property('[0][1]', 'matcha');\n   *     expect(arr).to.have.deep.property('[1][2].tea', 'konacha');\n   *\n   * Furthermore, `property` changes the subject of the assertion\n   * to be the value of that property from the original object. This\n   * permits for further chainable assertions on that property.\n   *\n   *     expect(obj).to.have.property('foo')\n   *       .that.is.a('string');\n   *     expect(deepObj).to.have.property('green')\n   *       .that.is.an('object')\n   *       .that.deep.equals({ tea: 'matcha' });\n   *     expect(deepObj).to.have.property('teas')\n   *       .that.is.an('array')\n   *       .with.deep.property('[2]')\n   *         .that.deep.equals({ tea: 'konacha' });\n   *\n   * @name property\n   * @alias deep.property\n   * @param {String} name\n   * @param {Mixed} value (optional)\n   * @param {String} message _optional_\n   * @returns value of property for chaining\n   * @api public\n   */\n\n  Assertion.addMethod('property', function (name, val, msg) {\n    if (msg) flag(this, 'message', msg);\n\n    var isDeep = !!flag(this, 'deep')\n      , descriptor = isDeep ? 'deep property ' : 'property '\n      , negate = flag(this, 'negate')\n      , obj = flag(this, 'object')\n      , pathInfo = isDeep ? _.getPathInfo(name, obj) : null\n      , hasProperty = isDeep\n        ? pathInfo.exists\n        : _.hasProperty(name, obj)\n      , value = isDeep\n        ? pathInfo.value\n        : obj[name];\n\n    if (negate && undefined !== val) {\n      if (undefined === value) {\n        msg = (msg != null) ? msg + ': ' : '';\n        throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name));\n      }\n    } else {\n      this.assert(\n          hasProperty\n        , 'expected #{this} to have a ' + descriptor + _.inspect(name)\n        , 'expected #{this} to not have ' + descriptor + _.inspect(name));\n    }\n\n    if (undefined !== val) {\n      this.assert(\n          val === value\n        , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'\n        , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'\n        , val\n        , value\n      );\n    }\n\n    flag(this, 'object', value);\n  });\n\n\n  /**\n   * ### .ownProperty(name)\n   *\n   * Asserts that the target has an own property `name`.\n   *\n   *     expect('test').to.have.ownProperty('length');\n   *\n   * @name ownProperty\n   * @alias haveOwnProperty\n   * @param {String} name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertOwnProperty (name, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    this.assert(\n        obj.hasOwnProperty(name)\n      , 'expected #{this} to have own property ' + _.inspect(name)\n      , 'expected #{this} to not have own property ' + _.inspect(name)\n    );\n  }\n\n  Assertion.addMethod('ownProperty', assertOwnProperty);\n  Assertion.addMethod('haveOwnProperty', assertOwnProperty);\n\n  /**\n   * ### .length(value)\n   *\n   * Asserts that the target's `length` property has\n   * the expected value.\n   *\n   *     expect([ 1, 2, 3]).to.have.length(3);\n   *     expect('foobar').to.have.length(6);\n   *\n   * Can also be used as a chain precursor to a value\n   * comparison for the length property.\n   *\n   *     expect('foo').to.have.length.above(2);\n   *     expect([ 1, 2, 3 ]).to.have.length.above(2);\n   *     expect('foo').to.have.length.below(4);\n   *     expect([ 1, 2, 3 ]).to.have.length.below(4);\n   *     expect('foo').to.have.length.within(2,4);\n   *     expect([ 1, 2, 3 ]).to.have.length.within(2,4);\n   *\n   * @name length\n   * @alias lengthOf\n   * @param {Number} length\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertLengthChain () {\n    flag(this, 'doLength', true);\n  }\n\n  function assertLength (n, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    new Assertion(obj, msg).to.have.property('length');\n    var len = obj.length;\n\n    this.assert(\n        len == n\n      , 'expected #{this} to have a length of #{exp} but got #{act}'\n      , 'expected #{this} to not have a length of #{act}'\n      , n\n      , len\n    );\n  }\n\n  Assertion.addChainableMethod('length', assertLength, assertLengthChain);\n  Assertion.addMethod('lengthOf', assertLength);\n\n  /**\n   * ### .match(regexp)\n   *\n   * Asserts that the target matches a regular expression.\n   *\n   *     expect('foobar').to.match(/^foo/);\n   *\n   * @name match\n   * @param {RegExp} RegularExpression\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  Assertion.addMethod('match', function (re, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    this.assert(\n        re.exec(obj)\n      , 'expected #{this} to match ' + re\n      , 'expected #{this} not to match ' + re\n    );\n  });\n\n  /**\n   * ### .string(string)\n   *\n   * Asserts that the string target contains another string.\n   *\n   *     expect('foobar').to.have.string('bar');\n   *\n   * @name string\n   * @param {String} string\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  Assertion.addMethod('string', function (str, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    new Assertion(obj, msg).is.a('string');\n\n    this.assert(\n        ~obj.indexOf(str)\n      , 'expected #{this} to contain ' + _.inspect(str)\n      , 'expected #{this} to not contain ' + _.inspect(str)\n    );\n  });\n\n\n  /**\n   * ### .keys(key1, [key2], [...])\n   *\n   * Asserts that the target contains any or all of the passed-in keys.\n   * Use in combination with `any`, `all`, `contains`, or `have` will affect \n   * what will pass.\n   * \n   * When used in conjunction with `any`, at least one key that is passed \n   * in must exist in the target object. This is regardless whether or not \n   * the `have` or `contain` qualifiers are used. Note, either `any` or `all`\n   * should be used in the assertion. If neither are used, the assertion is\n   * defaulted to `all`.\n   * \n   * When both `all` and `contain` are used, the target object must have at \n   * least all of the passed-in keys but may have more keys not listed.\n   * \n   * When both `all` and `have` are used, the target object must both contain\n   * all of the passed-in keys AND the number of keys in the target object must\n   * match the number of keys passed in (in other words, a target object must \n   * have all and only all of the passed-in keys).\n   * \n   *     expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz');\n   *     expect({ foo: 1, bar: 2 }).to.have.any.keys('foo');\n   *     expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz');\n   *     expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']);\n   *     expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6});\n   *     expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']);\n   *     expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo', 7});\n   *     expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']);\n   *     expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys([{'bar': 6}}]);\n   *\n   *\n   * @name keys\n   * @alias key\n   * @param {String...|Array|Object} keys\n   * @api public\n   */\n\n  function assertKeys (keys) {\n    var obj = flag(this, 'object')\n      , str\n      , ok = true\n      , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments';\n\n    switch (_.type(keys)) {\n      case \"array\":\n        if (arguments.length > 1) throw (new Error(mixedArgsMsg));\n        break;\n      case \"object\":\n        if (arguments.length > 1) throw (new Error(mixedArgsMsg));\n        keys = Object.keys(keys);\n        break;\n      default:\n        keys = Array.prototype.slice.call(arguments);\n    }\n\n    if (!keys.length) throw new Error('keys required');\n\n    var actual = Object.keys(obj)\n      , expected = keys\n      , len = keys.length\n      , any = flag(this, 'any')\n      , all = flag(this, 'all');\n\n    if (!any && !all) {\n      all = true;\n    }\n\n    // Has any\n    if (any) {\n      var intersection = expected.filter(function(key) {\n        return ~actual.indexOf(key);\n      });\n      ok = intersection.length > 0;\n    }\n\n    // Has all\n    if (all) {\n      ok = keys.every(function(key){\n        return ~actual.indexOf(key);\n      });\n      if (!flag(this, 'negate') && !flag(this, 'contains')) {\n        ok = ok && keys.length == actual.length;\n      }\n    }\n\n    // Key string\n    if (len > 1) {\n      keys = keys.map(function(key){\n        return _.inspect(key);\n      });\n      var last = keys.pop();\n      if (all) {\n        str = keys.join(', ') + ', and ' + last;\n      }\n      if (any) {\n        str = keys.join(', ') + ', or ' + last;\n      }\n    } else {\n      str = _.inspect(keys[0]);\n    }\n\n    // Form\n    str = (len > 1 ? 'keys ' : 'key ') + str;\n\n    // Have / include\n    str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;\n\n    // Assertion\n    this.assert(\n        ok\n      , 'expected #{this} to ' + str\n      , 'expected #{this} to not ' + str\n      , expected.slice(0).sort()\n      , actual.sort()\n      , true\n    );\n  }\n\n  Assertion.addMethod('keys', assertKeys);\n  Assertion.addMethod('key', assertKeys);\n\n  /**\n   * ### .throw(constructor)\n   *\n   * Asserts that the function target will throw a specific error, or specific type of error\n   * (as determined using `instanceof`), optionally with a RegExp or string inclusion test\n   * for the error's message.\n   *\n   *     var err = new ReferenceError('This is a bad function.');\n   *     var fn = function () { throw err; }\n   *     expect(fn).to.throw(ReferenceError);\n   *     expect(fn).to.throw(Error);\n   *     expect(fn).to.throw(/bad function/);\n   *     expect(fn).to.not.throw('good function');\n   *     expect(fn).to.throw(ReferenceError, /bad function/);\n   *     expect(fn).to.throw(err);\n   *     expect(fn).to.not.throw(new RangeError('Out of range.'));\n   *\n   * Please note that when a throw expectation is negated, it will check each\n   * parameter independently, starting with error constructor type. The appropriate way\n   * to check for the existence of a type of error but for a message that does not match\n   * is to use `and`.\n   *\n   *     expect(fn).to.throw(ReferenceError)\n   *        .and.not.throw(/good function/);\n   *\n   * @name throw\n   * @alias throws\n   * @alias Throw\n   * @param {ErrorConstructor} constructor\n   * @param {String|RegExp} expected error message\n   * @param {String} message _optional_\n   * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n   * @returns error for chaining (null if no error)\n   * @api public\n   */\n\n  function assertThrows (constructor, errMsg, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    new Assertion(obj, msg).is.a('function');\n\n    var thrown = false\n      , desiredError = null\n      , name = null\n      , thrownError = null;\n\n    if (arguments.length === 0) {\n      errMsg = null;\n      constructor = null;\n    } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {\n      errMsg = constructor;\n      constructor = null;\n    } else if (constructor && constructor instanceof Error) {\n      desiredError = constructor;\n      constructor = null;\n      errMsg = null;\n    } else if (typeof constructor === 'function') {\n      name = constructor.prototype.name || constructor.name;\n      if (name === 'Error' && constructor !== Error) {\n        name = (new constructor()).name;\n      }\n    } else {\n      constructor = null;\n    }\n\n    try {\n      obj();\n    } catch (err) {\n      // first, check desired error\n      if (desiredError) {\n        this.assert(\n            err === desiredError\n          , 'expected #{this} to throw #{exp} but #{act} was thrown'\n          , 'expected #{this} to not throw #{exp}'\n          , (desiredError instanceof Error ? desiredError.toString() : desiredError)\n          , (err instanceof Error ? err.toString() : err)\n        );\n\n        flag(this, 'object', err);\n        return this;\n      }\n\n      // next, check constructor\n      if (constructor) {\n        this.assert(\n            err instanceof constructor\n          , 'expected #{this} to throw #{exp} but #{act} was thrown'\n          , 'expected #{this} to not throw #{exp} but #{act} was thrown'\n          , name\n          , (err instanceof Error ? err.toString() : err)\n        );\n\n        if (!errMsg) {\n          flag(this, 'object', err);\n          return this;\n        }\n      }\n\n      // next, check message\n      var message = 'object' === _.type(err) && \"message\" in err\n        ? err.message\n        : '' + err;\n\n      if ((message != null) && errMsg && errMsg instanceof RegExp) {\n        this.assert(\n            errMsg.exec(message)\n          , 'expected #{this} to throw error matching #{exp} but got #{act}'\n          , 'expected #{this} to throw error not matching #{exp}'\n          , errMsg\n          , message\n        );\n\n        flag(this, 'object', err);\n        return this;\n      } else if ((message != null) && errMsg && 'string' === typeof errMsg) {\n        this.assert(\n            ~message.indexOf(errMsg)\n          , 'expected #{this} to throw error including #{exp} but got #{act}'\n          , 'expected #{this} to throw error not including #{act}'\n          , errMsg\n          , message\n        );\n\n        flag(this, 'object', err);\n        return this;\n      } else {\n        thrown = true;\n        thrownError = err;\n      }\n    }\n\n    var actuallyGot = ''\n      , expectedThrown = name !== null\n        ? name\n        : desiredError\n          ? '#{exp}' //_.inspect(desiredError)\n          : 'an error';\n\n    if (thrown) {\n      actuallyGot = ' but #{act} was thrown'\n    }\n\n    this.assert(\n        thrown === true\n      , 'expected #{this} to throw ' + expectedThrown + actuallyGot\n      , 'expected #{this} to not throw ' + expectedThrown + actuallyGot\n      , (desiredError instanceof Error ? desiredError.toString() : desiredError)\n      , (thrownError instanceof Error ? thrownError.toString() : thrownError)\n    );\n\n    flag(this, 'object', thrownError);\n  };\n\n  Assertion.addMethod('throw', assertThrows);\n  Assertion.addMethod('throws', assertThrows);\n  Assertion.addMethod('Throw', assertThrows);\n\n  /**\n   * ### .respondTo(method)\n   *\n   * Asserts that the object or class target will respond to a method.\n   *\n   *     Klass.prototype.bar = function(){};\n   *     expect(Klass).to.respondTo('bar');\n   *     expect(obj).to.respondTo('bar');\n   *\n   * To check if a constructor will respond to a static function,\n   * set the `itself` flag.\n   *\n   *     Klass.baz = function(){};\n   *     expect(Klass).itself.to.respondTo('baz');\n   *\n   * @name respondTo\n   * @param {String} method\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  Assertion.addMethod('respondTo', function (method, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object')\n      , itself = flag(this, 'itself')\n      , context = ('function' === _.type(obj) && !itself)\n        ? obj.prototype[method]\n        : obj[method];\n\n    this.assert(\n        'function' === typeof context\n      , 'expected #{this} to respond to ' + _.inspect(method)\n      , 'expected #{this} to not respond to ' + _.inspect(method)\n    );\n  });\n\n  /**\n   * ### .itself\n   *\n   * Sets the `itself` flag, later used by the `respondTo` assertion.\n   *\n   *     function Foo() {}\n   *     Foo.bar = function() {}\n   *     Foo.prototype.baz = function() {}\n   *\n   *     expect(Foo).itself.to.respondTo('bar');\n   *     expect(Foo).itself.not.to.respondTo('baz');\n   *\n   * @name itself\n   * @api public\n   */\n\n  Assertion.addProperty('itself', function () {\n    flag(this, 'itself', true);\n  });\n\n  /**\n   * ### .satisfy(method)\n   *\n   * Asserts that the target passes a given truth test.\n   *\n   *     expect(1).to.satisfy(function(num) { return num > 0; });\n   *\n   * @name satisfy\n   * @param {Function} matcher\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  Assertion.addMethod('satisfy', function (matcher, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n    var result = matcher(obj);\n    this.assert(\n        result\n      , 'expected #{this} to satisfy ' + _.objDisplay(matcher)\n      , 'expected #{this} to not satisfy' + _.objDisplay(matcher)\n      , this.negate ? false : true\n      , result\n    );\n  });\n\n  /**\n   * ### .closeTo(expected, delta)\n   *\n   * Asserts that the target is equal `expected`, to within a +/- `delta` range.\n   *\n   *     expect(1.5).to.be.closeTo(1, 0.5);\n   *\n   * @name closeTo\n   * @param {Number} expected\n   * @param {Number} delta\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  Assertion.addMethod('closeTo', function (expected, delta, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n\n    new Assertion(obj, msg).is.a('number');\n    if (_.type(expected) !== 'number' || _.type(delta) !== 'number') {\n      throw new Error('the arguments to closeTo must be numbers');\n    }\n\n    this.assert(\n        Math.abs(obj - expected) <= delta\n      , 'expected #{this} to be close to ' + expected + ' +/- ' + delta\n      , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta\n    );\n  });\n\n  function isSubsetOf(subset, superset, cmp) {\n    return subset.every(function(elem) {\n      if (!cmp) return superset.indexOf(elem) !== -1;\n\n      return superset.some(function(elem2) {\n        return cmp(elem, elem2);\n      });\n    })\n  }\n\n  /**\n   * ### .members(set)\n   *\n   * Asserts that the target is a superset of `set`,\n   * or that the target and `set` have the same strictly-equal (===) members.\n   * Alternately, if the `deep` flag is set, set members are compared for deep\n   * equality.\n   *\n   *     expect([1, 2, 3]).to.include.members([3, 2]);\n   *     expect([1, 2, 3]).to.not.include.members([3, 2, 8]);\n   *\n   *     expect([4, 2]).to.have.members([2, 4]);\n   *     expect([5, 2]).to.not.have.members([5, 2, 1]);\n   *\n   *     expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]);\n   *\n   * @name members\n   * @param {Array} set\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  Assertion.addMethod('members', function (subset, msg) {\n    if (msg) flag(this, 'message', msg);\n    var obj = flag(this, 'object');\n\n    new Assertion(obj).to.be.an('array');\n    new Assertion(subset).to.be.an('array');\n\n    var cmp = flag(this, 'deep') ? _.eql : undefined;\n\n    if (flag(this, 'contains')) {\n      return this.assert(\n          isSubsetOf(subset, obj, cmp)\n        , 'expected #{this} to be a superset of #{act}'\n        , 'expected #{this} to not be a superset of #{act}'\n        , obj\n        , subset\n      );\n    }\n\n    this.assert(\n        isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp)\n        , 'expected #{this} to have the same members as #{act}'\n        , 'expected #{this} to not have the same members as #{act}'\n        , obj\n        , subset\n    );\n  });\n\n  /**\n   * ### .change(function)\n   *\n   * Asserts that a function changes an object property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val += 3 };\n   *     var noChangeFn = function() { return 'foo' + 'bar'; }\n   *     expect(fn).to.change(obj, 'val');\n   *     expect(noChangFn).to.not.change(obj, 'val')\n   *\n   * @name change\n   * @alias changes\n   * @alias Change\n   * @param {String} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertChanges (object, prop, msg) {\n    if (msg) flag(this, 'message', msg);\n    var fn = flag(this, 'object');\n    new Assertion(object, msg).to.have.property(prop);\n    new Assertion(fn).is.a('function');\n\n    var initial = object[prop];\n    fn();\n\n    this.assert(\n      initial !== object[prop]\n      , 'expected .' + prop + ' to change'\n      , 'expected .' + prop + ' to not change'\n    );\n  }\n\n  Assertion.addChainableMethod('change', assertChanges);\n  Assertion.addChainableMethod('changes', assertChanges);\n\n  /**\n   * ### .increase(function)\n   *\n   * Asserts that a function increases an object property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 15 };\n   *     expect(fn).to.increase(obj, 'val');\n   *\n   * @name increase\n   * @alias increases\n   * @alias Increase\n   * @param {String} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertIncreases (object, prop, msg) {\n    if (msg) flag(this, 'message', msg);\n    var fn = flag(this, 'object');\n    new Assertion(object, msg).to.have.property(prop);\n    new Assertion(fn).is.a('function');\n\n    var initial = object[prop];\n    fn();\n\n    this.assert(\n      object[prop] - initial > 0\n      , 'expected .' + prop + ' to increase'\n      , 'expected .' + prop + ' to not increase'\n    );\n  }\n\n  Assertion.addChainableMethod('increase', assertIncreases);\n  Assertion.addChainableMethod('increases', assertIncreases);\n\n  /**\n   * ### .decrease(function)\n   *\n   * Asserts that a function decreases an object property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 5 };\n   *     expect(fn).to.decrease(obj, 'val');\n   *\n   * @name decrease\n   * @alias decreases\n   * @alias Decrease\n   * @param {String} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  function assertDecreases (object, prop, msg) {\n    if (msg) flag(this, 'message', msg);\n    var fn = flag(this, 'object');\n    new Assertion(object, msg).to.have.property(prop);\n    new Assertion(fn).is.a('function');\n\n    var initial = object[prop];\n    fn();\n\n    this.assert(\n      object[prop] - initial < 0\n      , 'expected .' + prop + ' to decrease'\n      , 'expected .' + prop + ' to not decrease'\n    );\n  }\n\n  Assertion.addChainableMethod('decrease', assertDecreases);\n  Assertion.addChainableMethod('decreases', assertDecreases);\n\n};\n\n});\n\nrequire.register(\"chai/lib/chai/interface/assert.js\", function (exports, module) {\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n\nmodule.exports = function (chai, util) {\n\n  /*!\n   * Chai dependencies.\n   */\n\n  var Assertion = chai.Assertion\n    , flag = util.flag;\n\n  /*!\n   * Module export.\n   */\n\n  /**\n   * ### assert(expression, message)\n   *\n   * Write your own test expressions.\n   *\n   *     assert('foo' !== 'bar', 'foo is not bar');\n   *     assert(Array.isArray([]), 'empty arrays are arrays');\n   *\n   * @param {Mixed} expression to test for truthiness\n   * @param {String} message to display on error\n   * @name assert\n   * @api public\n   */\n\n  var assert = chai.assert = function (express, errmsg) {\n    var test = new Assertion(null, null, chai.assert);\n    test.assert(\n        express\n      , errmsg\n      , '[ negation message unavailable ]'\n    );\n  };\n\n  /**\n   * ### .fail(actual, expected, [message], [operator])\n   *\n   * Throw a failure. Node.js `assert` module-compatible.\n   *\n   * @name fail\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @param {String} operator\n   * @api public\n   */\n\n  assert.fail = function (actual, expected, message, operator) {\n    message = message || 'assert.fail()';\n    throw new chai.AssertionError(message, {\n        actual: actual\n      , expected: expected\n      , operator: operator\n    }, assert.fail);\n  };\n\n  /**\n   * ### .ok(object, [message])\n   *\n   * Asserts that `object` is truthy.\n   *\n   *     assert.ok('everything', 'everything is ok');\n   *     assert.ok(false, 'this will fail');\n   *\n   * @name ok\n   * @param {Mixed} object to test\n   * @param {String} message\n   * @api public\n   */\n\n  assert.ok = function (val, msg) {\n    new Assertion(val, msg).is.ok;\n  };\n\n  /**\n   * ### .notOk(object, [message])\n   *\n   * Asserts that `object` is falsy.\n   *\n   *     assert.notOk('everything', 'this will fail');\n   *     assert.notOk(false, 'this will pass');\n   *\n   * @name notOk\n   * @param {Mixed} object to test\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notOk = function (val, msg) {\n    new Assertion(val, msg).is.not.ok;\n  };\n\n  /**\n   * ### .equal(actual, expected, [message])\n   *\n   * Asserts non-strict equality (`==`) of `actual` and `expected`.\n   *\n   *     assert.equal(3, '3', '== coerces values to strings');\n   *\n   * @name equal\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @api public\n   */\n\n  assert.equal = function (act, exp, msg) {\n    var test = new Assertion(act, msg, assert.equal);\n\n    test.assert(\n        exp == flag(test, 'object')\n      , 'expected #{this} to equal #{exp}'\n      , 'expected #{this} to not equal #{act}'\n      , exp\n      , act\n    );\n  };\n\n  /**\n   * ### .notEqual(actual, expected, [message])\n   *\n   * Asserts non-strict inequality (`!=`) of `actual` and `expected`.\n   *\n   *     assert.notEqual(3, 4, 'these numbers are not equal');\n   *\n   * @name notEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notEqual = function (act, exp, msg) {\n    var test = new Assertion(act, msg, assert.notEqual);\n\n    test.assert(\n        exp != flag(test, 'object')\n      , 'expected #{this} to not equal #{exp}'\n      , 'expected #{this} to equal #{act}'\n      , exp\n      , act\n    );\n  };\n\n  /**\n   * ### .strictEqual(actual, expected, [message])\n   *\n   * Asserts strict equality (`===`) of `actual` and `expected`.\n   *\n   *     assert.strictEqual(true, true, 'these booleans are strictly equal');\n   *\n   * @name strictEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @api public\n   */\n\n  assert.strictEqual = function (act, exp, msg) {\n    new Assertion(act, msg).to.equal(exp);\n  };\n\n  /**\n   * ### .notStrictEqual(actual, expected, [message])\n   *\n   * Asserts strict inequality (`!==`) of `actual` and `expected`.\n   *\n   *     assert.notStrictEqual(3, '3', 'no coercion for strict equality');\n   *\n   * @name notStrictEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notStrictEqual = function (act, exp, msg) {\n    new Assertion(act, msg).to.not.equal(exp);\n  };\n\n  /**\n   * ### .deepEqual(actual, expected, [message])\n   *\n   * Asserts that `actual` is deeply equal to `expected`.\n   *\n   *     assert.deepEqual({ tea: 'green' }, { tea: 'green' });\n   *\n   * @name deepEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @api public\n   */\n\n  assert.deepEqual = function (act, exp, msg) {\n    new Assertion(act, msg).to.eql(exp);\n  };\n\n  /**\n   * ### .notDeepEqual(actual, expected, [message])\n   *\n   * Assert that `actual` is not deeply equal to `expected`.\n   *\n   *     assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' });\n   *\n   * @name notDeepEqual\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notDeepEqual = function (act, exp, msg) {\n    new Assertion(act, msg).to.not.eql(exp);\n  };\n\n  /**\n   * ### .isTrue(value, [message])\n   *\n   * Asserts that `value` is true.\n   *\n   *     var teaServed = true;\n   *     assert.isTrue(teaServed, 'the tea has been served');\n   *\n   * @name isTrue\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isAbove = function (val, abv, msg) {\n    new Assertion(val, msg).to.be.above(abv);\n  };\n\n   /**\n   * ### .isAbove(valueToCheck, valueToBeAbove, [message])\n   *\n   * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove`\n   *\n   *     assert.isAbove(5, 2, '5 is strictly greater than 2');\n   *\n   * @name isAbove\n   * @param {Mixed} valueToCheck\n   * @param {Mixed} valueToBeAbove\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isBelow = function (val, blw, msg) {\n    new Assertion(val, msg).to.be.below(blw);\n  };\n\n   /**\n   * ### .isBelow(valueToCheck, valueToBeBelow, [message])\n   *\n   * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow`\n   *\n   *     assert.isBelow(3, 6, '3 is strictly less than 6');\n   *\n   * @name isBelow\n   * @param {Mixed} valueToCheck\n   * @param {Mixed} valueToBeBelow\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isTrue = function (val, msg) {\n    new Assertion(val, msg).is['true'];\n  };\n\n  /**\n   * ### .isFalse(value, [message])\n   *\n   * Asserts that `value` is false.\n   *\n   *     var teaServed = false;\n   *     assert.isFalse(teaServed, 'no tea yet? hmm...');\n   *\n   * @name isFalse\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isFalse = function (val, msg) {\n    new Assertion(val, msg).is['false'];\n  };\n\n  /**\n   * ### .isNull(value, [message])\n   *\n   * Asserts that `value` is null.\n   *\n   *     assert.isNull(err, 'there was no error');\n   *\n   * @name isNull\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNull = function (val, msg) {\n    new Assertion(val, msg).to.equal(null);\n  };\n\n  /**\n   * ### .isNotNull(value, [message])\n   *\n   * Asserts that `value` is not null.\n   *\n   *     var tea = 'tasty chai';\n   *     assert.isNotNull(tea, 'great, time for tea!');\n   *\n   * @name isNotNull\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNotNull = function (val, msg) {\n    new Assertion(val, msg).to.not.equal(null);\n  };\n\n  /**\n   * ### .isUndefined(value, [message])\n   *\n   * Asserts that `value` is `undefined`.\n   *\n   *     var tea;\n   *     assert.isUndefined(tea, 'no tea defined');\n   *\n   * @name isUndefined\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isUndefined = function (val, msg) {\n    new Assertion(val, msg).to.equal(undefined);\n  };\n\n  /**\n   * ### .isDefined(value, [message])\n   *\n   * Asserts that `value` is not `undefined`.\n   *\n   *     var tea = 'cup of chai';\n   *     assert.isDefined(tea, 'tea has been defined');\n   *\n   * @name isDefined\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isDefined = function (val, msg) {\n    new Assertion(val, msg).to.not.equal(undefined);\n  };\n\n  /**\n   * ### .isFunction(value, [message])\n   *\n   * Asserts that `value` is a function.\n   *\n   *     function serveTea() { return 'cup of tea'; };\n   *     assert.isFunction(serveTea, 'great, we can have tea now');\n   *\n   * @name isFunction\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isFunction = function (val, msg) {\n    new Assertion(val, msg).to.be.a('function');\n  };\n\n  /**\n   * ### .isNotFunction(value, [message])\n   *\n   * Asserts that `value` is _not_ a function.\n   *\n   *     var serveTea = [ 'heat', 'pour', 'sip' ];\n   *     assert.isNotFunction(serveTea, 'great, we have listed the steps');\n   *\n   * @name isNotFunction\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNotFunction = function (val, msg) {\n    new Assertion(val, msg).to.not.be.a('function');\n  };\n\n  /**\n   * ### .isObject(value, [message])\n   *\n   * Asserts that `value` is an object (as revealed by\n   * `Object.prototype.toString`).\n   *\n   *     var selection = { name: 'Chai', serve: 'with spices' };\n   *     assert.isObject(selection, 'tea selection is an object');\n   *\n   * @name isObject\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isObject = function (val, msg) {\n    new Assertion(val, msg).to.be.a('object');\n  };\n\n  /**\n   * ### .isNotObject(value, [message])\n   *\n   * Asserts that `value` is _not_ an object.\n   *\n   *     var selection = 'chai'\n   *     assert.isNotObject(selection, 'tea selection is not an object');\n   *     assert.isNotObject(null, 'null is not an object');\n   *\n   * @name isNotObject\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNotObject = function (val, msg) {\n    new Assertion(val, msg).to.not.be.a('object');\n  };\n\n  /**\n   * ### .isArray(value, [message])\n   *\n   * Asserts that `value` is an array.\n   *\n   *     var menu = [ 'green', 'chai', 'oolong' ];\n   *     assert.isArray(menu, 'what kind of tea do we want?');\n   *\n   * @name isArray\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isArray = function (val, msg) {\n    new Assertion(val, msg).to.be.an('array');\n  };\n\n  /**\n   * ### .isNotArray(value, [message])\n   *\n   * Asserts that `value` is _not_ an array.\n   *\n   *     var menu = 'green|chai|oolong';\n   *     assert.isNotArray(menu, 'what kind of tea do we want?');\n   *\n   * @name isNotArray\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNotArray = function (val, msg) {\n    new Assertion(val, msg).to.not.be.an('array');\n  };\n\n  /**\n   * ### .isString(value, [message])\n   *\n   * Asserts that `value` is a string.\n   *\n   *     var teaOrder = 'chai';\n   *     assert.isString(teaOrder, 'order placed');\n   *\n   * @name isString\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isString = function (val, msg) {\n    new Assertion(val, msg).to.be.a('string');\n  };\n\n  /**\n   * ### .isNotString(value, [message])\n   *\n   * Asserts that `value` is _not_ a string.\n   *\n   *     var teaOrder = 4;\n   *     assert.isNotString(teaOrder, 'order placed');\n   *\n   * @name isNotString\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNotString = function (val, msg) {\n    new Assertion(val, msg).to.not.be.a('string');\n  };\n\n  /**\n   * ### .isNumber(value, [message])\n   *\n   * Asserts that `value` is a number.\n   *\n   *     var cups = 2;\n   *     assert.isNumber(cups, 'how many cups');\n   *\n   * @name isNumber\n   * @param {Number} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNumber = function (val, msg) {\n    new Assertion(val, msg).to.be.a('number');\n  };\n\n  /**\n   * ### .isNotNumber(value, [message])\n   *\n   * Asserts that `value` is _not_ a number.\n   *\n   *     var cups = '2 cups please';\n   *     assert.isNotNumber(cups, 'how many cups');\n   *\n   * @name isNotNumber\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNotNumber = function (val, msg) {\n    new Assertion(val, msg).to.not.be.a('number');\n  };\n\n  /**\n   * ### .isBoolean(value, [message])\n   *\n   * Asserts that `value` is a boolean.\n   *\n   *     var teaReady = true\n   *       , teaServed = false;\n   *\n   *     assert.isBoolean(teaReady, 'is the tea ready');\n   *     assert.isBoolean(teaServed, 'has tea been served');\n   *\n   * @name isBoolean\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isBoolean = function (val, msg) {\n    new Assertion(val, msg).to.be.a('boolean');\n  };\n\n  /**\n   * ### .isNotBoolean(value, [message])\n   *\n   * Asserts that `value` is _not_ a boolean.\n   *\n   *     var teaReady = 'yep'\n   *       , teaServed = 'nope';\n   *\n   *     assert.isNotBoolean(teaReady, 'is the tea ready');\n   *     assert.isNotBoolean(teaServed, 'has tea been served');\n   *\n   * @name isNotBoolean\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.isNotBoolean = function (val, msg) {\n    new Assertion(val, msg).to.not.be.a('boolean');\n  };\n\n  /**\n   * ### .typeOf(value, name, [message])\n   *\n   * Asserts that `value`'s type is `name`, as determined by\n   * `Object.prototype.toString`.\n   *\n   *     assert.typeOf({ tea: 'chai' }, 'object', 'we have an object');\n   *     assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array');\n   *     assert.typeOf('tea', 'string', 'we have a string');\n   *     assert.typeOf(/tea/, 'regexp', 'we have a regular expression');\n   *     assert.typeOf(null, 'null', 'we have a null');\n   *     assert.typeOf(undefined, 'undefined', 'we have an undefined');\n   *\n   * @name typeOf\n   * @param {Mixed} value\n   * @param {String} name\n   * @param {String} message\n   * @api public\n   */\n\n  assert.typeOf = function (val, type, msg) {\n    new Assertion(val, msg).to.be.a(type);\n  };\n\n  /**\n   * ### .notTypeOf(value, name, [message])\n   *\n   * Asserts that `value`'s type is _not_ `name`, as determined by\n   * `Object.prototype.toString`.\n   *\n   *     assert.notTypeOf('tea', 'number', 'strings are not numbers');\n   *\n   * @name notTypeOf\n   * @param {Mixed} value\n   * @param {String} typeof name\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notTypeOf = function (val, type, msg) {\n    new Assertion(val, msg).to.not.be.a(type);\n  };\n\n  /**\n   * ### .instanceOf(object, constructor, [message])\n   *\n   * Asserts that `value` is an instance of `constructor`.\n   *\n   *     var Tea = function (name) { this.name = name; }\n   *       , chai = new Tea('chai');\n   *\n   *     assert.instanceOf(chai, Tea, 'chai is an instance of tea');\n   *\n   * @name instanceOf\n   * @param {Object} object\n   * @param {Constructor} constructor\n   * @param {String} message\n   * @api public\n   */\n\n  assert.instanceOf = function (val, type, msg) {\n    new Assertion(val, msg).to.be.instanceOf(type);\n  };\n\n  /**\n   * ### .notInstanceOf(object, constructor, [message])\n   *\n   * Asserts `value` is not an instance of `constructor`.\n   *\n   *     var Tea = function (name) { this.name = name; }\n   *       , chai = new String('chai');\n   *\n   *     assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea');\n   *\n   * @name notInstanceOf\n   * @param {Object} object\n   * @param {Constructor} constructor\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notInstanceOf = function (val, type, msg) {\n    new Assertion(val, msg).to.not.be.instanceOf(type);\n  };\n\n  /**\n   * ### .include(haystack, needle, [message])\n   *\n   * Asserts that `haystack` includes `needle`. Works\n   * for strings and arrays.\n   *\n   *     assert.include('foobar', 'bar', 'foobar contains string \"bar\"');\n   *     assert.include([ 1, 2, 3 ], 3, 'array contains value');\n   *\n   * @name include\n   * @param {Array|String} haystack\n   * @param {Mixed} needle\n   * @param {String} message\n   * @api public\n   */\n\n  assert.include = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.include).include(inc);\n  };\n\n  /**\n   * ### .notInclude(haystack, needle, [message])\n   *\n   * Asserts that `haystack` does not include `needle`. Works\n   * for strings and arrays.\n   *i\n   *     assert.notInclude('foobar', 'baz', 'string not include substring');\n   *     assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value');\n   *\n   * @name notInclude\n   * @param {Array|String} haystack\n   * @param {Mixed} needle\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notInclude = function (exp, inc, msg) {\n    new Assertion(exp, msg, assert.notInclude).not.include(inc);\n  };\n\n  /**\n   * ### .match(value, regexp, [message])\n   *\n   * Asserts that `value` matches the regular expression `regexp`.\n   *\n   *     assert.match('foobar', /^foo/, 'regexp matches');\n   *\n   * @name match\n   * @param {Mixed} value\n   * @param {RegExp} regexp\n   * @param {String} message\n   * @api public\n   */\n\n  assert.match = function (exp, re, msg) {\n    new Assertion(exp, msg).to.match(re);\n  };\n\n  /**\n   * ### .notMatch(value, regexp, [message])\n   *\n   * Asserts that `value` does not match the regular expression `regexp`.\n   *\n   *     assert.notMatch('foobar', /^foo/, 'regexp does not match');\n   *\n   * @name notMatch\n   * @param {Mixed} value\n   * @param {RegExp} regexp\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notMatch = function (exp, re, msg) {\n    new Assertion(exp, msg).to.not.match(re);\n  };\n\n  /**\n   * ### .property(object, property, [message])\n   *\n   * Asserts that `object` has a property named by `property`.\n   *\n   *     assert.property({ tea: { green: 'matcha' }}, 'tea');\n   *\n   * @name property\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @api public\n   */\n\n  assert.property = function (obj, prop, msg) {\n    new Assertion(obj, msg).to.have.property(prop);\n  };\n\n  /**\n   * ### .notProperty(object, property, [message])\n   *\n   * Asserts that `object` does _not_ have a property named by `property`.\n   *\n   *     assert.notProperty({ tea: { green: 'matcha' }}, 'coffee');\n   *\n   * @name notProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg).to.not.have.property(prop);\n  };\n\n  /**\n   * ### .deepProperty(object, property, [message])\n   *\n   * Asserts that `object` has a property named by `property`, which can be a\n   * string using dot- and bracket-notation for deep reference.\n   *\n   *     assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green');\n   *\n   * @name deepProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @api public\n   */\n\n  assert.deepProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg).to.have.deep.property(prop);\n  };\n\n  /**\n   * ### .notDeepProperty(object, property, [message])\n   *\n   * Asserts that `object` does _not_ have a property named by `property`, which\n   * can be a string using dot- and bracket-notation for deep reference.\n   *\n   *     assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong');\n   *\n   * @name notDeepProperty\n   * @param {Object} object\n   * @param {String} property\n   * @param {String} message\n   * @api public\n   */\n\n  assert.notDeepProperty = function (obj, prop, msg) {\n    new Assertion(obj, msg).to.not.have.deep.property(prop);\n  };\n\n  /**\n   * ### .propertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a property named by `property` with value given\n   * by `value`.\n   *\n   *     assert.propertyVal({ tea: 'is good' }, 'tea', 'is good');\n   *\n   * @name propertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.propertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg).to.have.property(prop, val);\n  };\n\n  /**\n   * ### .propertyNotVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a property named by `property`, but with a value\n   * different from that given by `value`.\n   *\n   *     assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad');\n   *\n   * @name propertyNotVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.propertyNotVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg).to.not.have.property(prop, val);\n  };\n\n  /**\n   * ### .deepPropertyVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a property named by `property` with value given\n   * by `value`. `property` can use dot- and bracket-notation for deep\n   * reference.\n   *\n   *     assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha');\n   *\n   * @name deepPropertyVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.deepPropertyVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg).to.have.deep.property(prop, val);\n  };\n\n  /**\n   * ### .deepPropertyNotVal(object, property, value, [message])\n   *\n   * Asserts that `object` has a property named by `property`, but with a value\n   * different from that given by `value`. `property` can use dot- and\n   * bracket-notation for deep reference.\n   *\n   *     assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha');\n   *\n   * @name deepPropertyNotVal\n   * @param {Object} object\n   * @param {String} property\n   * @param {Mixed} value\n   * @param {String} message\n   * @api public\n   */\n\n  assert.deepPropertyNotVal = function (obj, prop, val, msg) {\n    new Assertion(obj, msg).to.not.have.deep.property(prop, val);\n  };\n\n  /**\n   * ### .lengthOf(object, length, [message])\n   *\n   * Asserts that `object` has a `length` property with the expected value.\n   *\n   *     assert.lengthOf([1,2,3], 3, 'array has length of 3');\n   *     assert.lengthOf('foobar', 5, 'string has length of 6');\n   *\n   * @name lengthOf\n   * @param {Mixed} object\n   * @param {Number} length\n   * @param {String} message\n   * @api public\n   */\n\n  assert.lengthOf = function (exp, len, msg) {\n    new Assertion(exp, msg).to.have.length(len);\n  };\n\n  /**\n   * ### .throws(function, [constructor/string/regexp], [string/regexp], [message])\n   *\n   * Asserts that `function` will throw an error that is an instance of\n   * `constructor`, or alternately that it will throw an error with message\n   * matching `regexp`.\n   *\n   *     assert.throw(fn, 'function throws a reference error');\n   *     assert.throw(fn, /function throws a reference error/);\n   *     assert.throw(fn, ReferenceError);\n   *     assert.throw(fn, ReferenceError, 'function throws a reference error');\n   *     assert.throw(fn, ReferenceError, /function throws a reference error/);\n   *\n   * @name throws\n   * @alias throw\n   * @alias Throw\n   * @param {Function} function\n   * @param {ErrorConstructor} constructor\n   * @param {RegExp} regexp\n   * @param {String} message\n   * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n   * @api public\n   */\n\n  assert.Throw = function (fn, errt, errs, msg) {\n    if ('string' === typeof errt || errt instanceof RegExp) {\n      errs = errt;\n      errt = null;\n    }\n\n    var assertErr = new Assertion(fn, msg).to.Throw(errt, errs);\n    return flag(assertErr, 'object');\n  };\n\n  /**\n   * ### .doesNotThrow(function, [constructor/regexp], [message])\n   *\n   * Asserts that `function` will _not_ throw an error that is an instance of\n   * `constructor`, or alternately that it will not throw an error with message\n   * matching `regexp`.\n   *\n   *     assert.doesNotThrow(fn, Error, 'function does not throw');\n   *\n   * @name doesNotThrow\n   * @param {Function} function\n   * @param {ErrorConstructor} constructor\n   * @param {RegExp} regexp\n   * @param {String} message\n   * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types\n   * @api public\n   */\n\n  assert.doesNotThrow = function (fn, type, msg) {\n    if ('string' === typeof type) {\n      msg = type;\n      type = null;\n    }\n\n    new Assertion(fn, msg).to.not.Throw(type);\n  };\n\n  /**\n   * ### .operator(val1, operator, val2, [message])\n   *\n   * Compares two values using `operator`.\n   *\n   *     assert.operator(1, '<', 2, 'everything is ok');\n   *     assert.operator(1, '>', 2, 'this will fail');\n   *\n   * @name operator\n   * @param {Mixed} val1\n   * @param {String} operator\n   * @param {Mixed} val2\n   * @param {String} message\n   * @api public\n   */\n\n  assert.operator = function (val, operator, val2, msg) {\n    if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) {\n      throw new Error('Invalid operator \"' + operator + '\"');\n    }\n    var test = new Assertion(eval(val + operator + val2), msg);\n    test.assert(\n        true === flag(test, 'object')\n      , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2)\n      , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) );\n  };\n\n  /**\n   * ### .closeTo(actual, expected, delta, [message])\n   *\n   * Asserts that the target is equal `expected`, to within a +/- `delta` range.\n   *\n   *     assert.closeTo(1.5, 1, 0.5, 'numbers are close');\n   *\n   * @name closeTo\n   * @param {Number} actual\n   * @param {Number} expected\n   * @param {Number} delta\n   * @param {String} message\n   * @api public\n   */\n\n  assert.closeTo = function (act, exp, delta, msg) {\n    new Assertion(act, msg).to.be.closeTo(exp, delta);\n  };\n\n  /**\n   * ### .sameMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` have the same members.\n   * Order is not taken into account.\n   *\n   *     assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members');\n   *\n   * @name sameMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @api public\n   */\n\n  assert.sameMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg).to.have.same.members(set2);\n  }\n\n  /**\n   * ### .sameDeepMembers(set1, set2, [message])\n   *\n   * Asserts that `set1` and `set2` have the same members - using a deep equality checking.\n   * Order is not taken into account.\n   *\n   *     assert.sameDeepMembers([ {b: 3}, {a: 2}, {c: 5} ], [ {c: 5}, {b: 3}, {a: 2} ], 'same deep members');\n   *\n   * @name sameDeepMembers\n   * @param {Array} set1\n   * @param {Array} set2\n   * @param {String} message\n   * @api public\n   */\n\n  assert.sameDeepMembers = function (set1, set2, msg) {\n    new Assertion(set1, msg).to.have.same.deep.members(set2);\n  }\n\n  /**\n   * ### .includeMembers(superset, subset, [message])\n   *\n   * Asserts that `subset` is included in `superset`.\n   * Order is not taken into account.\n   *\n   *     assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members');\n   *\n   * @name includeMembers\n   * @param {Array} superset\n   * @param {Array} subset\n   * @param {String} message\n   * @api public\n   */\n\n  assert.includeMembers = function (superset, subset, msg) {\n    new Assertion(superset, msg).to.include.members(subset);\n  }\n\n   /**\n   * ### .changes(function, object, property)\n   *\n   * Asserts that a function changes the value of a property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 22 };\n   *     assert.changes(fn, obj, 'val');\n   *\n   * @name changes\n   * @param {Function} modifier function\n   * @param {Object} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  assert.changes = function (fn, obj, prop) {\n    new Assertion(fn).to.change(obj, prop);\n  }\n\n   /**\n   * ### .doesNotChange(function, object, property)\n   *\n   * Asserts that a function does not changes the value of a property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { console.log('foo'); };\n   *     assert.doesNotChange(fn, obj, 'val');\n   *\n   * @name doesNotChange\n   * @param {Function} modifier function\n   * @param {Object} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  assert.doesNotChange = function (fn, obj, prop) {\n    new Assertion(fn).to.not.change(obj, prop);\n  }\n\n   /**\n   * ### .increases(function, object, property)\n   *\n   * Asserts that a function increases an object property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 13 };\n   *     assert.increases(fn, obj, 'val');\n   *\n   * @name increases\n   * @param {Function} modifier function\n   * @param {Object} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  assert.increases = function (fn, obj, prop) {\n    new Assertion(fn).to.increase(obj, prop);\n  }\n\n   /**\n   * ### .doesNotIncrease(function, object, property)\n   *\n   * Asserts that a function does not increase object property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 8 };\n   *     assert.doesNotIncrease(fn, obj, 'val');\n   *\n   * @name doesNotIncrease\n   * @param {Function} modifier function\n   * @param {Object} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  assert.doesNotIncrease = function (fn, obj, prop) {\n    new Assertion(fn).to.not.increase(obj, prop);\n  }\n\n   /**\n   * ### .decreases(function, object, property)\n   *\n   * Asserts that a function decreases an object property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 5 };\n   *     assert.decreases(fn, obj, 'val');\n   *\n   * @name decreases\n   * @param {Function} modifier function\n   * @param {Object} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  assert.decreases = function (fn, obj, prop) {\n    new Assertion(fn).to.decrease(obj, prop);\n  }\n\n   /**\n   * ### .doesNotDecrease(function, object, property)\n   *\n   * Asserts that a function does not decreases an object property\n   *\n   *     var obj = { val: 10 };\n   *     var fn = function() { obj.val = 15 };\n   *     assert.doesNotDecrease(fn, obj, 'val');\n   *\n   * @name doesNotDecrease\n   * @param {Function} modifier function\n   * @param {Object} object\n   * @param {String} property name\n   * @param {String} message _optional_\n   * @api public\n   */\n\n  assert.doesNotDecrease = function (fn, obj, prop) {\n    new Assertion(fn).to.not.decrease(obj, prop);\n  }\n\n  /*!\n   * Undocumented / untested\n   */\n\n  assert.ifError = function (val, msg) {\n    new Assertion(val, msg).to.not.be.ok;\n  };\n\n  /*!\n   * Aliases.\n   */\n\n  (function alias(name, as){\n    assert[as] = assert[name];\n    return alias;\n  })\n  ('Throw', 'throw')\n  ('Throw', 'throws');\n};\n\n});\n\nrequire.register(\"chai/lib/chai/interface/expect.js\", function (exports, module) {\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, util) {\n  chai.expect = function (val, message) {\n    return new chai.Assertion(val, message);\n  };\n\n  /**\n   * ### .fail(actual, expected, [message], [operator])\n   *\n   * Throw a failure.\n   *\n   * @name fail\n   * @param {Mixed} actual\n   * @param {Mixed} expected\n   * @param {String} message\n   * @param {String} operator\n   * @api public\n   */\n\n  chai.expect.fail = function (actual, expected, message, operator) {\n    message = message || 'expect.fail()';\n    throw new chai.AssertionError(message, {\n        actual: actual\n      , expected: expected\n      , operator: operator\n    }, chai.expect.fail);\n  };\n};\n\n});\n\nrequire.register(\"chai/lib/chai/interface/should.js\", function (exports, module) {\n/*!\n * chai\n * Copyright(c) 2011-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nmodule.exports = function (chai, util) {\n  var Assertion = chai.Assertion;\n\n  function loadShould () {\n    // explicitly define this method as function as to have it's name to include as `ssfi`\n    function shouldGetter() {\n      if (this instanceof String || this instanceof Number) {\n        return new Assertion(this.constructor(this), null, shouldGetter);\n      } else if (this instanceof Boolean) {\n        return new Assertion(this == true, null, shouldGetter);\n      }\n      return new Assertion(this, null, shouldGetter);\n    }\n    function shouldSetter(value) {\n      // See https://github.com/chaijs/chai/issues/86: this makes\n      // `whatever.should = someValue` actually set `someValue`, which is\n      // especially useful for `global.should = require('chai').should()`.\n      //\n      // Note that we have to use [[DefineProperty]] instead of [[Put]]\n      // since otherwise we would trigger this very setter!\n      Object.defineProperty(this, 'should', {\n        value: value,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      });\n    }\n    // modify Object.prototype to have `should`\n    Object.defineProperty(Object.prototype, 'should', {\n      set: shouldSetter\n      , get: shouldGetter\n      , configurable: true\n    });\n\n    var should = {};\n\n    /**\n     * ### .fail(actual, expected, [message], [operator])\n     *\n     * Throw a failure.\n     *\n     * @name fail\n     * @param {Mixed} actual\n     * @param {Mixed} expected\n     * @param {String} message\n     * @param {String} operator\n     * @api public\n     */\n\n    should.fail = function (actual, expected, message, operator) {\n      message = message || 'should.fail()';\n      throw new chai.AssertionError(message, {\n          actual: actual\n        , expected: expected\n        , operator: operator\n      }, should.fail);\n    };\n\n    should.equal = function (val1, val2, msg) {\n      new Assertion(val1, msg).to.equal(val2);\n    };\n\n    should.Throw = function (fn, errt, errs, msg) {\n      new Assertion(fn, msg).to.Throw(errt, errs);\n    };\n\n    should.exist = function (val, msg) {\n      new Assertion(val, msg).to.exist;\n    }\n\n    // negation\n    should.not = {}\n\n    should.not.equal = function (val1, val2, msg) {\n      new Assertion(val1, msg).to.not.equal(val2);\n    };\n\n    should.not.Throw = function (fn, errt, errs, msg) {\n      new Assertion(fn, msg).to.not.Throw(errt, errs);\n    };\n\n    should.not.exist = function (val, msg) {\n      new Assertion(val, msg).to.not.exist;\n    }\n\n    should['throw'] = should['Throw'];\n    should.not['throw'] = should.not['Throw'];\n\n    return should;\n  };\n\n  chai.should = loadShould;\n  chai.Should = loadShould;\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/addChainableMethod.js\", function (exports, module) {\n/*!\n * Chai - addChainingMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependencies\n */\n\nvar transferFlags = require('chai/lib/chai/utils/transferFlags.js');\nvar flag = require('chai/lib/chai/utils/flag.js');\nvar config = require('chai/lib/chai/config.js');\n\n/*!\n * Module variables\n */\n\n// Check whether `__proto__` is supported\nvar hasProtoSupport = '__proto__' in Object;\n\n// Without `__proto__` support, this module will need to add properties to a function.\n// However, some Function.prototype methods cannot be overwritten,\n// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69).\nvar excludeNames = /^(?:length|name|arguments|caller)$/;\n\n// Cache `Function` properties\nvar call  = Function.prototype.call,\n    apply = Function.prototype.apply;\n\n/**\n * ### addChainableMethod (ctx, name, method, chainingBehavior)\n *\n * Adds a method to an object, such that the method can also be chained.\n *\n *     utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) {\n *       var obj = utils.flag(this, 'object');\n *       new chai.Assertion(obj).to.be.equal(str);\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.addChainableMethod('foo', fn, chainingBehavior);\n *\n * The result can then be used as both a method assertion, executing both `method` and\n * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`.\n *\n *     expect(fooStr).to.be.foo('bar');\n *     expect(fooStr).to.be.foo.equal('foo');\n *\n * @param {Object} ctx object to which the method is added\n * @param {String} name of method to add\n * @param {Function} method function to be used for `name`, when called\n * @param {Function} chainingBehavior function to be called every time the property is accessed\n * @name addChainableMethod\n * @api public\n */\n\nmodule.exports = function (ctx, name, method, chainingBehavior) {\n  if (typeof chainingBehavior !== 'function') {\n    chainingBehavior = function () { };\n  }\n\n  var chainableBehavior = {\n      method: method\n    , chainingBehavior: chainingBehavior\n  };\n\n  // save the methods so we can overwrite them later, if we need to.\n  if (!ctx.__methods) {\n    ctx.__methods = {};\n  }\n  ctx.__methods[name] = chainableBehavior;\n\n  Object.defineProperty(ctx, name,\n    { get: function () {\n        chainableBehavior.chainingBehavior.call(this);\n\n        var assert = function assert() {\n          var old_ssfi = flag(this, 'ssfi');\n          if (old_ssfi && config.includeStack === false)\n            flag(this, 'ssfi', assert);\n          var result = chainableBehavior.method.apply(this, arguments);\n          return result === undefined ? this : result;\n        };\n\n        // Use `__proto__` if available\n        if (hasProtoSupport) {\n          // Inherit all properties from the object by replacing the `Function` prototype\n          var prototype = assert.__proto__ = Object.create(this);\n          // Restore the `call` and `apply` methods from `Function`\n          prototype.call = call;\n          prototype.apply = apply;\n        }\n        // Otherwise, redefine all properties (slow!)\n        else {\n          var asserterNames = Object.getOwnPropertyNames(ctx);\n          asserterNames.forEach(function (asserterName) {\n            if (!excludeNames.test(asserterName)) {\n              var pd = Object.getOwnPropertyDescriptor(ctx, asserterName);\n              Object.defineProperty(assert, asserterName, pd);\n            }\n          });\n        }\n\n        transferFlags(this, assert);\n        return assert;\n      }\n    , configurable: true\n  });\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/addMethod.js\", function (exports, module) {\n/*!\n * Chai - addMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar config = require('chai/lib/chai/config.js');\n\n/**\n * ### .addMethod (ctx, name, method)\n *\n * Adds a method to the prototype of an object.\n *\n *     utils.addMethod(chai.Assertion.prototype, 'foo', function (str) {\n *       var obj = utils.flag(this, 'object');\n *       new chai.Assertion(obj).to.be.equal(str);\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.addMethod('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(fooStr).to.be.foo('bar');\n *\n * @param {Object} ctx object to which the method is added\n * @param {String} name of method to add\n * @param {Function} method function to be used for name\n * @name addMethod\n * @api public\n */\nvar flag = require('chai/lib/chai/utils/flag.js');\n\nmodule.exports = function (ctx, name, method) {\n  ctx[name] = function () {\n    var old_ssfi = flag(this, 'ssfi');\n    if (old_ssfi && config.includeStack === false)\n      flag(this, 'ssfi', ctx[name]);\n    var result = method.apply(this, arguments);\n    return result === undefined ? this : result;\n  };\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/addProperty.js\", function (exports, module) {\n/*!\n * Chai - addProperty utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### addProperty (ctx, name, getter)\n *\n * Adds a property to the prototype of an object.\n *\n *     utils.addProperty(chai.Assertion.prototype, 'foo', function () {\n *       var obj = utils.flag(this, 'object');\n *       new chai.Assertion(obj).to.be.instanceof(Foo);\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.addProperty('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.be.foo;\n *\n * @param {Object} ctx object to which the property is added\n * @param {String} name of property to add\n * @param {Function} getter function to be used for name\n * @name addProperty\n * @api public\n */\n\nmodule.exports = function (ctx, name, getter) {\n  Object.defineProperty(ctx, name,\n    { get: function () {\n        var result = getter.call(this);\n        return result === undefined ? this : result;\n      }\n    , configurable: true\n  });\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/flag.js\", function (exports, module) {\n/*!\n * Chai - flag utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### flag(object, key, [value])\n *\n * Get or set a flag value on an object. If a\n * value is provided it will be set, else it will\n * return the currently set value or `undefined` if\n * the value is not set.\n *\n *     utils.flag(this, 'foo', 'bar'); // setter\n *     utils.flag(this, 'foo'); // getter, returns `bar`\n *\n * @param {Object} object constructed Assertion\n * @param {String} key\n * @param {Mixed} value (optional)\n * @name flag\n * @api private\n */\n\nmodule.exports = function (obj, key, value) {\n  var flags = obj.__flags || (obj.__flags = Object.create(null));\n  if (arguments.length === 3) {\n    flags[key] = value;\n  } else {\n    return flags[key];\n  }\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/getActual.js\", function (exports, module) {\n/*!\n * Chai - getActual utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * # getActual(object, [actual])\n *\n * Returns the `actual` value for an Assertion\n *\n * @param {Object} object (constructed Assertion)\n * @param {Arguments} chai.Assertion.prototype.assert arguments\n */\n\nmodule.exports = function (obj, args) {\n  return args.length > 4 ? args[4] : obj._obj;\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/getEnumerableProperties.js\", function (exports, module) {\n/*!\n * Chai - getEnumerableProperties utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .getEnumerableProperties(object)\n *\n * This allows the retrieval of enumerable property names of an object,\n * inherited or not.\n *\n * @param {Object} object\n * @returns {Array}\n * @name getEnumerableProperties\n * @api public\n */\n\nmodule.exports = function getEnumerableProperties(object) {\n  var result = [];\n  for (var name in object) {\n    result.push(name);\n  }\n  return result;\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/getMessage.js\", function (exports, module) {\n/*!\n * Chai - message composition utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependancies\n */\n\nvar flag = require('chai/lib/chai/utils/flag.js')\n  , getActual = require('chai/lib/chai/utils/getActual.js')\n  , inspect = require('chai/lib/chai/utils/inspect.js')\n  , objDisplay = require('chai/lib/chai/utils/objDisplay.js');\n\n/**\n * ### .getMessage(object, message, negateMessage)\n *\n * Construct the error message based on flags\n * and template tags. Template tags will return\n * a stringified inspection of the object referenced.\n *\n * Message template tags:\n * - `#{this}` current asserted object\n * - `#{act}` actual value\n * - `#{exp}` expected value\n *\n * @param {Object} object (constructed Assertion)\n * @param {Arguments} chai.Assertion.prototype.assert arguments\n * @name getMessage\n * @api public\n */\n\nmodule.exports = function (obj, args) {\n  var negate = flag(obj, 'negate')\n    , val = flag(obj, 'object')\n    , expected = args[3]\n    , actual = getActual(obj, args)\n    , msg = negate ? args[2] : args[1]\n    , flagMsg = flag(obj, 'message');\n\n  if(typeof msg === \"function\") msg = msg();\n  msg = msg || '';\n  msg = msg\n    .replace(/#{this}/g, objDisplay(val))\n    .replace(/#{act}/g, objDisplay(actual))\n    .replace(/#{exp}/g, objDisplay(expected));\n\n  return flagMsg ? flagMsg + ': ' + msg : msg;\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/getName.js\", function (exports, module) {\n/*!\n * Chai - getName utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * # getName(func)\n *\n * Gets the name of a function, in a cross-browser way.\n *\n * @param {Function} a function (usually a constructor)\n */\n\nmodule.exports = function (func) {\n  if (func.name) return func.name;\n\n  var match = /^\\s?function ([^(]*)\\(/.exec(func);\n  return match && match[1] ? match[1] : \"\";\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/getPathValue.js\", function (exports, module) {\n/*!\n * Chai - getPathValue utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * @see https://github.com/logicalparadox/filtr\n * MIT Licensed\n */\n\nvar getPathInfo = require('chai/lib/chai/utils/getPathInfo.js');\n\n/**\n * ### .getPathValue(path, object)\n *\n * This allows the retrieval of values in an\n * object given a string path.\n *\n *     var obj = {\n *         prop1: {\n *             arr: ['a', 'b', 'c']\n *           , str: 'Hello'\n *         }\n *       , prop2: {\n *             arr: [ { nested: 'Universe' } ]\n *           , str: 'Hello again!'\n *         }\n *     }\n *\n * The following would be the results.\n *\n *     getPathValue('prop1.str', obj); // Hello\n *     getPathValue('prop1.att[2]', obj); // b\n *     getPathValue('prop2.arr[0].nested', obj); // Universe\n *\n * @param {String} path\n * @param {Object} object\n * @returns {Object} value or `undefined`\n * @name getPathValue\n * @api public\n */\nmodule.exports = function(path, obj) {\n  var info = getPathInfo(path, obj);\n  return info.value;\n}; \n\n});\n\nrequire.register(\"chai/lib/chai/utils/getPathInfo.js\", function (exports, module) {\n/*!\n * Chai - getPathInfo utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar hasProperty = require('chai/lib/chai/utils/hasProperty.js');\n\n/**\n * ### .getPathInfo(path, object)\n *\n * This allows the retrieval of property info in an\n * object given a string path.\n *\n * The path info consists of an object with the\n * following properties:\n *\n * * parent - The parent object of the property referenced by `path`\n * * name - The name of the final property, a number if it was an array indexer\n * * value - The value of the property, if it exists, otherwise `undefined`\n * * exists - Whether the property exists or not\n *\n * @param {String} path\n * @param {Object} object\n * @returns {Object} info\n * @name getPathInfo\n * @api public\n */\n\nmodule.exports = function getPathInfo(path, obj) {\n  var parsed = parsePath(path),\n      last = parsed[parsed.length - 1];\n\n  var info = {\n    parent: _getPathValue(parsed, obj, parsed.length - 1),\n    name: last.p || last.i,\n    value: _getPathValue(parsed, obj),\n  };\n  info.exists = hasProperty(info.name, info.parent);\n\n  return info;\n};\n\n\n/*!\n * ## parsePath(path)\n *\n * Helper function used to parse string object\n * paths. Use in conjunction with `_getPathValue`.\n *\n *      var parsed = parsePath('myobject.property.subprop');\n *\n * ### Paths:\n *\n * * Can be as near infinitely deep and nested\n * * Arrays are also valid using the formal `myobject.document[3].property`.\n *\n * @param {String} path\n * @returns {Object} parsed\n * @api private\n */\n\nfunction parsePath (path) {\n  var str = path.replace(/\\[/g, '.[')\n    , parts = str.match(/(\\\\\\.|[^.]+?)+/g);\n  return parts.map(function (value) {\n    var re = /\\[(\\d+)\\]$/\n      , mArr = re.exec(value);\n    if (mArr) return { i: parseFloat(mArr[1]) };\n    else return { p: value };\n  });\n}\n\n\n/*!\n * ## _getPathValue(parsed, obj)\n *\n * Helper companion function for `.parsePath` that returns\n * the value located at the parsed address.\n *\n *      var value = getPathValue(parsed, obj);\n *\n * @param {Object} parsed definition from `parsePath`.\n * @param {Object} object to search against\n * @param {Number} object to search against\n * @returns {Object|Undefined} value\n * @api private\n */\n\nfunction _getPathValue (parsed, obj, index) {\n  var tmp = obj\n    , res;\n\n  index = (index === undefined ? parsed.length : index);\n\n  for (var i = 0, l = index; i < l; i++) {\n    var part = parsed[i];\n    if (tmp) {\n      if ('undefined' !== typeof part.p)\n        tmp = tmp[part.p];\n      else if ('undefined' !== typeof part.i)\n        tmp = tmp[part.i];\n      if (i == (l - 1)) res = tmp;\n    } else {\n      res = undefined;\n    }\n  }\n  return res;\n}\n\n});\n\nrequire.register(\"chai/lib/chai/utils/hasProperty.js\", function (exports, module) {\n/*!\n * Chai - hasProperty utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\nvar type = require('chai/lib/chai/utils/type.js');\n\n/**\n * ### .hasProperty(object, name)\n *\n * This allows checking whether an object has\n * named property or numeric array index.\n *\n * Basically does the same thing as the `in`\n * operator but works properly with natives\n * and null/undefined values.\n *\n *     var obj = {\n *         arr: ['a', 'b', 'c']\n *       , str: 'Hello'\n *     }\n *\n * The following would be the results.\n *\n *     hasProperty('str', obj);  // true\n *     hasProperty('constructor', obj);  // true\n *     hasProperty('bar', obj);  // false\n *     \n *     hasProperty('length', obj.str); // true\n *     hasProperty(1, obj.str);  // true\n *     hasProperty(5, obj.str);  // false\n *\n *     hasProperty('length', obj.arr);  // true\n *     hasProperty(2, obj.arr);  // true\n *     hasProperty(3, obj.arr);  // false\n *\n * @param {Objuect} object\n * @param {String|Number} name\n * @returns {Boolean} whether it exists\n * @name getPathInfo\n * @api public\n */\n\nvar literals = {\n    'number': Number\n  , 'string': String\n};\n\nmodule.exports = function hasProperty(name, obj) {\n  var ot = type(obj);\n\n  // Bad Object, obviously no props at all\n  if(ot === 'null' || ot === 'undefined')\n    return false;\n\n  // The `in` operator does not work with certain literals\n  // box these before the check\n  if(literals[ot] && typeof obj !== 'object')\n    obj = new literals[ot](obj);\n\n  return name in obj;\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/getProperties.js\", function (exports, module) {\n/*!\n * Chai - getProperties utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### .getProperties(object)\n *\n * This allows the retrieval of property names of an object, enumerable or not,\n * inherited or not.\n *\n * @param {Object} object\n * @returns {Array}\n * @name getProperties\n * @api public\n */\n\nmodule.exports = function getProperties(object) {\n  var result = Object.getOwnPropertyNames(subject);\n\n  function addProperty(property) {\n    if (result.indexOf(property) === -1) {\n      result.push(property);\n    }\n  }\n\n  var proto = Object.getPrototypeOf(subject);\n  while (proto !== null) {\n    Object.getOwnPropertyNames(proto).forEach(addProperty);\n    proto = Object.getPrototypeOf(proto);\n  }\n\n  return result;\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/index.js\", function (exports, module) {\n/*!\n * chai\n * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Main exports\n */\n\nvar exports = module.exports = {};\n\n/*!\n * test utility\n */\n\nexports.test = require('chai/lib/chai/utils/test.js');\n\n/*!\n * type utility\n */\n\nexports.type = require('chai/lib/chai/utils/type.js');\n\n/*!\n * message utility\n */\n\nexports.getMessage = require('chai/lib/chai/utils/getMessage.js');\n\n/*!\n * actual utility\n */\n\nexports.getActual = require('chai/lib/chai/utils/getActual.js');\n\n/*!\n * Inspect util\n */\n\nexports.inspect = require('chai/lib/chai/utils/inspect.js');\n\n/*!\n * Object Display util\n */\n\nexports.objDisplay = require('chai/lib/chai/utils/objDisplay.js');\n\n/*!\n * Flag utility\n */\n\nexports.flag = require('chai/lib/chai/utils/flag.js');\n\n/*!\n * Flag transferring utility\n */\n\nexports.transferFlags = require('chai/lib/chai/utils/transferFlags.js');\n\n/*!\n * Deep equal utility\n */\n\nexports.eql = require('chaijs~deep-eql@0.1.3');\n\n/*!\n * Deep path value\n */\n\nexports.getPathValue = require('chai/lib/chai/utils/getPathValue.js');\n\n/*!\n * Deep path info\n */\n\nexports.getPathInfo = require('chai/lib/chai/utils/getPathInfo.js');\n\n/*!\n * Check if a property exists\n */\n\nexports.hasProperty = require('chai/lib/chai/utils/hasProperty.js');\n\n/*!\n * Function name\n */\n\nexports.getName = require('chai/lib/chai/utils/getName.js');\n\n/*!\n * add Property\n */\n\nexports.addProperty = require('chai/lib/chai/utils/addProperty.js');\n\n/*!\n * add Method\n */\n\nexports.addMethod = require('chai/lib/chai/utils/addMethod.js');\n\n/*!\n * overwrite Property\n */\n\nexports.overwriteProperty = require('chai/lib/chai/utils/overwriteProperty.js');\n\n/*!\n * overwrite Method\n */\n\nexports.overwriteMethod = require('chai/lib/chai/utils/overwriteMethod.js');\n\n/*!\n * Add a chainable method\n */\n\nexports.addChainableMethod = require('chai/lib/chai/utils/addChainableMethod.js');\n\n/*!\n * Overwrite chainable method\n */\n\nexports.overwriteChainableMethod = require('chai/lib/chai/utils/overwriteChainableMethod.js');\n\n\n});\n\nrequire.register(\"chai/lib/chai/utils/inspect.js\", function (exports, module) {\n// This is (almost) directly from Node.js utils\n// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js\n\nvar getName = require('chai/lib/chai/utils/getName.js');\nvar getProperties = require('chai/lib/chai/utils/getProperties.js');\nvar getEnumerableProperties = require('chai/lib/chai/utils/getEnumerableProperties.js');\n\nmodule.exports = inspect;\n\n/**\n * Echos the value of a value. Trys to print the value out\n * in the best way possible given the different types.\n *\n * @param {Object} obj The object to print out.\n * @param {Boolean} showHidden Flag that shows hidden (not enumerable)\n *    properties of objects.\n * @param {Number} depth Depth in which to descend in object. Default is 2.\n * @param {Boolean} colors Flag to turn on ANSI escape codes to color the\n *    output. Default is false (no coloring).\n */\nfunction inspect(obj, showHidden, depth, colors) {\n  var ctx = {\n    showHidden: showHidden,\n    seen: [],\n    stylize: function (str) { return str; }\n  };\n  return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth));\n}\n\n// Returns true if object is a DOM element.\nvar isDOMElement = function (object) {\n  if (typeof HTMLElement === 'object') {\n    return object instanceof HTMLElement;\n  } else {\n    return object &&\n      typeof object === 'object' &&\n      object.nodeType === 1 &&\n      typeof object.nodeName === 'string';\n  }\n};\n\nfunction formatValue(ctx, value, recurseTimes) {\n  // Provide a hook for user-specified inspect functions.\n  // Check that value is an object with an inspect function on it\n  if (value && typeof value.inspect === 'function' &&\n      // Filter out the util module, it's inspect function is special\n      value.inspect !== exports.inspect &&\n      // Also filter out any prototype objects using the circular check.\n      !(value.constructor && value.constructor.prototype === value)) {\n    var ret = value.inspect(recurseTimes);\n    if (typeof ret !== 'string') {\n      ret = formatValue(ctx, ret, recurseTimes);\n    }\n    return ret;\n  }\n\n  // Primitive types cannot have properties\n  var primitive = formatPrimitive(ctx, value);\n  if (primitive) {\n    return primitive;\n  }\n\n  // If this is a DOM element, try to get the outer HTML.\n  if (isDOMElement(value)) {\n    if ('outerHTML' in value) {\n      return value.outerHTML;\n      // This value does not have an outerHTML attribute,\n      //   it could still be an XML element\n    } else {\n      // Attempt to serialize it\n      try {\n        if (document.xmlVersion) {\n          var xmlSerializer = new XMLSerializer();\n          return xmlSerializer.serializeToString(value);\n        } else {\n          // Firefox 11- do not support outerHTML\n          //   It does, however, support innerHTML\n          //   Use the following to render the element\n          var ns = \"http://www.w3.org/1999/xhtml\";\n          var container = document.createElementNS(ns, '_');\n\n          container.appendChild(value.cloneNode(false));\n          html = container.innerHTML\n            .replace('><', '>' + value.innerHTML + '<');\n          container.innerHTML = '';\n          return html;\n        }\n      } catch (err) {\n        // This could be a non-native DOM implementation,\n        //   continue with the normal flow:\n        //   printing the element as if it is an object.\n      }\n    }\n  }\n\n  // Look up the keys of the object.\n  var visibleKeys = getEnumerableProperties(value);\n  var keys = ctx.showHidden ? getProperties(value) : visibleKeys;\n\n  // Some type of object without properties can be shortcutted.\n  // In IE, errors have a single `stack` property, or if they are vanilla `Error`,\n  // a `stack` plus `description` property; ignore those for consistency.\n  if (keys.length === 0 || (isError(value) && (\n      (keys.length === 1 && keys[0] === 'stack') ||\n      (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack')\n     ))) {\n    if (typeof value === 'function') {\n      var name = getName(value);\n      var nameSuffix = name ? ': ' + name : '';\n      return ctx.stylize('[Function' + nameSuffix + ']', 'special');\n    }\n    if (isRegExp(value)) {\n      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n    }\n    if (isDate(value)) {\n      return ctx.stylize(Date.prototype.toUTCString.call(value), 'date');\n    }\n    if (isError(value)) {\n      return formatError(value);\n    }\n  }\n\n  var base = '', array = false, braces = ['{', '}'];\n\n  // Make Array say that they are Array\n  if (isArray(value)) {\n    array = true;\n    braces = ['[', ']'];\n  }\n\n  // Make functions say that they are functions\n  if (typeof value === 'function') {\n    var name = getName(value);\n    var nameSuffix = name ? ': ' + name : '';\n    base = ' [Function' + nameSuffix + ']';\n  }\n\n  // Make RegExps say that they are RegExps\n  if (isRegExp(value)) {\n    base = ' ' + RegExp.prototype.toString.call(value);\n  }\n\n  // Make dates with properties first say the date\n  if (isDate(value)) {\n    base = ' ' + Date.prototype.toUTCString.call(value);\n  }\n\n  // Make error with message first say the error\n  if (isError(value)) {\n    return formatError(value);\n  }\n\n  if (keys.length === 0 && (!array || value.length == 0)) {\n    return braces[0] + base + braces[1];\n  }\n\n  if (recurseTimes < 0) {\n    if (isRegExp(value)) {\n      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n    } else {\n      return ctx.stylize('[Object]', 'special');\n    }\n  }\n\n  ctx.seen.push(value);\n\n  var output;\n  if (array) {\n    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);\n  } else {\n    output = keys.map(function(key) {\n      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);\n    });\n  }\n\n  ctx.seen.pop();\n\n  return reduceToSingleString(output, base, braces);\n}\n\n\nfunction formatPrimitive(ctx, value) {\n  switch (typeof value) {\n    case 'undefined':\n      return ctx.stylize('undefined', 'undefined');\n\n    case 'string':\n      var simple = '\\'' + JSON.stringify(value).replace(/^\"|\"$/g, '')\n                                               .replace(/'/g, \"\\\\'\")\n                                               .replace(/\\\\\"/g, '\"') + '\\'';\n      return ctx.stylize(simple, 'string');\n\n    case 'number':\n      if (value === 0 && (1/value) === -Infinity) {\n        return ctx.stylize('-0', 'number');\n      }\n      return ctx.stylize('' + value, 'number');\n\n    case 'boolean':\n      return ctx.stylize('' + value, 'boolean');\n  }\n  // For some reason typeof null is \"object\", so special case here.\n  if (value === null) {\n    return ctx.stylize('null', 'null');\n  }\n}\n\n\nfunction formatError(value) {\n  return '[' + Error.prototype.toString.call(value) + ']';\n}\n\n\nfunction formatArray(ctx, value, recurseTimes, visibleKeys, keys) {\n  var output = [];\n  for (var i = 0, l = value.length; i < l; ++i) {\n    if (Object.prototype.hasOwnProperty.call(value, String(i))) {\n      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n          String(i), true));\n    } else {\n      output.push('');\n    }\n  }\n  keys.forEach(function(key) {\n    if (!key.match(/^\\d+$/)) {\n      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n          key, true));\n    }\n  });\n  return output;\n}\n\n\nfunction formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {\n  var name, str;\n  if (value.__lookupGetter__) {\n    if (value.__lookupGetter__(key)) {\n      if (value.__lookupSetter__(key)) {\n        str = ctx.stylize('[Getter/Setter]', 'special');\n      } else {\n        str = ctx.stylize('[Getter]', 'special');\n      }\n    } else {\n      if (value.__lookupSetter__(key)) {\n        str = ctx.stylize('[Setter]', 'special');\n      }\n    }\n  }\n  if (visibleKeys.indexOf(key) < 0) {\n    name = '[' + key + ']';\n  }\n  if (!str) {\n    if (ctx.seen.indexOf(value[key]) < 0) {\n      if (recurseTimes === null) {\n        str = formatValue(ctx, value[key], null);\n      } else {\n        str = formatValue(ctx, value[key], recurseTimes - 1);\n      }\n      if (str.indexOf('\\n') > -1) {\n        if (array) {\n          str = str.split('\\n').map(function(line) {\n            return '  ' + line;\n          }).join('\\n').substr(2);\n        } else {\n          str = '\\n' + str.split('\\n').map(function(line) {\n            return '   ' + line;\n          }).join('\\n');\n        }\n      }\n    } else {\n      str = ctx.stylize('[Circular]', 'special');\n    }\n  }\n  if (typeof name === 'undefined') {\n    if (array && key.match(/^\\d+$/)) {\n      return str;\n    }\n    name = JSON.stringify('' + key);\n    if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n      name = name.substr(1, name.length - 2);\n      name = ctx.stylize(name, 'name');\n    } else {\n      name = name.replace(/'/g, \"\\\\'\")\n                 .replace(/\\\\\"/g, '\"')\n                 .replace(/(^\"|\"$)/g, \"'\");\n      name = ctx.stylize(name, 'string');\n    }\n  }\n\n  return name + ': ' + str;\n}\n\n\nfunction reduceToSingleString(output, base, braces) {\n  var numLinesEst = 0;\n  var length = output.reduce(function(prev, cur) {\n    numLinesEst++;\n    if (cur.indexOf('\\n') >= 0) numLinesEst++;\n    return prev + cur.length + 1;\n  }, 0);\n\n  if (length > 60) {\n    return braces[0] +\n           (base === '' ? '' : base + '\\n ') +\n           ' ' +\n           output.join(',\\n  ') +\n           ' ' +\n           braces[1];\n  }\n\n  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n}\n\nfunction isArray(ar) {\n  return Array.isArray(ar) ||\n         (typeof ar === 'object' && objectToString(ar) === '[object Array]');\n}\n\nfunction isRegExp(re) {\n  return typeof re === 'object' && objectToString(re) === '[object RegExp]';\n}\n\nfunction isDate(d) {\n  return typeof d === 'object' && objectToString(d) === '[object Date]';\n}\n\nfunction isError(e) {\n  return typeof e === 'object' && objectToString(e) === '[object Error]';\n}\n\nfunction objectToString(o) {\n  return Object.prototype.toString.call(o);\n}\n\n});\n\nrequire.register(\"chai/lib/chai/utils/objDisplay.js\", function (exports, module) {\n/*!\n * Chai - flag utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependancies\n */\n\nvar inspect = require('chai/lib/chai/utils/inspect.js');\nvar config = require('chai/lib/chai/config.js');\n\n/**\n * ### .objDisplay (object)\n *\n * Determines if an object or an array matches\n * criteria to be inspected in-line for error\n * messages or should be truncated.\n *\n * @param {Mixed} javascript object to inspect\n * @name objDisplay\n * @api public\n */\n\nmodule.exports = function (obj) {\n  var str = inspect(obj)\n    , type = Object.prototype.toString.call(obj);\n\n  if (config.truncateThreshold && str.length >= config.truncateThreshold) {\n    if (type === '[object Function]') {\n      return !obj.name || obj.name === ''\n        ? '[Function]'\n        : '[Function: ' + obj.name + ']';\n    } else if (type === '[object Array]') {\n      return '[ Array(' + obj.length + ') ]';\n    } else if (type === '[object Object]') {\n      var keys = Object.keys(obj)\n        , kstr = keys.length > 2\n          ? keys.splice(0, 2).join(', ') + ', ...'\n          : keys.join(', ');\n      return '{ Object (' + kstr + ') }';\n    } else {\n      return str;\n    }\n  } else {\n    return str;\n  }\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/overwriteMethod.js\", function (exports, module) {\n/*!\n * Chai - overwriteMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### overwriteMethod (ctx, name, fn)\n *\n * Overwites an already existing method and provides\n * access to previous function. Must return function\n * to be used for name.\n *\n *     utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) {\n *       return function (str) {\n *         var obj = utils.flag(this, 'object');\n *         if (obj instanceof Foo) {\n *           new chai.Assertion(obj.value).to.equal(str);\n *         } else {\n *           _super.apply(this, arguments);\n *         }\n *       }\n *     });\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.overwriteMethod('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.equal('bar');\n *\n * @param {Object} ctx object whose method is to be overwritten\n * @param {String} name of method to overwrite\n * @param {Function} method function that returns a function to be used for name\n * @name overwriteMethod\n * @api public\n */\n\nmodule.exports = function (ctx, name, method) {\n  var _method = ctx[name]\n    , _super = function () { return this; };\n\n  if (_method && 'function' === typeof _method)\n    _super = _method;\n\n  ctx[name] = function () {\n    var result = method(_super).apply(this, arguments);\n    return result === undefined ? this : result;\n  }\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/overwriteProperty.js\", function (exports, module) {\n/*!\n * Chai - overwriteProperty utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### overwriteProperty (ctx, name, fn)\n *\n * Overwites an already existing property getter and provides\n * access to previous value. Must return function to use as getter.\n *\n *     utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) {\n *       return function () {\n *         var obj = utils.flag(this, 'object');\n *         if (obj instanceof Foo) {\n *           new chai.Assertion(obj.name).to.equal('bar');\n *         } else {\n *           _super.call(this);\n *         }\n *       }\n *     });\n *\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.overwriteProperty('foo', fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.be.ok;\n *\n * @param {Object} ctx object whose property is to be overwritten\n * @param {String} name of property to overwrite\n * @param {Function} getter function that returns a getter function to be used for name\n * @name overwriteProperty\n * @api public\n */\n\nmodule.exports = function (ctx, name, getter) {\n  var _get = Object.getOwnPropertyDescriptor(ctx, name)\n    , _super = function () {};\n\n  if (_get && 'function' === typeof _get.get)\n    _super = _get.get\n\n  Object.defineProperty(ctx, name,\n    { get: function () {\n        var result = getter(_super).call(this);\n        return result === undefined ? this : result;\n      }\n    , configurable: true\n  });\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/overwriteChainableMethod.js\", function (exports, module) {\n/*!\n * Chai - overwriteChainableMethod utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### overwriteChainableMethod (ctx, name, method, chainingBehavior)\n *\n * Overwites an already existing chainable method\n * and provides access to the previous function or\n * property.  Must return functions to be used for\n * name.\n *\n *     utils.overwriteChainableMethod(chai.Assertion.prototype, 'length',\n *       function (_super) {\n *       }\n *     , function (_super) {\n *       }\n *     );\n *\n * Can also be accessed directly from `chai.Assertion`.\n *\n *     chai.Assertion.overwriteChainableMethod('foo', fn, fn);\n *\n * Then can be used as any other assertion.\n *\n *     expect(myFoo).to.have.length(3);\n *     expect(myFoo).to.have.length.above(3);\n *\n * @param {Object} ctx object whose method / property is to be overwritten\n * @param {String} name of method / property to overwrite\n * @param {Function} method function that returns a function to be used for name\n * @param {Function} chainingBehavior function that returns a function to be used for property\n * @name overwriteChainableMethod\n * @api public\n */\n\nmodule.exports = function (ctx, name, method, chainingBehavior) {\n  var chainableBehavior = ctx.__methods[name];\n\n  var _chainingBehavior = chainableBehavior.chainingBehavior;\n  chainableBehavior.chainingBehavior = function () {\n    var result = chainingBehavior(_chainingBehavior).call(this);\n    return result === undefined ? this : result;\n  };\n\n  var _method = chainableBehavior.method;\n  chainableBehavior.method = function () {\n    var result = method(_method).apply(this, arguments);\n    return result === undefined ? this : result;\n  };\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/test.js\", function (exports, module) {\n/*!\n * Chai - test utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Module dependancies\n */\n\nvar flag = require('chai/lib/chai/utils/flag.js');\n\n/**\n * # test(object, expression)\n *\n * Test and object for expression.\n *\n * @param {Object} object (constructed Assertion)\n * @param {Arguments} chai.Assertion.prototype.assert arguments\n */\n\nmodule.exports = function (obj, args) {\n  var negate = flag(obj, 'negate')\n    , expr = args[0];\n  return negate ? !expr : expr;\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/transferFlags.js\", function (exports, module) {\n/*!\n * Chai - transferFlags utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/**\n * ### transferFlags(assertion, object, includeAll = true)\n *\n * Transfer all the flags for `assertion` to `object`. If\n * `includeAll` is set to `false`, then the base Chai\n * assertion flags (namely `object`, `ssfi`, and `message`)\n * will not be transferred.\n *\n *\n *     var newAssertion = new Assertion();\n *     utils.transferFlags(assertion, newAssertion);\n *\n *     var anotherAsseriton = new Assertion(myObj);\n *     utils.transferFlags(assertion, anotherAssertion, false);\n *\n * @param {Assertion} assertion the assertion to transfer the flags from\n * @param {Object} object the object to transfer the flags to; usually a new assertion\n * @param {Boolean} includeAll\n * @name transferFlags\n * @api private\n */\n\nmodule.exports = function (assertion, object, includeAll) {\n  var flags = assertion.__flags || (assertion.__flags = Object.create(null));\n\n  if (!object.__flags) {\n    object.__flags = Object.create(null);\n  }\n\n  includeAll = arguments.length === 3 ? includeAll : true;\n\n  for (var flag in flags) {\n    if (includeAll ||\n        (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) {\n      object.__flags[flag] = flags[flag];\n    }\n  }\n};\n\n});\n\nrequire.register(\"chai/lib/chai/utils/type.js\", function (exports, module) {\n/*!\n * Chai - type utility\n * Copyright(c) 2012-2014 Jake Luer <jake@alogicalparadox.com>\n * MIT Licensed\n */\n\n/*!\n * Detectable javascript natives\n */\n\nvar natives = {\n    '[object Arguments]': 'arguments'\n  , '[object Array]': 'array'\n  , '[object Date]': 'date'\n  , '[object Function]': 'function'\n  , '[object Number]': 'number'\n  , '[object RegExp]': 'regexp'\n  , '[object String]': 'string'\n};\n\n/**\n * ### type(object)\n *\n * Better implementation of `typeof` detection that can\n * be used cross-browser. Handles the inconsistencies of\n * Array, `null`, and `undefined` detection.\n *\n *     utils.type({}) // 'object'\n *     utils.type(null) // `null'\n *     utils.type(undefined) // `undefined`\n *     utils.type([]) // `array`\n *\n * @param {Mixed} object to detect type of\n * @name type\n * @api private\n */\n\nmodule.exports = function (obj) {\n  var str = Object.prototype.toString.call(obj);\n  if (natives[str]) return natives[str];\n  if (obj === null) return 'null';\n  if (obj === undefined) return 'undefined';\n  if (obj === Object(obj)) return 'object';\n  return typeof obj;\n};\n\n});\n\nif (typeof exports == \"object\") {\n  module.exports = require(\"chai\");\n} else if (typeof define == \"function\" && define.amd) {\n  define(\"chai\", [], function(){ return require(\"chai\"); });\n} else {\n  (this || window)[\"chai\"] = require(\"chai\");\n}\n})()\n"
  },
  {
    "path": "browser-version/test/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Mocha tests for NeDB</title>\n  <link rel=\"stylesheet\" href=\"mocha.css\">\n</head>\n<body>\n  <div id=\"mocha\"></div>\n  <script src=\"jquery.min.js\"></script>\n  <script src=\"chai.js\"></script>\n  <script src=\"underscore.min.js\"></script>\n  <script src=\"mocha.js\"></script>\n  <script>mocha.setup('bdd')</script>\n  <script src=\"../out/nedb.min.js\"></script>\n  <script src=\"localforage.js\"></script>\n  <script src=\"nedb-browser.js\"></script>\n  <script>\n    mocha.checkLeaks();\n    mocha.globals(['jQuery']);\n    mocha.run();\n  </script>\n</body>\n</html>\n"
  },
  {
    "path": "browser-version/test/localforage.js",
    "content": "/*!\n    localForage -- Offline Storage, Improved\n    Version 1.3.0\n    https://mozilla.github.io/localForage\n    (c) 2013-2015 Mozilla, Apache License 2.0\n*/\n(function() {\nvar define, requireModule, require, requirejs;\n\n(function() {\n  var registry = {}, seen = {};\n\n  define = function(name, deps, callback) {\n    registry[name] = { deps: deps, callback: callback };\n  };\n\n  requirejs = require = requireModule = function(name) {\n  requirejs._eak_seen = registry;\n\n    if (seen[name]) { return seen[name]; }\n    seen[name] = {};\n\n    if (!registry[name]) {\n      throw new Error(\"Could not find module \" + name);\n    }\n\n    var mod = registry[name],\n        deps = mod.deps,\n        callback = mod.callback,\n        reified = [],\n        exports;\n\n    for (var i=0, l=deps.length; i<l; i++) {\n      if (deps[i] === 'exports') {\n        reified.push(exports = {});\n      } else {\n        reified.push(requireModule(resolve(deps[i])));\n      }\n    }\n\n    var value = callback.apply(this, reified);\n    return seen[name] = exports || value;\n\n    function resolve(child) {\n      if (child.charAt(0) !== '.') { return child; }\n      var parts = child.split(\"/\");\n      var parentBase = name.split(\"/\").slice(0, -1);\n\n      for (var i=0, l=parts.length; i<l; i++) {\n        var part = parts[i];\n\n        if (part === '..') { parentBase.pop(); }\n        else if (part === '.') { continue; }\n        else { parentBase.push(part); }\n      }\n\n      return parentBase.join(\"/\");\n    }\n  };\n})();\n\ndefine(\"promise/all\", \n  [\"./utils\",\"exports\"],\n  function(__dependency1__, __exports__) {\n    \"use strict\";\n    /* global toString */\n\n    var isArray = __dependency1__.isArray;\n    var isFunction = __dependency1__.isFunction;\n\n    /**\n      Returns a promise that is fulfilled when all the given promises have been\n      fulfilled, or rejected if any of them become rejected. The return promise\n      is fulfilled with an array that gives all the values in the order they were\n      passed in the `promises` array argument.\n      Example:\n      ```javascript\n      var promise1 = RSVP.resolve(1);\n      var promise2 = RSVP.resolve(2);\n      var promise3 = RSVP.resolve(3);\n      var promises = [ promise1, promise2, promise3 ];\n      RSVP.all(promises).then(function(array){\n        // The array here would be [ 1, 2, 3 ];\n      });\n      ```\n      If any of the `promises` given to `RSVP.all` are rejected, the first promise\n      that is rejected will be given as an argument to the returned promises's\n      rejection handler. For example:\n      Example:\n      ```javascript\n      var promise1 = RSVP.resolve(1);\n      var promise2 = RSVP.reject(new Error(\"2\"));\n      var promise3 = RSVP.reject(new Error(\"3\"));\n      var promises = [ promise1, promise2, promise3 ];\n      RSVP.all(promises).then(function(array){\n        // Code here never runs because there are rejected promises!\n      }, function(error) {\n        // error.message === \"2\"\n      });\n      ```\n      @method all\n      @for RSVP\n      @param {Array} promises\n      @param {String} label\n      @return {Promise} promise that is fulfilled when all `promises` have been\n      fulfilled, or rejected if any of them become rejected.\n    */\n    function all(promises) {\n      /*jshint validthis:true */\n      var Promise = this;\n\n      if (!isArray(promises)) {\n        throw new TypeError('You must pass an array to all.');\n      }\n\n      return new Promise(function(resolve, reject) {\n        var results = [], remaining = promises.length,\n        promise;\n\n        if (remaining === 0) {\n          resolve([]);\n        }\n\n        function resolver(index) {\n          return function(value) {\n            resolveAll(index, value);\n          };\n        }\n\n        function resolveAll(index, value) {\n          results[index] = value;\n          if (--remaining === 0) {\n            resolve(results);\n          }\n        }\n\n        for (var i = 0; i < promises.length; i++) {\n          promise = promises[i];\n\n          if (promise && isFunction(promise.then)) {\n            promise.then(resolver(i), reject);\n          } else {\n            resolveAll(i, promise);\n          }\n        }\n      });\n    }\n\n    __exports__.all = all;\n  });\ndefine(\"promise/asap\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    var browserGlobal = (typeof window !== 'undefined') ? window : {};\n    var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;\n    var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this);\n\n    // node\n    function useNextTick() {\n      return function() {\n        process.nextTick(flush);\n      };\n    }\n\n    function useMutationObserver() {\n      var iterations = 0;\n      var observer = new BrowserMutationObserver(flush);\n      var node = document.createTextNode('');\n      observer.observe(node, { characterData: true });\n\n      return function() {\n        node.data = (iterations = ++iterations % 2);\n      };\n    }\n\n    function useSetTimeout() {\n      return function() {\n        local.setTimeout(flush, 1);\n      };\n    }\n\n    var queue = [];\n    function flush() {\n      for (var i = 0; i < queue.length; i++) {\n        var tuple = queue[i];\n        var callback = tuple[0], arg = tuple[1];\n        callback(arg);\n      }\n      queue = [];\n    }\n\n    var scheduleFlush;\n\n    // Decide what async method to use to triggering processing of queued callbacks:\n    if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {\n      scheduleFlush = useNextTick();\n    } else if (BrowserMutationObserver) {\n      scheduleFlush = useMutationObserver();\n    } else {\n      scheduleFlush = useSetTimeout();\n    }\n\n    function asap(callback, arg) {\n      var length = queue.push([callback, arg]);\n      if (length === 1) {\n        // If length is 1, that means that we need to schedule an async flush.\n        // If additional callbacks are queued before the queue is flushed, they\n        // will be processed by this flush that we are scheduling.\n        scheduleFlush();\n      }\n    }\n\n    __exports__.asap = asap;\n  });\ndefine(\"promise/config\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    var config = {\n      instrument: false\n    };\n\n    function configure(name, value) {\n      if (arguments.length === 2) {\n        config[name] = value;\n      } else {\n        return config[name];\n      }\n    }\n\n    __exports__.config = config;\n    __exports__.configure = configure;\n  });\ndefine(\"promise/polyfill\", \n  [\"./promise\",\"./utils\",\"exports\"],\n  function(__dependency1__, __dependency2__, __exports__) {\n    \"use strict\";\n    /*global self*/\n    var RSVPPromise = __dependency1__.Promise;\n    var isFunction = __dependency2__.isFunction;\n\n    function polyfill() {\n      var local;\n\n      if (typeof global !== 'undefined') {\n        local = global;\n      } else if (typeof window !== 'undefined' && window.document) {\n        local = window;\n      } else {\n        local = self;\n      }\n\n      var es6PromiseSupport = \n        \"Promise\" in local &&\n        // Some of these methods are missing from\n        // Firefox/Chrome experimental implementations\n        \"resolve\" in local.Promise &&\n        \"reject\" in local.Promise &&\n        \"all\" in local.Promise &&\n        \"race\" in local.Promise &&\n        // Older version of the spec had a resolver object\n        // as the arg rather than a function\n        (function() {\n          var resolve;\n          new local.Promise(function(r) { resolve = r; });\n          return isFunction(resolve);\n        }());\n\n      if (!es6PromiseSupport) {\n        local.Promise = RSVPPromise;\n      }\n    }\n\n    __exports__.polyfill = polyfill;\n  });\ndefine(\"promise/promise\", \n  [\"./config\",\"./utils\",\"./all\",\"./race\",\"./resolve\",\"./reject\",\"./asap\",\"exports\"],\n  function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) {\n    \"use strict\";\n    var config = __dependency1__.config;\n    var configure = __dependency1__.configure;\n    var objectOrFunction = __dependency2__.objectOrFunction;\n    var isFunction = __dependency2__.isFunction;\n    var now = __dependency2__.now;\n    var all = __dependency3__.all;\n    var race = __dependency4__.race;\n    var staticResolve = __dependency5__.resolve;\n    var staticReject = __dependency6__.reject;\n    var asap = __dependency7__.asap;\n\n    var counter = 0;\n\n    config.async = asap; // default async is asap;\n\n    function Promise(resolver) {\n      if (!isFunction(resolver)) {\n        throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');\n      }\n\n      if (!(this instanceof Promise)) {\n        throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.\");\n      }\n\n      this._subscribers = [];\n\n      invokeResolver(resolver, this);\n    }\n\n    function invokeResolver(resolver, promise) {\n      function resolvePromise(value) {\n        resolve(promise, value);\n      }\n\n      function rejectPromise(reason) {\n        reject(promise, reason);\n      }\n\n      try {\n        resolver(resolvePromise, rejectPromise);\n      } catch(e) {\n        rejectPromise(e);\n      }\n    }\n\n    function invokeCallback(settled, promise, callback, detail) {\n      var hasCallback = isFunction(callback),\n          value, error, succeeded, failed;\n\n      if (hasCallback) {\n        try {\n          value = callback(detail);\n          succeeded = true;\n        } catch(e) {\n          failed = true;\n          error = e;\n        }\n      } else {\n        value = detail;\n        succeeded = true;\n      }\n\n      if (handleThenable(promise, value)) {\n        return;\n      } else if (hasCallback && succeeded) {\n        resolve(promise, value);\n      } else if (failed) {\n        reject(promise, error);\n      } else if (settled === FULFILLED) {\n        resolve(promise, value);\n      } else if (settled === REJECTED) {\n        reject(promise, value);\n      }\n    }\n\n    var PENDING   = void 0;\n    var SEALED    = 0;\n    var FULFILLED = 1;\n    var REJECTED  = 2;\n\n    function subscribe(parent, child, onFulfillment, onRejection) {\n      var subscribers = parent._subscribers;\n      var length = subscribers.length;\n\n      subscribers[length] = child;\n      subscribers[length + FULFILLED] = onFulfillment;\n      subscribers[length + REJECTED]  = onRejection;\n    }\n\n    function publish(promise, settled) {\n      var child, callback, subscribers = promise._subscribers, detail = promise._detail;\n\n      for (var i = 0; i < subscribers.length; i += 3) {\n        child = subscribers[i];\n        callback = subscribers[i + settled];\n\n        invokeCallback(settled, child, callback, detail);\n      }\n\n      promise._subscribers = null;\n    }\n\n    Promise.prototype = {\n      constructor: Promise,\n\n      _state: undefined,\n      _detail: undefined,\n      _subscribers: undefined,\n\n      then: function(onFulfillment, onRejection) {\n        var promise = this;\n\n        var thenPromise = new this.constructor(function() {});\n\n        if (this._state) {\n          var callbacks = arguments;\n          config.async(function invokePromiseCallback() {\n            invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);\n          });\n        } else {\n          subscribe(this, thenPromise, onFulfillment, onRejection);\n        }\n\n        return thenPromise;\n      },\n\n      'catch': function(onRejection) {\n        return this.then(null, onRejection);\n      }\n    };\n\n    Promise.all = all;\n    Promise.race = race;\n    Promise.resolve = staticResolve;\n    Promise.reject = staticReject;\n\n    function handleThenable(promise, value) {\n      var then = null,\n      resolved;\n\n      try {\n        if (promise === value) {\n          throw new TypeError(\"A promises callback cannot return that same promise.\");\n        }\n\n        if (objectOrFunction(value)) {\n          then = value.then;\n\n          if (isFunction(then)) {\n            then.call(value, function(val) {\n              if (resolved) { return true; }\n              resolved = true;\n\n              if (value !== val) {\n                resolve(promise, val);\n              } else {\n                fulfill(promise, val);\n              }\n            }, function(val) {\n              if (resolved) { return true; }\n              resolved = true;\n\n              reject(promise, val);\n            });\n\n            return true;\n          }\n        }\n      } catch (error) {\n        if (resolved) { return true; }\n        reject(promise, error);\n        return true;\n      }\n\n      return false;\n    }\n\n    function resolve(promise, value) {\n      if (promise === value) {\n        fulfill(promise, value);\n      } else if (!handleThenable(promise, value)) {\n        fulfill(promise, value);\n      }\n    }\n\n    function fulfill(promise, value) {\n      if (promise._state !== PENDING) { return; }\n      promise._state = SEALED;\n      promise._detail = value;\n\n      config.async(publishFulfillment, promise);\n    }\n\n    function reject(promise, reason) {\n      if (promise._state !== PENDING) { return; }\n      promise._state = SEALED;\n      promise._detail = reason;\n\n      config.async(publishRejection, promise);\n    }\n\n    function publishFulfillment(promise) {\n      publish(promise, promise._state = FULFILLED);\n    }\n\n    function publishRejection(promise) {\n      publish(promise, promise._state = REJECTED);\n    }\n\n    __exports__.Promise = Promise;\n  });\ndefine(\"promise/race\", \n  [\"./utils\",\"exports\"],\n  function(__dependency1__, __exports__) {\n    \"use strict\";\n    /* global toString */\n    var isArray = __dependency1__.isArray;\n\n    /**\n      `RSVP.race` allows you to watch a series of promises and act as soon as the\n      first promise given to the `promises` argument fulfills or rejects.\n      Example:\n      ```javascript\n      var promise1 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          resolve(\"promise 1\");\n        }, 200);\n      });\n      var promise2 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          resolve(\"promise 2\");\n        }, 100);\n      });\n      RSVP.race([promise1, promise2]).then(function(result){\n        // result === \"promise 2\" because it was resolved before promise1\n        // was resolved.\n      });\n      ```\n      `RSVP.race` is deterministic in that only the state of the first completed\n      promise matters. For example, even if other promises given to the `promises`\n      array argument are resolved, but the first completed promise has become\n      rejected before the other promises became fulfilled, the returned promise\n      will become rejected:\n      ```javascript\n      var promise1 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          resolve(\"promise 1\");\n        }, 200);\n      });\n      var promise2 = new RSVP.Promise(function(resolve, reject){\n        setTimeout(function(){\n          reject(new Error(\"promise 2\"));\n        }, 100);\n      });\n      RSVP.race([promise1, promise2]).then(function(result){\n        // Code here never runs because there are rejected promises!\n      }, function(reason){\n        // reason.message === \"promise2\" because promise 2 became rejected before\n        // promise 1 became fulfilled\n      });\n      ```\n      @method race\n      @for RSVP\n      @param {Array} promises array of promises to observe\n      @param {String} label optional string for describing the promise returned.\n      Useful for tooling.\n      @return {Promise} a promise that becomes fulfilled with the value the first\n      completed promises is resolved with if the first completed promise was\n      fulfilled, or rejected with the reason that the first completed promise\n      was rejected with.\n    */\n    function race(promises) {\n      /*jshint validthis:true */\n      var Promise = this;\n\n      if (!isArray(promises)) {\n        throw new TypeError('You must pass an array to race.');\n      }\n      return new Promise(function(resolve, reject) {\n        var results = [], promise;\n\n        for (var i = 0; i < promises.length; i++) {\n          promise = promises[i];\n\n          if (promise && typeof promise.then === 'function') {\n            promise.then(resolve, reject);\n          } else {\n            resolve(promise);\n          }\n        }\n      });\n    }\n\n    __exports__.race = race;\n  });\ndefine(\"promise/reject\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    /**\n      `RSVP.reject` returns a promise that will become rejected with the passed\n      `reason`. `RSVP.reject` is essentially shorthand for the following:\n      ```javascript\n      var promise = new RSVP.Promise(function(resolve, reject){\n        reject(new Error('WHOOPS'));\n      });\n      promise.then(function(value){\n        // Code here doesn't run because the promise is rejected!\n      }, function(reason){\n        // reason.message === 'WHOOPS'\n      });\n      ```\n      Instead of writing the above, your code now simply becomes the following:\n      ```javascript\n      var promise = RSVP.reject(new Error('WHOOPS'));\n      promise.then(function(value){\n        // Code here doesn't run because the promise is rejected!\n      }, function(reason){\n        // reason.message === 'WHOOPS'\n      });\n      ```\n      @method reject\n      @for RSVP\n      @param {Any} reason value that the returned promise will be rejected with.\n      @param {String} label optional string for identifying the returned promise.\n      Useful for tooling.\n      @return {Promise} a promise that will become rejected with the given\n      `reason`.\n    */\n    function reject(reason) {\n      /*jshint validthis:true */\n      var Promise = this;\n\n      return new Promise(function (resolve, reject) {\n        reject(reason);\n      });\n    }\n\n    __exports__.reject = reject;\n  });\ndefine(\"promise/resolve\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    function resolve(value) {\n      /*jshint validthis:true */\n      if (value && typeof value === 'object' && value.constructor === this) {\n        return value;\n      }\n\n      var Promise = this;\n\n      return new Promise(function(resolve) {\n        resolve(value);\n      });\n    }\n\n    __exports__.resolve = resolve;\n  });\ndefine(\"promise/utils\", \n  [\"exports\"],\n  function(__exports__) {\n    \"use strict\";\n    function objectOrFunction(x) {\n      return isFunction(x) || (typeof x === \"object\" && x !== null);\n    }\n\n    function isFunction(x) {\n      return typeof x === \"function\";\n    }\n\n    function isArray(x) {\n      return Object.prototype.toString.call(x) === \"[object Array]\";\n    }\n\n    // Date.now is not available in browsers < IE9\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility\n    var now = Date.now || function() { return new Date().getTime(); };\n\n\n    __exports__.objectOrFunction = objectOrFunction;\n    __exports__.isFunction = isFunction;\n    __exports__.isArray = isArray;\n    __exports__.now = now;\n  });\nrequireModule('promise/polyfill').polyfill();\n}());(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"localforage\"] = factory();\n\telse\n\t\troot[\"localforage\"] = factory();\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }\n\n\t(function () {\n\t    'use strict';\n\n\t    // Custom drivers are stored here when `defineDriver()` is called.\n\t    // They are shared across all instances of localForage.\n\t    var CustomDrivers = {};\n\n\t    var DriverType = {\n\t        INDEXEDDB: 'asyncStorage',\n\t        LOCALSTORAGE: 'localStorageWrapper',\n\t        WEBSQL: 'webSQLStorage'\n\t    };\n\n\t    var DefaultDriverOrder = [DriverType.INDEXEDDB, DriverType.WEBSQL, DriverType.LOCALSTORAGE];\n\n\t    var LibraryMethods = ['clear', 'getItem', 'iterate', 'key', 'keys', 'length', 'removeItem', 'setItem'];\n\n\t    var DefaultConfig = {\n\t        description: '',\n\t        driver: DefaultDriverOrder.slice(),\n\t        name: 'localforage',\n\t        // Default DB size is _JUST UNDER_ 5MB, as it's the highest size\n\t        // we can use without a prompt.\n\t        size: 4980736,\n\t        storeName: 'keyvaluepairs',\n\t        version: 1.0\n\t    };\n\n\t    // Check to see if IndexedDB is available and if it is the latest\n\t    // implementation; it's our preferred backend library. We use \"_spec_test\"\n\t    // as the name of the database because it's not the one we'll operate on,\n\t    // but it's useful to make sure its using the right spec.\n\t    // See: https://github.com/mozilla/localForage/issues/128\n\t    var driverSupport = (function (self) {\n\t        // Initialize IndexedDB; fall back to vendor-prefixed versions\n\t        // if needed.\n\t        var indexedDB = indexedDB || self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.OIndexedDB || self.msIndexedDB;\n\n\t        var result = {};\n\n\t        result[DriverType.WEBSQL] = !!self.openDatabase;\n\t        result[DriverType.INDEXEDDB] = !!(function () {\n\t            // We mimic PouchDB here; just UA test for Safari (which, as of\n\t            // iOS 8/Yosemite, doesn't properly support IndexedDB).\n\t            // IndexedDB support is broken and different from Blink's.\n\t            // This is faster than the test case (and it's sync), so we just\n\t            // do this. *SIGH*\n\t            // http://bl.ocks.org/nolanlawson/raw/c83e9039edf2278047e9/\n\t            //\n\t            // We test for openDatabase because IE Mobile identifies itself\n\t            // as Safari. Oh the lulz...\n\t            if (typeof self.openDatabase !== 'undefined' && self.navigator && self.navigator.userAgent && /Safari/.test(self.navigator.userAgent) && !/Chrome/.test(self.navigator.userAgent)) {\n\t                return false;\n\t            }\n\t            try {\n\t                return indexedDB && typeof indexedDB.open === 'function' &&\n\t                // Some Samsung/HTC Android 4.0-4.3 devices\n\t                // have older IndexedDB specs; if this isn't available\n\t                // their IndexedDB is too old for us to use.\n\t                // (Replaces the onupgradeneeded test.)\n\t                typeof self.IDBKeyRange !== 'undefined';\n\t            } catch (e) {\n\t                return false;\n\t            }\n\t        })();\n\n\t        result[DriverType.LOCALSTORAGE] = !!(function () {\n\t            try {\n\t                return self.localStorage && 'setItem' in self.localStorage && self.localStorage.setItem;\n\t            } catch (e) {\n\t                return false;\n\t            }\n\t        })();\n\n\t        return result;\n\t    })(this);\n\n\t    var isArray = Array.isArray || function (arg) {\n\t        return Object.prototype.toString.call(arg) === '[object Array]';\n\t    };\n\n\t    function callWhenReady(localForageInstance, libraryMethod) {\n\t        localForageInstance[libraryMethod] = function () {\n\t            var _args = arguments;\n\t            return localForageInstance.ready().then(function () {\n\t                return localForageInstance[libraryMethod].apply(localForageInstance, _args);\n\t            });\n\t        };\n\t    }\n\n\t    function extend() {\n\t        for (var i = 1; i < arguments.length; i++) {\n\t            var arg = arguments[i];\n\n\t            if (arg) {\n\t                for (var key in arg) {\n\t                    if (arg.hasOwnProperty(key)) {\n\t                        if (isArray(arg[key])) {\n\t                            arguments[0][key] = arg[key].slice();\n\t                        } else {\n\t                            arguments[0][key] = arg[key];\n\t                        }\n\t                    }\n\t                }\n\t            }\n\t        }\n\n\t        return arguments[0];\n\t    }\n\n\t    function isLibraryDriver(driverName) {\n\t        for (var driver in DriverType) {\n\t            if (DriverType.hasOwnProperty(driver) && DriverType[driver] === driverName) {\n\t                return true;\n\t            }\n\t        }\n\n\t        return false;\n\t    }\n\n\t    var LocalForage = (function () {\n\t        function LocalForage(options) {\n\t            _classCallCheck(this, LocalForage);\n\n\t            this.INDEXEDDB = DriverType.INDEXEDDB;\n\t            this.LOCALSTORAGE = DriverType.LOCALSTORAGE;\n\t            this.WEBSQL = DriverType.WEBSQL;\n\n\t            this._defaultConfig = extend({}, DefaultConfig);\n\t            this._config = extend({}, this._defaultConfig, options);\n\t            this._driverSet = null;\n\t            this._initDriver = null;\n\t            this._ready = false;\n\t            this._dbInfo = null;\n\n\t            this._wrapLibraryMethodsWithReady();\n\t            this.setDriver(this._config.driver);\n\t        }\n\n\t        // The actual localForage object that we expose as a module or via a\n\t        // global. It's extended by pulling in one of our other libraries.\n\n\t        // Set any config values for localForage; can be called anytime before\n\t        // the first API call (e.g. `getItem`, `setItem`).\n\t        // We loop through options so we don't overwrite existing config\n\t        // values.\n\n\t        LocalForage.prototype.config = function config(options) {\n\t            // If the options argument is an object, we use it to set values.\n\t            // Otherwise, we return either a specified config value or all\n\t            // config values.\n\t            if (typeof options === 'object') {\n\t                // If localforage is ready and fully initialized, we can't set\n\t                // any new configuration values. Instead, we return an error.\n\t                if (this._ready) {\n\t                    return new Error(\"Can't call config() after localforage \" + 'has been used.');\n\t                }\n\n\t                for (var i in options) {\n\t                    if (i === 'storeName') {\n\t                        options[i] = options[i].replace(/\\W/g, '_');\n\t                    }\n\n\t                    this._config[i] = options[i];\n\t                }\n\n\t                // after all config options are set and\n\t                // the driver option is used, try setting it\n\t                if ('driver' in options && options.driver) {\n\t                    this.setDriver(this._config.driver);\n\t                }\n\n\t                return true;\n\t            } else if (typeof options === 'string') {\n\t                return this._config[options];\n\t            } else {\n\t                return this._config;\n\t            }\n\t        };\n\n\t        // Used to define a custom driver, shared across all instances of\n\t        // localForage.\n\n\t        LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) {\n\t            var promise = new Promise(function (resolve, reject) {\n\t                try {\n\t                    var driverName = driverObject._driver;\n\t                    var complianceError = new Error('Custom driver not compliant; see ' + 'https://mozilla.github.io/localForage/#definedriver');\n\t                    var namingError = new Error('Custom driver name already in use: ' + driverObject._driver);\n\n\t                    // A driver name should be defined and not overlap with the\n\t                    // library-defined, default drivers.\n\t                    if (!driverObject._driver) {\n\t                        reject(complianceError);\n\t                        return;\n\t                    }\n\t                    if (isLibraryDriver(driverObject._driver)) {\n\t                        reject(namingError);\n\t                        return;\n\t                    }\n\n\t                    var customDriverMethods = LibraryMethods.concat('_initStorage');\n\t                    for (var i = 0; i < customDriverMethods.length; i++) {\n\t                        var customDriverMethod = customDriverMethods[i];\n\t                        if (!customDriverMethod || !driverObject[customDriverMethod] || typeof driverObject[customDriverMethod] !== 'function') {\n\t                            reject(complianceError);\n\t                            return;\n\t                        }\n\t                    }\n\n\t                    var supportPromise = Promise.resolve(true);\n\t                    if ('_support' in driverObject) {\n\t                        if (driverObject._support && typeof driverObject._support === 'function') {\n\t                            supportPromise = driverObject._support();\n\t                        } else {\n\t                            supportPromise = Promise.resolve(!!driverObject._support);\n\t                        }\n\t                    }\n\n\t                    supportPromise.then(function (supportResult) {\n\t                        driverSupport[driverName] = supportResult;\n\t                        CustomDrivers[driverName] = driverObject;\n\t                        resolve();\n\t                    }, reject);\n\t                } catch (e) {\n\t                    reject(e);\n\t                }\n\t            });\n\n\t            promise.then(callback, errorCallback);\n\t            return promise;\n\t        };\n\n\t        LocalForage.prototype.driver = function driver() {\n\t            return this._driver || null;\n\t        };\n\n\t        LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) {\n\t            var self = this;\n\t            var getDriverPromise = (function () {\n\t                if (isLibraryDriver(driverName)) {\n\t                    switch (driverName) {\n\t                        case self.INDEXEDDB:\n\t                            return new Promise(function (resolve, reject) {\n\t                                resolve(__webpack_require__(1));\n\t                            });\n\t                        case self.LOCALSTORAGE:\n\t                            return new Promise(function (resolve, reject) {\n\t                                resolve(__webpack_require__(2));\n\t                            });\n\t                        case self.WEBSQL:\n\t                            return new Promise(function (resolve, reject) {\n\t                                resolve(__webpack_require__(4));\n\t                            });\n\t                    }\n\t                } else if (CustomDrivers[driverName]) {\n\t                    return Promise.resolve(CustomDrivers[driverName]);\n\t                }\n\n\t                return Promise.reject(new Error('Driver not found.'));\n\t            })();\n\n\t            getDriverPromise.then(callback, errorCallback);\n\t            return getDriverPromise;\n\t        };\n\n\t        LocalForage.prototype.getSerializer = function getSerializer(callback) {\n\t            var serializerPromise = new Promise(function (resolve, reject) {\n\t                resolve(__webpack_require__(3));\n\t            });\n\t            if (callback && typeof callback === 'function') {\n\t                serializerPromise.then(function (result) {\n\t                    callback(result);\n\t                });\n\t            }\n\t            return serializerPromise;\n\t        };\n\n\t        LocalForage.prototype.ready = function ready(callback) {\n\t            var self = this;\n\n\t            var promise = self._driverSet.then(function () {\n\t                if (self._ready === null) {\n\t                    self._ready = self._initDriver();\n\t                }\n\n\t                return self._ready;\n\t            });\n\n\t            promise.then(callback, callback);\n\t            return promise;\n\t        };\n\n\t        LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) {\n\t            var self = this;\n\n\t            if (!isArray(drivers)) {\n\t                drivers = [drivers];\n\t            }\n\n\t            var supportedDrivers = this._getSupportedDrivers(drivers);\n\n\t            function setDriverToConfig() {\n\t                self._config.driver = self.driver();\n\t            }\n\n\t            function initDriver(supportedDrivers) {\n\t                return function () {\n\t                    var currentDriverIndex = 0;\n\n\t                    function driverPromiseLoop() {\n\t                        while (currentDriverIndex < supportedDrivers.length) {\n\t                            var driverName = supportedDrivers[currentDriverIndex];\n\t                            currentDriverIndex++;\n\n\t                            self._dbInfo = null;\n\t                            self._ready = null;\n\n\t                            return self.getDriver(driverName).then(function (driver) {\n\t                                self._extend(driver);\n\t                                setDriverToConfig();\n\n\t                                self._ready = self._initStorage(self._config);\n\t                                return self._ready;\n\t                            })['catch'](driverPromiseLoop);\n\t                        }\n\n\t                        setDriverToConfig();\n\t                        var error = new Error('No available storage method found.');\n\t                        self._driverSet = Promise.reject(error);\n\t                        return self._driverSet;\n\t                    }\n\n\t                    return driverPromiseLoop();\n\t                };\n\t            }\n\n\t            // There might be a driver initialization in progress\n\t            // so wait for it to finish in order to avoid a possible\n\t            // race condition to set _dbInfo\n\t            var oldDriverSetDone = this._driverSet !== null ? this._driverSet['catch'](function () {\n\t                return Promise.resolve();\n\t            }) : Promise.resolve();\n\n\t            this._driverSet = oldDriverSetDone.then(function () {\n\t                var driverName = supportedDrivers[0];\n\t                self._dbInfo = null;\n\t                self._ready = null;\n\n\t                return self.getDriver(driverName).then(function (driver) {\n\t                    self._driver = driver._driver;\n\t                    setDriverToConfig();\n\t                    self._wrapLibraryMethodsWithReady();\n\t                    self._initDriver = initDriver(supportedDrivers);\n\t                });\n\t            })['catch'](function () {\n\t                setDriverToConfig();\n\t                var error = new Error('No available storage method found.');\n\t                self._driverSet = Promise.reject(error);\n\t                return self._driverSet;\n\t            });\n\n\t            this._driverSet.then(callback, errorCallback);\n\t            return this._driverSet;\n\t        };\n\n\t        LocalForage.prototype.supports = function supports(driverName) {\n\t            return !!driverSupport[driverName];\n\t        };\n\n\t        LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) {\n\t            extend(this, libraryMethodsAndProperties);\n\t        };\n\n\t        LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) {\n\t            var supportedDrivers = [];\n\t            for (var i = 0, len = drivers.length; i < len; i++) {\n\t                var driverName = drivers[i];\n\t                if (this.supports(driverName)) {\n\t                    supportedDrivers.push(driverName);\n\t                }\n\t            }\n\t            return supportedDrivers;\n\t        };\n\n\t        LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() {\n\t            // Add a stub for each driver API method that delays the call to the\n\t            // corresponding driver method until localForage is ready. These stubs\n\t            // will be replaced by the driver methods as soon as the driver is\n\t            // loaded, so there is no performance impact.\n\t            for (var i = 0; i < LibraryMethods.length; i++) {\n\t                callWhenReady(this, LibraryMethods[i]);\n\t            }\n\t        };\n\n\t        LocalForage.prototype.createInstance = function createInstance(options) {\n\t            return new LocalForage(options);\n\t        };\n\n\t        return LocalForage;\n\t    })();\n\n\t    var localForage = new LocalForage();\n\n\t    exports['default'] = localForage;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t// Some code originally from async_storage.js in\n\t// [Gaia](https://github.com/mozilla-b2g/gaia).\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    var globalObject = this;\n\t    // Initialize IndexedDB; fall back to vendor-prefixed versions if needed.\n\t    var indexedDB = indexedDB || this.indexedDB || this.webkitIndexedDB || this.mozIndexedDB || this.OIndexedDB || this.msIndexedDB;\n\n\t    // If IndexedDB isn't available, we get outta here!\n\t    if (!indexedDB) {\n\t        return;\n\t    }\n\n\t    var DETECT_BLOB_SUPPORT_STORE = 'local-forage-detect-blob-support';\n\t    var supportsBlobs;\n\t    var dbContexts;\n\n\t    // Abstracts constructing a Blob object, so it also works in older\n\t    // browsers that don't support the native Blob constructor. (i.e.\n\t    // old QtWebKit versions, at least).\n\t    function _createBlob(parts, properties) {\n\t        parts = parts || [];\n\t        properties = properties || {};\n\t        try {\n\t            return new Blob(parts, properties);\n\t        } catch (e) {\n\t            if (e.name !== 'TypeError') {\n\t                throw e;\n\t            }\n\t            var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;\n\t            var builder = new BlobBuilder();\n\t            for (var i = 0; i < parts.length; i += 1) {\n\t                builder.append(parts[i]);\n\t            }\n\t            return builder.getBlob(properties.type);\n\t        }\n\t    }\n\n\t    // Transform a binary string to an array buffer, because otherwise\n\t    // weird stuff happens when you try to work with the binary string directly.\n\t    // It is known.\n\t    // From http://stackoverflow.com/questions/14967647/ (continues on next line)\n\t    // encode-decode-image-with-base64-breaks-image (2013-04-21)\n\t    function _binStringToArrayBuffer(bin) {\n\t        var length = bin.length;\n\t        var buf = new ArrayBuffer(length);\n\t        var arr = new Uint8Array(buf);\n\t        for (var i = 0; i < length; i++) {\n\t            arr[i] = bin.charCodeAt(i);\n\t        }\n\t        return buf;\n\t    }\n\n\t    // Fetch a blob using ajax. This reveals bugs in Chrome < 43.\n\t    // For details on all this junk:\n\t    // https://github.com/nolanlawson/state-of-binary-data-in-the-browser#readme\n\t    function _blobAjax(url) {\n\t        return new Promise(function (resolve, reject) {\n\t            var xhr = new XMLHttpRequest();\n\t            xhr.open('GET', url);\n\t            xhr.withCredentials = true;\n\t            xhr.responseType = 'arraybuffer';\n\n\t            xhr.onreadystatechange = function () {\n\t                if (xhr.readyState !== 4) {\n\t                    return;\n\t                }\n\t                if (xhr.status === 200) {\n\t                    return resolve({\n\t                        response: xhr.response,\n\t                        type: xhr.getResponseHeader('Content-Type')\n\t                    });\n\t                }\n\t                reject({ status: xhr.status, response: xhr.response });\n\t            };\n\t            xhr.send();\n\t        });\n\t    }\n\n\t    //\n\t    // Detect blob support. Chrome didn't support it until version 38.\n\t    // In version 37 they had a broken version where PNGs (and possibly\n\t    // other binary types) aren't stored correctly, because when you fetch\n\t    // them, the content type is always null.\n\t    //\n\t    // Furthermore, they have some outstanding bugs where blobs occasionally\n\t    // are read by FileReader as null, or by ajax as 404s.\n\t    //\n\t    // Sadly we use the 404 bug to detect the FileReader bug, so if they\n\t    // get fixed independently and released in different versions of Chrome,\n\t    // then the bug could come back. So it's worthwhile to watch these issues:\n\t    // 404 bug: https://code.google.com/p/chromium/issues/detail?id=447916\n\t    // FileReader bug: https://code.google.com/p/chromium/issues/detail?id=447836\n\t    //\n\t    function _checkBlobSupportWithoutCaching(idb) {\n\t        return new Promise(function (resolve, reject) {\n\t            var blob = _createBlob([''], { type: 'image/png' });\n\t            var txn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');\n\t            txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key');\n\t            txn.oncomplete = function () {\n\t                // have to do it in a separate transaction, else the correct\n\t                // content type is always returned\n\t                var blobTxn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');\n\t                var getBlobReq = blobTxn.objectStore(DETECT_BLOB_SUPPORT_STORE).get('key');\n\t                getBlobReq.onerror = reject;\n\t                getBlobReq.onsuccess = function (e) {\n\n\t                    var storedBlob = e.target.result;\n\t                    var url = URL.createObjectURL(storedBlob);\n\n\t                    _blobAjax(url).then(function (res) {\n\t                        resolve(!!(res && res.type === 'image/png'));\n\t                    }, function () {\n\t                        resolve(false);\n\t                    }).then(function () {\n\t                        URL.revokeObjectURL(url);\n\t                    });\n\t                };\n\t            };\n\t        })['catch'](function () {\n\t            return false; // error, so assume unsupported\n\t        });\n\t    }\n\n\t    function _checkBlobSupport(idb) {\n\t        if (typeof supportsBlobs === 'boolean') {\n\t            return Promise.resolve(supportsBlobs);\n\t        }\n\t        return _checkBlobSupportWithoutCaching(idb).then(function (value) {\n\t            supportsBlobs = value;\n\t            return supportsBlobs;\n\t        });\n\t    }\n\n\t    // encode a blob for indexeddb engines that don't support blobs\n\t    function _encodeBlob(blob) {\n\t        return new Promise(function (resolve, reject) {\n\t            var reader = new FileReader();\n\t            reader.onerror = reject;\n\t            reader.onloadend = function (e) {\n\t                var base64 = btoa(e.target.result || '');\n\t                resolve({\n\t                    __local_forage_encoded_blob: true,\n\t                    data: base64,\n\t                    type: blob.type\n\t                });\n\t            };\n\t            reader.readAsBinaryString(blob);\n\t        });\n\t    }\n\n\t    // decode an encoded blob\n\t    function _decodeBlob(encodedBlob) {\n\t        var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));\n\t        return _createBlob([arrayBuff], { type: encodedBlob.type });\n\t    }\n\n\t    // is this one of our fancy encoded blobs?\n\t    function _isEncodedBlob(value) {\n\t        return value && value.__local_forage_encoded_blob;\n\t    }\n\n\t    // Open the IndexedDB database (automatically creates one if one didn't\n\t    // previously exist), using any options set in the config.\n\t    function _initStorage(options) {\n\t        var self = this;\n\t        var dbInfo = {\n\t            db: null\n\t        };\n\n\t        if (options) {\n\t            for (var i in options) {\n\t                dbInfo[i] = options[i];\n\t            }\n\t        }\n\n\t        // Initialize a singleton container for all running localForages.\n\t        if (!dbContexts) {\n\t            dbContexts = {};\n\t        }\n\n\t        // Get the current context of the database;\n\t        var dbContext = dbContexts[dbInfo.name];\n\n\t        // ...or create a new context.\n\t        if (!dbContext) {\n\t            dbContext = {\n\t                // Running localForages sharing a database.\n\t                forages: [],\n\t                // Shared database.\n\t                db: null\n\t            };\n\t            // Register the new context in the global container.\n\t            dbContexts[dbInfo.name] = dbContext;\n\t        }\n\n\t        // Register itself as a running localForage in the current context.\n\t        dbContext.forages.push(this);\n\n\t        // Create an array of readiness of the related localForages.\n\t        var readyPromises = [];\n\n\t        function ignoreErrors() {\n\t            // Don't handle errors here,\n\t            // just makes sure related localForages aren't pending.\n\t            return Promise.resolve();\n\t        }\n\n\t        for (var j = 0; j < dbContext.forages.length; j++) {\n\t            var forage = dbContext.forages[j];\n\t            if (forage !== this) {\n\t                // Don't wait for itself...\n\t                readyPromises.push(forage.ready()['catch'](ignoreErrors));\n\t            }\n\t        }\n\n\t        // Take a snapshot of the related localForages.\n\t        var forages = dbContext.forages.slice(0);\n\n\t        // Initialize the connection process only when\n\t        // all the related localForages aren't pending.\n\t        return Promise.all(readyPromises).then(function () {\n\t            dbInfo.db = dbContext.db;\n\t            // Get the connection or open a new one without upgrade.\n\t            return _getOriginalConnection(dbInfo);\n\t        }).then(function (db) {\n\t            dbInfo.db = db;\n\t            if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) {\n\t                // Reopen the database for upgrading.\n\t                return _getUpgradedConnection(dbInfo);\n\t            }\n\t            return db;\n\t        }).then(function (db) {\n\t            dbInfo.db = dbContext.db = db;\n\t            self._dbInfo = dbInfo;\n\t            // Share the final connection amongst related localForages.\n\t            for (var k in forages) {\n\t                var forage = forages[k];\n\t                if (forage !== self) {\n\t                    // Self is already up-to-date.\n\t                    forage._dbInfo.db = dbInfo.db;\n\t                    forage._dbInfo.version = dbInfo.version;\n\t                }\n\t            }\n\t        });\n\t    }\n\n\t    function _getOriginalConnection(dbInfo) {\n\t        return _getConnection(dbInfo, false);\n\t    }\n\n\t    function _getUpgradedConnection(dbInfo) {\n\t        return _getConnection(dbInfo, true);\n\t    }\n\n\t    function _getConnection(dbInfo, upgradeNeeded) {\n\t        return new Promise(function (resolve, reject) {\n\t            if (dbInfo.db) {\n\t                if (upgradeNeeded) {\n\t                    dbInfo.db.close();\n\t                } else {\n\t                    return resolve(dbInfo.db);\n\t                }\n\t            }\n\n\t            var dbArgs = [dbInfo.name];\n\n\t            if (upgradeNeeded) {\n\t                dbArgs.push(dbInfo.version);\n\t            }\n\n\t            var openreq = indexedDB.open.apply(indexedDB, dbArgs);\n\n\t            if (upgradeNeeded) {\n\t                openreq.onupgradeneeded = function (e) {\n\t                    var db = openreq.result;\n\t                    try {\n\t                        db.createObjectStore(dbInfo.storeName);\n\t                        if (e.oldVersion <= 1) {\n\t                            // Added when support for blob shims was added\n\t                            db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);\n\t                        }\n\t                    } catch (ex) {\n\t                        if (ex.name === 'ConstraintError') {\n\t                            globalObject.console.warn('The database \"' + dbInfo.name + '\"' + ' has been upgraded from version ' + e.oldVersion + ' to version ' + e.newVersion + ', but the storage \"' + dbInfo.storeName + '\" already exists.');\n\t                        } else {\n\t                            throw ex;\n\t                        }\n\t                    }\n\t                };\n\t            }\n\n\t            openreq.onerror = function () {\n\t                reject(openreq.error);\n\t            };\n\n\t            openreq.onsuccess = function () {\n\t                resolve(openreq.result);\n\t            };\n\t        });\n\t    }\n\n\t    function _isUpgradeNeeded(dbInfo, defaultVersion) {\n\t        if (!dbInfo.db) {\n\t            return true;\n\t        }\n\n\t        var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);\n\t        var isDowngrade = dbInfo.version < dbInfo.db.version;\n\t        var isUpgrade = dbInfo.version > dbInfo.db.version;\n\n\t        if (isDowngrade) {\n\t            // If the version is not the default one\n\t            // then warn for impossible downgrade.\n\t            if (dbInfo.version !== defaultVersion) {\n\t                globalObject.console.warn('The database \"' + dbInfo.name + '\"' + ' can\\'t be downgraded from version ' + dbInfo.db.version + ' to version ' + dbInfo.version + '.');\n\t            }\n\t            // Align the versions to prevent errors.\n\t            dbInfo.version = dbInfo.db.version;\n\t        }\n\n\t        if (isUpgrade || isNewStore) {\n\t            // If the store is new then increment the version (if needed).\n\t            // This will trigger an \"upgradeneeded\" event which is required\n\t            // for creating a store.\n\t            if (isNewStore) {\n\t                var incVersion = dbInfo.db.version + 1;\n\t                if (incVersion > dbInfo.version) {\n\t                    dbInfo.version = incVersion;\n\t                }\n\t            }\n\n\t            return true;\n\t        }\n\n\t        return false;\n\t    }\n\n\t    function getItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\t                var req = store.get(key);\n\n\t                req.onsuccess = function () {\n\t                    var value = req.result;\n\t                    if (value === undefined) {\n\t                        value = null;\n\t                    }\n\t                    if (_isEncodedBlob(value)) {\n\t                        value = _decodeBlob(value);\n\t                    }\n\t                    resolve(value);\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Iterate over all items stored in database.\n\t    function iterate(iterator, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\n\t                var req = store.openCursor();\n\t                var iterationNumber = 1;\n\n\t                req.onsuccess = function () {\n\t                    var cursor = req.result;\n\n\t                    if (cursor) {\n\t                        var value = cursor.value;\n\t                        if (_isEncodedBlob(value)) {\n\t                            value = _decodeBlob(value);\n\t                        }\n\t                        var result = iterator(value, cursor.key, iterationNumber++);\n\n\t                        if (result !== void 0) {\n\t                            resolve(result);\n\t                        } else {\n\t                            cursor['continue']();\n\t                        }\n\t                    } else {\n\t                        resolve();\n\t                    }\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\n\t        return promise;\n\t    }\n\n\t    function setItem(key, value, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            var dbInfo;\n\t            self.ready().then(function () {\n\t                dbInfo = self._dbInfo;\n\t                return _checkBlobSupport(dbInfo.db);\n\t            }).then(function (blobSupport) {\n\t                if (!blobSupport && value instanceof Blob) {\n\t                    return _encodeBlob(value);\n\t                }\n\t                return value;\n\t            }).then(function (value) {\n\t                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');\n\t                var store = transaction.objectStore(dbInfo.storeName);\n\n\t                // The reason we don't _save_ null is because IE 10 does\n\t                // not support saving the `null` type in IndexedDB. How\n\t                // ironic, given the bug below!\n\t                // See: https://github.com/mozilla/localForage/issues/161\n\t                if (value === null) {\n\t                    value = undefined;\n\t                }\n\n\t                var req = store.put(value, key);\n\t                transaction.oncomplete = function () {\n\t                    // Cast to undefined so the value passed to\n\t                    // callback/promise is the same as what one would get out\n\t                    // of `getItem()` later. This leads to some weirdness\n\t                    // (setItem('foo', undefined) will return `null`), but\n\t                    // it's not my fault localStorage is our baseline and that\n\t                    // it's weird.\n\t                    if (value === undefined) {\n\t                        value = null;\n\t                    }\n\n\t                    resolve(value);\n\t                };\n\t                transaction.onabort = transaction.onerror = function () {\n\t                    var err = req.error ? req.error : req.transaction.error;\n\t                    reject(err);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function removeItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');\n\t                var store = transaction.objectStore(dbInfo.storeName);\n\n\t                // We use a Grunt task to make this safe for IE and some\n\t                // versions of Android (including those used by Cordova).\n\t                // Normally IE won't like `.delete()` and will insist on\n\t                // using `['delete']()`, but we have a build step that\n\t                // fixes this for us now.\n\t                var req = store['delete'](key);\n\t                transaction.oncomplete = function () {\n\t                    resolve();\n\t                };\n\n\t                transaction.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\n\t                // The request will be also be aborted if we've exceeded our storage\n\t                // space.\n\t                transaction.onabort = function () {\n\t                    var err = req.error ? req.error : req.transaction.error;\n\t                    reject(err);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function clear(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');\n\t                var store = transaction.objectStore(dbInfo.storeName);\n\t                var req = store.clear();\n\n\t                transaction.oncomplete = function () {\n\t                    resolve();\n\t                };\n\n\t                transaction.onabort = transaction.onerror = function () {\n\t                    var err = req.error ? req.error : req.transaction.error;\n\t                    reject(err);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function length(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\t                var req = store.count();\n\n\t                req.onsuccess = function () {\n\t                    resolve(req.result);\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function key(n, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            if (n < 0) {\n\t                resolve(null);\n\n\t                return;\n\t            }\n\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\n\t                var advanced = false;\n\t                var req = store.openCursor();\n\t                req.onsuccess = function () {\n\t                    var cursor = req.result;\n\t                    if (!cursor) {\n\t                        // this means there weren't enough keys\n\t                        resolve(null);\n\n\t                        return;\n\t                    }\n\n\t                    if (n === 0) {\n\t                        // We have the first key, return it if that's what they\n\t                        // wanted.\n\t                        resolve(cursor.key);\n\t                    } else {\n\t                        if (!advanced) {\n\t                            // Otherwise, ask the cursor to skip ahead n\n\t                            // records.\n\t                            advanced = true;\n\t                            cursor.advance(n);\n\t                        } else {\n\t                            // When we get here, we've got the nth key.\n\t                            resolve(cursor.key);\n\t                        }\n\t                    }\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function keys(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);\n\n\t                var req = store.openCursor();\n\t                var keys = [];\n\n\t                req.onsuccess = function () {\n\t                    var cursor = req.result;\n\n\t                    if (!cursor) {\n\t                        resolve(keys);\n\t                        return;\n\t                    }\n\n\t                    keys.push(cursor.key);\n\t                    cursor['continue']();\n\t                };\n\n\t                req.onerror = function () {\n\t                    reject(req.error);\n\t                };\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function executeCallback(promise, callback) {\n\t        if (callback) {\n\t            promise.then(function (result) {\n\t                callback(null, result);\n\t            }, function (error) {\n\t                callback(error);\n\t            });\n\t        }\n\t    }\n\n\t    var asyncStorage = {\n\t        _driver: 'asyncStorage',\n\t        _initStorage: _initStorage,\n\t        iterate: iterate,\n\t        getItem: getItem,\n\t        setItem: setItem,\n\t        removeItem: removeItem,\n\t        clear: clear,\n\t        length: length,\n\t        key: key,\n\t        keys: keys\n\t    };\n\n\t    exports['default'] = asyncStorage;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 2 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t// If IndexedDB isn't available, we'll fall back to localStorage.\n\t// Note that this will have considerable performance and storage\n\t// side-effects (all data will be serialized on save and only data that\n\t// can be converted to a string via `JSON.stringify()` will be saved).\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    var globalObject = this;\n\t    var localStorage = null;\n\n\t    // If the app is running inside a Google Chrome packaged webapp, or some\n\t    // other context where localStorage isn't available, we don't use\n\t    // localStorage. This feature detection is preferred over the old\n\t    // `if (window.chrome && window.chrome.runtime)` code.\n\t    // See: https://github.com/mozilla/localForage/issues/68\n\t    try {\n\t        // If localStorage isn't available, we get outta here!\n\t        // This should be inside a try catch\n\t        if (!this.localStorage || !('setItem' in this.localStorage)) {\n\t            return;\n\t        }\n\t        // Initialize localStorage and create a variable to use throughout\n\t        // the code.\n\t        localStorage = this.localStorage;\n\t    } catch (e) {\n\t        return;\n\t    }\n\n\t    // Config the localStorage backend, using options set in the config.\n\t    function _initStorage(options) {\n\t        var self = this;\n\t        var dbInfo = {};\n\t        if (options) {\n\t            for (var i in options) {\n\t                dbInfo[i] = options[i];\n\t            }\n\t        }\n\n\t        dbInfo.keyPrefix = dbInfo.name + '/';\n\n\t        if (dbInfo.storeName !== self._defaultConfig.storeName) {\n\t            dbInfo.keyPrefix += dbInfo.storeName + '/';\n\t        }\n\n\t        self._dbInfo = dbInfo;\n\n\t        return new Promise(function (resolve, reject) {\n\t            resolve(__webpack_require__(3));\n\t        }).then(function (lib) {\n\t            dbInfo.serializer = lib;\n\t            return Promise.resolve();\n\t        });\n\t    }\n\n\t    // Remove all keys from the datastore, effectively destroying all data in\n\t    // the app's key/value store!\n\t    function clear(callback) {\n\t        var self = this;\n\t        var promise = self.ready().then(function () {\n\t            var keyPrefix = self._dbInfo.keyPrefix;\n\n\t            for (var i = localStorage.length - 1; i >= 0; i--) {\n\t                var key = localStorage.key(i);\n\n\t                if (key.indexOf(keyPrefix) === 0) {\n\t                    localStorage.removeItem(key);\n\t                }\n\t            }\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Retrieve an item from the store. Unlike the original async_storage\n\t    // library in Gaia, we don't modify return values at all. If a key's value\n\t    // is `undefined`, we pass that value to the callback function.\n\t    function getItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var result = localStorage.getItem(dbInfo.keyPrefix + key);\n\n\t            // If a result was found, parse it from the serialized\n\t            // string into a JS object. If result isn't truthy, the key\n\t            // is likely undefined and we'll pass it straight to the\n\t            // callback.\n\t            if (result) {\n\t                result = dbInfo.serializer.deserialize(result);\n\t            }\n\n\t            return result;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Iterate over all items in the store.\n\t    function iterate(iterator, callback) {\n\t        var self = this;\n\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var keyPrefix = dbInfo.keyPrefix;\n\t            var keyPrefixLength = keyPrefix.length;\n\t            var length = localStorage.length;\n\n\t            // We use a dedicated iterator instead of the `i` variable below\n\t            // so other keys we fetch in localStorage aren't counted in\n\t            // the `iterationNumber` argument passed to the `iterate()`\n\t            // callback.\n\t            //\n\t            // See: github.com/mozilla/localForage/pull/435#discussion_r38061530\n\t            var iterationNumber = 1;\n\n\t            for (var i = 0; i < length; i++) {\n\t                var key = localStorage.key(i);\n\t                if (key.indexOf(keyPrefix) !== 0) {\n\t                    continue;\n\t                }\n\t                var value = localStorage.getItem(key);\n\n\t                // If a result was found, parse it from the serialized\n\t                // string into a JS object. If result isn't truthy, the\n\t                // key is likely undefined and we'll pass it straight\n\t                // to the iterator.\n\t                if (value) {\n\t                    value = dbInfo.serializer.deserialize(value);\n\t                }\n\n\t                value = iterator(value, key.substring(keyPrefixLength), iterationNumber++);\n\n\t                if (value !== void 0) {\n\t                    return value;\n\t                }\n\t            }\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Same as localStorage's key() method, except takes a callback.\n\t    function key(n, callback) {\n\t        var self = this;\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var result;\n\t            try {\n\t                result = localStorage.key(n);\n\t            } catch (error) {\n\t                result = null;\n\t            }\n\n\t            // Remove the prefix from the key, if a key is found.\n\t            if (result) {\n\t                result = result.substring(dbInfo.keyPrefix.length);\n\t            }\n\n\t            return result;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function keys(callback) {\n\t        var self = this;\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            var length = localStorage.length;\n\t            var keys = [];\n\n\t            for (var i = 0; i < length; i++) {\n\t                if (localStorage.key(i).indexOf(dbInfo.keyPrefix) === 0) {\n\t                    keys.push(localStorage.key(i).substring(dbInfo.keyPrefix.length));\n\t                }\n\t            }\n\n\t            return keys;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Supply the number of keys in the datastore to the callback function.\n\t    function length(callback) {\n\t        var self = this;\n\t        var promise = self.keys().then(function (keys) {\n\t            return keys.length;\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Remove an item from the store, nice and simple.\n\t    function removeItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = self.ready().then(function () {\n\t            var dbInfo = self._dbInfo;\n\t            localStorage.removeItem(dbInfo.keyPrefix + key);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Set a key's value and run an optional callback once the value is set.\n\t    // Unlike Gaia's implementation, the callback function is passed the value,\n\t    // in case you want to operate on that value only after you're sure it\n\t    // saved, or something like that.\n\t    function setItem(key, value, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = self.ready().then(function () {\n\t            // Convert undefined values to null.\n\t            // https://github.com/mozilla/localForage/pull/42\n\t            if (value === undefined) {\n\t                value = null;\n\t            }\n\n\t            // Save the original value to pass to the callback.\n\t            var originalValue = value;\n\n\t            return new Promise(function (resolve, reject) {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.serializer.serialize(value, function (value, error) {\n\t                    if (error) {\n\t                        reject(error);\n\t                    } else {\n\t                        try {\n\t                            localStorage.setItem(dbInfo.keyPrefix + key, value);\n\t                            resolve(originalValue);\n\t                        } catch (e) {\n\t                            // localStorage capacity exceeded.\n\t                            // TODO: Make this a specific error/event.\n\t                            if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {\n\t                                reject(e);\n\t                            }\n\t                            reject(e);\n\t                        }\n\t                    }\n\t                });\n\t            });\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function executeCallback(promise, callback) {\n\t        if (callback) {\n\t            promise.then(function (result) {\n\t                callback(null, result);\n\t            }, function (error) {\n\t                callback(error);\n\t            });\n\t        }\n\t    }\n\n\t    var localStorageWrapper = {\n\t        _driver: 'localStorageWrapper',\n\t        _initStorage: _initStorage,\n\t        // Default API, from Gaia/localStorage.\n\t        iterate: iterate,\n\t        getItem: getItem,\n\t        setItem: setItem,\n\t        removeItem: removeItem,\n\t        clear: clear,\n\t        length: length,\n\t        key: key,\n\t        keys: keys\n\t    };\n\n\t    exports['default'] = localStorageWrapper;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    // Sadly, the best way to save binary data in WebSQL/localStorage is serializing\n\t    // it to Base64, so this is how we store it to prevent very strange errors with less\n\t    // verbose ways of binary <-> string data storage.\n\t    var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n\t    var BLOB_TYPE_PREFIX = '~~local_forage_type~';\n\t    var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;\n\n\t    var SERIALIZED_MARKER = '__lfsc__:';\n\t    var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;\n\n\t    // OMG the serializations!\n\t    var TYPE_ARRAYBUFFER = 'arbf';\n\t    var TYPE_BLOB = 'blob';\n\t    var TYPE_INT8ARRAY = 'si08';\n\t    var TYPE_UINT8ARRAY = 'ui08';\n\t    var TYPE_UINT8CLAMPEDARRAY = 'uic8';\n\t    var TYPE_INT16ARRAY = 'si16';\n\t    var TYPE_INT32ARRAY = 'si32';\n\t    var TYPE_UINT16ARRAY = 'ur16';\n\t    var TYPE_UINT32ARRAY = 'ui32';\n\t    var TYPE_FLOAT32ARRAY = 'fl32';\n\t    var TYPE_FLOAT64ARRAY = 'fl64';\n\t    var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;\n\n\t    // Get out of our habit of using `window` inline, at least.\n\t    var globalObject = this;\n\n\t    // Abstracts constructing a Blob object, so it also works in older\n\t    // browsers that don't support the native Blob constructor. (i.e.\n\t    // old QtWebKit versions, at least).\n\t    function _createBlob(parts, properties) {\n\t        parts = parts || [];\n\t        properties = properties || {};\n\n\t        try {\n\t            return new Blob(parts, properties);\n\t        } catch (err) {\n\t            if (err.name !== 'TypeError') {\n\t                throw err;\n\t            }\n\n\t            var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;\n\n\t            var builder = new BlobBuilder();\n\t            for (var i = 0; i < parts.length; i += 1) {\n\t                builder.append(parts[i]);\n\t            }\n\n\t            return builder.getBlob(properties.type);\n\t        }\n\t    }\n\n\t    // Serialize a value, afterwards executing a callback (which usually\n\t    // instructs the `setItem()` callback/promise to be executed). This is how\n\t    // we store binary data with localStorage.\n\t    function serialize(value, callback) {\n\t        var valueString = '';\n\t        if (value) {\n\t            valueString = value.toString();\n\t        }\n\n\t        // Cannot use `value instanceof ArrayBuffer` or such here, as these\n\t        // checks fail when running the tests using casper.js...\n\t        //\n\t        // TODO: See why those tests fail and use a better solution.\n\t        if (value && (value.toString() === '[object ArrayBuffer]' || value.buffer && value.buffer.toString() === '[object ArrayBuffer]')) {\n\t            // Convert binary arrays to a string and prefix the string with\n\t            // a special marker.\n\t            var buffer;\n\t            var marker = SERIALIZED_MARKER;\n\n\t            if (value instanceof ArrayBuffer) {\n\t                buffer = value;\n\t                marker += TYPE_ARRAYBUFFER;\n\t            } else {\n\t                buffer = value.buffer;\n\n\t                if (valueString === '[object Int8Array]') {\n\t                    marker += TYPE_INT8ARRAY;\n\t                } else if (valueString === '[object Uint8Array]') {\n\t                    marker += TYPE_UINT8ARRAY;\n\t                } else if (valueString === '[object Uint8ClampedArray]') {\n\t                    marker += TYPE_UINT8CLAMPEDARRAY;\n\t                } else if (valueString === '[object Int16Array]') {\n\t                    marker += TYPE_INT16ARRAY;\n\t                } else if (valueString === '[object Uint16Array]') {\n\t                    marker += TYPE_UINT16ARRAY;\n\t                } else if (valueString === '[object Int32Array]') {\n\t                    marker += TYPE_INT32ARRAY;\n\t                } else if (valueString === '[object Uint32Array]') {\n\t                    marker += TYPE_UINT32ARRAY;\n\t                } else if (valueString === '[object Float32Array]') {\n\t                    marker += TYPE_FLOAT32ARRAY;\n\t                } else if (valueString === '[object Float64Array]') {\n\t                    marker += TYPE_FLOAT64ARRAY;\n\t                } else {\n\t                    callback(new Error('Failed to get type for BinaryArray'));\n\t                }\n\t            }\n\n\t            callback(marker + bufferToString(buffer));\n\t        } else if (valueString === '[object Blob]') {\n\t            // Conver the blob to a binaryArray and then to a string.\n\t            var fileReader = new FileReader();\n\n\t            fileReader.onload = function () {\n\t                // Backwards-compatible prefix for the blob type.\n\t                var str = BLOB_TYPE_PREFIX + value.type + '~' + bufferToString(this.result);\n\n\t                callback(SERIALIZED_MARKER + TYPE_BLOB + str);\n\t            };\n\n\t            fileReader.readAsArrayBuffer(value);\n\t        } else {\n\t            try {\n\t                callback(JSON.stringify(value));\n\t            } catch (e) {\n\t                console.error(\"Couldn't convert value into a JSON string: \", value);\n\n\t                callback(null, e);\n\t            }\n\t        }\n\t    }\n\n\t    // Deserialize data we've inserted into a value column/field. We place\n\t    // special markers into our strings to mark them as encoded; this isn't\n\t    // as nice as a meta field, but it's the only sane thing we can do whilst\n\t    // keeping localStorage support intact.\n\t    //\n\t    // Oftentimes this will just deserialize JSON content, but if we have a\n\t    // special marker (SERIALIZED_MARKER, defined above), we will extract\n\t    // some kind of arraybuffer/binary data/typed array out of the string.\n\t    function deserialize(value) {\n\t        // If we haven't marked this string as being specially serialized (i.e.\n\t        // something other than serialized JSON), we can just return it and be\n\t        // done with it.\n\t        if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {\n\t            return JSON.parse(value);\n\t        }\n\n\t        // The following code deals with deserializing some kind of Blob or\n\t        // TypedArray. First we separate out the type of data we're dealing\n\t        // with from the data itself.\n\t        var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);\n\t        var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);\n\n\t        var blobType;\n\t        // Backwards-compatible blob type serialization strategy.\n\t        // DBs created with older versions of localForage will simply not have the blob type.\n\t        if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {\n\t            var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);\n\t            blobType = matcher[1];\n\t            serializedString = serializedString.substring(matcher[0].length);\n\t        }\n\t        var buffer = stringToBuffer(serializedString);\n\n\t        // Return the right type based on the code/type set during\n\t        // serialization.\n\t        switch (type) {\n\t            case TYPE_ARRAYBUFFER:\n\t                return buffer;\n\t            case TYPE_BLOB:\n\t                return _createBlob([buffer], { type: blobType });\n\t            case TYPE_INT8ARRAY:\n\t                return new Int8Array(buffer);\n\t            case TYPE_UINT8ARRAY:\n\t                return new Uint8Array(buffer);\n\t            case TYPE_UINT8CLAMPEDARRAY:\n\t                return new Uint8ClampedArray(buffer);\n\t            case TYPE_INT16ARRAY:\n\t                return new Int16Array(buffer);\n\t            case TYPE_UINT16ARRAY:\n\t                return new Uint16Array(buffer);\n\t            case TYPE_INT32ARRAY:\n\t                return new Int32Array(buffer);\n\t            case TYPE_UINT32ARRAY:\n\t                return new Uint32Array(buffer);\n\t            case TYPE_FLOAT32ARRAY:\n\t                return new Float32Array(buffer);\n\t            case TYPE_FLOAT64ARRAY:\n\t                return new Float64Array(buffer);\n\t            default:\n\t                throw new Error('Unkown type: ' + type);\n\t        }\n\t    }\n\n\t    function stringToBuffer(serializedString) {\n\t        // Fill the string into a ArrayBuffer.\n\t        var bufferLength = serializedString.length * 0.75;\n\t        var len = serializedString.length;\n\t        var i;\n\t        var p = 0;\n\t        var encoded1, encoded2, encoded3, encoded4;\n\n\t        if (serializedString[serializedString.length - 1] === '=') {\n\t            bufferLength--;\n\t            if (serializedString[serializedString.length - 2] === '=') {\n\t                bufferLength--;\n\t            }\n\t        }\n\n\t        var buffer = new ArrayBuffer(bufferLength);\n\t        var bytes = new Uint8Array(buffer);\n\n\t        for (i = 0; i < len; i += 4) {\n\t            encoded1 = BASE_CHARS.indexOf(serializedString[i]);\n\t            encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);\n\t            encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);\n\t            encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);\n\n\t            /*jslint bitwise: true */\n\t            bytes[p++] = encoded1 << 2 | encoded2 >> 4;\n\t            bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;\n\t            bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;\n\t        }\n\t        return buffer;\n\t    }\n\n\t    // Converts a buffer to a string to store, serialized, in the backend\n\t    // storage library.\n\t    function bufferToString(buffer) {\n\t        // base64-arraybuffer\n\t        var bytes = new Uint8Array(buffer);\n\t        var base64String = '';\n\t        var i;\n\n\t        for (i = 0; i < bytes.length; i += 3) {\n\t            /*jslint bitwise: true */\n\t            base64String += BASE_CHARS[bytes[i] >> 2];\n\t            base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];\n\t            base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];\n\t            base64String += BASE_CHARS[bytes[i + 2] & 63];\n\t        }\n\n\t        if (bytes.length % 3 === 2) {\n\t            base64String = base64String.substring(0, base64String.length - 1) + '=';\n\t        } else if (bytes.length % 3 === 1) {\n\t            base64String = base64String.substring(0, base64String.length - 2) + '==';\n\t        }\n\n\t        return base64String;\n\t    }\n\n\t    var localforageSerializer = {\n\t        serialize: serialize,\n\t        deserialize: deserialize,\n\t        stringToBuffer: stringToBuffer,\n\t        bufferToString: bufferToString\n\t    };\n\n\t    exports['default'] = localforageSerializer;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ },\n/* 4 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t/*\n\t * Includes code from:\n\t *\n\t * base64-arraybuffer\n\t * https://github.com/niklasvh/base64-arraybuffer\n\t *\n\t * Copyright (c) 2012 Niklas von Hertzen\n\t * Licensed under the MIT license.\n\t */\n\t'use strict';\n\n\texports.__esModule = true;\n\t(function () {\n\t    'use strict';\n\n\t    var globalObject = this;\n\t    var openDatabase = this.openDatabase;\n\n\t    // If WebSQL methods aren't available, we can stop now.\n\t    if (!openDatabase) {\n\t        return;\n\t    }\n\n\t    // Open the WebSQL database (automatically creates one if one didn't\n\t    // previously exist), using any options set in the config.\n\t    function _initStorage(options) {\n\t        var self = this;\n\t        var dbInfo = {\n\t            db: null\n\t        };\n\n\t        if (options) {\n\t            for (var i in options) {\n\t                dbInfo[i] = typeof options[i] !== 'string' ? options[i].toString() : options[i];\n\t            }\n\t        }\n\n\t        var dbInfoPromise = new Promise(function (resolve, reject) {\n\t            // Open the database; the openDatabase API will automatically\n\t            // create it for us if it doesn't exist.\n\t            try {\n\t                dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size);\n\t            } catch (e) {\n\t                return self.setDriver(self.LOCALSTORAGE).then(function () {\n\t                    return self._initStorage(options);\n\t                }).then(resolve)['catch'](reject);\n\t            }\n\n\t            // Create our key/value table if it doesn't exist.\n\t            dbInfo.db.transaction(function (t) {\n\t                t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName + ' (id INTEGER PRIMARY KEY, key unique, value)', [], function () {\n\t                    self._dbInfo = dbInfo;\n\t                    resolve();\n\t                }, function (t, error) {\n\t                    reject(error);\n\t                });\n\t            });\n\t        });\n\n\t        return new Promise(function (resolve, reject) {\n\t            resolve(__webpack_require__(3));\n\t        }).then(function (lib) {\n\t            dbInfo.serializer = lib;\n\t            return dbInfoPromise;\n\t        });\n\t    }\n\n\t    function getItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT * FROM ' + dbInfo.storeName + ' WHERE key = ? LIMIT 1', [key], function (t, results) {\n\t                        var result = results.rows.length ? results.rows.item(0).value : null;\n\n\t                        // Check to see if this is serialized content we need to\n\t                        // unpack.\n\t                        if (result) {\n\t                            result = dbInfo.serializer.deserialize(result);\n\t                        }\n\n\t                        resolve(result);\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function iterate(iterator, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT * FROM ' + dbInfo.storeName, [], function (t, results) {\n\t                        var rows = results.rows;\n\t                        var length = rows.length;\n\n\t                        for (var i = 0; i < length; i++) {\n\t                            var item = rows.item(i);\n\t                            var result = item.value;\n\n\t                            // Check to see if this is serialized content\n\t                            // we need to unpack.\n\t                            if (result) {\n\t                                result = dbInfo.serializer.deserialize(result);\n\t                            }\n\n\t                            result = iterator(result, item.key, i + 1);\n\n\t                            // void(0) prevents problems with redefinition\n\t                            // of `undefined`.\n\t                            if (result !== void 0) {\n\t                                resolve(result);\n\t                                return;\n\t                            }\n\t                        }\n\n\t                        resolve();\n\t                    }, function (t, error) {\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function setItem(key, value, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                // The localStorage API doesn't return undefined values in an\n\t                // \"expected\" way, so undefined is always cast to null in all\n\t                // drivers. See: https://github.com/mozilla/localForage/pull/42\n\t                if (value === undefined) {\n\t                    value = null;\n\t                }\n\n\t                // Save the original value to pass to the callback.\n\t                var originalValue = value;\n\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.serializer.serialize(value, function (value, error) {\n\t                    if (error) {\n\t                        reject(error);\n\t                    } else {\n\t                        dbInfo.db.transaction(function (t) {\n\t                            t.executeSql('INSERT OR REPLACE INTO ' + dbInfo.storeName + ' (key, value) VALUES (?, ?)', [key, value], function () {\n\t                                resolve(originalValue);\n\t                            }, function (t, error) {\n\t                                reject(error);\n\t                            });\n\t                        }, function (sqlError) {\n\t                            // The transaction failed; check\n\t                            // to see if it's a quota error.\n\t                            if (sqlError.code === sqlError.QUOTA_ERR) {\n\t                                // We reject the callback outright for now, but\n\t                                // it's worth trying to re-run the transaction.\n\t                                // Even if the user accepts the prompt to use\n\t                                // more storage on Safari, this error will\n\t                                // be called.\n\t                                //\n\t                                // TODO: Try to re-run the transaction.\n\t                                reject(sqlError);\n\t                            }\n\t                        });\n\t                    }\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function removeItem(key, callback) {\n\t        var self = this;\n\n\t        // Cast the key to a string, as that's all we can set as a key.\n\t        if (typeof key !== 'string') {\n\t            globalObject.console.warn(key + ' used as a key, but it is not a string.');\n\t            key = String(key);\n\t        }\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('DELETE FROM ' + dbInfo.storeName + ' WHERE key = ?', [key], function () {\n\t                        resolve();\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Deletes every item in the table.\n\t    // TODO: Find out if this resets the AUTO_INCREMENT number.\n\t    function clear(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('DELETE FROM ' + dbInfo.storeName, [], function () {\n\t                        resolve();\n\t                    }, function (t, error) {\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Does a simple `COUNT(key)` to get the number of items stored in\n\t    // localForage.\n\t    function length(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    // Ahhh, SQL makes this one soooooo easy.\n\t                    t.executeSql('SELECT COUNT(key) as c FROM ' + dbInfo.storeName, [], function (t, results) {\n\t                        var result = results.rows.item(0).c;\n\n\t                        resolve(result);\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    // Return the key located at key index X; essentially gets the key from a\n\t    // `WHERE id = ?`. This is the most efficient way I can think to implement\n\t    // this rarely-used (in my experience) part of the API, but it can seem\n\t    // inconsistent, because we do `INSERT OR REPLACE INTO` on `setItem()`, so\n\t    // the ID of each key will change every time it's updated. Perhaps a stored\n\t    // procedure for the `setItem()` SQL would solve this problem?\n\t    // TODO: Don't change ID on `setItem()`.\n\t    function key(n, callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT key FROM ' + dbInfo.storeName + ' WHERE id = ? LIMIT 1', [n + 1], function (t, results) {\n\t                        var result = results.rows.length ? results.rows.item(0).key : null;\n\t                        resolve(result);\n\t                    }, function (t, error) {\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function keys(callback) {\n\t        var self = this;\n\n\t        var promise = new Promise(function (resolve, reject) {\n\t            self.ready().then(function () {\n\t                var dbInfo = self._dbInfo;\n\t                dbInfo.db.transaction(function (t) {\n\t                    t.executeSql('SELECT key FROM ' + dbInfo.storeName, [], function (t, results) {\n\t                        var keys = [];\n\n\t                        for (var i = 0; i < results.rows.length; i++) {\n\t                            keys.push(results.rows.item(i).key);\n\t                        }\n\n\t                        resolve(keys);\n\t                    }, function (t, error) {\n\n\t                        reject(error);\n\t                    });\n\t                });\n\t            })['catch'](reject);\n\t        });\n\n\t        executeCallback(promise, callback);\n\t        return promise;\n\t    }\n\n\t    function executeCallback(promise, callback) {\n\t        if (callback) {\n\t            promise.then(function (result) {\n\t                callback(null, result);\n\t            }, function (error) {\n\t                callback(error);\n\t            });\n\t        }\n\t    }\n\n\t    var webSQLStorage = {\n\t        _driver: 'webSQLStorage',\n\t        _initStorage: _initStorage,\n\t        iterate: iterate,\n\t        getItem: getItem,\n\t        setItem: setItem,\n\t        removeItem: removeItem,\n\t        clear: clear,\n\t        length: length,\n\t        key: key,\n\t        keys: keys\n\t    };\n\n\t    exports['default'] = webSQLStorage;\n\t}).call(typeof window !== 'undefined' ? window : self);\n\tmodule.exports = exports['default'];\n\n/***/ }\n/******/ ])\n});\n;\n"
  },
  {
    "path": "browser-version/test/mocha.css",
    "content": "@charset \"UTF-8\";\nbody {\n  font: 20px/1.5 \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  padding: 60px 50px;\n}\n\n#mocha ul, #mocha li {\n  margin: 0;\n  padding: 0;\n}\n\n#mocha ul {\n  list-style: none;\n}\n\n#mocha h1, #mocha h2 {\n  margin: 0;\n}\n\n#mocha h1 {\n  margin-top: 15px;\n  font-size: 1em;\n  font-weight: 200;\n}\n\n#mocha h1 a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#mocha h1 a:hover {\n  text-decoration: underline;\n}\n\n#mocha .suite .suite h1 {\n  margin-top: 0;\n  font-size: .8em;\n}\n\n#mocha h2 {\n  font-size: 12px;\n  font-weight: normal;\n  cursor: pointer;\n}\n\n#mocha .suite {\n  margin-left: 15px;\n}\n\n#mocha .test {\n  margin-left: 15px;\n}\n\n#mocha .test:hover h2::after {\n  position: relative;\n  top: 0;\n  right: -10px;\n  content: '(view source)';\n  font-size: 12px;\n  font-family: arial;\n  color: #888;\n}\n\n#mocha .test.pending:hover h2::after {\n  content: '(pending)';\n  font-family: arial;\n}\n\n#mocha .test.pass.medium .duration {\n  background: #C09853;\n}\n\n#mocha .test.pass.slow .duration {\n  background: #B94A48;\n}\n\n#mocha .test.pass::before {\n  content: '✓';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #00d6b2;\n}\n\n#mocha .test.pass .duration {\n  font-size: 9px;\n  margin-left: 5px;\n  padding: 2px 5px;\n  color: white;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.2);\n  -webkit-border-radius: 5px;\n  -moz-border-radius: 5px;\n  -ms-border-radius: 5px;\n  -o-border-radius: 5px;\n  border-radius: 5px;\n}\n\n#mocha .test.pass.fast .duration {\n  display: none;\n}\n\n#mocha .test.pending {\n  color: #0b97c4;\n}\n\n#mocha .test.pending::before {\n  content: '◦';\n  color: #0b97c4;\n}\n\n#mocha .test.fail {\n  color: #c00;\n}\n\n#mocha .test.fail pre {\n  color: black;\n}\n\n#mocha .test.fail::before {\n  content: '✖';\n  font-size: 12px;\n  display: block;\n  float: left;\n  margin-right: 5px;\n  color: #c00;\n}\n\n#mocha .test pre.error {\n  color: #c00;\n}\n\n#mocha .test pre {\n  display: inline-block;\n  font: 12px/1.5 monaco, monospace;\n  margin: 5px;\n  padding: 15px;\n  border: 1px solid #eee;\n  border-bottom-color: #ddd;\n  -webkit-border-radius: 3px;\n  -webkit-box-shadow: 0 1px 3px #eee;\n}\n\n#report.pass .test.fail {\n  display: none;\n}\n\n#report.fail .test.pass {\n  display: none;\n}\n\n#error {\n  color: #c00;\n  font-size: 1.5  em;\n  font-weight: 100;\n  letter-spacing: 1px;\n}\n\n#stats {\n  position: fixed;\n  top: 15px;\n  right: 10px;\n  font-size: 12px;\n  margin: 0;\n  color: #888;\n}\n\n#stats .progress {\n  float: right;\n  padding-top: 0;\n}\n\n#stats em {\n  color: black;\n}\n\n#stats a {\n  text-decoration: none;\n  color: inherit;\n}\n\n#stats a:hover {\n  border-bottom: 1px solid #eee;\n}\n\n#stats li {\n  display: inline-block;\n  margin: 0 5px;\n  list-style: none;\n  padding-top: 11px;\n}\n\ncode .comment { color: #ddd }\ncode .init { color: #2F6FAD }\ncode .string { color: #5890AD }\ncode .keyword { color: #8A6343 }\ncode .number { color: #2F6FAD }\n"
  },
  {
    "path": "browser-version/test/mocha.js",
    "content": ";(function(){\n\n\n// CommonJS require()\n\nfunction require(p){\n    var path = require.resolve(p)\n      , mod = require.modules[path];\n    if (!mod) throw new Error('failed to require \"' + p + '\"');\n    if (!mod.exports) {\n      mod.exports = {};\n      mod.call(mod.exports, mod, mod.exports, require.relative(path));\n    }\n    return mod.exports;\n  }\n\nrequire.modules = {};\n\nrequire.resolve = function (path){\n    var orig = path\n      , reg = path + '.js'\n      , index = path + '/index.js';\n    return require.modules[reg] && reg\n      || require.modules[index] && index\n      || orig;\n  };\n\nrequire.register = function (path, fn){\n    require.modules[path] = fn;\n  };\n\nrequire.relative = function (parent) {\n    return function(p){\n      if ('.' != p.charAt(0)) return require(p);\n      \n      var path = parent.split('/')\n        , segs = p.split('/');\n      path.pop();\n      \n      for (var i = 0; i < segs.length; i++) {\n        var seg = segs[i];\n        if ('..' == seg) path.pop();\n        else if ('.' != seg) path.push(seg);\n      }\n\n      return require(path.join('/'));\n    };\n  };\n\n\nrequire.register(\"browser/debug.js\", function(module, exports, require){\n\nmodule.exports = function(type){\n  return function(){\n    \n  }\n};\n}); // module: browser/debug.js\n\nrequire.register(\"browser/diff.js\", function(module, exports, require){\n\n}); // module: browser/diff.js\n\nrequire.register(\"browser/events.js\", function(module, exports, require){\n\n/**\n * Module exports.\n */\n\nexports.EventEmitter = EventEmitter;\n\n/**\n * Check if `obj` is an array.\n */\n\nfunction isArray(obj) {\n  return '[object Array]' == {}.toString.call(obj);\n}\n\n/**\n * Event emitter constructor.\n *\n * @api public\n */\n\nfunction EventEmitter(){};\n\n/**\n * Adds a listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.on = function (name, fn) {\n  if (!this.$events) {\n    this.$events = {};\n  }\n\n  if (!this.$events[name]) {\n    this.$events[name] = fn;\n  } else if (isArray(this.$events[name])) {\n    this.$events[name].push(fn);\n  } else {\n    this.$events[name] = [this.$events[name], fn];\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n/**\n * Adds a volatile listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.once = function (name, fn) {\n  var self = this;\n\n  function on () {\n    self.removeListener(name, on);\n    fn.apply(this, arguments);\n  };\n\n  on.listener = fn;\n  this.on(name, on);\n\n  return this;\n};\n\n/**\n * Removes a listener.\n *\n * @api public\n */\n\nEventEmitter.prototype.removeListener = function (name, fn) {\n  if (this.$events && this.$events[name]) {\n    var list = this.$events[name];\n\n    if (isArray(list)) {\n      var pos = -1;\n\n      for (var i = 0, l = list.length; i < l; i++) {\n        if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {\n          pos = i;\n          break;\n        }\n      }\n\n      if (pos < 0) {\n        return this;\n      }\n\n      list.splice(pos, 1);\n\n      if (!list.length) {\n        delete this.$events[name];\n      }\n    } else if (list === fn || (list.listener && list.listener === fn)) {\n      delete this.$events[name];\n    }\n  }\n\n  return this;\n};\n\n/**\n * Removes all listeners for an event.\n *\n * @api public\n */\n\nEventEmitter.prototype.removeAllListeners = function (name) {\n  if (name === undefined) {\n    this.$events = {};\n    return this;\n  }\n\n  if (this.$events && this.$events[name]) {\n    this.$events[name] = null;\n  }\n\n  return this;\n};\n\n/**\n * Gets all listeners for a certain event.\n *\n * @api public\n */\n\nEventEmitter.prototype.listeners = function (name) {\n  if (!this.$events) {\n    this.$events = {};\n  }\n\n  if (!this.$events[name]) {\n    this.$events[name] = [];\n  }\n\n  if (!isArray(this.$events[name])) {\n    this.$events[name] = [this.$events[name]];\n  }\n\n  return this.$events[name];\n};\n\n/**\n * Emits an event.\n *\n * @api public\n */\n\nEventEmitter.prototype.emit = function (name) {\n  if (!this.$events) {\n    return false;\n  }\n\n  var handler = this.$events[name];\n\n  if (!handler) {\n    return false;\n  }\n\n  var args = [].slice.call(arguments, 1);\n\n  if ('function' == typeof handler) {\n    handler.apply(this, args);\n  } else if (isArray(handler)) {\n    var listeners = handler.slice();\n\n    for (var i = 0, l = listeners.length; i < l; i++) {\n      listeners[i].apply(this, args);\n    }\n  } else {\n    return false;\n  }\n\n  return true;\n};\n}); // module: browser/events.js\n\nrequire.register(\"browser/fs.js\", function(module, exports, require){\n\n}); // module: browser/fs.js\n\nrequire.register(\"browser/path.js\", function(module, exports, require){\n\n}); // module: browser/path.js\n\nrequire.register(\"browser/progress.js\", function(module, exports, require){\n\n/**\n * Expose `Progress`.\n */\n\nmodule.exports = Progress;\n\n/**\n * Initialize a new `Progress` indicator.\n */\n\nfunction Progress() {\n  this.percent = 0;\n  this.size(0);\n  this.fontSize(11);\n  this.font('helvetica, arial, sans-serif');\n}\n\n/**\n * Set progress size to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.size = function(n){\n  this._size = n;\n  return this;\n};\n\n/**\n * Set text to `str`.\n *\n * @param {String} str\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.text = function(str){\n  this._text = str;\n  return this;\n};\n\n/**\n * Set font size to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n * @api public\n */\n\nProgress.prototype.fontSize = function(n){\n  this._fontSize = n;\n  return this;\n};\n\n/**\n * Set font `family`.\n *\n * @param {String} family\n * @return {Progress} for chaining\n */\n\nProgress.prototype.font = function(family){\n  this._font = family;\n  return this;\n};\n\n/**\n * Update percentage to `n`.\n *\n * @param {Number} n\n * @return {Progress} for chaining\n */\n\nProgress.prototype.update = function(n){\n  this.percent = n;\n  return this;\n};\n\n/**\n * Draw on `ctx`.\n *\n * @param {CanvasRenderingContext2d} ctx\n * @return {Progress} for chaining\n */\n\nProgress.prototype.draw = function(ctx){\n  var percent = Math.min(this.percent, 100)\n    , size = this._size\n    , half = size / 2\n    , x = half\n    , y = half\n    , rad = half - 1\n    , fontSize = this._fontSize;\n\n  ctx.font = fontSize + 'px ' + this._font;\n\n  var angle = Math.PI * 2 * (percent / 100);\n  ctx.clearRect(0, 0, size, size);\n\n  // outer circle\n  ctx.strokeStyle = '#9f9f9f';\n  ctx.beginPath();\n  ctx.arc(x, y, rad, 0, angle, false);\n  ctx.stroke();\n\n  // inner circle\n  ctx.strokeStyle = '#eee';\n  ctx.beginPath();\n  ctx.arc(x, y, rad - 1, 0, angle, true);\n  ctx.stroke();\n\n  // text\n  var text = this._text || (percent | 0) + '%'\n    , w = ctx.measureText(text).width;\n\n  ctx.fillText(\n      text\n    , x - w / 2 + 1\n    , y + fontSize / 2 - 1);\n\n  return this;\n};\n\n}); // module: browser/progress.js\n\nrequire.register(\"browser/tty.js\", function(module, exports, require){\n\nexports.isatty = function(){\n  return true;\n};\n\nexports.getWindowSize = function(){\n  return [window.innerHeight, window.innerWidth];\n};\n}); // module: browser/tty.js\n\nrequire.register(\"context.js\", function(module, exports, require){\n\n/**\n * Expose `Context`.\n */\n\nmodule.exports = Context;\n\n/**\n * Initialize a new `Context`.\n *\n * @api private\n */\n\nfunction Context(){}\n\n/**\n * Set or get the context `Runnable` to `runnable`.\n *\n * @param {Runnable} runnable\n * @return {Context}\n * @api private\n */\n\nContext.prototype.runnable = function(runnable){\n  if (0 == arguments.length) return this._runnable;\n  this.test = this._runnable = runnable;\n  return this;\n};\n\n/**\n * Set test timeout `ms`.\n *\n * @param {Number} ms\n * @return {Context} self\n * @api private\n */\n\nContext.prototype.timeout = function(ms){\n  this.runnable().timeout(ms);\n  return this;\n};\n\n/**\n * Set test slowness threshold `ms`.\n *\n * @param {Number} ms\n * @return {Context} self\n * @api private\n */\n\nContext.prototype.slow = function(ms){\n  this.runnable().slow(ms);\n  return this;\n};\n\n/**\n * Inspect the context void of `._runnable`.\n *\n * @return {String}\n * @api private\n */\n\nContext.prototype.inspect = function(){\n  return JSON.stringify(this, function(key, val){\n    if ('_runnable' == key) return;\n    if ('test' == key) return;\n    return val;\n  }, 2);\n};\n\n}); // module: context.js\n\nrequire.register(\"hook.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Runnable = require('./runnable');\n\n/**\n * Expose `Hook`.\n */\n\nmodule.exports = Hook;\n\n/**\n * Initialize a new `Hook` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Hook(title, fn) {\n  Runnable.call(this, title, fn);\n  this.type = 'hook';\n}\n\n/**\n * Inherit from `Runnable.prototype`.\n */\n\nHook.prototype = new Runnable;\nHook.prototype.constructor = Hook;\n\n\n/**\n * Get or set the test `err`.\n *\n * @param {Error} err\n * @return {Error}\n * @api public\n */\n\nHook.prototype.error = function(err){\n  if (0 == arguments.length) {\n    var err = this._error;\n    this._error = null;\n    return err;\n  }\n\n  this._error = err;\n};\n\n\n}); // module: hook.js\n\nrequire.register(\"interfaces/bdd.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * BDD-style interface:\n * \n *      describe('Array', function(){\n *        describe('#indexOf()', function(){\n *          it('should return -1 when not present', function(){\n *\n *          });\n *\n *          it('should return the index when present', function(){\n *\n *          });\n *        });\n *      });\n * \n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context, file, mocha){\n\n    /**\n     * Execute before running tests.\n     */\n\n    context.before = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after running tests.\n     */\n\n    context.after = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.beforeEach = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.afterEach = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`\n     * and callback `fn` containing nested suites\n     * and/or tests.\n     */\n  \n    context.describe = context.context = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n      fn();\n      suites.shift();\n      return suite;\n    };\n\n    /**\n     * Pending describe.\n     */\n\n    context.xdescribe =\n    context.xcontext =\n    context.describe.skip = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suite.pending = true;\n      suites.unshift(suite);\n      fn();\n      suites.shift();\n    };\n\n    /**\n     * Exclusive suite.\n     */\n\n    context.describe.only = function(title, fn){\n      var suite = context.describe(title, fn);\n      mocha.grep(suite.fullTitle());\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.it = context.specify = function(title, fn){\n      var suite = suites[0];\n      if (suite.pending) var fn = null;\n      var test = new Test(title, fn);\n      suite.addTest(test);\n      return test;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.it.only = function(title, fn){\n      var test = context.it(title, fn);\n      mocha.grep(test.fullTitle());\n    };\n\n    /**\n     * Pending test case.\n     */\n\n    context.xit =\n    context.xspecify =\n    context.it.skip = function(title){\n      context.it(title);\n    };\n  });\n};\n\n}); // module: interfaces/bdd.js\n\nrequire.register(\"interfaces/exports.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * TDD-style interface:\n * \n *     exports.Array = {\n *       '#indexOf()': {\n *         'should return -1 when the value is not present': function(){\n *           \n *         },\n *\n *         'should return the correct index when the value is present': function(){\n *           \n *         }\n *       }\n *     };\n * \n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('require', visit);\n\n  function visit(obj) {\n    var suite;\n    for (var key in obj) {\n      if ('function' == typeof obj[key]) {\n        var fn = obj[key];\n        switch (key) {\n          case 'before':\n            suites[0].beforeAll(fn);\n            break;\n          case 'after':\n            suites[0].afterAll(fn);\n            break;\n          case 'beforeEach':\n            suites[0].beforeEach(fn);\n            break;\n          case 'afterEach':\n            suites[0].afterEach(fn);\n            break;\n          default:\n            suites[0].addTest(new Test(key, fn));\n        }\n      } else {\n        var suite = Suite.create(suites[0], key);\n        suites.unshift(suite);\n        visit(obj[key]);\n        suites.shift();\n      }\n    }\n  }\n};\n}); // module: interfaces/exports.js\n\nrequire.register(\"interfaces/index.js\", function(module, exports, require){\n\nexports.bdd = require('./bdd');\nexports.tdd = require('./tdd');\nexports.qunit = require('./qunit');\nexports.exports = require('./exports');\n\n}); // module: interfaces/index.js\n\nrequire.register(\"interfaces/qunit.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * QUnit-style interface:\n * \n *     suite('Array');\n *     \n *     test('#length', function(){\n *       var arr = [1,2,3];\n *       ok(arr.length == 3);\n *     });\n *     \n *     test('#indexOf()', function(){\n *       var arr = [1,2,3];\n *       ok(arr.indexOf(1) == 0);\n *       ok(arr.indexOf(2) == 1);\n *       ok(arr.indexOf(3) == 2);\n *     });\n *     \n *     suite('String');\n *     \n *     test('#length', function(){\n *       ok('foo'.length == 3);\n *     });\n * \n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context){\n\n    /**\n     * Execute before running tests.\n     */\n\n    context.before = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after running tests.\n     */\n\n    context.after = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.beforeEach = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.afterEach = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`.\n     */\n  \n    context.suite = function(title){\n      if (suites.length > 1) suites.shift();\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.test = function(title, fn){\n      suites[0].addTest(new Test(title, fn));\n    };\n  });\n};\n\n}); // module: interfaces/qunit.js\n\nrequire.register(\"interfaces/tdd.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Suite = require('../suite')\n  , Test = require('../test');\n\n/**\n * TDD-style interface:\n *\n *      suite('Array', function(){\n *        suite('#indexOf()', function(){\n *          suiteSetup(function(){\n *\n *          });\n *          \n *          test('should return -1 when not present', function(){\n *\n *          });\n *\n *          test('should return the index when present', function(){\n *\n *          });\n *\n *          suiteTeardown(function(){\n *\n *          });\n *        });\n *      });\n *\n */\n\nmodule.exports = function(suite){\n  var suites = [suite];\n\n  suite.on('pre-require', function(context, file, mocha){\n\n    /**\n     * Execute before each test case.\n     */\n\n    context.setup = function(fn){\n      suites[0].beforeEach(fn);\n    };\n\n    /**\n     * Execute after each test case.\n     */\n\n    context.teardown = function(fn){\n      suites[0].afterEach(fn);\n    };\n\n    /**\n     * Execute before the suite.\n     */\n\n    context.suiteSetup = function(fn){\n      suites[0].beforeAll(fn);\n    };\n\n    /**\n     * Execute after the suite.\n     */\n\n    context.suiteTeardown = function(fn){\n      suites[0].afterAll(fn);\n    };\n\n    /**\n     * Describe a \"suite\" with the given `title`\n     * and callback `fn` containing nested suites\n     * and/or tests.\n     */\n\n    context.suite = function(title, fn){\n      var suite = Suite.create(suites[0], title);\n      suites.unshift(suite);\n      fn();\n      suites.shift();\n      return suite;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.suite.only = function(title, fn){\n      var suite = context.suite(title, fn);\n      mocha.grep(suite.fullTitle());\n    };\n\n    /**\n     * Describe a specification or test-case\n     * with the given `title` and callback `fn`\n     * acting as a thunk.\n     */\n\n    context.test = function(title, fn){\n      var test = new Test(title, fn);\n      suites[0].addTest(test);\n      return test;\n    };\n\n    /**\n     * Exclusive test-case.\n     */\n\n    context.test.only = function(title, fn){\n      var test = context.test(title, fn);\n      mocha.grep(test.fullTitle());\n    };\n  });\n};\n\n}); // module: interfaces/tdd.js\n\nrequire.register(\"mocha.js\", function(module, exports, require){\n/*!\n * mocha\n * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar path = require('browser/path')\n  , utils = require('./utils');\n\n/**\n * Expose `Mocha`.\n */\n\nexports = module.exports = Mocha;\n\n/**\n * Expose internals.\n */\n\nexports.utils = utils;\nexports.interfaces = require('./interfaces');\nexports.reporters = require('./reporters');\nexports.Runnable = require('./runnable');\nexports.Context = require('./context');\nexports.Runner = require('./runner');\nexports.Suite = require('./suite');\nexports.Hook = require('./hook');\nexports.Test = require('./test');\n\n/**\n * Return image `name` path.\n *\n * @param {String} name\n * @return {String}\n * @api private\n */\n\nfunction image(name) {\n  return __dirname + '/../images/' + name + '.png';\n}\n\n/**\n * Setup mocha with `options`.\n *\n * Options:\n *\n *   - `ui` name \"bdd\", \"tdd\", \"exports\" etc\n *   - `reporter` reporter instance, defaults to `mocha.reporters.Dot`\n *   - `globals` array of accepted globals\n *   - `timeout` timeout in milliseconds\n *   - `slow` milliseconds to wait before considering a test slow\n *   - `ignoreLeaks` ignore global leaks\n *   - `grep` string or regexp to filter tests with\n *\n * @param {Object} options\n * @api public\n */\n\nfunction Mocha(options) {\n  options = options || {};\n  this.files = [];\n  this.options = options;\n  this.grep(options.grep);\n  this.suite = new exports.Suite('', new exports.Context);\n  this.ui(options.ui);\n  this.reporter(options.reporter);\n  if (options.timeout) this.timeout(options.timeout);\n  if (options.slow) this.slow(options.slow);\n}\n\n/**\n * Add test `file`.\n *\n * @param {String} file\n * @api public\n */\n\nMocha.prototype.addFile = function(file){\n  this.files.push(file);\n  return this;\n};\n\n/**\n * Set reporter to `reporter`, defaults to \"dot\".\n *\n * @param {String|Function} reporter name of a reporter or a reporter constructor\n * @api public\n */\n\nMocha.prototype.reporter = function(reporter){\n  if ('function' == typeof reporter) {\n    this._reporter = reporter;\n  } else {\n    reporter = reporter || 'dot';\n    try {\n      this._reporter = require('./reporters/' + reporter);\n    } catch (err) {\n      this._reporter = require(reporter);\n    }\n    if (!this._reporter) throw new Error('invalid reporter \"' + reporter + '\"');\n  }\n  return this;\n};\n\n/**\n * Set test UI `name`, defaults to \"bdd\".\n *\n * @param {String} bdd\n * @api public\n */\n\nMocha.prototype.ui = function(name){\n  name = name || 'bdd';\n  this._ui = exports.interfaces[name];\n  if (!this._ui) throw new Error('invalid interface \"' + name + '\"');\n  this._ui = this._ui(this.suite);\n  return this;\n};\n\n/**\n * Load registered files.\n *\n * @api private\n */\n\nMocha.prototype.loadFiles = function(fn){\n  var self = this;\n  var suite = this.suite;\n  var pending = this.files.length;\n  this.files.forEach(function(file){\n    file = path.resolve(file);\n    suite.emit('pre-require', global, file, self);\n    suite.emit('require', require(file), file, self);\n    suite.emit('post-require', global, file, self);\n    --pending || (fn && fn());\n  });\n};\n\n/**\n * Enable growl support.\n *\n * @api private\n */\n\nMocha.prototype._growl = function(runner, reporter) {\n  var notify = require('growl');\n\n  runner.on('end', function(){\n    var stats = reporter.stats;\n    if (stats.failures) {\n      var msg = stats.failures + ' of ' + runner.total + ' tests failed';\n      notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });\n    } else {\n      notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {\n          name: 'mocha'\n        , title: 'Passed'\n        , image: image('ok')\n      });\n    }\n  });\n};\n\n/**\n * Add regexp to grep, if `re` is a string it is escaped.\n *\n * @param {RegExp|String} re\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.grep = function(re){\n  this.options.grep = 'string' == typeof re\n    ? new RegExp(utils.escapeRegexp(re))\n    : re;\n  return this;\n};\n\n/**\n * Invert `.grep()` matches.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.invert = function(){\n  this.options.invert = true;\n  return this;\n};\n\n/**\n * Ignore global leaks.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.ignoreLeaks = function(){\n  this.options.ignoreLeaks = true;\n  return this;\n};\n\n/**\n * Enable global leak checking.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.checkLeaks = function(){\n  this.options.ignoreLeaks = false;\n  return this;\n};\n\n/**\n * Enable growl support.\n *\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.growl = function(){\n  this.options.growl = true;\n  return this;\n};\n\n/**\n * Ignore `globals` array or string.\n *\n * @param {Array|String} globals\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.globals = function(globals){\n  this.options.globals = (this.options.globals || []).concat(globals);\n  return this;\n};\n\n/**\n * Set the timeout in milliseconds.\n *\n * @param {Number} timeout\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.timeout = function(timeout){\n  this.suite.timeout(timeout);\n  return this;\n};\n\n/**\n * Set slowness threshold in milliseconds.\n *\n * @param {Number} slow\n * @return {Mocha}\n * @api public\n */\n\nMocha.prototype.slow = function(slow){\n  this.suite.slow(slow);\n  return this;\n};\n\n/**\n * Run tests and invoke `fn()` when complete.\n *\n * @param {Function} fn\n * @return {Runner}\n * @api public\n */\n\nMocha.prototype.run = function(fn){\n  if (this.files.length) this.loadFiles();\n  var suite = this.suite;\n  var options = this.options;\n  var runner = new exports.Runner(suite);\n  var reporter = new this._reporter(runner);\n  runner.ignoreLeaks = options.ignoreLeaks;\n  if (options.grep) runner.grep(options.grep, options.invert);\n  if (options.globals) runner.globals(options.globals);\n  if (options.growl) this._growl(runner, reporter);\n  return runner.run(fn);\n};\n\n}); // module: mocha.js\n\nrequire.register(\"ms.js\", function(module, exports, require){\n\n/**\n * Helpers.\n */\n\nvar s = 1000;\nvar m = s * 60;\nvar h = m * 60;\nvar d = h * 24;\n\n/**\n * Parse or format the given `val`.\n *\n * @param {String|Number} val\n * @return {String|Number}\n * @api public\n */\n\nmodule.exports = function(val){\n  if ('string' == typeof val) return parse(val);\n  return format(val);\n}\n\n/**\n * Parse the given `str` and return milliseconds.\n *\n * @param {String} str\n * @return {Number}\n * @api private\n */\n\nfunction parse(str) {\n  var m = /^((?:\\d+)?\\.?\\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);\n  if (!m) return;\n  var n = parseFloat(m[1]);\n  var type = (m[2] || 'ms').toLowerCase();\n  switch (type) {\n    case 'years':\n    case 'year':\n    case 'y':\n      return n * 31557600000;\n    case 'days':\n    case 'day':\n    case 'd':\n      return n * 86400000;\n    case 'hours':\n    case 'hour':\n    case 'h':\n      return n * 3600000;\n    case 'minutes':\n    case 'minute':\n    case 'm':\n      return n * 60000;\n    case 'seconds':\n    case 'second':\n    case 's':\n      return n * 1000;\n    case 'ms':\n      return n;\n  }\n}\n\n/**\n * Format the given `ms`.\n *\n * @param {Number} ms\n * @return {String}\n * @api public\n */\n\nfunction format(ms) {\n  if (ms == d) return (ms / d) + ' day';\n  if (ms > d) return (ms / d) + ' days';\n  if (ms == h) return (ms / h) + ' hour';\n  if (ms > h) return (ms / h) + ' hours';\n  if (ms == m) return (ms / m) + ' minute';\n  if (ms > m) return (ms / m) + ' minutes';\n  if (ms == s) return (ms / s) + ' second';\n  if (ms > s) return (ms / s) + ' seconds';\n  return ms + ' ms';\n}\n}); // module: ms.js\n\nrequire.register(\"reporters/base.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar tty = require('browser/tty')\n  , diff = require('browser/diff')\n  , ms = require('../ms');\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Check if both stdio streams are associated with a tty.\n */\n\nvar isatty = tty.isatty(1) && tty.isatty(2);\n\n/**\n * Expose `Base`.\n */\n\nexports = module.exports = Base;\n\n/**\n * Enable coloring by default.\n */\n\nexports.useColors = isatty;\n\n/**\n * Default color map.\n */\n\nexports.colors = {\n    'pass': 90\n  , 'fail': 31\n  , 'bright pass': 92\n  , 'bright fail': 91\n  , 'bright yellow': 93\n  , 'pending': 36\n  , 'suite': 0\n  , 'error title': 0\n  , 'error message': 31\n  , 'error stack': 90\n  , 'checkmark': 32\n  , 'fast': 90\n  , 'medium': 33\n  , 'slow': 31\n  , 'green': 32\n  , 'light': 90\n  , 'diff gutter': 90\n  , 'diff added': 42\n  , 'diff removed': 41\n};\n\n/**\n * Color `str` with the given `type`,\n * allowing colors to be disabled,\n * as well as user-defined color\n * schemes.\n *\n * @param {String} type\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nvar color = exports.color = function(type, str) {\n  if (!exports.useColors) return str;\n  return '\\u001b[' + exports.colors[type] + 'm' + str + '\\u001b[0m';\n};\n\n/**\n * Expose term window size, with some\n * defaults for when stderr is not a tty.\n */\n\nexports.window = {\n  width: isatty\n    ? process.stdout.getWindowSize\n      ? process.stdout.getWindowSize(1)[0]\n      : tty.getWindowSize()[1]\n    : 75\n};\n\n/**\n * Expose some basic cursor interactions\n * that are common among reporters.\n */\n\nexports.cursor = {\n  hide: function(){\n    process.stdout.write('\\u001b[?25l');\n  },\n\n  show: function(){\n    process.stdout.write('\\u001b[?25h');\n  },\n\n  deleteLine: function(){\n    process.stdout.write('\\u001b[2K');\n  },\n\n  beginningOfLine: function(){\n    process.stdout.write('\\u001b[0G');\n  },\n\n  CR: function(){\n    exports.cursor.deleteLine();\n    exports.cursor.beginningOfLine();\n  }\n};\n\n/**\n * Outut the given `failures` as a list.\n *\n * @param {Array} failures\n * @api public\n */\n\nexports.list = function(failures){\n  console.error();\n  failures.forEach(function(test, i){\n    // format\n    var fmt = color('error title', '  %s) %s:\\n')\n      + color('error message', '     %s')\n      + color('error stack', '\\n%s\\n');\n\n    // msg\n    var err = test.err\n      , message = err.message || ''\n      , stack = err.stack || message\n      , index = stack.indexOf(message) + message.length\n      , msg = stack.slice(0, index)\n      , actual = err.actual\n      , expected = err.expected;\n\n    // actual / expected diff\n    if ('string' == typeof actual && 'string' == typeof expected) {\n      var len = Math.max(actual.length, expected.length);\n\n      if (len < 20) msg = errorDiff(err, 'Chars');\n      else msg = errorDiff(err, 'Words');\n\n      // linenos\n      var lines = msg.split('\\n');\n      if (lines.length > 4) {\n        var width = String(lines.length).length;\n        msg = lines.map(function(str, i){\n          return pad(++i, width) + ' |' + ' ' + str;\n        }).join('\\n');\n      }\n\n      // legend\n      msg = '\\n'\n        + color('diff removed', 'actual')\n        + ' '\n        + color('diff added', 'expected')\n        + '\\n\\n'\n        + msg\n        + '\\n';\n\n      // indent\n      msg = msg.replace(/^/gm, '      ');\n\n      fmt = color('error title', '  %s) %s:\\n%s')\n        + color('error stack', '\\n%s\\n');\n    }\n\n    // indent stack trace without msg\n    stack = stack.slice(index ? index + 1 : index)\n      .replace(/^/gm, '  ');\n\n    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);\n  });\n};\n\n/**\n * Initialize a new `Base` reporter.\n *\n * All other reporters generally\n * inherit from this reporter, providing\n * stats such as test duration, number\n * of tests passed / failed etc.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Base(runner) {\n  var self = this\n    , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }\n    , failures = this.failures = [];\n\n  if (!runner) return;\n  this.runner = runner;\n\n  runner.on('start', function(){\n    stats.start = new Date;\n  });\n\n  runner.on('suite', function(suite){\n    stats.suites = stats.suites || 0;\n    suite.root || stats.suites++;\n  });\n\n  runner.on('test end', function(test){\n    stats.tests = stats.tests || 0;\n    stats.tests++;\n  });\n\n  runner.on('pass', function(test){\n    stats.passes = stats.passes || 0;\n\n    var medium = test.slow() / 2;\n    test.speed = test.duration > test.slow()\n      ? 'slow'\n      : test.duration > medium\n        ? 'medium'\n        : 'fast';\n\n    stats.passes++;\n  });\n\n  runner.on('fail', function(test, err){\n    stats.failures = stats.failures || 0;\n    stats.failures++;\n    test.err = err;\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    stats.end = new Date;\n    stats.duration = new Date - stats.start;\n  });\n\n  runner.on('pending', function(){\n    stats.pending++;\n  });\n}\n\n/**\n * Output common epilogue used by many of\n * the bundled reporters.\n *\n * @api public\n */\n\nBase.prototype.epilogue = function(){\n  var stats = this.stats\n    , fmt\n    , tests;\n\n  console.log();\n\n  function pluralize(n) {\n    return 1 == n ? 'test' : 'tests';\n  }\n\n  // failure\n  if (stats.failures) {\n    fmt = color('bright fail', '  ✖')\n      + color('fail', ' %d of %d %s failed')\n      + color('light', ':')\n\n    console.error(fmt,\n      stats.failures,\n      this.runner.total,\n      pluralize(this.runner.total));\n\n    Base.list(this.failures);\n    console.error();\n    return;\n  }\n\n  // pass\n  fmt = color('bright pass', '  ✔')\n    + color('green', ' %d %s complete')\n    + color('light', ' (%s)');\n\n  console.log(fmt,\n    stats.tests || 0,\n    pluralize(stats.tests),\n    ms(stats.duration));\n\n  // pending\n  if (stats.pending) {\n    fmt = color('pending', '  •')\n      + color('pending', ' %d %s pending');\n\n    console.log(fmt, stats.pending, pluralize(stats.pending));\n  }\n\n  console.log();\n};\n\n/**\n * Pad the given `str` to `len`.\n *\n * @param {String} str\n * @param {String} len\n * @return {String}\n * @api private\n */\n\nfunction pad(str, len) {\n  str = String(str);\n  return Array(len - str.length + 1).join(' ') + str;\n}\n\n/**\n * Return a character diff for `err`.\n *\n * @param {Error} err\n * @return {String}\n * @api private\n */\n\nfunction errorDiff(err, type) {\n  return diff['diff' + type](err.actual, err.expected).map(function(str){\n    str.value = str.value\n      .replace(/\\t/g, '<tab>')\n      .replace(/\\r/g, '<CR>')\n      .replace(/\\n/g, '<LF>\\n');\n    if (str.added) return colorLines('diff added', str.value);\n    if (str.removed) return colorLines('diff removed', str.value);\n    return str.value;\n  }).join('');\n}\n\n/**\n * Color lines for `str`, using the color `name`.\n *\n * @param {String} name\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nfunction colorLines(name, str) {\n  return str.split('\\n').map(function(str){\n    return color(name, str);\n  }).join('\\n');\n}\n\n}); // module: reporters/base.js\n\nrequire.register(\"reporters/doc.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils');\n\n/**\n * Expose `Doc`.\n */\n\nexports = module.exports = Doc;\n\n/**\n * Initialize a new `Doc` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Doc(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total\n    , indents = 2;\n\n  function indent() {\n    return Array(indents).join('  ');\n  }\n\n  runner.on('suite', function(suite){\n    if (suite.root) return;\n    ++indents;\n    console.log('%s<section class=\"suite\">', indent());\n    ++indents;\n    console.log('%s<h1>%s</h1>', indent(), suite.title);\n    console.log('%s<dl>', indent());\n  });\n\n  runner.on('suite end', function(suite){\n    if (suite.root) return;\n    console.log('%s</dl>', indent());\n    --indents;\n    console.log('%s</section>', indent());\n    --indents;\n  });\n\n  runner.on('pass', function(test){\n    console.log('%s  <dt>%s</dt>', indent(), test.title);\n    var code = utils.escape(utils.clean(test.fn.toString()));\n    console.log('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);\n  });\n}\n\n}); // module: reporters/doc.js\n\nrequire.register(\"reporters/dot.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `Dot`.\n */\n\nexports = module.exports = Dot;\n\n/**\n * Initialize a new `Dot` matrix test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Dot(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , c = '․'\n    , n = 0;\n\n  runner.on('start', function(){\n    process.stdout.write('\\n  ');\n  });\n\n  runner.on('pending', function(test){\n    process.stdout.write(color('pending', c));\n  });\n\n  runner.on('pass', function(test){\n    if (++n % width == 0) process.stdout.write('\\n  ');\n    if ('slow' == test.speed) {\n      process.stdout.write(color('bright yellow', c));\n    } else {\n      process.stdout.write(color(test.speed, c));\n    }\n  });\n\n  runner.on('fail', function(test, err){\n    if (++n % width == 0) process.stdout.write('\\n  ');\n    process.stdout.write(color('fail', c));\n  });\n\n  runner.on('end', function(){\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nDot.prototype = new Base;\nDot.prototype.constructor = Dot;\n\n}); // module: reporters/dot.js\n\nrequire.register(\"reporters/html-cov.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar JSONCov = require('./json-cov')\n  , fs = require('browser/fs');\n\n/**\n * Expose `HTMLCov`.\n */\n\nexports = module.exports = HTMLCov;\n\n/**\n * Initialize a new `JsCoverage` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction HTMLCov(runner) {\n  var jade = require('jade')\n    , file = __dirname + '/templates/coverage.jade'\n    , str = fs.readFileSync(file, 'utf8')\n    , fn = jade.compile(str, { filename: file })\n    , self = this;\n\n  JSONCov.call(this, runner, false);\n\n  runner.on('end', function(){\n    process.stdout.write(fn({\n        cov: self.cov\n      , coverageClass: coverageClass\n    }));\n  });\n}\n\n/**\n * Return coverage class for `n`.\n *\n * @return {String}\n * @api private\n */\n\nfunction coverageClass(n) {\n  if (n >= 75) return 'high';\n  if (n >= 50) return 'medium';\n  if (n >= 25) return 'low';\n  return 'terrible';\n}\n}); // module: reporters/html-cov.js\n\nrequire.register(\"reporters/html.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils')\n  , Progress = require('../browser/progress')\n  , escape = utils.escape;\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Expose `Doc`.\n */\n\nexports = module.exports = HTML;\n\n/**\n * Stats template.\n */\n\nvar statsTemplate = '<ul id=\"stats\">'\n  + '<li class=\"progress\"><canvas width=\"40\" height=\"40\"></canvas></li>'\n  + '<li class=\"passes\"><a href=\"#\">passes:</a> <em>0</em></li>'\n  + '<li class=\"failures\"><a href=\"#\">failures:</a> <em>0</em></li>'\n  + '<li class=\"duration\">duration: <em>0</em>s</li>'\n  + '</ul>';\n\n/**\n * Initialize a new `Doc` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction HTML(runner, root) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total\n    , stat = fragment(statsTemplate)\n    , items = stat.getElementsByTagName('li')\n    , passes = items[1].getElementsByTagName('em')[0]\n    , passesLink = items[1].getElementsByTagName('a')[0]\n    , failures = items[2].getElementsByTagName('em')[0]\n    , failuresLink = items[2].getElementsByTagName('a')[0]\n    , duration = items[3].getElementsByTagName('em')[0]\n    , canvas = stat.getElementsByTagName('canvas')[0]\n    , report = fragment('<ul id=\"report\"></ul>')\n    , stack = [report]\n    , progress\n    , ctx\n\n  root = root || document.getElementById('mocha');\n\n  if (canvas.getContext) {\n    var ratio = window.devicePixelRatio || 1;\n    canvas.style.width = canvas.width;\n    canvas.style.height = canvas.height;\n    canvas.width *= ratio;\n    canvas.height *= ratio;\n    ctx = canvas.getContext('2d');\n    ctx.scale(ratio, ratio);\n    progress = new Progress;\n  }\n\n  if (!root) return error('#mocha div missing, add it to your document');\n\n  // pass toggle\n  on(passesLink, 'click', function () {\n    var className = /pass/.test(report.className) ? '' : ' pass';\n    report.className = report.className.replace(/fail|pass/g, '') + className;\n  });\n\n  // failure toggle\n  on(failuresLink, 'click', function () {\n    var className = /fail/.test(report.className) ? '' : ' fail';\n    report.className = report.className.replace(/fail|pass/g, '') + className;\n  });\n\n  root.appendChild(stat);\n  root.appendChild(report);\n\n  if (progress) progress.size(40);\n\n  runner.on('suite', function(suite){\n    if (suite.root) return;\n\n    // suite\n    var url = '?grep=' + encodeURIComponent(suite.fullTitle());\n    var el = fragment('<li class=\"suite\"><h1><a href=\"%s\">%s</a></h1></li>', url, escape(suite.title));\n\n    // container\n    stack[0].appendChild(el);\n    stack.unshift(document.createElement('ul'));\n    el.appendChild(stack[0]);\n  });\n\n  runner.on('suite end', function(suite){\n    if (suite.root) return;\n    stack.shift();\n  });\n\n  runner.on('fail', function(test, err){\n    if ('hook' == test.type || err.uncaught) runner.emit('test end', test);\n  });\n\n  runner.on('test end', function(test){\n    window.scrollTo(0, document.body.scrollHeight);\n\n    // TODO: add to stats\n    var percent = stats.tests / total * 100 | 0;\n    if (progress) progress.update(percent).draw(ctx);\n\n    // update stats\n    var ms = new Date - stats.start;\n    text(passes, stats.passes);\n    text(failures, stats.failures);\n    text(duration, (ms / 1000).toFixed(2));\n\n    // test\n    if ('passed' == test.state) {\n      var el = fragment('<li class=\"test pass %e\"><h2>%e<span class=\"duration\">%ems</span></h2></li>', test.speed, test.title, test.duration);\n    } else if (test.pending) {\n      var el = fragment('<li class=\"test pass pending\"><h2>%e</h2></li>', test.title);\n    } else {\n      var el = fragment('<li class=\"test fail\"><h2>%e</h2></li>', test.title);\n      var str = test.err.stack || test.err.toString();\n\n      // FF / Opera do not add the message\n      if (!~str.indexOf(test.err.message)) {\n        str = test.err.message + '\\n' + str;\n      }\n\n      // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we\n      // check for the result of the stringifying.\n      if ('[object Error]' == str) str = test.err.message;\n\n      // Safari doesn't give you a stack. Let's at least provide a source line.\n      if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {\n        str += \"\\n(\" + test.err.sourceURL + \":\" + test.err.line + \")\";\n      }\n\n      el.appendChild(fragment('<pre class=\"error\">%e</pre>', str));\n    }\n\n    // toggle code\n    // TODO: defer\n    if (!test.pending) {\n      var h2 = el.getElementsByTagName('h2')[0];\n\n      on(h2, 'click', function(){\n        pre.style.display = 'none' == pre.style.display\n          ? 'inline-block'\n          : 'none';\n      });\n\n      var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));\n      el.appendChild(pre);\n      pre.style.display = 'none';\n    }\n\n    stack[0].appendChild(el);\n  });\n}\n\n/**\n * Display error `msg`.\n */\n\nfunction error(msg) {\n  document.body.appendChild(fragment('<div id=\"error\">%s</div>', msg));\n}\n\n/**\n * Return a DOM fragment from `html`.\n */\n\nfunction fragment(html) {\n  var args = arguments\n    , div = document.createElement('div')\n    , i = 1;\n\n  div.innerHTML = html.replace(/%([se])/g, function(_, type){\n    switch (type) {\n      case 's': return String(args[i++]);\n      case 'e': return escape(args[i++]);\n    }\n  });\n\n  return div.firstChild;\n}\n\n/**\n * Set `el` text to `str`.\n */\n\nfunction text(el, str) {\n  if (el.textContent) {\n    el.textContent = str;\n  } else {\n    el.innerText = str;\n  }\n}\n\n/**\n * Listen on `event` with callback `fn`.\n */\n\nfunction on(el, event, fn) {\n  if (el.addEventListener) {\n    el.addEventListener(event, fn, false);\n  } else {\n    el.attachEvent('on' + event, fn);\n  }\n}\n\n}); // module: reporters/html.js\n\nrequire.register(\"reporters/index.js\", function(module, exports, require){\n\nexports.Base = require('./base');\nexports.Dot = require('./dot');\nexports.Doc = require('./doc');\nexports.TAP = require('./tap');\nexports.JSON = require('./json');\nexports.HTML = require('./html');\nexports.List = require('./list');\nexports.Min = require('./min');\nexports.Spec = require('./spec');\nexports.Nyan = require('./nyan');\nexports.XUnit = require('./xunit');\nexports.Markdown = require('./markdown');\nexports.Progress = require('./progress');\nexports.Landing = require('./landing');\nexports.JSONCov = require('./json-cov');\nexports.HTMLCov = require('./html-cov');\nexports.JSONStream = require('./json-stream');\nexports.Teamcity = require('./teamcity');\n\n}); // module: reporters/index.js\n\nrequire.register(\"reporters/json-cov.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `JSONCov`.\n */\n\nexports = module.exports = JSONCov;\n\n/**\n * Initialize a new `JsCoverage` reporter.\n *\n * @param {Runner} runner\n * @param {Boolean} output\n * @api public\n */\n\nfunction JSONCov(runner, output) {\n  var self = this\n    , output = 1 == arguments.length ? true : output;\n\n  Base.call(this, runner);\n\n  var tests = []\n    , failures = []\n    , passes = [];\n\n  runner.on('test end', function(test){\n    tests.push(test);\n  });\n\n  runner.on('pass', function(test){\n    passes.push(test);\n  });\n\n  runner.on('fail', function(test){\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    var cov = global._$jscoverage || {};\n    var result = self.cov = map(cov);\n    result.stats = self.stats;\n    result.tests = tests.map(clean);\n    result.failures = failures.map(clean);\n    result.passes = passes.map(clean);\n    if (!output) return;\n    process.stdout.write(JSON.stringify(result, null, 2 ));\n  });\n}\n\n/**\n * Map jscoverage data to a JSON structure\n * suitable for reporting.\n *\n * @param {Object} cov\n * @return {Object}\n * @api private\n */\n\nfunction map(cov) {\n  var ret = {\n      instrumentation: 'node-jscoverage'\n    , sloc: 0\n    , hits: 0\n    , misses: 0\n    , coverage: 0\n    , files: []\n  };\n\n  for (var filename in cov) {\n    var data = coverage(filename, cov[filename]);\n    ret.files.push(data);\n    ret.hits += data.hits;\n    ret.misses += data.misses;\n    ret.sloc += data.sloc;\n  }\n\n  if (ret.sloc > 0) {\n    ret.coverage = (ret.hits / ret.sloc) * 100;\n  }\n\n  return ret;\n};\n\n/**\n * Map jscoverage data for a single source file\n * to a JSON structure suitable for reporting.\n *\n * @param {String} filename name of the source file\n * @param {Object} data jscoverage coverage data\n * @return {Object}\n * @api private\n */\n\nfunction coverage(filename, data) {\n  var ret = {\n    filename: filename,\n    coverage: 0,\n    hits: 0,\n    misses: 0,\n    sloc: 0,\n    source: {}\n  };\n\n  data.source.forEach(function(line, num){\n    num++;\n\n    if (data[num] === 0) {\n      ret.misses++;\n      ret.sloc++;\n    } else if (data[num] !== undefined) {\n      ret.hits++;\n      ret.sloc++;\n    }\n\n    ret.source[num] = {\n        source: line\n      , coverage: data[num] === undefined\n        ? ''\n        : data[num]\n    };\n  });\n\n  ret.coverage = ret.hits / ret.sloc * 100;\n\n  return ret;\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n\n}); // module: reporters/json-cov.js\n\nrequire.register(\"reporters/json-stream.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `List`.\n */\n\nexports = module.exports = List;\n\n/**\n * Initialize a new `List` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction List(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total;\n\n  runner.on('start', function(){\n    console.log(JSON.stringify(['start', { total: total }]));\n  });\n\n  runner.on('pass', function(test){\n    console.log(JSON.stringify(['pass', clean(test)]));\n  });\n\n  runner.on('fail', function(test, err){\n    console.log(JSON.stringify(['fail', clean(test)]));\n  });\n\n  runner.on('end', function(){\n    process.stdout.write(JSON.stringify(['end', self.stats]));\n  });\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n}); // module: reporters/json-stream.js\n\nrequire.register(\"reporters/json.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `JSON`.\n */\n\nexports = module.exports = JSONReporter;\n\n/**\n * Initialize a new `JSON` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction JSONReporter(runner) {\n  var self = this;\n  Base.call(this, runner);\n\n  var tests = []\n    , failures = []\n    , passes = [];\n\n  runner.on('test end', function(test){\n    tests.push(test);\n  });\n\n  runner.on('pass', function(test){\n    passes.push(test);\n  });\n\n  runner.on('fail', function(test){\n    failures.push(test);\n  });\n\n  runner.on('end', function(){\n    var obj = {\n        stats: self.stats\n      , tests: tests.map(clean)\n      , failures: failures.map(clean)\n      , passes: passes.map(clean)\n    };\n\n    process.stdout.write(JSON.stringify(obj, null, 2));\n  });\n}\n\n/**\n * Return a plain-object representation of `test`\n * free of cyclic properties etc.\n *\n * @param {Object} test\n * @return {Object}\n * @api private\n */\n\nfunction clean(test) {\n  return {\n      title: test.title\n    , fullTitle: test.fullTitle()\n    , duration: test.duration\n  }\n}\n}); // module: reporters/json.js\n\nrequire.register(\"reporters/landing.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Landing`.\n */\n\nexports = module.exports = Landing;\n\n/**\n * Airplane color.\n */\n\nBase.colors.plane = 0;\n\n/**\n * Airplane crash color.\n */\n\nBase.colors['plane crash'] = 31;\n\n/**\n * Runway color.\n */\n\nBase.colors.runway = 90;\n\n/**\n * Initialize a new `Landing` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Landing(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , total = runner.total\n    , stream = process.stdout\n    , plane = color('plane', '✈')\n    , crashed = -1\n    , n = 0;\n\n  function runway() {\n    var buf = Array(width).join('-');\n    return '  ' + color('runway', buf);\n  }\n\n  runner.on('start', function(){\n    stream.write('\\n  ');\n    cursor.hide();\n  });\n\n  runner.on('test end', function(test){\n    // check if the plane crashed\n    var col = -1 == crashed\n      ? width * ++n / total | 0\n      : crashed;\n\n    // show the crash\n    if ('failed' == test.state) {\n      plane = color('plane crash', '✈');\n      crashed = col;\n    }\n\n    // render landing strip\n    stream.write('\\u001b[4F\\n\\n');\n    stream.write(runway());\n    stream.write('\\n  ');\n    stream.write(color('runway', Array(col).join('⋅')));\n    stream.write(plane)\n    stream.write(color('runway', Array(width - col).join('⋅') + '\\n'));\n    stream.write(runway());\n    stream.write('\\u001b[0m');\n  });\n\n  runner.on('end', function(){\n    cursor.show();\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nLanding.prototype = new Base;\nLanding.prototype.constructor = Landing;\n\n}); // module: reporters/landing.js\n\nrequire.register(\"reporters/list.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `List`.\n */\n\nexports = module.exports = List;\n\n/**\n * Initialize a new `List` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction List(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , n = 0;\n\n  runner.on('start', function(){\n    console.log();\n  });\n\n  runner.on('test', function(test){\n    process.stdout.write(color('pass', '    ' + test.fullTitle() + ': '));\n  });\n\n  runner.on('pending', function(test){\n    var fmt = color('checkmark', '  -')\n      + color('pending', ' %s');\n    console.log(fmt, test.fullTitle());\n  });\n\n  runner.on('pass', function(test){\n    var fmt = color('checkmark', '  ✓')\n      + color('pass', ' %s: ')\n      + color(test.speed, '%dms');\n    cursor.CR();\n    console.log(fmt, test.fullTitle(), test.duration);\n  });\n\n  runner.on('fail', function(test, err){\n    cursor.CR();\n    console.log(color('fail', '  %d) %s'), ++n, test.fullTitle());\n  });\n\n  runner.on('end', self.epilogue.bind(self));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nList.prototype = new Base;\nList.prototype.constructor = List;\n\n\n}); // module: reporters/list.js\n\nrequire.register(\"reporters/markdown.js\", function(module, exports, require){\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils');\n\n/**\n * Expose `Markdown`.\n */\n\nexports = module.exports = Markdown;\n\n/**\n * Initialize a new `Markdown` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Markdown(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , total = runner.total\n    , level = 0\n    , buf = '';\n\n  function title(str) {\n    return Array(level).join('#') + ' ' + str;\n  }\n\n  function indent() {\n    return Array(level).join('  ');\n  }\n\n  function mapTOC(suite, obj) {\n    var ret = obj;\n    obj = obj[suite.title] = obj[suite.title] || { suite: suite };\n    suite.suites.forEach(function(suite){\n      mapTOC(suite, obj);\n    });\n    return ret;\n  }\n\n  function stringifyTOC(obj, level) {\n    ++level;\n    var buf = '';\n    var link;\n    for (var key in obj) {\n      if ('suite' == key) continue;\n      if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\\n';\n      if (key) buf += Array(level).join('  ') + link;\n      buf += stringifyTOC(obj[key], level);\n    }\n    --level;\n    return buf;\n  }\n\n  function generateTOC(suite) {\n    var obj = mapTOC(suite, {});\n    return stringifyTOC(obj, 0);\n  }\n\n  generateTOC(runner.suite);\n\n  runner.on('suite', function(suite){\n    ++level;\n    var slug = utils.slug(suite.fullTitle());\n    buf += '<a name=\"' + slug + '\" />' + '\\n';\n    buf += title(suite.title) + '\\n';\n  });\n\n  runner.on('suite end', function(suite){\n    --level;\n  });\n\n  runner.on('pass', function(test){\n    var code = utils.clean(test.fn.toString());\n    buf += test.title + '.\\n';\n    buf += '\\n```js\\n';\n    buf += code + '\\n';\n    buf += '```\\n\\n';\n  });\n\n  runner.on('end', function(){\n    process.stdout.write('# TOC\\n');\n    process.stdout.write(generateTOC(runner.suite));\n    process.stdout.write(buf);\n  });\n}\n}); // module: reporters/markdown.js\n\nrequire.register(\"reporters/min.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `Min`.\n */\n\nexports = module.exports = Min;\n\n/**\n * Initialize a new `Min` minimal test reporter (best used with --watch).\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Min(runner) {\n  Base.call(this, runner);\n  \n  runner.on('start', function(){\n    // clear screen\n    process.stdout.write('\\u001b[2J');\n    // set cursor position\n    process.stdout.write('\\u001b[1;3H');\n  });\n\n  runner.on('end', this.epilogue.bind(this));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nMin.prototype = new Base;\nMin.prototype.constructor = Min;\n\n}); // module: reporters/min.js\n\nrequire.register(\"reporters/nyan.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , color = Base.color;\n\n/**\n * Expose `Dot`.\n */\n\nexports = module.exports = NyanCat;\n\n/**\n * Initialize a new `Dot` matrix test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction NyanCat(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , width = Base.window.width * .75 | 0\n    , rainbowColors = this.rainbowColors = self.generateColors()\n    , colorIndex = this.colorIndex = 0\n    , numerOfLines = this.numberOfLines = 4\n    , trajectories = this.trajectories = [[], [], [], []]\n    , nyanCatWidth = this.nyanCatWidth = 11\n    , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)\n    , scoreboardWidth = this.scoreboardWidth = 5\n    , tick = this.tick = 0\n    , n = 0;\n\n  runner.on('start', function(){\n    Base.cursor.hide();\n    self.draw('start');\n  });\n\n  runner.on('pending', function(test){\n    self.draw('pending');\n  });\n\n  runner.on('pass', function(test){\n    self.draw('pass');\n  });\n\n  runner.on('fail', function(test, err){\n    self.draw('fail');\n  });\n\n  runner.on('end', function(){\n    Base.cursor.show();\n    for (var i = 0; i < self.numberOfLines; i++) write('\\n');\n    self.epilogue();\n  });\n}\n\n/**\n * Draw the nyan cat with runner `status`.\n *\n * @param {String} status\n * @api private\n */\n\nNyanCat.prototype.draw = function(status){\n  this.appendRainbow();\n  this.drawScoreboard();\n  this.drawRainbow();\n  this.drawNyanCat(status);\n  this.tick = !this.tick;\n};\n\n/**\n * Draw the \"scoreboard\" showing the number\n * of passes, failures and pending tests.\n *\n * @api private\n */\n\nNyanCat.prototype.drawScoreboard = function(){\n  var stats = this.stats;\n  var colors = Base.colors;\n\n  function draw(color, n) {\n    write(' ');\n    write('\\u001b[' + color + 'm' + n + '\\u001b[0m');\n    write('\\n');\n  }\n\n  draw(colors.green, stats.passes);\n  draw(colors.fail, stats.failures);\n  draw(colors.pending, stats.pending);\n  write('\\n');\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Append the rainbow.\n *\n * @api private\n */\n\nNyanCat.prototype.appendRainbow = function(){\n  var segment = this.tick ? '_' : '-';\n  var rainbowified = this.rainbowify(segment);\n\n  for (var index = 0; index < this.numberOfLines; index++) {\n    var trajectory = this.trajectories[index];\n    if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift();\n    trajectory.push(rainbowified);\n  }\n};\n\n/**\n * Draw the rainbow.\n *\n * @api private\n */\n\nNyanCat.prototype.drawRainbow = function(){\n  var self = this;\n\n  this.trajectories.forEach(function(line, index) {\n    write('\\u001b[' + self.scoreboardWidth + 'C');\n    write(line.join(''));\n    write('\\n');\n  });\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Draw the nyan cat with `status`.\n *\n * @param {String} status\n * @api private\n */\n\nNyanCat.prototype.drawNyanCat = function(status) {\n  var self = this;\n  var startWidth = this.scoreboardWidth + this.trajectories[0].length;\n\n  [0, 1, 2, 3].forEach(function(index) {\n    write('\\u001b[' + startWidth + 'C');\n\n    switch (index) {\n      case 0:\n        write('_,------,');\n        write('\\n');\n        break;\n      case 1:\n        var padding = self.tick ? '  ' : '   ';\n        write('_|' + padding + '/\\\\_/\\\\ ');\n        write('\\n');\n        break;\n      case 2:\n        var padding = self.tick ? '_' : '__';\n        var tail = self.tick ? '~' : '^';\n        var face;\n        switch (status) {\n          case 'pass':\n            face = '( ^ .^)';\n            break;\n          case 'fail':\n            face = '( o .o)';\n            break;\n          default:\n            face = '( - .-)';\n        }\n        write(tail + '|' + padding + face + ' ');\n        write('\\n');\n        break;\n      case 3:\n        var padding = self.tick ? ' ' : '  ';\n        write(padding + '\"\"  \"\" ');\n        write('\\n');\n        break;\n    }\n  });\n\n  this.cursorUp(this.numberOfLines);\n};\n\n/**\n * Move cursor up `n`.\n *\n * @param {Number} n\n * @api private\n */\n\nNyanCat.prototype.cursorUp = function(n) {\n  write('\\u001b[' + n + 'A');\n};\n\n/**\n * Move cursor down `n`.\n *\n * @param {Number} n\n * @api private\n */\n\nNyanCat.prototype.cursorDown = function(n) {\n  write('\\u001b[' + n + 'B');\n};\n\n/**\n * Generate rainbow colors.\n *\n * @return {Array}\n * @api private\n */\n\nNyanCat.prototype.generateColors = function(){\n  var colors = [];\n\n  for (var i = 0; i < (6 * 7); i++) {\n    var pi3 = Math.floor(Math.PI / 3);\n    var n = (i * (1.0 / 6));\n    var r = Math.floor(3 * Math.sin(n) + 3);\n    var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);\n    var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);\n    colors.push(36 * r + 6 * g + b + 16);\n  }\n\n  return colors;\n};\n\n/**\n * Apply rainbow to the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nNyanCat.prototype.rainbowify = function(str){\n  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];\n  this.colorIndex += 1;\n  return '\\u001b[38;5;' + color + 'm' + str + '\\u001b[0m';\n};\n\n/**\n * Stdout helper.\n */\n\nfunction write(string) {\n  process.stdout.write(string);\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nNyanCat.prototype = new Base;\nNyanCat.prototype.constructor = NyanCat;\n\n\n}); // module: reporters/nyan.js\n\nrequire.register(\"reporters/progress.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Progress`.\n */\n\nexports = module.exports = Progress;\n\n/**\n * General progress bar color.\n */\n\nBase.colors.progress = 90;\n\n/**\n * Initialize a new `Progress` bar test reporter.\n *\n * @param {Runner} runner\n * @param {Object} options\n * @api public\n */\n\nfunction Progress(runner, options) {\n  Base.call(this, runner);\n\n  var self = this\n    , options = options || {}\n    , stats = this.stats\n    , width = Base.window.width * .50 | 0\n    , total = runner.total\n    , complete = 0\n    , max = Math.max;\n\n  // default chars\n  options.open = options.open || '[';\n  options.complete = options.complete || '▬';\n  options.incomplete = options.incomplete || '⋅';\n  options.close = options.close || ']';\n  options.verbose = false;\n\n  // tests started\n  runner.on('start', function(){\n    console.log();\n    cursor.hide();\n  });\n\n  // tests complete\n  runner.on('test end', function(){\n    complete++;\n    var incomplete = total - complete\n      , percent = complete / total\n      , n = width * percent | 0\n      , i = width - n;\n\n    cursor.CR();\n    process.stdout.write('\\u001b[J');\n    process.stdout.write(color('progress', '  ' + options.open));\n    process.stdout.write(Array(n).join(options.complete));\n    process.stdout.write(Array(i).join(options.incomplete));\n    process.stdout.write(color('progress', options.close));\n    if (options.verbose) {\n      process.stdout.write(color('progress', ' ' + complete + ' of ' + total));\n    }\n  });\n\n  // tests are complete, output some stats\n  // and the failures if any\n  runner.on('end', function(){\n    cursor.show();\n    console.log();\n    self.epilogue();\n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nProgress.prototype = new Base;\nProgress.prototype.constructor = Progress;\n\n\n}); // module: reporters/progress.js\n\nrequire.register(\"reporters/spec.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `Spec`.\n */\n\nexports = module.exports = Spec;\n\n/**\n * Initialize a new `Spec` test reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Spec(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , indents = 0\n    , n = 0;\n\n  function indent() {\n    return Array(indents).join('  ')\n  }\n\n  runner.on('start', function(){\n    console.log();\n  });\n\n  runner.on('suite', function(suite){\n    ++indents;\n    console.log(color('suite', '%s%s'), indent(), suite.title);\n  });\n\n  runner.on('suite end', function(suite){\n    --indents;\n    if (1 == indents) console.log();\n  });\n\n  runner.on('test', function(test){\n    process.stdout.write(indent() + color('pass', '  ◦ ' + test.title + ': '));\n  });\n\n  runner.on('pending', function(test){\n    var fmt = indent() + color('pending', '  - %s');\n    console.log(fmt, test.title);\n  });\n\n  runner.on('pass', function(test){\n    if ('fast' == test.speed) {\n      var fmt = indent()\n        + color('checkmark', '  ✓')\n        + color('pass', ' %s ');\n      cursor.CR();\n      console.log(fmt, test.title);\n    } else {\n      var fmt = indent()\n        + color('checkmark', '  ✓')\n        + color('pass', ' %s ')\n        + color(test.speed, '(%dms)');\n      cursor.CR();\n      console.log(fmt, test.title, test.duration);\n    }\n  });\n\n  runner.on('fail', function(test, err){\n    cursor.CR();\n    console.log(indent() + color('fail', '  %d) %s'), ++n, test.title);\n  });\n\n  runner.on('end', self.epilogue.bind(self));\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nSpec.prototype = new Base;\nSpec.prototype.constructor = Spec;\n\n\n}); // module: reporters/spec.js\n\nrequire.register(\"reporters/tap.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , cursor = Base.cursor\n  , color = Base.color;\n\n/**\n * Expose `TAP`.\n */\n\nexports = module.exports = TAP;\n\n/**\n * Initialize a new `TAP` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction TAP(runner) {\n  Base.call(this, runner);\n\n  var self = this\n    , stats = this.stats\n    , n = 1;\n\n  runner.on('start', function(){\n    var total = runner.grepTotal(runner.suite);\n    console.log('%d..%d', 1, total);\n  });\n\n  runner.on('test end', function(){\n    ++n;\n  });\n\n  runner.on('pending', function(test){\n    console.log('ok %d %s # SKIP -', n, title(test));\n  });\n\n  runner.on('pass', function(test){\n    console.log('ok %d %s', n, title(test));\n  });\n\n  runner.on('fail', function(test, err){\n    console.log('not ok %d %s', n, title(test));\n    console.log(err.stack.replace(/^/gm, '  '));\n  });\n}\n\n/**\n * Return a TAP-safe title of `test`\n *\n * @param {Object} test\n * @return {String}\n * @api private\n */\n\nfunction title(test) {\n  return test.fullTitle().replace(/#/g, '');\n}\n\n}); // module: reporters/tap.js\n\nrequire.register(\"reporters/teamcity.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base');\n\n/**\n * Expose `Teamcity`.\n */\n\nexports = module.exports = Teamcity;\n\n/**\n * Initialize a new `Teamcity` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction Teamcity(runner) {\n  Base.call(this, runner);\n  var stats = this.stats;\n\n  runner.on('start', function() {\n    console.log(\"##teamcity[testSuiteStarted name='mocha.suite']\");\n  });\n\n  runner.on('test', function(test) {\n    console.log(\"##teamcity[testStarted name='\" + escape(test.fullTitle()) + \"']\");\n  });\n\n  runner.on('fail', function(test, err) {\n    console.log(\"##teamcity[testFailed name='\" + escape(test.fullTitle()) + \"' message='\" + escape(err.message) + \"']\");\n  });\n\n  runner.on('pending', function(test) {\n    console.log(\"##teamcity[testIgnored name='\" + escape(test.fullTitle()) + \"' message='pending']\");\n  });\n\n  runner.on('test end', function(test) {\n    console.log(\"##teamcity[testFinished name='\" + escape(test.fullTitle()) + \"' duration='\" + test.duration + \"']\");\n  });\n\n  runner.on('end', function() {\n    console.log(\"##teamcity[testSuiteFinished name='mocha.suite' duration='\" + stats.duration + \"']\");\n  });\n}\n\n/**\n * Escape the given `str`.\n */\n\nfunction escape(str) {\n  return str\n    .replace(/\\|/g, \"||\")\n    .replace(/\\n/g, \"|n\")\n    .replace(/\\r/g, \"|r\")\n    .replace(/\\[/g, \"|[\")\n    .replace(/\\]/g, \"|]\")\n    .replace(/\\u0085/g, \"|x\")\n    .replace(/\\u2028/g, \"|l\")\n    .replace(/\\u2029/g, \"|p\")\n    .replace(/'/g, \"|'\");\n}\n\n}); // module: reporters/teamcity.js\n\nrequire.register(\"reporters/xunit.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Base = require('./base')\n  , utils = require('../utils')\n  , escape = utils.escape;\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Expose `XUnit`.\n */\n\nexports = module.exports = XUnit;\n\n/**\n * Initialize a new `XUnit` reporter.\n *\n * @param {Runner} runner\n * @api public\n */\n\nfunction XUnit(runner) {\n  Base.call(this, runner);\n  var stats = this.stats\n    , tests = []\n    , self = this;\n\n  runner.on('pass', function(test){\n    tests.push(test);\n  });\n  \n  runner.on('fail', function(test){\n    tests.push(test);\n  });\n\n  runner.on('end', function(){\n    console.log(tag('testsuite', {\n        name: 'Mocha Tests'\n      , tests: stats.tests\n      , failures: stats.failures\n      , errors: stats.failures\n      , skip: stats.tests - stats.failures - stats.passes\n      , timestamp: (new Date).toUTCString()\n      , time: stats.duration / 1000\n    }, false));\n\n    tests.forEach(test);\n    console.log('</testsuite>');    \n  });\n}\n\n/**\n * Inherit from `Base.prototype`.\n */\n\nXUnit.prototype = new Base;\nXUnit.prototype.constructor = XUnit;\n\n\n/**\n * Output tag for the given `test.`\n */\n\nfunction test(test) {\n  var attrs = {\n      classname: test.parent.fullTitle()\n    , name: test.title\n    , time: test.duration / 1000\n  };\n\n  if ('failed' == test.state) {\n    var err = test.err;\n    attrs.message = escape(err.message);\n    console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));\n  } else if (test.pending) {\n    console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));\n  } else {\n    console.log(tag('testcase', attrs, true) );\n  }\n}\n\n/**\n * HTML tag helper.\n */\n\nfunction tag(name, attrs, close, content) {\n  var end = close ? '/>' : '>'\n    , pairs = []\n    , tag;\n\n  for (var key in attrs) {\n    pairs.push(key + '=\"' + escape(attrs[key]) + '\"');\n  }\n\n  tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;\n  if (content) tag += content + '</' + name + end;\n  return tag;\n}\n\n/**\n * Return cdata escaped CDATA `str`.\n */\n\nfunction cdata(str) {\n  return '<![CDATA[' + escape(str) + ']]>';\n}\n\n}); // module: reporters/xunit.js\n\nrequire.register(\"runnable.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:runnable');\n\n/**\n * Save timer references to avoid Sinon interfering (see GH-237).\n */\n\nvar Date = global.Date\n  , setTimeout = global.setTimeout\n  , setInterval = global.setInterval\n  , clearTimeout = global.clearTimeout\n  , clearInterval = global.clearInterval;\n\n/**\n * Expose `Runnable`.\n */\n\nmodule.exports = Runnable;\n\n/**\n * Initialize a new `Runnable` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Runnable(title, fn) {\n  this.title = title;\n  this.fn = fn;\n  this.async = fn && fn.length;\n  this.sync = ! this.async;\n  this._timeout = 2000;\n  this._slow = 75;\n  this.timedOut = false;\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nRunnable.prototype = new EventEmitter;\nRunnable.prototype.constructor = Runnable;\n\n\n/**\n * Set & get timeout `ms`.\n *\n * @param {Number} ms\n * @return {Runnable|Number} ms or self\n * @api private\n */\n\nRunnable.prototype.timeout = function(ms){\n  if (0 == arguments.length) return this._timeout;\n  debug('timeout %d', ms);\n  this._timeout = ms;\n  if (this.timer) this.resetTimeout();\n  return this;\n};\n\n/**\n * Set & get slow `ms`.\n *\n * @param {Number} ms\n * @return {Runnable|Number} ms or self\n * @api private\n */\n\nRunnable.prototype.slow = function(ms){\n  if (0 === arguments.length) return this._slow;\n  debug('timeout %d', ms);\n  this._slow = ms;\n  return this;\n};\n\n/**\n * Return the full title generated by recursively\n * concatenating the parent's full title.\n *\n * @return {String}\n * @api public\n */\n\nRunnable.prototype.fullTitle = function(){\n  return this.parent.fullTitle() + ' ' + this.title;\n};\n\n/**\n * Clear the timeout.\n *\n * @api private\n */\n\nRunnable.prototype.clearTimeout = function(){\n  clearTimeout(this.timer);\n};\n\n/**\n * Inspect the runnable void of private properties.\n *\n * @return {String}\n * @api private\n */\n\nRunnable.prototype.inspect = function(){\n  return JSON.stringify(this, function(key, val){\n    if ('_' == key[0]) return;\n    if ('parent' == key) return '#<Suite>';\n    if ('ctx' == key) return '#<Context>';\n    return val;\n  }, 2);\n};\n\n/**\n * Reset the timeout.\n *\n * @api private\n */\n\nRunnable.prototype.resetTimeout = function(){\n  var self = this\n    , ms = this.timeout();\n\n  this.clearTimeout();\n  if (ms) {\n    this.timer = setTimeout(function(){\n      self.callback(new Error('timeout of ' + ms + 'ms exceeded'));\n      self.timedOut = true;\n    }, ms);\n  }\n};\n\n/**\n * Run the test and invoke `fn(err)`.\n *\n * @param {Function} fn\n * @api private\n */\n\nRunnable.prototype.run = function(fn){\n  var self = this\n    , ms = this.timeout()\n    , start = new Date\n    , ctx = this.ctx\n    , finished\n    , emitted;\n\n  if (ctx) ctx.runnable(this);\n\n  // timeout\n  if (this.async) {\n    if (ms) {\n      this.timer = setTimeout(function(){\n        done(new Error('timeout of ' + ms + 'ms exceeded'));\n        self.timedOut = true;\n      }, ms);\n    }\n  }\n\n  // called multiple times\n  function multiple(err) {\n    if (emitted) return;\n    emitted = true;\n    self.emit('error', err || new Error('done() called multiple times'));\n  }\n\n  // finished\n  function done(err) {\n    if (self.timedOut) return;\n    if (finished) return multiple(err);\n    self.clearTimeout();\n    self.duration = new Date - start;\n    finished = true;\n    fn(err);\n  }\n\n  // for .resetTimeout()\n  this.callback = done;\n\n  // async\n  if (this.async) {\n    try {\n      this.fn.call(ctx, function(err){\n        if (err instanceof Error) return done(err);\n        if (null != err) return done(new Error('done() invoked with non-Error: ' + err));\n        done();\n      });\n    } catch (err) {\n      done(err);\n    }\n    return;\n  }\n  \n  // sync\n  try {\n    if (!this.pending) this.fn.call(ctx);\n    this.duration = new Date - start;\n    fn();\n  } catch (err) {\n    fn(err);\n  }\n};\n\n}); // module: runnable.js\n\nrequire.register(\"runner.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:runner')\n  , Test = require('./test')\n  , utils = require('./utils')\n  , filter = utils.filter\n  , keys = utils.keys\n  , noop = function(){};\n\n/**\n * Expose `Runner`.\n */\n\nmodule.exports = Runner;\n\n/**\n * Initialize a `Runner` for the given `suite`.\n *\n * Events:\n *\n *   - `start`  execution started\n *   - `end`  execution complete\n *   - `suite`  (suite) test suite execution started\n *   - `suite end`  (suite) all tests (and sub-suites) have finished\n *   - `test`  (test) test execution started\n *   - `test end`  (test) test completed\n *   - `hook`  (hook) hook execution started\n *   - `hook end`  (hook) hook complete\n *   - `pass`  (test) test passed\n *   - `fail`  (test, err) test failed\n *\n * @api public\n */\n\nfunction Runner(suite) {\n  var self = this;\n  this._globals = [];\n  this.suite = suite;\n  this.total = suite.total();\n  this.failures = 0;\n  this.on('test end', function(test){ self.checkGlobals(test); });\n  this.on('hook end', function(hook){ self.checkGlobals(hook); });\n  this.grep(/.*/);\n  this.globals(utils.keys(global).concat(['errno']));\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nRunner.prototype = new EventEmitter;\nRunner.prototype.constructor = Runner;\n\n\n/**\n * Run tests with full titles matching `re`. Updates runner.total\n * with number of tests matched.\n *\n * @param {RegExp} re\n * @param {Boolean} invert\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.grep = function(re, invert){\n  debug('grep %s', re);\n  this._grep = re;\n  this._invert = invert;\n  this.total = this.grepTotal(this.suite);\n  return this;\n};\n\n/**\n * Returns the number of tests matching the grep search for the\n * given suite.\n *\n * @param {Suite} suite\n * @return {Number}\n * @api public\n */\n\nRunner.prototype.grepTotal = function(suite) {\n  var self = this;\n  var total = 0;\n\n  suite.eachTest(function(test){\n    var match = self._grep.test(test.fullTitle());\n    if (self._invert) match = !match;\n    if (match) total++;\n  });\n\n  return total;\n};\n\n/**\n * Allow the given `arr` of globals.\n *\n * @param {Array} arr\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.globals = function(arr){\n  if (0 == arguments.length) return this._globals;\n  debug('globals %j', arr);\n  utils.forEach(arr, function(arr){\n    this._globals.push(arr);\n  }, this);\n  return this;\n};\n\n/**\n * Check for global variable leaks.\n *\n * @api private\n */\n\nRunner.prototype.checkGlobals = function(test){\n  if (this.ignoreLeaks) return;\n  var leaks = filterLeaks(this._globals);\n\n  this._globals = this._globals.concat(leaks);\n\n  if (leaks.length > 1) {\n    this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));\n  } else if (leaks.length) {\n    this.fail(test, new Error('global leak detected: ' + leaks[0]));\n  }\n};\n\n/**\n * Fail the given `test`.\n *\n * @param {Test} test\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.fail = function(test, err){\n  ++this.failures;\n  test.state = 'failed';\n  if ('string' == typeof err) {\n    err = new Error('the string \"' + err + '\" was thrown, throw an Error :)');\n  }\n  this.emit('fail', test, err);\n};\n\n/**\n * Fail the given `hook` with `err`.\n *\n * Hook failures (currently) hard-end due\n * to that fact that a failing hook will\n * surely cause subsequent tests to fail,\n * causing jumbled reporting.\n *\n * @param {Hook} hook\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.failHook = function(hook, err){\n  this.fail(hook, err);\n  this.emit('end');\n};\n\n/**\n * Run hook `name` callbacks and then invoke `fn()`.\n *\n * @param {String} name\n * @param {Function} function\n * @api private\n */\n\nRunner.prototype.hook = function(name, fn){\n  var suite = this.suite\n    , hooks = suite['_' + name]\n    , self = this\n    , timer;\n\n  function next(i) {\n    var hook = hooks[i];\n    if (!hook) return fn();\n    self.currentRunnable = hook;\n\n    self.emit('hook', hook);\n\n    hook.on('error', function(err){\n      self.failHook(hook, err);\n    });\n\n    hook.run(function(err){\n      hook.removeAllListeners('error');\n      var testError = hook.error();\n      if (testError) self.fail(self.test, testError);\n      if (err) return self.failHook(hook, err);\n      self.emit('hook end', hook);\n      next(++i);\n    });\n  }\n\n  process.nextTick(function(){\n    next(0);\n  });\n};\n\n/**\n * Run hook `name` for the given array of `suites`\n * in order, and callback `fn(err)`.\n *\n * @param {String} name\n * @param {Array} suites\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hooks = function(name, suites, fn){\n  var self = this\n    , orig = this.suite;\n\n  function next(suite) {\n    self.suite = suite;\n\n    if (!suite) {\n      self.suite = orig;\n      return fn();\n    }\n\n    self.hook(name, function(err){\n      if (err) {\n        self.suite = orig;\n        return fn(err);\n      }\n\n      next(suites.pop());\n    });\n  }\n\n  next(suites.pop());\n};\n\n/**\n * Run hooks from the top level down.\n *\n * @param {String} name\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hookUp = function(name, fn){\n  var suites = [this.suite].concat(this.parents()).reverse();\n  this.hooks(name, suites, fn);\n};\n\n/**\n * Run hooks from the bottom up.\n *\n * @param {String} name\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.hookDown = function(name, fn){\n  var suites = [this.suite].concat(this.parents());\n  this.hooks(name, suites, fn);\n};\n\n/**\n * Return an array of parent Suites from\n * closest to furthest.\n *\n * @return {Array}\n * @api private\n */\n\nRunner.prototype.parents = function(){\n  var suite = this.suite\n    , suites = [];\n  while (suite = suite.parent) suites.push(suite);\n  return suites;\n};\n\n/**\n * Run the current test and callback `fn(err)`.\n *\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runTest = function(fn){\n  var test = this.test\n    , self = this;\n\n  try {\n    test.on('error', function(err){\n      self.fail(test, err);\n    });\n    test.run(fn);\n  } catch (err) {\n    fn(err);\n  }\n};\n\n/**\n * Run tests in the given `suite` and invoke\n * the callback `fn()` when complete.\n *\n * @param {Suite} suite\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runTests = function(suite, fn){\n  var self = this\n    , tests = suite.tests\n    , test;\n\n  function next(err) {\n    // if we bail after first err\n    if (self.failures && suite._bail) return fn();\n\n    // next test\n    test = tests.shift();\n\n    // all done\n    if (!test) return fn();\n\n    // grep\n    var match = self._grep.test(test.fullTitle());\n    if (self._invert) match = !match;\n    if (!match) return next();\n\n    // pending\n    if (test.pending) {\n      self.emit('pending', test);\n      self.emit('test end', test);\n      return next();\n    }\n\n    // execute test and hook(s)\n    self.emit('test', self.test = test);\n    self.hookDown('beforeEach', function(){\n      self.currentRunnable = self.test;\n      self.runTest(function(err){\n        test = self.test;\n\n        if (err) {\n          self.fail(test, err);\n          self.emit('test end', test);\n          return self.hookUp('afterEach', next);\n        }\n\n        test.state = 'passed';\n        self.emit('pass', test);\n        self.emit('test end', test);\n        self.hookUp('afterEach', next);\n      });\n    });\n  }\n\n  this.next = next;\n  next();\n};\n\n/**\n * Run the given `suite` and invoke the\n * callback `fn()` when complete.\n *\n * @param {Suite} suite\n * @param {Function} fn\n * @api private\n */\n\nRunner.prototype.runSuite = function(suite, fn){\n  var total = this.grepTotal(suite)\n    , self = this\n    , i = 0;\n\n  debug('run suite %s', suite.fullTitle());\n\n  if (!total) return fn();\n\n  this.emit('suite', this.suite = suite);\n\n  function next() {\n    var curr = suite.suites[i++];\n    if (!curr) return done();\n    self.runSuite(curr, next);\n  }\n\n  function done() {\n    self.suite = suite;\n    self.hook('afterAll', function(){\n      self.emit('suite end', suite);\n      fn();\n    });\n  }\n\n  this.hook('beforeAll', function(){\n    self.runTests(suite, next);\n  });\n};\n\n/**\n * Handle uncaught exceptions.\n *\n * @param {Error} err\n * @api private\n */\n\nRunner.prototype.uncaught = function(err){\n  debug('uncaught exception %s', err.message);\n  var runnable = this.currentRunnable;\n  if (!runnable || 'failed' == runnable.state) return;\n  runnable.clearTimeout();\n  err.uncaught = true;\n  this.fail(runnable, err);\n\n  // recover from test\n  if ('test' == runnable.type) {\n    this.emit('test end', runnable);\n    this.hookUp('afterEach', this.next);\n    return;\n  }\n\n  // bail on hooks\n  this.emit('end');\n};\n\n/**\n * Run the root suite and invoke `fn(failures)`\n * on completion.\n *\n * @param {Function} fn\n * @return {Runner} for chaining\n * @api public\n */\n\nRunner.prototype.run = function(fn){\n  var self = this\n    , fn = fn || function(){};\n\n  debug('start');\n\n  // uncaught callback\n  function uncaught(err) {\n    self.uncaught(err);\n  }\n\n  // callback\n  this.on('end', function(){\n    debug('end');\n    process.removeListener('uncaughtException', uncaught);\n    fn(self.failures);\n  });\n\n  // run suites\n  this.emit('start');\n  this.runSuite(this.suite, function(){\n    debug('finished running');\n    self.emit('end');\n  });\n\n  // uncaught exception\n  process.on('uncaughtException', uncaught);\n\n  return this;\n};\n\n/**\n * Filter leaks with the given globals flagged as `ok`.\n *\n * @param {Array} ok\n * @return {Array}\n * @api private\n */\n\nfunction filterLeaks(ok) {\n  return filter(keys(global), function(key){\n    var matched = filter(ok, function(ok){\n      if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);\n      return key == ok;\n    });\n    return matched.length == 0 && (!global.navigator || 'onerror' !== key);\n  });\n}\n\n}); // module: runner.js\n\nrequire.register(\"suite.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('browser/events').EventEmitter\n  , debug = require('browser/debug')('mocha:suite')\n  , milliseconds = require('./ms')\n  , utils = require('./utils')\n  , Hook = require('./hook');\n\n/**\n * Expose `Suite`.\n */\n\nexports = module.exports = Suite;\n\n/**\n * Create a new `Suite` with the given `title`\n * and parent `Suite`. When a suite with the\n * same title is already present, that suite\n * is returned to provide nicer reporter\n * and more flexible meta-testing.\n *\n * @param {Suite} parent\n * @param {String} title\n * @return {Suite}\n * @api public\n */\n\nexports.create = function(parent, title){\n  var suite = new Suite(title, parent.ctx);\n  suite.parent = parent;\n  if (parent.pending) suite.pending = true;\n  title = suite.fullTitle();\n  parent.addSuite(suite);\n  return suite;\n};\n\n/**\n * Initialize a new `Suite` with the given\n * `title` and `ctx`.\n *\n * @param {String} title\n * @param {Context} ctx\n * @api private\n */\n\nfunction Suite(title, ctx) {\n  this.title = title;\n  this.ctx = ctx;\n  this.suites = [];\n  this.tests = [];\n  this.pending = false;\n  this._beforeEach = [];\n  this._beforeAll = [];\n  this._afterEach = [];\n  this._afterAll = [];\n  this.root = !title;\n  this._timeout = 2000;\n  this._slow = 75;\n  this._bail = false;\n}\n\n/**\n * Inherit from `EventEmitter.prototype`.\n */\n\nSuite.prototype = new EventEmitter;\nSuite.prototype.constructor = Suite;\n\n\n/**\n * Return a clone of this `Suite`.\n *\n * @return {Suite}\n * @api private\n */\n\nSuite.prototype.clone = function(){\n  var suite = new Suite(this.title);\n  debug('clone');\n  suite.ctx = this.ctx;\n  suite.timeout(this.timeout());\n  suite.slow(this.slow());\n  suite.bail(this.bail());\n  return suite;\n};\n\n/**\n * Set timeout `ms` or short-hand such as \"2s\".\n *\n * @param {Number|String} ms\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.timeout = function(ms){\n  if (0 == arguments.length) return this._timeout;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('timeout %d', ms);\n  this._timeout = parseInt(ms, 10);\n  return this;\n};\n\n/**\n * Set slow `ms` or short-hand such as \"2s\".\n *\n * @param {Number|String} ms\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.slow = function(ms){\n  if (0 === arguments.length) return this._slow;\n  if ('string' == typeof ms) ms = milliseconds(ms);\n  debug('slow %d', ms);\n  this._slow = ms;\n  return this;\n};\n\n/**\n * Sets whether to bail after first error.\n *\n * @parma {Boolean} bail\n * @return {Suite|Number} for chaining\n * @api private\n */\n\nSuite.prototype.bail = function(bail){\n  if (0 == arguments.length) return this._bail;\n  debug('bail %s', bail);\n  this._bail = bail;\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` before running tests.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.beforeAll = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"before all\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._beforeAll.push(hook);\n  this.emit('beforeAll', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` after running tests.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.afterAll = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"after all\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._afterAll.push(hook);\n  this.emit('afterAll', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` before each test case.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.beforeEach = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"before each\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._beforeEach.push(hook);\n  this.emit('beforeEach', hook);\n  return this;\n};\n\n/**\n * Run `fn(test[, done])` after each test case.\n *\n * @param {Function} fn\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.afterEach = function(fn){\n  if (this.pending) return this;\n  var hook = new Hook('\"after each\" hook', fn);\n  hook.parent = this;\n  hook.timeout(this.timeout());\n  hook.slow(this.slow());\n  hook.ctx = this.ctx;\n  this._afterEach.push(hook);\n  this.emit('afterEach', hook);\n  return this;\n};\n\n/**\n * Add a test `suite`.\n *\n * @param {Suite} suite\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.addSuite = function(suite){\n  suite.parent = this;\n  suite.timeout(this.timeout());\n  suite.slow(this.slow());\n  suite.bail(this.bail());\n  this.suites.push(suite);\n  this.emit('suite', suite);\n  return this;\n};\n\n/**\n * Add a `test` to this suite.\n *\n * @param {Test} test\n * @return {Suite} for chaining\n * @api private\n */\n\nSuite.prototype.addTest = function(test){\n  test.parent = this;\n  test.timeout(this.timeout());\n  test.slow(this.slow());\n  test.ctx = this.ctx;\n  this.tests.push(test);\n  this.emit('test', test);\n  return this;\n};\n\n/**\n * Return the full title generated by recursively\n * concatenating the parent's full title.\n *\n * @return {String}\n * @api public\n */\n\nSuite.prototype.fullTitle = function(){\n  if (this.parent) {\n    var full = this.parent.fullTitle();\n    if (full) return full + ' ' + this.title;\n  }\n  return this.title;\n};\n\n/**\n * Return the total number of tests.\n *\n * @return {Number}\n * @api public\n */\n\nSuite.prototype.total = function(){\n  return utils.reduce(this.suites, function(sum, suite){\n    return sum + suite.total();\n  }, 0) + this.tests.length;\n};\n\n/**\n * Iterates through each suite recursively to find\n * all tests. Applies a function in the format\n * `fn(test)`.\n *\n * @param {Function} fn\n * @return {Suite}\n * @api private\n */\n\nSuite.prototype.eachTest = function(fn){\n  utils.forEach(this.tests, fn);\n  utils.forEach(this.suites, function(suite){\n    suite.eachTest(fn);\n  });\n  return this;\n};\n\n}); // module: suite.js\n\nrequire.register(\"test.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar Runnable = require('./runnable');\n\n/**\n * Expose `Test`.\n */\n\nmodule.exports = Test;\n\n/**\n * Initialize a new `Test` with the given `title` and callback `fn`.\n *\n * @param {String} title\n * @param {Function} fn\n * @api private\n */\n\nfunction Test(title, fn) {\n  Runnable.call(this, title, fn);\n  this.pending = !fn;\n  this.type = 'test';\n}\n\n/**\n * Inherit from `Runnable.prototype`.\n */\n\nTest.prototype = new Runnable;\nTest.prototype.constructor = Test;\n\n\n}); // module: test.js\n\nrequire.register(\"utils.js\", function(module, exports, require){\n\n/**\n * Module dependencies.\n */\n\nvar fs = require('browser/fs')\n  , path = require('browser/path')\n  , join = path.join\n  , debug = require('browser/debug')('mocha:watch');\n\n/**\n * Ignored directories.\n */\n\nvar ignore = ['node_modules', '.git'];\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param  {String} html\n * @return {String}\n * @api private\n */\n\nexports.escape = function(html){\n  return String(html)\n    .replace(/&/g, '&amp;')\n    .replace(/\"/g, '&quot;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;');\n};\n\n/**\n * Array#forEach (<=IE8)\n *\n * @param {Array} array\n * @param {Function} fn\n * @param {Object} scope\n * @api private\n */\n\nexports.forEach = function(arr, fn, scope){\n  for (var i = 0, l = arr.length; i < l; i++)\n    fn.call(scope, arr[i], i);\n};\n\n/**\n * Array#indexOf (<=IE8)\n *\n * @parma {Array} arr\n * @param {Object} obj to find index of\n * @param {Number} start\n * @api private\n */\n\nexports.indexOf = function(arr, obj, start){\n  for (var i = start || 0, l = arr.length; i < l; i++) {\n    if (arr[i] === obj)\n      return i;\n  }\n  return -1;\n};\n\n/**\n * Array#reduce (<=IE8)\n * \n * @param {Array} array\n * @param {Function} fn\n * @param {Object} initial value\n * @api private\n */\n\nexports.reduce = function(arr, fn, val){\n  var rval = val;\n\n  for (var i = 0, l = arr.length; i < l; i++) {\n    rval = fn(rval, arr[i], i, arr);\n  }\n\n  return rval;\n};\n\n/**\n * Array#filter (<=IE8)\n *\n * @param {Array} array\n * @param {Function} fn\n * @api private\n */\n\nexports.filter = function(arr, fn){\n  var ret = [];\n\n  for (var i = 0, l = arr.length; i < l; i++) {\n    var val = arr[i];\n    if (fn(val, i, arr)) ret.push(val);\n  }\n\n  return ret;\n};\n\n/**\n * Object.keys (<=IE8)\n *\n * @param {Object} obj\n * @return {Array} keys\n * @api private\n */\n\nexports.keys = Object.keys || function(obj) {\n  var keys = []\n    , has = Object.prototype.hasOwnProperty // for `window` on <=IE8\n\n  for (var key in obj) {\n    if (has.call(obj, key)) {\n      keys.push(key);\n    }\n  }\n\n  return keys;\n};\n\n/**\n * Watch the given `files` for changes\n * and invoke `fn(file)` on modification.\n *\n * @param {Array} files\n * @param {Function} fn\n * @api private\n */\n\nexports.watch = function(files, fn){\n  var options = { interval: 100 };\n  files.forEach(function(file){\n    debug('file %s', file);\n    fs.watchFile(file, options, function(curr, prev){\n      if (prev.mtime < curr.mtime) fn(file);\n    });\n  });\n};\n\n/**\n * Ignored files.\n */\n\nfunction ignored(path){\n  return !~ignore.indexOf(path);\n}\n\n/**\n * Lookup files in the given `dir`.\n *\n * @return {Array}\n * @api private\n */\n\nexports.files = function(dir, ret){\n  ret = ret || [];\n\n  fs.readdirSync(dir)\n  .filter(ignored)\n  .forEach(function(path){\n    path = join(dir, path);\n    if (fs.statSync(path).isDirectory()) {\n      exports.files(path, ret);\n    } else if (path.match(/\\.(js|coffee)$/)) {\n      ret.push(path);\n    }\n  });\n\n  return ret;\n};\n\n/**\n * Compute a slug from the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.slug = function(str){\n  return str\n    .toLowerCase()\n    .replace(/ +/g, '-')\n    .replace(/[^-\\w]/g, '');\n};\n\n/**\n * Strip the function definition from `str`,\n * and re-indent for pre whitespace.\n */\n\nexports.clean = function(str) {\n  str = str\n    .replace(/^function *\\(.*\\) *{/, '')\n    .replace(/\\s+\\}$/, '');\n\n  var spaces = str.match(/^\\n?( *)/)[1].length\n    , re = new RegExp('^ {' + spaces + '}', 'gm');\n\n  str = str.replace(re, '');\n\n  return exports.trim(str);\n};\n\n/**\n * Escape regular expression characters in `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.escapeRegexp = function(str){\n  return str.replace(/[-\\\\^$*+?.()|[\\]{}]/g, \"\\\\$&\");\n};\n\n/**\n * Trim the given `str`.\n *\n * @param {String} str\n * @return {String}\n * @api private\n */\n\nexports.trim = function(str){\n  return str.replace(/^\\s+|\\s+$/g, '');\n};\n\n/**\n * Parse the given `qs`.\n *\n * @param {String} qs\n * @return {Object}\n * @api private\n */\n\nexports.parseQuery = function(qs){\n  return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){\n    var i = pair.indexOf('=')\n      , key = pair.slice(0, i)\n      , val = pair.slice(++i);\n\n    obj[key] = decodeURIComponent(val);\n    return obj;\n  }, {});\n};\n\n/**\n * Highlight the given string of `js`.\n *\n * @param {String} js\n * @return {String}\n * @api private\n */\n\nfunction highlight(js) {\n  return js\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\\/\\/(.*)/gm, '<span class=\"comment\">//$1</span>')\n    .replace(/('.*?')/gm, '<span class=\"string\">$1</span>')\n    .replace(/(\\d+\\.\\d+)/gm, '<span class=\"number\">$1</span>')\n    .replace(/(\\d+)/gm, '<span class=\"number\">$1</span>')\n    .replace(/\\bnew *(\\w+)/gm, '<span class=\"keyword\">new</span> <span class=\"init\">$1</span>')\n    .replace(/\\b(function|new|throw|return|var|if|else)\\b/gm, '<span class=\"keyword\">$1</span>')\n}\n\n/**\n * Highlight the contents of tag `name`.\n *\n * @param {String} name\n * @api private\n */\n\nexports.highlightTags = function(name) {\n  var code = document.getElementsByTagName(name);\n  for (var i = 0, len = code.length; i < len; ++i) {\n    code[i].innerHTML = highlight(code[i].innerHTML);\n  }\n};\n\n}); // module: utils.js\n/**\n * Node shims.\n *\n * These are meant only to allow\n * mocha.js to run untouched, not\n * to allow running node code in\n * the browser.\n */\n\nprocess = {};\nprocess.exit = function(status){};\nprocess.stdout = {};\nglobal = window;\n\n/**\n * next tick implementation.\n */\n\nprocess.nextTick = (function(){\n  // postMessage behaves badly on IE8\n  if (window.ActiveXObject || !window.postMessage) {\n    return function(fn){ fn() };\n  }\n\n  // based on setZeroTimeout by David Baron\n  // - http://dbaron.org/log/20100309-faster-timeouts\n  var timeouts = []\n    , name = 'mocha-zero-timeout'\n\n  window.addEventListener('message', function(e){\n    if (e.source == window && e.data == name) {\n      if (e.stopPropagation) e.stopPropagation();\n      if (timeouts.length) timeouts.shift()();\n    }\n  }, true);\n\n  return function(fn){\n    timeouts.push(fn);\n    window.postMessage(name, '*');\n  }\n})();\n\n/**\n * Remove uncaughtException listener.\n */\n\nprocess.removeListener = function(e){\n  if ('uncaughtException' == e) {\n    window.onerror = null;\n  }\n};\n\n/**\n * Implements uncaughtException listener.\n */\n\nprocess.on = function(e, fn){\n  if ('uncaughtException' == e) {\n    window.onerror = fn;\n  }\n};\n\n// boot\n;(function(){\n\n  /**\n   * Expose mocha.\n   */\n\n  var Mocha = window.Mocha = require('mocha'),\n      mocha = window.mocha = new Mocha({ reporter: 'html' });\n\n  /**\n   * Override ui to ensure that the ui functions are initialized.\n   * Normally this would happen in Mocha.prototype.loadFiles.\n   */\n\n  mocha.ui = function(ui){\n    Mocha.prototype.ui.call(this, ui);\n    this.suite.emit('pre-require', window, null, this);\n    return this;\n  };\n\n  /**\n   * Setup mocha with the given setting options.\n   */\n\n  mocha.setup = function(opts){\n    if ('string' == typeof opts) opts = { ui: opts };\n    for (var opt in opts) this[opt](opts[opt]);\n    return this;\n  };\n\n  /**\n   * Run mocha, returning the Runner.\n   */\n\n  mocha.run = function(fn){\n    var options = mocha.options;\n    mocha.globals('location');\n\n    var query = Mocha.utils.parseQuery(window.location.search || '');\n    if (query.grep) mocha.grep(query.grep);\n\n    return Mocha.prototype.run.call(mocha, function(){\n      Mocha.utils.highlightTags('code');\n      if (fn) fn();\n    });\n  };\n})();\n})();"
  },
  {
    "path": "browser-version/test/nedb-browser.js",
    "content": "/**\n * Testing the browser version of NeDB\n * The goal of these tests is not to be exhaustive, we have the server-side NeDB tests for that\n * This is more of a sanity check which executes most of the code at least once and checks\n * it behaves as the server version does\n */\n\nvar assert = chai.assert;\n\n/**\n * Given a docs array and an id, return the document whose id matches, or null if none is found\n */\nfunction findById (docs, id) {\n  return _.find(docs, function (doc) { return doc._id === id; }) || null;\n}\n\n\ndescribe('Basic CRUD functionality', function () {\n\n  it('Able to create a database object in the browser', function () {\n    var db = new Nedb();\n\n    assert.equal(db.inMemoryOnly, true);\n    assert.equal(db.persistence.inMemoryOnly, true);\n  });\n\n  it('Insertion and querying', function (done) {\n    var db = new Nedb();\n\n    db.insert({ a: 4 }, function (err, newDoc1) {\n      assert.isNull(err);\n      db.insert({ a: 40 }, function (err, newDoc2) {\n        assert.isNull(err);\n        db.insert({ a: 400 }, function (err, newDoc3) {\n          assert.isNull(err);\n\n          db.find({ a: { $gt: 36 } }, function (err, docs) {\n            var doc2 = _.find(docs, function (doc) { return doc._id === newDoc2._id; })\n              , doc3 = _.find(docs, function (doc) { return doc._id === newDoc3._id; })\n              ;\n\n            assert.isNull(err);\n            assert.equal(docs.length, 2);\n            assert.equal(doc2.a, 40);\n            assert.equal(doc3.a, 400);\n\n            db.find({ a: { $lt: 36 } }, function (err, docs) {\n              assert.isNull(err);\n              assert.equal(docs.length, 1);\n              assert.equal(docs[0].a, 4);\n              done();\n            });\n          });\n        });\n      });\n    });\n  });\n\n  it('Querying with regular expressions', function (done) {\n    var db = new Nedb();\n\n    db.insert({ planet: 'Earth' }, function (err, newDoc1) {\n      assert.isNull(err);\n      db.insert({ planet: 'Mars' }, function (err, newDoc2) {\n        assert.isNull(err);\n        db.insert({ planet: 'Jupiter' }, function (err, newDoc3) {\n          assert.isNull(err);\n          db.insert({ planet: 'Eaaaaaarth' }, function (err, newDoc4) {\n            assert.isNull(err);\n            db.insert({ planet: 'Maaaars' }, function (err, newDoc5) {\n              assert.isNull(err);\n\n              db.find({ planet: /ar/ }, function (err, docs) {\n                assert.isNull(err);\n                assert.equal(docs.length, 4);\n                assert.equal(_.find(docs, function (doc) { return doc._id === newDoc1._id; }).planet, 'Earth');\n                assert.equal(_.find(docs, function (doc) { return doc._id === newDoc2._id; }).planet, 'Mars');\n                assert.equal(_.find(docs, function (doc) { return doc._id === newDoc4._id; }).planet, 'Eaaaaaarth');\n                assert.equal(_.find(docs, function (doc) { return doc._id === newDoc5._id; }).planet, 'Maaaars');\n\n                db.find({ planet: /aa+r/ }, function (err, docs) {\n                  assert.isNull(err);\n                  assert.equal(docs.length, 2);\n                  assert.equal(_.find(docs, function (doc) { return doc._id === newDoc4._id; }).planet, 'Eaaaaaarth');\n                  assert.equal(_.find(docs, function (doc) { return doc._id === newDoc5._id; }).planet, 'Maaaars');\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n  });\n\n  it('Updating documents', function (done) {\n    var db = new Nedb();\n\n    db.insert({ planet: 'Eaaaaarth' }, function (err, newDoc1) {\n      db.insert({ planet: 'Maaaaars' }, function (err, newDoc2) {\n        // Simple update\n        db.update({ _id: newDoc2._id }, { $set: { planet: 'Saturn' } }, {}, function (err, nr) {\n          assert.isNull(err);\n          assert.equal(nr, 1);\n\n          db.find({}, function (err, docs) {\n            assert.equal(docs.length, 2);\n            assert.equal(findById(docs, newDoc1._id).planet, 'Eaaaaarth');\n            assert.equal(findById(docs, newDoc2._id).planet, 'Saturn');\n\n            // Failing update\n            db.update({ _id: 'unknown' }, { $inc: { count: 1 } }, {}, function (err, nr) {\n              assert.isNull(err);\n              assert.equal(nr, 0);\n\n              db.find({}, function (err, docs) {\n                assert.equal(docs.length, 2);\n                assert.equal(findById(docs, newDoc1._id).planet, 'Eaaaaarth');\n                assert.equal(findById(docs, newDoc2._id).planet, 'Saturn');\n\n                // Document replacement\n                db.update({ planet: 'Eaaaaarth' }, { planet: 'Uranus' }, { multi: false }, function (err, nr) {\n                  assert.isNull(err);\n                  assert.equal(nr, 1);\n\n                  db.find({}, function (err, docs) {\n                    assert.equal(docs.length, 2);\n                    assert.equal(findById(docs, newDoc1._id).planet, 'Uranus');\n                    assert.equal(findById(docs, newDoc2._id).planet, 'Saturn');\n\n                    // Multi update\n                    db.update({}, { $inc: { count: 3 } }, { multi: true }, function (err, nr) {\n                      assert.isNull(err);\n                      assert.equal(nr, 2);\n\n                      db.find({}, function (err, docs) {\n                        assert.equal(docs.length, 2);\n                        assert.equal(findById(docs, newDoc1._id).planet, 'Uranus');\n                        assert.equal(findById(docs, newDoc1._id).count, 3);\n                        assert.equal(findById(docs, newDoc2._id).planet, 'Saturn');\n                        assert.equal(findById(docs, newDoc2._id).count, 3);\n\n                        done();\n                      });\n                    });\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n  });\n\n  it('Updating documents: special modifiers', function (done) {\n    var db = new Nedb();\n\n    db.insert({ planet: 'Earth' }, function (err, newDoc1) {\n      // Pushing to an array\n      db.update({}, { $push: { satellites: 'Phobos' } }, {}, function (err, nr) {\n        assert.isNull(err);\n        assert.equal(nr, 1);\n\n        db.findOne({}, function (err, doc) {\n          assert.deepEqual(doc, { planet: 'Earth', _id: newDoc1._id, satellites: ['Phobos'] });\n\n          db.update({}, { $push: { satellites: 'Deimos' } }, {}, function (err, nr) {\n            assert.isNull(err);\n            assert.equal(nr, 1);\n\n            db.findOne({}, function (err, doc) {\n              assert.deepEqual(doc, { planet: 'Earth', _id: newDoc1._id, satellites: ['Phobos', 'Deimos'] });\n\n              done();\n            });\n          });\n        });\n      });\n    });\n  });\n\n  it('Upserts', function (done) {\n    var db = new Nedb();\n\n    db.update({ a: 4 }, { $inc: { b: 1 } }, { upsert: true }, function (err, nr, upsert) {\n      assert.isNull(err);\n      // Return upserted document\n      assert.equal(upsert.a, 4);\n      assert.equal(upsert.b, 1);\n      assert.equal(nr, 1);\n\n      db.find({}, function (err, docs) {\n        assert.equal(docs.length, 1);\n        assert.equal(docs[0].a, 4);\n        assert.equal(docs[0].b, 1);\n\n        done();\n      });\n    });\n  });\n\n  it('Removing documents', function (done) {\n    var db = new Nedb();\n\n    db.insert({ a: 2 });\n    db.insert({ a: 5 });\n    db.insert({ a: 7 });\n\n    // Multi remove\n    db.remove({ a: { $in: [ 5, 7 ] } }, { multi: true }, function (err, nr) {\n      assert.isNull(err);\n      assert.equal(nr, 2);\n\n      db.find({}, function (err, docs) {\n        assert.equal(docs.length, 1);\n        assert.equal(docs[0].a, 2);\n\n        // Remove with no match\n        db.remove({ b: { $exists: true } }, { multi: true }, function (err, nr) {\n          assert.isNull(err);\n          assert.equal(nr, 0);\n\n          db.find({}, function (err, docs) {\n            assert.equal(docs.length, 1);\n            assert.equal(docs[0].a, 2);\n\n            // Simple remove\n            db.remove({ a: { $exists: true } }, { multi: true }, function (err, nr) {\n              assert.isNull(err);\n              assert.equal(nr, 1);\n\n              db.find({}, function (err, docs) {\n                assert.equal(docs.length, 0);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n  });\n\n});   // ==== End of 'Basic CRUD functionality' ==== //\n\n\ndescribe('Indexing', function () {\n\n  it('getCandidates works as expected', function (done) {\n    var db = new Nedb();\n\n    db.insert({ a: 4 }, function () {\n      db.insert({ a: 6 }, function () {\n        db.insert({ a: 7 }, function () {\n          db.getCandidates({ a: 6 }, function (err, candidates) {\n            console.log(candidates);\n            assert.equal(candidates.length, 3);\n            assert.isDefined(_.find(candidates, function (doc) { return doc.a === 4; }));\n            assert.isDefined(_.find(candidates, function (doc) { return doc.a === 6; }));\n            assert.isDefined(_.find(candidates, function (doc) { return doc.a === 7; }));\n\n            db.ensureIndex({ fieldName: 'a' });\n\n            db.getCandidates({ a: 6 }, function (err, candidates) {\n              assert.equal(candidates.length, 1);\n              assert.isDefined(_.find(candidates, function (doc) { return doc.a === 6; }));\n\n              done();\n            });\n          });\n        });\n      });\n    });\n  });\n\n  it('Can use indexes to enforce a unique constraint', function (done) {\n    var db = new Nedb();\n\n    db.ensureIndex({ fieldName: 'u', unique: true });\n\n    db.insert({ u : 5 }, function (err) {\n      assert.isNull(err);\n\n      db.insert({ u : 98 }, function (err) {\n        assert.isNull(err);\n\n        db.insert({ u : 5 }, function (err) {\n          assert.equal(err.errorType, 'uniqueViolated');\n\n          done();\n        });\n      });\n    });\n  });\n\n});   // ==== End of 'Indexing' ==== //\n\n\ndescribe(\"Don't forget to launch persistence tests!\", function () {\n\n  it(\"See file testPersistence.html\", function (done) {\n    done();\n  });\n\n});   // ===== End of 'persistent in-browser database' =====\n\n\n"
  },
  {
    "path": "browser-version/test/playground.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Playground for NeDB</title>\n</head>\n<body>\n  <script src=\"../out/nedb.min.js\"></script>\n</body>\n</html>\n\n"
  },
  {
    "path": "browser-version/test/testLoad.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Test NeDB persistence load in the browser</title>\n  <link rel=\"stylesheet\" href=\"mocha.css\">\n</head>\n<body>\n  <div id=\"results\"></div>\n  <script src=\"./localforage.js\"></script>\n  <script src=\"./async.js\"></script>\n  <script src=\"../out/nedb.js\"></script>\n  <script src=\"./testLoad.js\"></script>\n</body>\n</html>\n\n"
  },
  {
    "path": "browser-version/test/testLoad.js",
    "content": "console.log('BEGINNING');\n\nvar N = 50000\n  , db = new Nedb({ filename: 'loadTest', autoload: true })\n  , t, i\n  , sample = JSON.stringify({ data: Math.random(), _id: Math.random() });\n  ;\n\n// Some inserts in sequence, using the default storage mechanism (IndexedDB in my case)\nfunction someInserts (sn, N, callback) {\n  var i = 0, beg = Date.now();\n  async.whilst( function () { return i < N; }\n              , function (_cb) {\n                  db.insert({ data: Math.random() }, function (err) { i += 1; return _cb(err); });\n                }\n              , function (err) {\n                  console.log(\"Inserts, series \" + sn + \" \" + (Date.now() - beg));\n                  return callback(err);\n                });\n}\n\n// Manually updating the localStorage on the same variable\nfunction someLS (sn, N, callback) {\n  var i = 0, beg = Date.now();\n  for (i = 0; i < N; i += 1) {\n    localStorage.setItem('loadTestLS', getItem('loadTestLS') + sample);\n  }\n  console.log(\"localStorage, series \" + sn + \" \" + (Date.now() - beg));\n  return callback();\n}\n\n// Manually updating the localStorage on different variables\nfunction someLSDiff (sn, N, callback) {\n  var i = 0, beg = Date.now();\n  for (i = 0; i < N; i += 1) {\n    localStorage.setItem('loadTestLS-' + i, sample);\n  }\n  console.log(\"localStorage, series \" + sn + \" \" + (Date.now() - beg));\n  return callback();\n}\n\n// Manually updating the localforage default on the same variable (IndexedDB on my machine)\nfunction someLF (sn, N, callback) {\n  var i = 0, beg = Date.now();\n  async.whilst( function () { return i < N; }\n              , function (_cb) {\n                  localforage.getItem('loadTestLF', function (err, value) {\n                    if (err) { return _cb(err); }\n                    localforage.setItem('loadTestLF', value + sample, function (err) { i += 1; return _cb(err); });\n                  });\n                }\n              , function (err) {\n                  console.log(\"localForage/IDB, series \" + sn + \" \" + (Date.now() - beg));\n                  return callback(err);\n                });\n}\n\n// Manually updating the localforage default on the different variables (IndexedDB on my machine)\nfunction someLFDiff (sn, N, callback) {\n  var i = 0, beg = Date.now();\n  async.whilst( function () { return i < N; }\n              , function (_cb) {\n                  localforage.setItem('loadTestLF-' + i, sample, function (err) { i += 1; return _cb(err); });\n                }\n              , function (err) {\n                  console.log(\"localForage/IDB, series \" + sn + \" \" + (Date.now() - beg));\n                  return callback(err);\n                });\n}\n\n\n\nlocalStorage.setItem('loadTestLS', '');\nasync.waterfall([\n  function (cb) { db.remove({}, { multi: true }, function (err) { return cb(err); }); }\n\n// Slow and gets slower with database size\n//, async.apply(someInserts, \"#1\", N)   // N=5000, 141s\n//, async.apply(someInserts, \"#2\", N)   // N=5000, 208s\n//, async.apply(someInserts, \"#3\", N)   // N=5000, 281s\n//, async.apply(someInserts, \"#4\", N)   // N=5000, 350s\n\n// Slow and gets slower really fast with database size, then outright crashes\n//, async.apply(someLS, \"#1\", N)   // N=4000, 2.5s\n//, async.apply(someLS, \"#2\", N)   // N=4000, 8.0s\n//, async.apply(someLS, \"#3\", N)   // N=4000, 26.5s\n//, async.apply(someLS, \"#4\", N)   // N=4000, 47.8s then crash, can't get string (with N=5000 crash happens on second pass)\n\n// Much faster and more consistent\n//, async.apply(someLSDiff, \"#1\", N)   // N=50000, 0.7s\n//, async.apply(someLSDiff, \"#2\", N)   // N=50000, 0.5s\n//, async.apply(someLSDiff, \"#3\", N)   // N=50000, 0.5s\n//, async.apply(someLSDiff, \"#4\", N)   // N=50000, 0.5s\n\n// Slow and gets slower with database size\n//, function (cb) { localforage.setItem('loadTestLF', '', function (err) { return cb(err) }) }\n//, async.apply(someLF, \"#1\", N)   // N=5000, 69s\n//, async.apply(someLF, \"#2\", N)   // N=5000, 108s\n//, async.apply(someLF, \"#3\", N)   // N=5000, 137s\n//, async.apply(someLF, \"#4\", N)   // N=5000, 169s\n\n// Quite fast and speed doesn't change with database size (tested with N=10000 and N=50000, still no slow-down)\n//, async.apply(someLFDiff, \"#1\", N)   // N=5000, 18s\n//, async.apply(someLFDiff, \"#2\", N)   // N=5000, 18s\n//, async.apply(someLFDiff, \"#3\", N)   // N=5000, 18s\n//, async.apply(someLFDiff, \"#4\", N)   // N=5000, 18s\n]);\n\n\n\n\n"
  },
  {
    "path": "browser-version/test/testPersistence.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Test NeDB persistence in the browser</title>\n  <link rel=\"stylesheet\" href=\"mocha.css\">\n</head>\n<body>\n  <div id=\"results\"></div>\n  <script src=\"../out/nedb.js\"></script>\n  <script src=\"./testPersistence.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "browser-version/test/testPersistence.js",
    "content": "console.log(\"Beginning tests\");\nconsole.log(\"Please note these tests work on Chrome latest, might not work on other browsers due to discrepancies in how local storage works for the file:// protocol\");\n\nfunction testsFailed () {\n  document.getElementById(\"results\").innerHTML = \"TESTS FAILED\";\n}\n\nvar filename = 'test';\n\nvar db = new Nedb({ filename: filename, autoload: true });\ndb.remove({}, { multi: true }, function () {\n  db.insert({ hello: 'world' }, function (err) {\n    if (err) {\n      testsFailed();\n      return;\n    }\n\n    window.location = './testPersistence2.html';\n  });\n});\n"
  },
  {
    "path": "browser-version/test/testPersistence2.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <title>Test NeDB persistence in the browser - Results</title>\n  <link rel=\"stylesheet\" href=\"mocha.css\">\n</head>\n<body>\n  <div id=\"results\"></div>\n  <script src=\"jquery.min.js\"></script>\n  <script src=\"../out/nedb.js\"></script>\n  <script src=\"./testPersistence2.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "browser-version/test/testPersistence2.js",
    "content": "// Capture F5 to reload the base page testPersistence.html not this one\n$(document).on('keydown', function (e) {\n  if (e.keyCode === 116) {\n    e.preventDefault();\n    window.location = 'testPersistence.html';\n  }\n});\n\n\nconsole.log(\"Checking tests results\");\nconsole.log(\"Please note these tests work on Chrome latest, might not work on other browsers due to discrepancies in how local storage works for the file:// protocol\");\n\nfunction testsFailed () {\n  document.getElementById(\"results\").innerHTML = \"TESTS FAILED\";\n}\n\nvar filename = 'test';\n\nvar db = new Nedb({ filename: filename, autoload: true });\ndb.find({}, function (err, docs) {\n  if (docs.length !== 1) {\n    console.log(docs);\n    console.log(\"Unexpected length of document database\");\n    return testsFailed();\n  }\n\n  if (Object.keys(docs[0]).length !== 2) {\n    console.log(\"Unexpected length insert document in database\");\n    return testsFailed();\n  }\n\n  if (docs[0].hello !== 'world') {\n    console.log(\"Unexpected document\");\n    return testsFailed();\n  }\n\n  document.getElementById(\"results\").innerHTML = \"BROWSER PERSISTENCE TEST PASSED\";\n});\n\n"
  },
  {
    "path": "index.js",
    "content": "var Datastore = require('./lib/datastore');\n\nmodule.exports = Datastore;\n"
  },
  {
    "path": "lib/cursor.js",
    "content": "/**\n * Manage access to data, be it to find, update or remove it\n */\nvar model = require('./model')\n  , _ = require('underscore')\n  ;\n\n\n\n/**\n * Create a new cursor for this collection\n * @param {Datastore} db - The datastore this cursor is bound to\n * @param {Query} query - The query this cursor will operate on\n * @param {Function} execFn - Handler to be executed after cursor has found the results and before the callback passed to find/findOne/update/remove\n */\nfunction Cursor (db, query, execFn) {\n  this.db = db;\n  this.query = query || {};\n  if (execFn) { this.execFn = execFn; }\n}\n\n\n/**\n * Set a limit to the number of results\n */\nCursor.prototype.limit = function(limit) {\n  this._limit = limit;\n  return this;\n};\n\n\n/**\n * Skip a the number of results\n */\nCursor.prototype.skip = function(skip) {\n  this._skip = skip;\n  return this;\n};\n\n\n/**\n * Sort results of the query\n * @param {SortQuery} sortQuery - SortQuery is { field: order }, field can use the dot-notation, order is 1 for ascending and -1 for descending\n */\nCursor.prototype.sort = function(sortQuery) {\n  this._sort = sortQuery;\n  return this;\n};\n\n\n/**\n * Add the use of a projection\n * @param {Object} projection - MongoDB-style projection. {} means take all fields. Then it's { key1: 1, key2: 1 } to take only key1 and key2\n *                              { key1: 0, key2: 0 } to omit only key1 and key2. Except _id, you can't mix takes and omits\n */\nCursor.prototype.projection = function(projection) {\n  this._projection = projection;\n  return this;\n};\n\n\n/**\n * Apply the projection\n */\nCursor.prototype.project = function (candidates) {\n  var res = [], self = this\n    , keepId, action, keys\n    ;\n\n  if (this._projection === undefined || Object.keys(this._projection).length === 0) {\n    return candidates;\n  }\n\n  keepId = this._projection._id === 0 ? false : true;\n  this._projection = _.omit(this._projection, '_id');\n\n  // Check for consistency\n  keys = Object.keys(this._projection);\n  keys.forEach(function (k) {\n    if (action !== undefined && self._projection[k] !== action) { throw new Error(\"Can't both keep and omit fields except for _id\"); }\n    action = self._projection[k];\n  });\n\n  // Do the actual projection\n  candidates.forEach(function (candidate) {\n    var toPush;\n    if (action === 1) {   // pick-type projection\n      toPush = { $set: {} };\n      keys.forEach(function (k) {\n        toPush.$set[k] = model.getDotValue(candidate, k);\n        if (toPush.$set[k] === undefined) { delete toPush.$set[k]; }\n      });\n      toPush = model.modify({}, toPush);\n    } else {   // omit-type projection\n      toPush = { $unset: {} };\n      keys.forEach(function (k) { toPush.$unset[k] = true });\n      toPush = model.modify(candidate, toPush);\n    }\n    if (keepId) {\n      toPush._id = candidate._id;\n    } else {\n      delete toPush._id;\n    }\n    res.push(toPush);\n  });\n\n  return res;\n};\n\n\n/**\n * Get all matching elements\n * Will return pointers to matched elements (shallow copies), returning full copies is the role of find or findOne\n * This is an internal function, use exec which uses the executor\n *\n * @param {Function} callback - Signature: err, results\n */\nCursor.prototype._exec = function(_callback) {\n  var res = [], added = 0, skipped = 0, self = this\n    , error = null\n    , i, keys, key\n    ;\n\n  function callback (error, res) {\n    if (self.execFn) {\n      return self.execFn(error, res, _callback);\n    } else {\n      return _callback(error, res);\n    }\n  }\n\n  this.db.getCandidates(this.query, function (err, candidates) {\n    if (err) { return callback(err); }\n\n    try {\n      for (i = 0; i < candidates.length; i += 1) {\n        if (model.match(candidates[i], self.query)) {\n          // If a sort is defined, wait for the results to be sorted before applying limit and skip\n          if (!self._sort) {\n            if (self._skip && self._skip > skipped) {\n              skipped += 1;\n            } else {\n              res.push(candidates[i]);\n              added += 1;\n              if (self._limit && self._limit <= added) { break; }\n            }\n          } else {\n            res.push(candidates[i]);\n          }\n        }\n      }\n    } catch (err) {\n      return callback(err);\n    }\n\n    // Apply all sorts\n    if (self._sort) {\n      keys = Object.keys(self._sort);\n\n      // Sorting\n      var criteria = [];\n      for (i = 0; i < keys.length; i++) {\n        key = keys[i];\n        criteria.push({ key: key, direction: self._sort[key] });\n      }\n      res.sort(function(a, b) {\n        var criterion, compare, i;\n        for (i = 0; i < criteria.length; i++) {\n          criterion = criteria[i];\n          compare = criterion.direction * model.compareThings(model.getDotValue(a, criterion.key), model.getDotValue(b, criterion.key), self.db.compareStrings);\n          if (compare !== 0) {\n            return compare;\n          }\n        }\n        return 0;\n      });\n\n      // Applying limit and skip\n      var limit = self._limit || res.length\n        , skip = self._skip || 0;\n\n      res = res.slice(skip, skip + limit);\n    }\n\n    // Apply projection\n    try {\n      res = self.project(res);\n    } catch (e) {\n      error = e;\n      res = undefined;\n    }\n\n    return callback(error, res);\n  });\n};\n\nCursor.prototype.exec = function () {\n  this.db.executor.push({ this: this, fn: this._exec, arguments: arguments });\n};\n\n\n\n// Interface\nmodule.exports = Cursor;\n"
  },
  {
    "path": "lib/customUtils.js",
    "content": "var crypto = require('crypto')\n  ;\n\n/**\n * Return a random alphanumerical string of length len\n * There is a very small probability (less than 1/1,000,000) for the length to be less than len\n * (il the base64 conversion yields too many pluses and slashes) but\n * that's not an issue here\n * The probability of a collision is extremely small (need 3*10^12 documents to have one chance in a million of a collision)\n * See http://en.wikipedia.org/wiki/Birthday_problem\n */\nfunction uid (len) {\n  return crypto.randomBytes(Math.ceil(Math.max(8, len * 2)))\n    .toString('base64')\n    .replace(/[+\\/]/g, '')\n    .slice(0, len);\n}\n\n\n// Interface\nmodule.exports.uid = uid;\n\n"
  },
  {
    "path": "lib/datastore.js",
    "content": "var customUtils = require('./customUtils')\n  , model = require('./model')\n  , async = require('async')\n  , Executor = require('./executor')\n  , Index = require('./indexes')\n  , util = require('util')\n  , _ = require('underscore')\n  , Persistence = require('./persistence')\n  , Cursor = require('./cursor')\n  ;\n\n\n/**\n * Create a new collection\n * @param {String} options.filename Optional, datastore will be in-memory only if not provided\n * @param {Boolean} options.timestampData Optional, defaults to false. If set to true, createdAt and updatedAt will be created and populated automatically (if not specified by user)\n * @param {Boolean} options.inMemoryOnly Optional, defaults to false\n * @param {String} options.nodeWebkitAppName Optional, specify the name of your NW app if you want options.filename to be relative to the directory where\n *                                            Node Webkit stores application data such as cookies and local storage (the best place to store data in my opinion)\n * @param {Boolean} options.autoload Optional, defaults to false\n * @param {Function} options.onload Optional, if autoload is used this will be called after the load database with the error object as parameter. If you don't pass it the error will be thrown\n * @param {Function} options.afterSerialization/options.beforeDeserialization Optional, serialization hooks\n * @param {Number} options.corruptAlertThreshold Optional, threshold after which an alert is thrown if too much data is corrupt\n * @param {Function} options.compareStrings Optional, string comparison function that overrides default for sorting\n *\n * Event Emitter - Events\n * * compaction.done - Fired whenever a compaction operation was finished\n */\nfunction Datastore (options) {\n  var filename;\n\n  // Retrocompatibility with v0.6 and before\n  if (typeof options === 'string') {\n    filename = options;\n    this.inMemoryOnly = false;   // Default\n  } else {\n    options = options || {};\n    filename = options.filename;\n    this.inMemoryOnly = options.inMemoryOnly || false;\n    this.autoload = options.autoload || false;\n    this.timestampData = options.timestampData || false;\n  }\n\n  // Determine whether in memory or persistent\n  if (!filename || typeof filename !== 'string' || filename.length === 0) {\n    this.filename = null;\n    this.inMemoryOnly = true;\n  } else {\n    this.filename = filename;\n  }\n\n  // String comparison function\n  this.compareStrings = options.compareStrings;\n\n  // Persistence handling\n  this.persistence = new Persistence({ db: this, nodeWebkitAppName: options.nodeWebkitAppName\n                                      , afterSerialization: options.afterSerialization\n                                      , beforeDeserialization: options.beforeDeserialization\n                                      , corruptAlertThreshold: options.corruptAlertThreshold\n                                      });\n\n  // This new executor is ready if we don't use persistence\n  // If we do, it will only be ready once loadDatabase is called\n  this.executor = new Executor();\n  if (this.inMemoryOnly) { this.executor.ready = true; }\n\n  // Indexed by field name, dot notation can be used\n  // _id is always indexed and since _ids are generated randomly the underlying\n  // binary is always well-balanced\n  this.indexes = {};\n  this.indexes._id = new Index({ fieldName: '_id', unique: true });\n  this.ttlIndexes = {};\n\n  // Queue a load of the database right away and call the onload handler\n  // By default (no onload handler), if there is an error there, no operation will be possible so warn the user by throwing an exception\n  if (this.autoload) { this.loadDatabase(options.onload || function (err) {\n    if (err) { throw err; }\n  }); }\n}\n\nutil.inherits(Datastore, require('events').EventEmitter);\n\n\n/**\n * Load the database from the datafile, and trigger the execution of buffered commands if any\n */\nDatastore.prototype.loadDatabase = function () {\n  this.executor.push({ this: this.persistence, fn: this.persistence.loadDatabase, arguments: arguments }, true);\n};\n\n\n/**\n * Get an array of all the data in the database\n */\nDatastore.prototype.getAllData = function () {\n  return this.indexes._id.getAll();\n};\n\n\n/**\n * Reset all currently defined indexes\n */\nDatastore.prototype.resetIndexes = function (newData) {\n  var self = this;\n\n  Object.keys(this.indexes).forEach(function (i) {\n    self.indexes[i].reset(newData);\n  });\n};\n\n\n/**\n * Ensure an index is kept for this field. Same parameters as lib/indexes\n * For now this function is synchronous, we need to test how much time it takes\n * We use an async API for consistency with the rest of the code\n * @param {String} options.fieldName\n * @param {Boolean} options.unique\n * @param {Boolean} options.sparse\n * @param {Number} options.expireAfterSeconds - Optional, if set this index becomes a TTL index (only works on Date fields, not arrays of Date)\n * @param {Function} cb Optional callback, signature: err\n */\nDatastore.prototype.ensureIndex = function (options, cb) {\n  var err\n    , callback = cb || function () {};\n\n  options = options || {};\n\n  if (!options.fieldName) {\n    err = new Error(\"Cannot create an index without a fieldName\");\n    err.missingFieldName = true;\n    return callback(err);\n  }\n  if (this.indexes[options.fieldName]) { return callback(null); }\n\n  this.indexes[options.fieldName] = new Index(options);\n  if (options.expireAfterSeconds !== undefined) { this.ttlIndexes[options.fieldName] = options.expireAfterSeconds; }   // With this implementation index creation is not necessary to ensure TTL but we stick with MongoDB's API here\n\n  try {\n    this.indexes[options.fieldName].insert(this.getAllData());\n  } catch (e) {\n    delete this.indexes[options.fieldName];\n    return callback(e);\n  }\n\n  // We may want to force all options to be persisted including defaults, not just the ones passed the index creation function\n  this.persistence.persistNewState([{ $$indexCreated: options }], function (err) {\n    if (err) { return callback(err); }\n    return callback(null);\n  });\n};\n\n\n/**\n * Remove an index\n * @param {String} fieldName\n * @param {Function} cb Optional callback, signature: err\n */\nDatastore.prototype.removeIndex = function (fieldName, cb) {\n  var callback = cb || function () {};\n\n  delete this.indexes[fieldName];\n\n  this.persistence.persistNewState([{ $$indexRemoved: fieldName }], function (err) {\n    if (err) { return callback(err); }\n    return callback(null);\n  });\n};\n\n\n/**\n * Add one or several document(s) to all indexes\n */\nDatastore.prototype.addToIndexes = function (doc) {\n  var i, failingIndex, error\n    , keys = Object.keys(this.indexes)\n    ;\n\n  for (i = 0; i < keys.length; i += 1) {\n    try {\n      this.indexes[keys[i]].insert(doc);\n    } catch (e) {\n      failingIndex = i;\n      error = e;\n      break;\n    }\n  }\n\n  // If an error happened, we need to rollback the insert on all other indexes\n  if (error) {\n    for (i = 0; i < failingIndex; i += 1) {\n      this.indexes[keys[i]].remove(doc);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Remove one or several document(s) from all indexes\n */\nDatastore.prototype.removeFromIndexes = function (doc) {\n  var self = this;\n\n  Object.keys(this.indexes).forEach(function (i) {\n    self.indexes[i].remove(doc);\n  });\n};\n\n\n/**\n * Update one or several documents in all indexes\n * To update multiple documents, oldDoc must be an array of { oldDoc, newDoc } pairs\n * If one update violates a constraint, all changes are rolled back\n */\nDatastore.prototype.updateIndexes = function (oldDoc, newDoc) {\n  var i, failingIndex, error\n    , keys = Object.keys(this.indexes)\n    ;\n\n  for (i = 0; i < keys.length; i += 1) {\n    try {\n      this.indexes[keys[i]].update(oldDoc, newDoc);\n    } catch (e) {\n      failingIndex = i;\n      error = e;\n      break;\n    }\n  }\n\n  // If an error happened, we need to rollback the update on all other indexes\n  if (error) {\n    for (i = 0; i < failingIndex; i += 1) {\n      this.indexes[keys[i]].revertUpdate(oldDoc, newDoc);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Return the list of candidates for a given query\n * Crude implementation for now, we return the candidates given by the first usable index if any\n * We try the following query types, in this order: basic match, $in match, comparison match\n * One way to make it better would be to enable the use of multiple indexes if the first usable index\n * returns too much data. I may do it in the future.\n *\n * Returned candidates will be scanned to find and remove all expired documents\n *\n * @param {Query} query\n * @param {Boolean} dontExpireStaleDocs Optional, defaults to false, if true don't remove stale docs. Useful for the remove function which shouldn't be impacted by expirations\n * @param {Function} callback Signature err, candidates\n */\nDatastore.prototype.getCandidates = function (query, dontExpireStaleDocs, callback) {\n  var indexNames = Object.keys(this.indexes)\n    , self = this\n    , usableQueryKeys;\n\n  if (typeof dontExpireStaleDocs === 'function') {\n    callback = dontExpireStaleDocs;\n    dontExpireStaleDocs = false;\n  }\n\n\n  async.waterfall([\n  // STEP 1: get candidates list by checking indexes from most to least frequent usecase\n  function (cb) {\n    // For a basic match\n    usableQueryKeys = [];\n    Object.keys(query).forEach(function (k) {\n      if (typeof query[k] === 'string' || typeof query[k] === 'number' || typeof query[k] === 'boolean' || util.isDate(query[k]) || query[k] === null) {\n        usableQueryKeys.push(k);\n      }\n    });\n    usableQueryKeys = _.intersection(usableQueryKeys, indexNames);\n    if (usableQueryKeys.length > 0) {\n      return cb(null, self.indexes[usableQueryKeys[0]].getMatching(query[usableQueryKeys[0]]));\n    }\n\n    // For a $in match\n    usableQueryKeys = [];\n    Object.keys(query).forEach(function (k) {\n      if (query[k] && query[k].hasOwnProperty('$in')) {\n        usableQueryKeys.push(k);\n      }\n    });\n    usableQueryKeys = _.intersection(usableQueryKeys, indexNames);\n    if (usableQueryKeys.length > 0) {\n      return cb(null, self.indexes[usableQueryKeys[0]].getMatching(query[usableQueryKeys[0]].$in));\n    }\n\n    // For a comparison match\n    usableQueryKeys = [];\n    Object.keys(query).forEach(function (k) {\n      if (query[k] && (query[k].hasOwnProperty('$lt') || query[k].hasOwnProperty('$lte') || query[k].hasOwnProperty('$gt') || query[k].hasOwnProperty('$gte'))) {\n        usableQueryKeys.push(k);\n      }\n    });\n    usableQueryKeys = _.intersection(usableQueryKeys, indexNames);\n    if (usableQueryKeys.length > 0) {\n      return cb(null, self.indexes[usableQueryKeys[0]].getBetweenBounds(query[usableQueryKeys[0]]));\n    }\n\n    // By default, return all the DB data\n    return cb(null, self.getAllData());\n  }\n  // STEP 2: remove all expired documents\n  , function (docs) {\n    if (dontExpireStaleDocs) { return callback(null, docs); }\n\n    var expiredDocsIds = [], validDocs = [], ttlIndexesFieldNames = Object.keys(self.ttlIndexes);\n\n    docs.forEach(function (doc) {\n      var valid = true;\n      ttlIndexesFieldNames.forEach(function (i) {\n        if (doc[i] !== undefined && util.isDate(doc[i]) && Date.now() > doc[i].getTime() + self.ttlIndexes[i] * 1000) {\n          valid = false;\n        }\n      });\n      if (valid) { validDocs.push(doc); } else { expiredDocsIds.push(doc._id); }\n    });\n\n    async.eachSeries(expiredDocsIds, function (_id, cb) {\n      self._remove({ _id: _id }, {}, function (err) {\n        if (err) { return callback(err); }\n        return cb();\n      });\n    }, function (err) {\n      return callback(null, validDocs);\n    });\n  }]);\n};\n\n\n/**\n * Insert a new document\n * @param {Function} cb Optional callback, signature: err, insertedDoc\n *\n * @api private Use Datastore.insert which has the same signature\n */\nDatastore.prototype._insert = function (newDoc, cb) {\n  var callback = cb || function () {}\n    , preparedDoc\n    ;\n\n  try {\n    preparedDoc = this.prepareDocumentForInsertion(newDoc)\n    this._insertInCache(preparedDoc);\n  } catch (e) {\n    return callback(e);\n  }\n\n  this.persistence.persistNewState(util.isArray(preparedDoc) ? preparedDoc : [preparedDoc], function (err) {\n    if (err) { return callback(err); }\n    return callback(null, model.deepCopy(preparedDoc));\n  });\n};\n\n/**\n * Create a new _id that's not already in use\n */\nDatastore.prototype.createNewId = function () {\n  var tentativeId = customUtils.uid(16);\n  // Try as many times as needed to get an unused _id. As explained in customUtils, the probability of this ever happening is extremely small, so this is O(1)\n  if (this.indexes._id.getMatching(tentativeId).length > 0) {\n    tentativeId = this.createNewId();\n  }\n  return tentativeId;\n};\n\n/**\n * Prepare a document (or array of documents) to be inserted in a database\n * Meaning adds _id and timestamps if necessary on a copy of newDoc to avoid any side effect on user input\n * @api private\n */\nDatastore.prototype.prepareDocumentForInsertion = function (newDoc) {\n  var preparedDoc, self = this;\n\n  if (util.isArray(newDoc)) {\n    preparedDoc = [];\n    newDoc.forEach(function (doc) { preparedDoc.push(self.prepareDocumentForInsertion(doc)); });\n  } else {\n    preparedDoc = model.deepCopy(newDoc);\n    if (preparedDoc._id === undefined) { preparedDoc._id = this.createNewId(); }\n    var now = new Date();\n    if (this.timestampData && preparedDoc.createdAt === undefined) { preparedDoc.createdAt = now; }\n    if (this.timestampData && preparedDoc.updatedAt === undefined) { preparedDoc.updatedAt = now; }\n    model.checkObject(preparedDoc);\n  }\n\n  return preparedDoc;\n};\n\n/**\n * If newDoc is an array of documents, this will insert all documents in the cache\n * @api private\n */\nDatastore.prototype._insertInCache = function (preparedDoc) {\n  if (util.isArray(preparedDoc)) {\n    this._insertMultipleDocsInCache(preparedDoc);\n  } else {\n    this.addToIndexes(preparedDoc);\n  }\n};\n\n/**\n * If one insertion fails (e.g. because of a unique constraint), roll back all previous\n * inserts and throws the error\n * @api private\n */\nDatastore.prototype._insertMultipleDocsInCache = function (preparedDocs) {\n  var i, failingI, error;\n\n  for (i = 0; i < preparedDocs.length; i += 1) {\n    try {\n      this.addToIndexes(preparedDocs[i]);\n    } catch (e) {\n      error = e;\n      failingI = i;\n      break;\n    }\n  }\n\n  if (error) {\n    for (i = 0; i < failingI; i += 1) {\n      this.removeFromIndexes(preparedDocs[i]);\n    }\n\n    throw error;\n  }\n};\n\nDatastore.prototype.insert = function () {\n  this.executor.push({ this: this, fn: this._insert, arguments: arguments });\n};\n\n\n/**\n * Count all documents matching the query\n * @param {Object} query MongoDB-style query\n */\nDatastore.prototype.count = function(query, callback) {\n  var cursor = new Cursor(this, query, function(err, docs, callback) {\n    if (err) { return callback(err); }\n    return callback(null, docs.length);\n  });\n\n  if (typeof callback === 'function') {\n    cursor.exec(callback);\n  } else {\n    return cursor;\n  }\n};\n\n\n/**\n * Find all documents matching the query\n * If no callback is passed, we return the cursor so that user can limit, skip and finally exec\n * @param {Object} query MongoDB-style query\n * @param {Object} projection MongoDB-style projection\n */\nDatastore.prototype.find = function (query, projection, callback) {\n  switch (arguments.length) {\n    case 1:\n      projection = {};\n      // callback is undefined, will return a cursor\n      break;\n    case 2:\n      if (typeof projection === 'function') {\n        callback = projection;\n        projection = {};\n      }   // If not assume projection is an object and callback undefined\n      break;\n  }\n\n  var cursor = new Cursor(this, query, function(err, docs, callback) {\n    var res = [], i;\n\n    if (err) { return callback(err); }\n\n    for (i = 0; i < docs.length; i += 1) {\n      res.push(model.deepCopy(docs[i]));\n    }\n    return callback(null, res);\n  });\n\n  cursor.projection(projection);\n  if (typeof callback === 'function') {\n    cursor.exec(callback);\n  } else {\n    return cursor;\n  }\n};\n\n\n/**\n * Find one document matching the query\n * @param {Object} query MongoDB-style query\n * @param {Object} projection MongoDB-style projection\n */\nDatastore.prototype.findOne = function (query, projection, callback) {\n  switch (arguments.length) {\n    case 1:\n      projection = {};\n      // callback is undefined, will return a cursor\n      break;\n    case 2:\n      if (typeof projection === 'function') {\n        callback = projection;\n        projection = {};\n      }   // If not assume projection is an object and callback undefined\n      break;\n  }\n\n  var cursor = new Cursor(this, query, function(err, docs, callback) {\n    if (err) { return callback(err); }\n    if (docs.length === 1) {\n      return callback(null, model.deepCopy(docs[0]));\n    } else {\n      return callback(null, null);\n    }\n  });\n\n  cursor.projection(projection).limit(1);\n  if (typeof callback === 'function') {\n    cursor.exec(callback);\n  } else {\n    return cursor;\n  }\n};\n\n\n/**\n * Update all docs matching query\n * @param {Object} query\n * @param {Object} updateQuery\n * @param {Object} options Optional options\n *                 options.multi If true, can update multiple documents (defaults to false)\n *                 options.upsert If true, document is inserted if the query doesn't match anything\n *                 options.returnUpdatedDocs Defaults to false, if true return as third argument the array of updated matched documents (even if no change actually took place)\n * @param {Function} cb Optional callback, signature: (err, numAffected, affectedDocuments, upsert)\n *                      If update was an upsert, upsert flag is set to true\n *                      affectedDocuments can be one of the following:\n *                        * For an upsert, the upserted document\n *                        * For an update with returnUpdatedDocs option false, null\n *                        * For an update with returnUpdatedDocs true and multi false, the updated document\n *                        * For an update with returnUpdatedDocs true and multi true, the array of updated documents\n *\n * WARNING: The API was changed between v1.7.4 and v1.8, for consistency and readability reasons. Prior and including to v1.7.4,\n *          the callback signature was (err, numAffected, updated) where updated was the updated document in case of an upsert\n *          or the array of updated documents for an update if the returnUpdatedDocs option was true. That meant that the type of\n *          affectedDocuments in a non multi update depended on whether there was an upsert or not, leaving only two ways for the\n *          user to check whether an upsert had occured: checking the type of affectedDocuments or running another find query on\n *          the whole dataset to check its size. Both options being ugly, the breaking change was necessary.\n *\n * @api private Use Datastore.update which has the same signature\n */\nDatastore.prototype._update = function (query, updateQuery, options, cb) {\n  var callback\n    , self = this\n    , numReplaced = 0\n    , multi, upsert\n    , i\n    ;\n\n  if (typeof options === 'function') { cb = options; options = {}; }\n  callback = cb || function () {};\n  multi = options.multi !== undefined ? options.multi : false;\n  upsert = options.upsert !== undefined ? options.upsert : false;\n\n  async.waterfall([\n  function (cb) {   // If upsert option is set, check whether we need to insert the doc\n    if (!upsert) { return cb(); }\n\n    // Need to use an internal function not tied to the executor to avoid deadlock\n    var cursor = new Cursor(self, query);\n    cursor.limit(1)._exec(function (err, docs) {\n      if (err) { return callback(err); }\n      if (docs.length === 1) {\n        return cb();\n      } else {\n        var toBeInserted;\n\n        try {\n          model.checkObject(updateQuery);\n          // updateQuery is a simple object with no modifier, use it as the document to insert\n          toBeInserted = updateQuery;\n        } catch (e) {\n          // updateQuery contains modifiers, use the find query as the base,\n          // strip it from all operators and update it according to updateQuery\n          try {\n            toBeInserted = model.modify(model.deepCopy(query, true), updateQuery);\n          } catch (err) {\n            return callback(err);\n          }\n        }\n\n        return self._insert(toBeInserted, function (err, newDoc) {\n          if (err) { return callback(err); }\n          return callback(null, 1, newDoc, true);\n        });\n      }\n    });\n  }\n  , function () {   // Perform the update\n    var modifiedDoc , modifications = [], createdAt;\n\n    self.getCandidates(query, function (err, candidates) {\n      if (err) { return callback(err); }\n\n      // Preparing update (if an error is thrown here neither the datafile nor\n      // the in-memory indexes are affected)\n      try {\n        for (i = 0; i < candidates.length; i += 1) {\n          if (model.match(candidates[i], query) && (multi || numReplaced === 0)) {\n            numReplaced += 1;\n            if (self.timestampData) { createdAt = candidates[i].createdAt; }\n            modifiedDoc = model.modify(candidates[i], updateQuery);\n            if (self.timestampData) {\n              modifiedDoc.createdAt = createdAt;\n              modifiedDoc.updatedAt = new Date();\n            }\n            modifications.push({ oldDoc: candidates[i], newDoc: modifiedDoc });\n          }\n        }\n      } catch (err) {\n        return callback(err);\n      }\n\n      // Change the docs in memory\n      try {\n        self.updateIndexes(modifications);\n      } catch (err) {\n        return callback(err);\n      }\n\n      // Update the datafile\n      var updatedDocs = _.pluck(modifications, 'newDoc');\n      self.persistence.persistNewState(updatedDocs, function (err) {\n        if (err) { return callback(err); }\n        if (!options.returnUpdatedDocs) {\n          return callback(null, numReplaced);\n        } else {\n          var updatedDocsDC = [];\n          updatedDocs.forEach(function (doc) { updatedDocsDC.push(model.deepCopy(doc)); });\n          if (! multi) { updatedDocsDC = updatedDocsDC[0]; }\n          return callback(null, numReplaced, updatedDocsDC);\n        }\n      });\n    });\n  }]);\n};\n\nDatastore.prototype.update = function () {\n  this.executor.push({ this: this, fn: this._update, arguments: arguments });\n};\n\n\n/**\n * Remove all docs matching the query\n * For now very naive implementation (similar to update)\n * @param {Object} query\n * @param {Object} options Optional options\n *                 options.multi If true, can update multiple documents (defaults to false)\n * @param {Function} cb Optional callback, signature: err, numRemoved\n *\n * @api private Use Datastore.remove which has the same signature\n */\nDatastore.prototype._remove = function (query, options, cb) {\n  var callback\n    , self = this, numRemoved = 0, removedDocs = [], multi\n    ;\n\n  if (typeof options === 'function') { cb = options; options = {}; }\n  callback = cb || function () {};\n  multi = options.multi !== undefined ? options.multi : false;\n\n  this.getCandidates(query, true, function (err, candidates) {\n    if (err) { return callback(err); }\n\n    try {\n      candidates.forEach(function (d) {\n        if (model.match(d, query) && (multi || numRemoved === 0)) {\n          numRemoved += 1;\n          removedDocs.push({ $$deleted: true, _id: d._id });\n          self.removeFromIndexes(d);\n        }\n      });\n    } catch (err) { return callback(err); }\n\n    self.persistence.persistNewState(removedDocs, function (err) {\n      if (err) { return callback(err); }\n      return callback(null, numRemoved);\n    });\n  });\n};\n\nDatastore.prototype.remove = function () {\n  this.executor.push({ this: this, fn: this._remove, arguments: arguments });\n};\n\n\n\nmodule.exports = Datastore;\n"
  },
  {
    "path": "lib/executor.js",
    "content": "/**\n * Responsible for sequentially executing actions on the database\n */\n\nvar async = require('async')\n  ;\n\nfunction Executor () {\n  this.buffer = [];\n  this.ready = false;\n\n  // This queue will execute all commands, one-by-one in order\n  this.queue = async.queue(function (task, cb) {\n    var newArguments = [];\n\n    // task.arguments is an array-like object on which adding a new field doesn't work, so we transform it into a real array\n    for (var i = 0; i < task.arguments.length; i += 1) { newArguments.push(task.arguments[i]); }\n    var lastArg = task.arguments[task.arguments.length - 1];\n\n    // Always tell the queue task is complete. Execute callback if any was given.\n    if (typeof lastArg === 'function') {\n      // Callback was supplied\n      newArguments[newArguments.length - 1] = function () {\n        if (typeof setImmediate === 'function') {\n           setImmediate(cb);\n        } else {\n          process.nextTick(cb);\n        }\n        lastArg.apply(null, arguments);\n      };\n    } else if (!lastArg && task.arguments.length !== 0) {\n      // false/undefined/null supplied as callbback\n      newArguments[newArguments.length - 1] = function () { cb(); };\n    } else {\n      // Nothing supplied as callback\n      newArguments.push(function () { cb(); });\n    }\n\n\n    task.fn.apply(task.this, newArguments);\n  }, 1);\n}\n\n\n/**\n * If executor is ready, queue task (and process it immediately if executor was idle)\n * If not, buffer task for later processing\n * @param {Object} task\n *                 task.this - Object to use as this\n *                 task.fn - Function to execute\n *                 task.arguments - Array of arguments, IMPORTANT: only the last argument may be a function (the callback)\n *                                                                 and the last argument cannot be false/undefined/null\n * @param {Boolean} forceQueuing Optional (defaults to false) force executor to queue task even if it is not ready\n */\nExecutor.prototype.push = function (task, forceQueuing) {\n  if (this.ready || forceQueuing) {\n    this.queue.push(task);\n  } else {\n    this.buffer.push(task);\n  }\n};\n\n\n/**\n * Queue all tasks in buffer (in the same order they came in)\n * Automatically sets executor as ready\n */\nExecutor.prototype.processBuffer = function () {\n  var i;\n  this.ready = true;\n  for (i = 0; i < this.buffer.length; i += 1) { this.queue.push(this.buffer[i]); }\n  this.buffer = [];\n};\n\n\n\n// Interface\nmodule.exports = Executor;\n"
  },
  {
    "path": "lib/indexes.js",
    "content": "var BinarySearchTree = require('binary-search-tree').AVLTree\n  , model = require('./model')\n  , _ = require('underscore')\n  , util = require('util')\n  ;\n\n/**\n * Two indexed pointers are equal iif they point to the same place\n */\nfunction checkValueEquality (a, b) {\n  return a === b;\n}\n\n/**\n * Type-aware projection\n */\nfunction projectForUnique (elt) {\n  if (elt === null) { return '$null'; }\n  if (typeof elt === 'string') { return '$string' + elt; }\n  if (typeof elt === 'boolean') { return '$boolean' + elt; }\n  if (typeof elt === 'number') { return '$number' + elt; }\n  if (util.isArray(elt)) { return '$date' + elt.getTime(); }\n\n  return elt;   // Arrays and objects, will check for pointer equality\n}\n\n\n/**\n * Create a new index\n * All methods on an index guarantee that either the whole operation was successful and the index changed\n * or the operation was unsuccessful and an error is thrown while the index is unchanged\n * @param {String} options.fieldName On which field should the index apply (can use dot notation to index on sub fields)\n * @param {Boolean} options.unique Optional, enforce a unique constraint (default: false)\n * @param {Boolean} options.sparse Optional, allow a sparse index (we can have documents for which fieldName is undefined) (default: false)\n */\nfunction Index (options) {\n  this.fieldName = options.fieldName;\n  this.unique = options.unique || false;\n  this.sparse = options.sparse || false;\n\n  this.treeOptions = { unique: this.unique, compareKeys: model.compareThings, checkValueEquality: checkValueEquality };\n\n  this.reset();   // No data in the beginning\n}\n\n\n/**\n * Reset an index\n * @param {Document or Array of documents} newData Optional, data to initialize the index with\n *                                                 If an error is thrown during insertion, the index is not modified\n */\nIndex.prototype.reset = function (newData) {\n  this.tree = new BinarySearchTree(this.treeOptions);\n\n  if (newData) { this.insert(newData); }\n};\n\n\n/**\n * Insert a new document in the index\n * If an array is passed, we insert all its elements (if one insertion fails the index is not modified)\n * O(log(n))\n */\nIndex.prototype.insert = function (doc) {\n  var key, self = this\n    , keys, i, failingI, error\n    ;\n\n  if (util.isArray(doc)) { this.insertMultipleDocs(doc); return; }\n\n  key = model.getDotValue(doc, this.fieldName);\n\n  // We don't index documents that don't contain the field if the index is sparse\n  if (key === undefined && this.sparse) { return; }\n\n  if (!util.isArray(key)) {\n    this.tree.insert(key, doc);\n  } else {\n    // If an insert fails due to a unique constraint, roll back all inserts before it\n    keys = _.uniq(key, projectForUnique);\n\n    for (i = 0; i < keys.length; i += 1) {\n      try {\n        this.tree.insert(keys[i], doc);\n      } catch (e) {\n        error = e;\n        failingI = i;\n        break;\n      }\n    }\n\n    if (error) {\n      for (i = 0; i < failingI; i += 1) {\n        this.tree.delete(keys[i], doc);\n      }\n\n      throw error;\n    }\n  }\n};\n\n\n/**\n * Insert an array of documents in the index\n * If a constraint is violated, the changes should be rolled back and an error thrown\n *\n * @API private\n */\nIndex.prototype.insertMultipleDocs = function (docs) {\n  var i, error, failingI;\n\n  for (i = 0; i < docs.length; i += 1) {\n    try {\n      this.insert(docs[i]);\n    } catch (e) {\n      error = e;\n      failingI = i;\n      break;\n    }\n  }\n\n  if (error) {\n    for (i = 0; i < failingI; i += 1) {\n      this.remove(docs[i]);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Remove a document from the index\n * If an array is passed, we remove all its elements\n * The remove operation is safe with regards to the 'unique' constraint\n * O(log(n))\n */\nIndex.prototype.remove = function (doc) {\n  var key, self = this;\n\n  if (util.isArray(doc)) { doc.forEach(function (d) { self.remove(d); }); return; }\n\n  key = model.getDotValue(doc, this.fieldName);\n\n  if (key === undefined && this.sparse) { return; }\n\n  if (!util.isArray(key)) {\n    this.tree.delete(key, doc);\n  } else {\n    _.uniq(key, projectForUnique).forEach(function (_key) {\n      self.tree.delete(_key, doc);\n    });\n  }\n};\n\n\n/**\n * Update a document in the index\n * If a constraint is violated, changes are rolled back and an error thrown\n * Naive implementation, still in O(log(n))\n */\nIndex.prototype.update = function (oldDoc, newDoc) {\n  if (util.isArray(oldDoc)) { this.updateMultipleDocs(oldDoc); return; }\n\n  this.remove(oldDoc);\n\n  try {\n    this.insert(newDoc);\n  } catch (e) {\n    this.insert(oldDoc);\n    throw e;\n  }\n};\n\n\n/**\n * Update multiple documents in the index\n * If a constraint is violated, the changes need to be rolled back\n * and an error thrown\n * @param {Array of oldDoc, newDoc pairs} pairs\n *\n * @API private\n */\nIndex.prototype.updateMultipleDocs = function (pairs) {\n  var i, failingI, error;\n\n  for (i = 0; i < pairs.length; i += 1) {\n    this.remove(pairs[i].oldDoc);\n  }\n\n  for (i = 0; i < pairs.length; i += 1) {\n    try {\n      this.insert(pairs[i].newDoc);\n    } catch (e) {\n      error = e;\n      failingI = i;\n      break;\n    }\n  }\n\n  // If an error was raised, roll back changes in the inverse order\n  if (error) {\n    for (i = 0; i < failingI; i += 1) {\n      this.remove(pairs[i].newDoc);\n    }\n\n    for (i = 0; i < pairs.length; i += 1) {\n      this.insert(pairs[i].oldDoc);\n    }\n\n    throw error;\n  }\n};\n\n\n/**\n * Revert an update\n */\nIndex.prototype.revertUpdate = function (oldDoc, newDoc) {\n  var revert = [];\n\n  if (!util.isArray(oldDoc)) {\n    this.update(newDoc, oldDoc);\n  } else {\n    oldDoc.forEach(function (pair) {\n      revert.push({ oldDoc: pair.newDoc, newDoc: pair.oldDoc });\n    });\n    this.update(revert);\n  }\n};\n\n\n/**\n * Get all documents in index whose key match value (if it is a Thing) or one of the elements of value (if it is an array of Things)\n * @param {Thing} value Value to match the key against\n * @return {Array of documents}\n */\nIndex.prototype.getMatching = function (value) {\n  var self = this;\n\n  if (!util.isArray(value)) {\n    return self.tree.search(value);\n  } else {\n    var _res = {}, res = [];\n\n    value.forEach(function (v) {\n      self.getMatching(v).forEach(function (doc) {\n        _res[doc._id] = doc;\n      });\n    });\n\n    Object.keys(_res).forEach(function (_id) {\n      res.push(_res[_id]);\n    });\n\n    return res;\n  }\n};\n\n\n/**\n * Get all documents in index whose key is between bounds are they are defined by query\n * Documents are sorted by key\n * @param {Query} query\n * @return {Array of documents}\n */\nIndex.prototype.getBetweenBounds = function (query) {\n  return this.tree.betweenBounds(query);\n};\n\n\n/**\n * Get all elements in the index\n * @return {Array of documents}\n */\nIndex.prototype.getAll = function () {\n  var res = [];\n\n  this.tree.executeOnEveryNode(function (node) {\n    var i;\n\n    for (i = 0; i < node.data.length; i += 1) {\n      res.push(node.data[i]);\n    }\n  });\n\n  return res;\n};\n\n\n\n\n// Interface\nmodule.exports = Index;\n"
  },
  {
    "path": "lib/model.js",
    "content": "/**\n * Handle models (i.e. docs)\n * Serialization/deserialization\n * Copying\n * Querying, update\n */\n\nvar util = require('util')\n  , _ = require('underscore')\n  , modifierFunctions = {}\n  , lastStepModifierFunctions = {}\n  , comparisonFunctions = {}\n  , logicalOperators = {}\n  , arrayComparisonFunctions = {}\n  ;\n\n\n/**\n * Check a key, throw an error if the key is non valid\n * @param {String} k key\n * @param {Model} v value, needed to treat the Date edge case\n * Non-treatable edge cases here: if part of the object if of the form { $$date: number } or { $$deleted: true }\n * Its serialized-then-deserialized version it will transformed into a Date object\n * But you really need to want it to trigger such behaviour, even when warned not to use '$' at the beginning of the field names...\n */\nfunction checkKey (k, v) {\n  if (typeof k === 'number') {\n    k = k.toString();\n  }\n\n  if (k[0] === '$' && !(k === '$$date' && typeof v === 'number') && !(k === '$$deleted' && v === true) && !(k === '$$indexCreated') && !(k === '$$indexRemoved')) {\n    throw new Error('Field names cannot begin with the $ character');\n  }\n\n  if (k.indexOf('.') !== -1) {\n    throw new Error('Field names cannot contain a .');\n  }\n}\n\n\n/**\n * Check a DB object and throw an error if it's not valid\n * Works by applying the above checkKey function to all fields recursively\n */\nfunction checkObject (obj) {\n  if (util.isArray(obj)) {\n    obj.forEach(function (o) {\n      checkObject(o);\n    });\n  }\n\n  if (typeof obj === 'object' && obj !== null) {\n    Object.keys(obj).forEach(function (k) {\n      checkKey(k, obj[k]);\n      checkObject(obj[k]);\n    });\n  }\n}\n\n\n/**\n * Serialize an object to be persisted to a one-line string\n * For serialization/deserialization, we use the native JSON parser and not eval or Function\n * That gives us less freedom but data entered in the database may come from users\n * so eval and the like are not safe\n * Accepted primitive types: Number, String, Boolean, Date, null\n * Accepted secondary types: Objects, Arrays\n */\nfunction serialize (obj) {\n  var res;\n\n  res = JSON.stringify(obj, function (k, v) {\n    checkKey(k, v);\n\n    if (v === undefined) { return undefined; }\n    if (v === null) { return null; }\n\n    // Hackish way of checking if object is Date (this way it works between execution contexts in node-webkit).\n    // We can't use value directly because for dates it is already string in this function (date.toJSON was already called), so we use this\n    if (typeof this[k].getTime === 'function') { return { $$date: this[k].getTime() }; }\n\n    return v;\n  });\n\n  return res;\n}\n\n\n/**\n * From a one-line representation of an object generate by the serialize function\n * Return the object itself\n */\nfunction deserialize (rawData) {\n  return JSON.parse(rawData, function (k, v) {\n    if (k === '$$date') { return new Date(v); }\n    if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || v === null) { return v; }\n    if (v && v.$$date) { return v.$$date; }\n\n    return v;\n  });\n}\n\n\n/**\n * Deep copy a DB object\n * The optional strictKeys flag (defaulting to false) indicates whether to copy everything or only fields\n * where the keys are valid, i.e. don't begin with $ and don't contain a .\n */\nfunction deepCopy (obj, strictKeys) {\n  var res;\n\n  if ( typeof obj === 'boolean' ||\n       typeof obj === 'number' ||\n       typeof obj === 'string' ||\n       obj === null ||\n       (util.isDate(obj)) ) {\n    return obj;\n  }\n\n  if (util.isArray(obj)) {\n    res = [];\n    obj.forEach(function (o) { res.push(deepCopy(o, strictKeys)); });\n    return res;\n  }\n\n  if (typeof obj === 'object') {\n    res = {};\n    Object.keys(obj).forEach(function (k) {\n      if (!strictKeys || (k[0] !== '$' && k.indexOf('.') === -1)) {\n        res[k] = deepCopy(obj[k], strictKeys);\n      }\n    });\n    return res;\n  }\n\n  return undefined;   // For now everything else is undefined. We should probably throw an error instead\n}\n\n\n/**\n * Tells if an object is a primitive type or a \"real\" object\n * Arrays are considered primitive\n */\nfunction isPrimitiveType (obj) {\n  return ( typeof obj === 'boolean' ||\n       typeof obj === 'number' ||\n       typeof obj === 'string' ||\n       obj === null ||\n       util.isDate(obj) ||\n       util.isArray(obj));\n}\n\n\n/**\n * Utility functions for comparing things\n * Assumes type checking was already done (a and b already have the same type)\n * compareNSB works for numbers, strings and booleans\n */\nfunction compareNSB (a, b) {\n  if (a < b) { return -1; }\n  if (a > b) { return 1; }\n  return 0;\n}\n\nfunction compareArrays (a, b) {\n  var i, comp;\n\n  for (i = 0; i < Math.min(a.length, b.length); i += 1) {\n    comp = compareThings(a[i], b[i]);\n\n    if (comp !== 0) { return comp; }\n  }\n\n  // Common section was identical, longest one wins\n  return compareNSB(a.length, b.length);\n}\n\n\n/**\n * Compare { things U undefined }\n * Things are defined as any native types (string, number, boolean, null, date) and objects\n * We need to compare with undefined as it will be used in indexes\n * In the case of objects and arrays, we deep-compare\n * If two objects dont have the same type, the (arbitrary) type hierarchy is: undefined, null, number, strings, boolean, dates, arrays, objects\n * Return -1 if a < b, 1 if a > b and 0 if a = b (note that equality here is NOT the same as defined in areThingsEqual!)\n *\n * @param {Function} _compareStrings String comparing function, returning -1, 0 or 1, overriding default string comparison (useful for languages with accented letters)\n */\nfunction compareThings (a, b, _compareStrings) {\n  var aKeys, bKeys, comp, i\n    , compareStrings = _compareStrings || compareNSB;\n\n  // undefined\n  if (a === undefined) { return b === undefined ? 0 : -1; }\n  if (b === undefined) { return a === undefined ? 0 : 1; }\n\n  // null\n  if (a === null) { return b === null ? 0 : -1; }\n  if (b === null) { return a === null ? 0 : 1; }\n\n  // Numbers\n  if (typeof a === 'number') { return typeof b === 'number' ? compareNSB(a, b) : -1; }\n  if (typeof b === 'number') { return typeof a === 'number' ? compareNSB(a, b) : 1; }\n\n  // Strings\n  if (typeof a === 'string') { return typeof b === 'string' ? compareStrings(a, b) : -1; }\n  if (typeof b === 'string') { return typeof a === 'string' ? compareStrings(a, b) : 1; }\n\n  // Booleans\n  if (typeof a === 'boolean') { return typeof b === 'boolean' ? compareNSB(a, b) : -1; }\n  if (typeof b === 'boolean') { return typeof a === 'boolean' ? compareNSB(a, b) : 1; }\n\n  // Dates\n  if (util.isDate(a)) { return util.isDate(b) ? compareNSB(a.getTime(), b.getTime()) : -1; }\n  if (util.isDate(b)) { return util.isDate(a) ? compareNSB(a.getTime(), b.getTime()) : 1; }\n\n  // Arrays (first element is most significant and so on)\n  if (util.isArray(a)) { return util.isArray(b) ? compareArrays(a, b) : -1; }\n  if (util.isArray(b)) { return util.isArray(a) ? compareArrays(a, b) : 1; }\n\n  // Objects\n  aKeys = Object.keys(a).sort();\n  bKeys = Object.keys(b).sort();\n\n  for (i = 0; i < Math.min(aKeys.length, bKeys.length); i += 1) {\n    comp = compareThings(a[aKeys[i]], b[bKeys[i]]);\n\n    if (comp !== 0) { return comp; }\n  }\n\n  return compareNSB(aKeys.length, bKeys.length);\n}\n\n\n\n// ==============================================================\n// Updating documents\n// ==============================================================\n\n/**\n * The signature of modifier functions is as follows\n * Their structure is always the same: recursively follow the dot notation while creating\n * the nested documents if needed, then apply the \"last step modifier\"\n * @param {Object} obj The model to modify\n * @param {String} field Can contain dots, in that case that means we will set a subfield recursively\n * @param {Model} value\n */\n\n/**\n * Set a field to a new value\n */\nlastStepModifierFunctions.$set = function (obj, field, value) {\n  obj[field] = value;\n};\n\n\n/**\n * Unset a field\n */\nlastStepModifierFunctions.$unset = function (obj, field, value) {\n  delete obj[field];\n};\n\n\n/**\n * Push an element to the end of an array field\n * Optional modifier $each instead of value to push several values\n * Optional modifier $slice to slice the resulting array, see https://docs.mongodb.org/manual/reference/operator/update/slice/\n * Différeence with MongoDB: if $slice is specified and not $each, we act as if value is an empty array\n */\nlastStepModifierFunctions.$push = function (obj, field, value) {\n  // Create the array if it doesn't exist\n  if (!obj.hasOwnProperty(field)) { obj[field] = []; }\n\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $push an element on non-array values\"); }\n\n  if (value !== null && typeof value === 'object' && value.$slice && value.$each === undefined) {\n    value.$each = [];\n  }\n\n  if (value !== null && typeof value === 'object' && value.$each) {\n    if (Object.keys(value).length >= 3 || (Object.keys(value).length === 2 && value.$slice === undefined)) { throw new Error(\"Can only use $slice in cunjunction with $each when $push to array\"); }\n    if (!util.isArray(value.$each)) { throw new Error(\"$each requires an array value\"); }\n\n    value.$each.forEach(function (v) {\n      obj[field].push(v);\n    });\n\n    if (value.$slice === undefined || typeof value.$slice !== 'number') { return; }\n\n    if (value.$slice === 0) {\n      obj[field] = [];\n    } else {\n      var start, end, n = obj[field].length;\n      if (value.$slice < 0) {\n        start = Math.max(0, n + value.$slice);\n        end = n;\n      } else if (value.$slice > 0) {\n        start = 0;\n        end = Math.min(n, value.$slice);\n      }\n      obj[field] = obj[field].slice(start, end);\n    }\n  } else {\n    obj[field].push(value);\n  }\n};\n\n\n/**\n * Add an element to an array field only if it is not already in it\n * No modification if the element is already in the array\n * Note that it doesn't check whether the original array contains duplicates\n */\nlastStepModifierFunctions.$addToSet = function (obj, field, value) {\n  var addToSet = true;\n\n  // Create the array if it doesn't exist\n  if (!obj.hasOwnProperty(field)) { obj[field] = []; }\n\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $addToSet an element on non-array values\"); }\n\n  if (value !== null && typeof value === 'object' && value.$each) {\n    if (Object.keys(value).length > 1) { throw new Error(\"Can't use another field in conjunction with $each\"); }\n    if (!util.isArray(value.$each)) { throw new Error(\"$each requires an array value\"); }\n\n    value.$each.forEach(function (v) {\n      lastStepModifierFunctions.$addToSet(obj, field, v);\n    });\n  } else {\n    obj[field].forEach(function (v) {\n      if (compareThings(v, value) === 0) { addToSet = false; }\n    });\n    if (addToSet) { obj[field].push(value); }\n  }\n};\n\n\n/**\n * Remove the first or last element of an array\n */\nlastStepModifierFunctions.$pop = function (obj, field, value) {\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $pop an element from non-array values\"); }\n  if (typeof value !== 'number') { throw new Error(value + \" isn't an integer, can't use it with $pop\"); }\n  if (value === 0) { return; }\n\n  if (value > 0) {\n    obj[field] = obj[field].slice(0, obj[field].length - 1);\n  } else {\n    obj[field] = obj[field].slice(1);\n  }\n};\n\n\n/**\n * Removes all instances of a value from an existing array\n */\nlastStepModifierFunctions.$pull = function (obj, field, value) {\n  var arr, i;\n\n  if (!util.isArray(obj[field])) { throw new Error(\"Can't $pull an element from non-array values\"); }\n\n  arr = obj[field];\n  for (i = arr.length - 1; i >= 0; i -= 1) {\n    if (match(arr[i], value)) {\n      arr.splice(i, 1);\n    }\n  }\n};\n\n\n/**\n * Increment a numeric field's value\n */\nlastStepModifierFunctions.$inc = function (obj, field, value) {\n  if (typeof value !== 'number') { throw new Error(value + \" must be a number\"); }\n\n  if (typeof obj[field] !== 'number') {\n    if (!_.has(obj, field)) {\n      obj[field] = value;\n    } else {\n      throw new Error(\"Don't use the $inc modifier on non-number fields\");\n    }\n  } else {\n    obj[field] += value;\n  }\n};\n\n/**\n * Updates the value of the field, only if specified field is greater than the current value of the field\n */\nlastStepModifierFunctions.$max = function (obj, field, value) {\n  if (typeof obj[field] === 'undefined') {\n    obj[field] = value;\n  } else if (value > obj[field]) {\n    obj[field] = value;\n  }\n};\n\n/**\n * Updates the value of the field, only if specified field is smaller than the current value of the field\n */\nlastStepModifierFunctions.$min = function (obj, field, value) {\n  if (typeof obj[field] === 'undefined') { \n    obj[field] = value;\n  } else if (value < obj[field]) {\n    obj[field] = value;\n  }\n};\n\n// Given its name, create the complete modifier function\nfunction createModifierFunction (modifier) {\n  return function (obj, field, value) {\n    var fieldParts = typeof field === 'string' ? field.split('.') : field;\n\n    if (fieldParts.length === 1) {\n      lastStepModifierFunctions[modifier](obj, field, value);\n    } else {\n      if (obj[fieldParts[0]] === undefined) {\n        if (modifier === '$unset') { return; }   // Bad looking specific fix, needs to be generalized modifiers that behave like $unset are implemented\n        obj[fieldParts[0]] = {};\n      }\n      modifierFunctions[modifier](obj[fieldParts[0]], fieldParts.slice(1), value);\n    }\n  };\n}\n\n// Actually create all modifier functions\nObject.keys(lastStepModifierFunctions).forEach(function (modifier) {\n  modifierFunctions[modifier] = createModifierFunction(modifier);\n});\n\n\n/**\n * Modify a DB object according to an update query\n */\nfunction modify (obj, updateQuery) {\n  var keys = Object.keys(updateQuery)\n    , firstChars = _.map(keys, function (item) { return item[0]; })\n    , dollarFirstChars = _.filter(firstChars, function (c) { return c === '$'; })\n    , newDoc, modifiers\n    ;\n\n  if (keys.indexOf('_id') !== -1 && updateQuery._id !== obj._id) { throw new Error(\"You cannot change a document's _id\"); }\n\n  if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) {\n    throw new Error(\"You cannot mix modifiers and normal fields\");\n  }\n\n  if (dollarFirstChars.length === 0) {\n    // Simply replace the object with the update query contents\n    newDoc = deepCopy(updateQuery);\n    newDoc._id = obj._id;\n  } else {\n    // Apply modifiers\n    modifiers = _.uniq(keys);\n    newDoc = deepCopy(obj);\n    modifiers.forEach(function (m) {\n      var keys;\n\n      if (!modifierFunctions[m]) { throw new Error(\"Unknown modifier \" + m); }\n\n      // Can't rely on Object.keys throwing on non objects since ES6\n      // Not 100% satisfying as non objects can be interpreted as objects but no false negatives so we can live with it\n      if (typeof updateQuery[m] !== 'object') {\n        throw new Error(\"Modifier \" + m + \"'s argument must be an object\");\n      }\n\n      keys = Object.keys(updateQuery[m]);\n      keys.forEach(function (k) {\n        modifierFunctions[m](newDoc, k, updateQuery[m][k]);\n      });\n    });\n  }\n\n  // Check result is valid and return it\n  checkObject(newDoc);\n\n  if (obj._id !== newDoc._id) { throw new Error(\"You can't change a document's _id\"); }\n  return newDoc;\n};\n\n\n// ==============================================================\n// Finding documents\n// ==============================================================\n\n/**\n * Get a value from object with dot notation\n * @param {Object} obj\n * @param {String} field\n */\nfunction getDotValue (obj, field) {\n  var fieldParts = typeof field === 'string' ? field.split('.') : field\n    , i, objs;\n\n  if (!obj) { return undefined; }   // field cannot be empty so that means we should return undefined so that nothing can match\n\n  if (fieldParts.length === 0) { return obj; }\n\n  if (fieldParts.length === 1) { return obj[fieldParts[0]]; }\n\n  if (util.isArray(obj[fieldParts[0]])) {\n    // If the next field is an integer, return only this item of the array\n    i = parseInt(fieldParts[1], 10);\n    if (typeof i === 'number' && !isNaN(i)) {\n      return getDotValue(obj[fieldParts[0]][i], fieldParts.slice(2))\n    }\n\n    // Return the array of values\n    objs = new Array();\n    for (i = 0; i < obj[fieldParts[0]].length; i += 1) {\n       objs.push(getDotValue(obj[fieldParts[0]][i], fieldParts.slice(1)));\n    }\n    return objs;\n  } else {\n    return getDotValue(obj[fieldParts[0]], fieldParts.slice(1));\n  }\n}\n\n\n/**\n * Check whether 'things' are equal\n * Things are defined as any native types (string, number, boolean, null, date) and objects\n * In the case of object, we check deep equality\n * Returns true if they are, false otherwise\n */\nfunction areThingsEqual (a, b) {\n  var aKeys , bKeys , i;\n\n  // Strings, booleans, numbers, null\n  if (a === null || typeof a === 'string' || typeof a === 'boolean' || typeof a === 'number' ||\n      b === null || typeof b === 'string' || typeof b === 'boolean' || typeof b === 'number') { return a === b; }\n\n  // Dates\n  if (util.isDate(a) || util.isDate(b)) { return util.isDate(a) && util.isDate(b) && a.getTime() === b.getTime(); }\n\n  // Arrays (no match since arrays are used as a $in)\n  // undefined (no match since they mean field doesn't exist and can't be serialized)\n  if ((!(util.isArray(a) && util.isArray(b)) && (util.isArray(a) || util.isArray(b))) || a === undefined || b === undefined) { return false; }\n\n  // General objects (check for deep equality)\n  // a and b should be objects at this point\n  try {\n    aKeys = Object.keys(a);\n    bKeys = Object.keys(b);\n  } catch (e) {\n    return false;\n  }\n\n  if (aKeys.length !== bKeys.length) { return false; }\n  for (i = 0; i < aKeys.length; i += 1) {\n    if (bKeys.indexOf(aKeys[i]) === -1) { return false; }\n    if (!areThingsEqual(a[aKeys[i]], b[aKeys[i]])) { return false; }\n  }\n  return true;\n}\n\n\n/**\n * Check that two values are comparable\n */\nfunction areComparable (a, b) {\n  if (typeof a !== 'string' && typeof a !== 'number' && !util.isDate(a) &&\n      typeof b !== 'string' && typeof b !== 'number' && !util.isDate(b)) {\n    return false;\n  }\n\n  if (typeof a !== typeof b) { return false; }\n\n  return true;\n}\n\n\n/**\n * Arithmetic and comparison operators\n * @param {Native value} a Value in the object\n * @param {Native value} b Value in the query\n */\ncomparisonFunctions.$lt = function (a, b) {\n  return areComparable(a, b) && a < b;\n};\n\ncomparisonFunctions.$lte = function (a, b) {\n  return areComparable(a, b) && a <= b;\n};\n\ncomparisonFunctions.$gt = function (a, b) {\n  return areComparable(a, b) && a > b;\n};\n\ncomparisonFunctions.$gte = function (a, b) {\n  return areComparable(a, b) && a >= b;\n};\n\ncomparisonFunctions.$ne = function (a, b) {\n  if (a === undefined) { return true; }\n  return !areThingsEqual(a, b);\n};\n\ncomparisonFunctions.$in = function (a, b) {\n  var i;\n\n  if (!util.isArray(b)) { throw new Error(\"$in operator called with a non-array\"); }\n\n  for (i = 0; i < b.length; i += 1) {\n    if (areThingsEqual(a, b[i])) { return true; }\n  }\n\n  return false;\n};\n\ncomparisonFunctions.$nin = function (a, b) {\n  if (!util.isArray(b)) { throw new Error(\"$nin operator called with a non-array\"); }\n\n  return !comparisonFunctions.$in(a, b);\n};\n\ncomparisonFunctions.$regex = function (a, b) {\n  if (!util.isRegExp(b)) { throw new Error(\"$regex operator called with non regular expression\"); }\n\n  if (typeof a !== 'string') {\n    return false\n  } else {\n    return b.test(a);\n  }\n};\n\ncomparisonFunctions.$exists = function (value, exists) {\n  if (exists || exists === '') {   // This will be true for all values of exists except false, null, undefined and 0\n    exists = true;                 // That's strange behaviour (we should only use true/false) but that's the way Mongo does it...\n  } else {\n    exists = false;\n  }\n\n  if (value === undefined) {\n    return !exists\n  } else {\n    return exists;\n  }\n};\n\n// Specific to arrays\ncomparisonFunctions.$size = function (obj, value) {\n    if (!util.isArray(obj)) { return false; }\n    if (value % 1 !== 0) { throw new Error(\"$size operator called without an integer\"); }\n\n    return (obj.length == value);\n};\ncomparisonFunctions.$elemMatch = function (obj, value) {\n  if (!util.isArray(obj)) { return false; }\n  var i = obj.length;\n  var result = false;   // Initialize result\n  while (i--) {\n    if (match(obj[i], value)) {   // If match for array element, return true\n      result = true;\n      break;\n    }\n  }\n  return result;\n};\narrayComparisonFunctions.$size = true;\narrayComparisonFunctions.$elemMatch = true;\n\n\n/**\n * Match any of the subqueries\n * @param {Model} obj\n * @param {Array of Queries} query\n */\nlogicalOperators.$or = function (obj, query) {\n  var i;\n\n  if (!util.isArray(query)) { throw new Error(\"$or operator used without an array\"); }\n\n  for (i = 0; i < query.length; i += 1) {\n    if (match(obj, query[i])) { return true; }\n  }\n\n  return false;\n};\n\n\n/**\n * Match all of the subqueries\n * @param {Model} obj\n * @param {Array of Queries} query\n */\nlogicalOperators.$and = function (obj, query) {\n  var i;\n\n  if (!util.isArray(query)) { throw new Error(\"$and operator used without an array\"); }\n\n  for (i = 0; i < query.length; i += 1) {\n    if (!match(obj, query[i])) { return false; }\n  }\n\n  return true;\n};\n\n\n/**\n * Inverted match of the query\n * @param {Model} obj\n * @param {Query} query\n */\nlogicalOperators.$not = function (obj, query) {\n  return !match(obj, query);\n};\n\n\n/**\n * Use a function to match\n * @param {Model} obj\n * @param {Query} query\n */\nlogicalOperators.$where = function (obj, fn) {\n  var result;\n\n  if (!_.isFunction(fn)) { throw new Error(\"$where operator used without a function\"); }\n\n  result = fn.call(obj);\n  if (!_.isBoolean(result)) { throw new Error(\"$where function must return boolean\"); }\n\n  return result;\n};\n\n\n/**\n * Tell if a given document matches a query\n * @param {Object} obj Document to check\n * @param {Object} query\n */\nfunction match (obj, query) {\n  var queryKeys, queryKey, queryValue, i;\n\n  // Primitive query against a primitive type\n  // This is a bit of a hack since we construct an object with an arbitrary key only to dereference it later\n  // But I don't have time for a cleaner implementation now\n  if (isPrimitiveType(obj) || isPrimitiveType(query)) {\n    return matchQueryPart({ needAKey: obj }, 'needAKey', query);\n  }\n\n  // Normal query\n  queryKeys = Object.keys(query);\n  for (i = 0; i < queryKeys.length; i += 1) {\n    queryKey = queryKeys[i];\n    queryValue = query[queryKey];\n\n    if (queryKey[0] === '$') {\n      if (!logicalOperators[queryKey]) { throw new Error(\"Unknown logical operator \" + queryKey); }\n      if (!logicalOperators[queryKey](obj, queryValue)) { return false; }\n    } else {\n      if (!matchQueryPart(obj, queryKey, queryValue)) { return false; }\n    }\n  }\n\n  return true;\n};\n\n\n/**\n * Match an object against a specific { key: value } part of a query\n * if the treatObjAsValue flag is set, don't try to match every part separately, but the array as a whole\n */\nfunction matchQueryPart (obj, queryKey, queryValue, treatObjAsValue) {\n  var objValue = getDotValue(obj, queryKey)\n    , i, keys, firstChars, dollarFirstChars;\n\n  // Check if the value is an array if we don't force a treatment as value\n  if (util.isArray(objValue) && !treatObjAsValue) {\n    // If the queryValue is an array, try to perform an exact match\n    if (util.isArray(queryValue)) {\n      return matchQueryPart(obj, queryKey, queryValue, true);\n    }\n\n    // Check if we are using an array-specific comparison function\n    if (queryValue !== null && typeof queryValue === 'object' && !util.isRegExp(queryValue)) {\n      keys = Object.keys(queryValue);\n      for (i = 0; i < keys.length; i += 1) {\n        if (arrayComparisonFunctions[keys[i]]) { return matchQueryPart(obj, queryKey, queryValue, true); }\n      }\n    }\n\n    // If not, treat it as an array of { obj, query } where there needs to be at least one match\n    for (i = 0; i < objValue.length; i += 1) {\n      if (matchQueryPart({ k: objValue[i] }, 'k', queryValue)) { return true; }   // k here could be any string\n    }\n    return false;\n  }\n\n  // queryValue is an actual object. Determine whether it contains comparison operators\n  // or only normal fields. Mixed objects are not allowed\n  if (queryValue !== null && typeof queryValue === 'object' && !util.isRegExp(queryValue) && !util.isArray(queryValue)) {\n    keys = Object.keys(queryValue);\n    firstChars = _.map(keys, function (item) { return item[0]; });\n    dollarFirstChars = _.filter(firstChars, function (c) { return c === '$'; });\n\n    if (dollarFirstChars.length !== 0 && dollarFirstChars.length !== firstChars.length) {\n      throw new Error(\"You cannot mix operators and normal fields\");\n    }\n\n    // queryValue is an object of this form: { $comparisonOperator1: value1, ... }\n    if (dollarFirstChars.length > 0) {\n      for (i = 0; i < keys.length; i += 1) {\n        if (!comparisonFunctions[keys[i]]) { throw new Error(\"Unknown comparison function \" + keys[i]); }\n\n        if (!comparisonFunctions[keys[i]](objValue, queryValue[keys[i]])) { return false; }\n      }\n      return true;\n    }\n  }\n\n  // Using regular expressions with basic querying\n  if (util.isRegExp(queryValue)) { return comparisonFunctions.$regex(objValue, queryValue); }\n\n  // queryValue is either a native value or a normal object\n  // Basic matching is possible\n  if (!areThingsEqual(objValue, queryValue)) { return false; }\n\n  return true;\n}\n\n\n// Interface\nmodule.exports.serialize = serialize;\nmodule.exports.deserialize = deserialize;\nmodule.exports.deepCopy = deepCopy;\nmodule.exports.checkObject = checkObject;\nmodule.exports.isPrimitiveType = isPrimitiveType;\nmodule.exports.modify = modify;\nmodule.exports.getDotValue = getDotValue;\nmodule.exports.match = match;\nmodule.exports.areThingsEqual = areThingsEqual;\nmodule.exports.compareThings = compareThings;\n"
  },
  {
    "path": "lib/persistence.js",
    "content": "/**\n * Handle every persistence-related task\n * The interface Datastore expects to be implemented is\n * * Persistence.loadDatabase(callback) and callback has signature err\n * * Persistence.persistNewState(newDocs, callback) where newDocs is an array of documents and callback has signature err\n */\n\nvar storage = require('./storage')\n  , path = require('path')\n  , model = require('./model')\n  , async = require('async')\n  , customUtils = require('./customUtils')\n  , Index = require('./indexes')\n  ;\n\n\n/**\n * Create a new Persistence object for database options.db\n * @param {Datastore} options.db\n * @param {Boolean} options.nodeWebkitAppName Optional, specify the name of your NW app if you want options.filename to be relative to the directory where\n *                                            Node Webkit stores application data such as cookies and local storage (the best place to store data in my opinion)\n */\nfunction Persistence (options) {\n  var i, j, randomString;\n\n  this.db = options.db;\n  this.inMemoryOnly = this.db.inMemoryOnly;\n  this.filename = this.db.filename;\n  this.corruptAlertThreshold = options.corruptAlertThreshold !== undefined ? options.corruptAlertThreshold : 0.1;\n\n  if (!this.inMemoryOnly && this.filename && this.filename.charAt(this.filename.length - 1) === '~') {\n    throw new Error(\"The datafile name can't end with a ~, which is reserved for crash safe backup files\");\n  }\n\n  // After serialization and before deserialization hooks with some basic sanity checks\n  if (options.afterSerialization && !options.beforeDeserialization) {\n    throw new Error(\"Serialization hook defined but deserialization hook undefined, cautiously refusing to start NeDB to prevent dataloss\");\n  }\n  if (!options.afterSerialization && options.beforeDeserialization) {\n    throw new Error(\"Serialization hook undefined but deserialization hook defined, cautiously refusing to start NeDB to prevent dataloss\");\n  }\n  this.afterSerialization = options.afterSerialization || function (s) { return s; };\n  this.beforeDeserialization = options.beforeDeserialization || function (s) { return s; };\n  for (i = 1; i < 30; i += 1) {\n    for (j = 0; j < 10; j += 1) {\n      randomString = customUtils.uid(i);\n      if (this.beforeDeserialization(this.afterSerialization(randomString)) !== randomString) {\n        throw new Error(\"beforeDeserialization is not the reverse of afterSerialization, cautiously refusing to start NeDB to prevent dataloss\");\n      }\n    }\n  }\n\n  // For NW apps, store data in the same directory where NW stores application data\n  if (this.filename && options.nodeWebkitAppName) {\n    console.log(\"==================================================================\");\n    console.log(\"WARNING: The nodeWebkitAppName option is deprecated\");\n    console.log(\"To get the path to the directory where Node Webkit stores the data\");\n    console.log(\"for your app, use the internal nw.gui module like this\");\n    console.log(\"require('nw.gui').App.dataPath\");\n    console.log(\"See https://github.com/rogerwang/node-webkit/issues/500\");\n    console.log(\"==================================================================\");\n    this.filename = Persistence.getNWAppFilename(options.nodeWebkitAppName, this.filename);\n  }\n};\n\n\n/**\n * Check if a directory exists and create it on the fly if it is not the case\n * cb is optional, signature: err\n */\nPersistence.ensureDirectoryExists = function (dir, cb) {\n  var callback = cb || function () {}\n    ;\n\n  storage.mkdirp(dir, function (err) { return callback(err); });\n};\n\n\n\n\n/**\n * Return the path the datafile if the given filename is relative to the directory where Node Webkit stores\n * data for this application. Probably the best place to store data\n */\nPersistence.getNWAppFilename = function (appName, relativeFilename) {\n  var home;\n\n  switch (process.platform) {\n    case 'win32':\n    case 'win64':\n      home = process.env.LOCALAPPDATA || process.env.APPDATA;\n      if (!home) { throw new Error(\"Couldn't find the base application data folder\"); }\n      home = path.join(home, appName);\n      break;\n    case 'darwin':\n      home = process.env.HOME;\n      if (!home) { throw new Error(\"Couldn't find the base application data directory\"); }\n      home = path.join(home, 'Library', 'Application Support', appName);\n      break;\n    case 'linux':\n      home = process.env.HOME;\n      if (!home) { throw new Error(\"Couldn't find the base application data directory\"); }\n      home = path.join(home, '.config', appName);\n      break;\n    default:\n      throw new Error(\"Can't use the Node Webkit relative path for platform \" + process.platform);\n      break;\n  }\n\n  return path.join(home, 'nedb-data', relativeFilename);\n}\n\n\n/**\n * Persist cached database\n * This serves as a compaction function since the cache always contains only the number of documents in the collection\n * while the data file is append-only so it may grow larger\n * @param {Function} cb Optional callback, signature: err\n */\nPersistence.prototype.persistCachedDatabase = function (cb) {\n  var callback = cb || function () {}\n    , toPersist = ''\n    , self = this\n    ;\n\n  if (this.inMemoryOnly) { return callback(null); }\n\n  this.db.getAllData().forEach(function (doc) {\n    toPersist += self.afterSerialization(model.serialize(doc)) + '\\n';\n  });\n  Object.keys(this.db.indexes).forEach(function (fieldName) {\n    if (fieldName != \"_id\") {   // The special _id index is managed by datastore.js, the others need to be persisted\n      toPersist += self.afterSerialization(model.serialize({ $$indexCreated: { fieldName: fieldName, unique: self.db.indexes[fieldName].unique, sparse: self.db.indexes[fieldName].sparse }})) + '\\n';\n    }\n  });\n\n  storage.crashSafeWriteFile(this.filename, toPersist, function (err) {\n    if (err) { return callback(err); }\n    self.db.emit('compaction.done');\n    return callback(null);\n  });\n};\n\n\n/**\n * Queue a rewrite of the datafile\n */\nPersistence.prototype.compactDatafile = function () {\n  this.db.executor.push({ this: this, fn: this.persistCachedDatabase, arguments: [] });\n};\n\n\n/**\n * Set automatic compaction every interval ms\n * @param {Number} interval in milliseconds, with an enforced minimum of 5 seconds\n */\nPersistence.prototype.setAutocompactionInterval = function (interval) {\n  var self = this\n    , minInterval = 5000\n    , realInterval = Math.max(interval || 0, minInterval)\n    ;\n\n  this.stopAutocompaction();\n\n  this.autocompactionIntervalId = setInterval(function () {\n    self.compactDatafile();\n  }, realInterval);\n};\n\n\n/**\n * Stop autocompaction (do nothing if autocompaction was not running)\n */\nPersistence.prototype.stopAutocompaction = function () {\n  if (this.autocompactionIntervalId) { clearInterval(this.autocompactionIntervalId); }\n};\n\n\n/**\n * Persist new state for the given newDocs (can be insertion, update or removal)\n * Use an append-only format\n * @param {Array} newDocs Can be empty if no doc was updated/removed\n * @param {Function} cb Optional, signature: err\n */\nPersistence.prototype.persistNewState = function (newDocs, cb) {\n  var self = this\n    , toPersist = ''\n    , callback = cb || function () {}\n    ;\n\n  // In-memory only datastore\n  if (self.inMemoryOnly) { return callback(null); }\n\n  newDocs.forEach(function (doc) {\n    toPersist += self.afterSerialization(model.serialize(doc)) + '\\n';\n  });\n\n  if (toPersist.length === 0) { return callback(null); }\n\n  storage.appendFile(self.filename, toPersist, 'utf8', function (err) {\n    return callback(err);\n  });\n};\n\n\n/**\n * From a database's raw data, return the corresponding\n * machine understandable collection\n */\nPersistence.prototype.treatRawData = function (rawData) {\n  var data = rawData.split('\\n')\n    , dataById = {}\n    , tdata = []\n    , i\n    , indexes = {}\n    , corruptItems = -1   // Last line of every data file is usually blank so not really corrupt\n    ;\n\n  for (i = 0; i < data.length; i += 1) {\n    var doc;\n\n    try {\n      doc = model.deserialize(this.beforeDeserialization(data[i]));\n      if (doc._id) {\n        if (doc.$$deleted === true) {\n          delete dataById[doc._id];\n        } else {\n          dataById[doc._id] = doc;\n        }\n      } else if (doc.$$indexCreated && doc.$$indexCreated.fieldName != undefined) {\n        indexes[doc.$$indexCreated.fieldName] = doc.$$indexCreated;\n      } else if (typeof doc.$$indexRemoved === \"string\") {\n        delete indexes[doc.$$indexRemoved];\n      }\n    } catch (e) {\n      corruptItems += 1;\n    }\n  }\n\n  // A bit lenient on corruption\n  if (data.length > 0 && corruptItems / data.length > this.corruptAlertThreshold) {\n    throw new Error(\"More than \" + Math.floor(100 * this.corruptAlertThreshold) + \"% of the data file is corrupt, the wrong beforeDeserialization hook may be used. Cautiously refusing to start NeDB to prevent dataloss\");\n  }\n\n  Object.keys(dataById).forEach(function (k) {\n    tdata.push(dataById[k]);\n  });\n\n  return { data: tdata, indexes: indexes };\n};\n\n\n/**\n * Load the database\n * 1) Create all indexes\n * 2) Insert all data\n * 3) Compact the database\n * This means pulling data out of the data file or creating it if it doesn't exist\n * Also, all data is persisted right away, which has the effect of compacting the database file\n * This operation is very quick at startup for a big collection (60ms for ~10k docs)\n * @param {Function} cb Optional callback, signature: err\n */\nPersistence.prototype.loadDatabase = function (cb) {\n  var callback = cb || function () {}\n    , self = this\n    ;\n\n  self.db.resetIndexes();\n\n  // In-memory only datastore\n  if (self.inMemoryOnly) { return callback(null); }\n\n  async.waterfall([\n    function (cb) {\n      Persistence.ensureDirectoryExists(path.dirname(self.filename), function (err) {\n        storage.ensureDatafileIntegrity(self.filename, function (err) {\n          storage.readFile(self.filename, 'utf8', function (err, rawData) {\n            if (err) { return cb(err); }\n\n            try {\n              var treatedData = self.treatRawData(rawData);\n            } catch (e) {\n              return cb(e);\n            }\n\n            // Recreate all indexes in the datafile\n            Object.keys(treatedData.indexes).forEach(function (key) {\n              self.db.indexes[key] = new Index(treatedData.indexes[key]);\n            });\n\n            // Fill cached database (i.e. all indexes) with data\n            try {\n              self.db.resetIndexes(treatedData.data);\n            } catch (e) {\n              self.db.resetIndexes();   // Rollback any index which didn't fail\n              return cb(e);\n            }\n\n            self.db.persistence.persistCachedDatabase(cb);\n          });\n        });\n      });\n    }\n  ], function (err) {\n       if (err) { return callback(err); }\n\n       self.db.executor.processBuffer();\n       return callback(null);\n     });\n};\n\n\n// Interface\nmodule.exports = Persistence;\n"
  },
  {
    "path": "lib/storage.js",
    "content": "/**\n * Way data is stored for this database\n * For a Node.js/Node Webkit database it's the file system\n * For a browser-side database it's localforage which chooses the best option depending on user browser (IndexedDB then WebSQL then localStorage)\n *\n * This version is the Node.js/Node Webkit version\n * It's essentially fs, mkdirp and crash safe write and read functions\n */\n\nvar fs = require('fs')\n  , mkdirp = require('mkdirp')\n  , async = require('async')\n  , path = require('path')\n  , storage = {}\n  ;\n\nstorage.exists = fs.exists;\nstorage.rename = fs.rename;\nstorage.writeFile = fs.writeFile;\nstorage.unlink = fs.unlink;\nstorage.appendFile = fs.appendFile;\nstorage.readFile = fs.readFile;\nstorage.mkdirp = mkdirp;\n\n\n/**\n * Explicit name ...\n */\nstorage.ensureFileDoesntExist = function (file, callback) {\n  storage.exists(file, function (exists) {\n    if (!exists) { return callback(null); }\n\n    storage.unlink(file, function (err) { return callback(err); });\n  });\n};\n\n\n/**\n * Flush data in OS buffer to storage if corresponding option is set\n * @param {String} options.filename\n * @param {Boolean} options.isDir Optional, defaults to false\n * If options is a string, it is assumed that the flush of the file (not dir) called options was requested\n */\nstorage.flushToStorage = function (options, callback) {\n  var filename, flags;\n  if (typeof options === 'string') {\n    filename = options;\n    flags = 'r+';\n  } else {\n    filename = options.filename;\n    flags = options.isDir ? 'r' : 'r+';\n  }\n\n  // Windows can't fsync (FlushFileBuffers) directories. We can live with this as it cannot cause 100% dataloss\n  // except in the very rare event of the first time database is loaded and a crash happens\n  if (flags === 'r' && (process.platform === 'win32' || process.platform === 'win64')) { return callback(null); }\n\n  fs.open(filename, flags, function (err, fd) {\n    if (err) { return callback(err); }\n    fs.fsync(fd, function (errFS) {\n      fs.close(fd, function (errC) {\n        if (errFS || errC) {\n          var e = new Error('Failed to flush to storage');\n          e.errorOnFsync = errFS;\n          e.errorOnClose = errC;\n          return callback(e);\n        } else {\n          return callback(null);\n        }\n      });\n    });\n  });\n};\n\n\n/**\n * Fully write or rewrite the datafile, immune to crashes during the write operation (data will not be lost)\n * @param {String} filename\n * @param {String} data\n * @param {Function} cb Optional callback, signature: err\n */\nstorage.crashSafeWriteFile = function (filename, data, cb) {\n  var callback = cb || function () {}\n    , tempFilename = filename + '~';\n\n  async.waterfall([\n    async.apply(storage.flushToStorage, { filename: path.dirname(filename), isDir: true })\n  , function (cb) {\n      storage.exists(filename, function (exists) {\n        if (exists) {\n          storage.flushToStorage(filename, function (err) { return cb(err); });\n        } else {\n          return cb();\n        }\n      });\n    }\n  , function (cb) {\n      storage.writeFile(tempFilename, data, function (err) { return cb(err); });\n    }\n  , async.apply(storage.flushToStorage, tempFilename)\n  , function (cb) {\n      storage.rename(tempFilename, filename, function (err) { return cb(err); });\n    }\n  , async.apply(storage.flushToStorage, { filename: path.dirname(filename), isDir: true })\n  ], function (err) { return callback(err); })\n};\n\n\n/**\n * Ensure the datafile contains all the data, even if there was a crash during a full file write\n * @param {String} filename\n * @param {Function} callback signature: err\n */\nstorage.ensureDatafileIntegrity = function (filename, callback) {\n  var tempFilename = filename + '~';\n\n  storage.exists(filename, function (filenameExists) {\n    // Write was successful\n    if (filenameExists) { return callback(null); }\n\n    storage.exists(tempFilename, function (oldFilenameExists) {\n      // New database\n      if (!oldFilenameExists) {\n        return storage.writeFile(filename, '', 'utf8', function (err) { callback(err); });\n      }\n\n      // Write failed, use old version\n      storage.rename(tempFilename, filename, function (err) { return callback(err); });\n    });\n  });\n};\n\n\n\n// Interface\nmodule.exports = storage;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"nedb\",\n  \"version\": \"1.8.0\",\n  \"author\": {\n    \"name\": \"Louis Chatriot\",\n    \"email\": \"louis.chatriot@gmail.com\"\n  },\n  \"contributors\": [\n    \"Louis Chatriot\"\n  ],\n  \"description\": \"File-based embedded data store for node.js\",\n  \"keywords\": [\n    \"database\",\n    \"datastore\",\n    \"embedded\"\n  ],\n  \"homepage\": \"https://github.com/louischatriot/nedb\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git@github.com:louischatriot/nedb.git\"\n  },\n  \"dependencies\": {\n    \"async\": \"0.2.10\",\n    \"binary-search-tree\": \"0.2.5\",\n    \"localforage\": \"^1.3.0\",\n    \"mkdirp\": \"~0.5.1\",\n    \"underscore\": \"~1.4.4\"\n  },\n  \"devDependencies\": {\n    \"chai\": \"^3.2.0\",\n    \"mocha\": \"1.4.x\",\n    \"request\": \"2.9.x\",\n    \"sinon\": \"1.3.x\",\n    \"exec-time\": \"0.0.2\",\n    \"commander\": \"1.1.1\"\n  },\n  \"scripts\": {\n    \"test\": \"./node_modules/.bin/mocha --reporter spec --timeout 10000\"\n  },\n  \"main\": \"index\",\n  \"browser\": {\n    \"./lib/customUtils.js\": \"./browser-version/browser-specific/lib/customUtils.js\",\n    \"./lib/storage.js\": \"./browser-version/browser-specific/lib/storage.js\"\n  },\n  \"license\": \"SEE LICENSE IN LICENSE\"\n}\n"
  },
  {
    "path": "test/cursor.test.js",
    "content": "var should = require('chai').should()\n  , assert = require('chai').assert\n  , testDb = 'workspace/test.db'\n  , fs = require('fs')\n  , path = require('path')\n  , _ = require('underscore')\n  , async = require('async')\n  , model = require('../lib/model')\n  , Datastore = require('../lib/datastore')\n  , Persistence = require('../lib/persistence')\n  , Cursor = require('../lib/cursor')\n  ;\n\n\ndescribe('Cursor', function () {\n  var d;\n\n  beforeEach(function (done) {\n    d = new Datastore({ filename: testDb });\n    d.filename.should.equal(testDb);\n    d.inMemoryOnly.should.equal(false);\n\n    async.waterfall([\n      function (cb) {\n        Persistence.ensureDirectoryExists(path.dirname(testDb), function () {\n          fs.exists(testDb, function (exists) {\n            if (exists) {\n              fs.unlink(testDb, cb);\n            } else { return cb(); }\n          });\n        });\n      }\n    , function (cb) {\n        d.loadDatabase(function (err) {\n          assert.isNull(err);\n          d.getAllData().length.should.equal(0);\n          return cb();\n        });\n      }\n    ], done);\n  });\n\n  describe('Without sorting', function () {\n\n    beforeEach(function (done) {\n      d.insert({ age: 5 }, function (err) {\n        d.insert({ age: 57 }, function (err) {\n          d.insert({ age: 52 }, function (err) {\n            d.insert({ age: 23 }, function (err) {\n              d.insert({ age: 89 }, function (err) {\n                return done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Without query, an empty query or a simple query and no skip or limit', function (done) {\n      async.waterfall([\n        function (cb) {\n        var cursor = new Cursor(d);\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(5);\n          _.filter(docs, function(doc) { return doc.age === 5; })[0].age.should.equal(5);\n          _.filter(docs, function(doc) { return doc.age === 57; })[0].age.should.equal(57);\n          _.filter(docs, function(doc) { return doc.age === 52; })[0].age.should.equal(52);\n          _.filter(docs, function(doc) { return doc.age === 23; })[0].age.should.equal(23);\n          _.filter(docs, function(doc) { return doc.age === 89; })[0].age.should.equal(89);\n          cb();\n        });\n      }\n      , function (cb) {\n        var cursor = new Cursor(d, {});\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(5);\n          _.filter(docs, function(doc) { return doc.age === 5; })[0].age.should.equal(5);\n          _.filter(docs, function(doc) { return doc.age === 57; })[0].age.should.equal(57);\n          _.filter(docs, function(doc) { return doc.age === 52; })[0].age.should.equal(52);\n          _.filter(docs, function(doc) { return doc.age === 23; })[0].age.should.equal(23);\n          _.filter(docs, function(doc) { return doc.age === 89; })[0].age.should.equal(89);\n          cb();\n        });\n      }\n      , function (cb) {\n        var cursor = new Cursor(d, { age: { $gt: 23 } });\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(3);\n          _.filter(docs, function(doc) { return doc.age === 57; })[0].age.should.equal(57);\n          _.filter(docs, function(doc) { return doc.age === 52; })[0].age.should.equal(52);\n          _.filter(docs, function(doc) { return doc.age === 89; })[0].age.should.equal(89);\n          cb();\n        });\n      }\n      ], done);\n    });\n\n    it('With an empty collection', function (done) {\n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function(err) { return cb(err); })\n        }\n      , function (cb) {\n          var cursor = new Cursor(d);\n          cursor.exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(0);\n            cb();\n          });\n        }\n      ], done);\n    });\n\n    it('With a limit', function (done) {\n      var cursor = new Cursor(d);\n      cursor.limit(3);\n      cursor.exec(function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(3);\n        // No way to predict which results are returned of course ...\n        done();\n      });\n    });\n\n    it('With a skip', function (done) {\n      var cursor = new Cursor(d);\n      cursor.skip(2).exec(function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(3);\n        // No way to predict which results are returned of course ...\n        done();\n      });\n    });\n\n    it('With a limit and a skip and method chaining', function (done) {\n      var cursor = new Cursor(d);\n      cursor.limit(4).skip(3);   // Only way to know that the right number of results was skipped is if limit + skip > number of results\n      cursor.exec(function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(2);\n        // No way to predict which results are returned of course ...\n        done();\n      });\n    });\n\n  });   // ===== End of 'Without sorting' =====\n\n\n  describe('Sorting of the results', function () {\n\n    beforeEach(function (done) {\n      // We don't know the order in which docs wil be inserted but we ensure correctness by testing both sort orders\n      d.insert({ age: 5 }, function (err) {\n        d.insert({ age: 57 }, function (err) {\n          d.insert({ age: 52 }, function (err) {\n            d.insert({ age: 23 }, function (err) {\n              d.insert({ age: 89 }, function (err) {\n                return done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Using one sort', function (done) {\n      var cursor, i;\n\n      cursor = new Cursor(d, {});\n      cursor.sort({ age: 1 });\n      cursor.exec(function (err, docs) {\n        assert.isNull(err);\n        // Results are in ascending order\n        for (i = 0; i < docs.length - 1; i += 1) {\n          assert(docs[i].age < docs[i + 1].age)\n        }\n\n        cursor.sort({ age: -1 });\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          // Results are in descending order\n          for (i = 0; i < docs.length - 1; i += 1) {\n            assert(docs[i].age > docs[i + 1].age)\n          }\n\n          done();\n        });\n      });\n    });\n\n    it(\"Sorting strings with custom string comparison function\", function (done) {\n      var db = new Datastore({ inMemoryOnly: true, autoload: true\n                             , compareStrings: function (a, b) { return a.length - b.length; }\n                             });\n\n      db.insert({ name: 'alpha' });\n      db.insert({ name: 'charlie' });\n      db.insert({ name: 'zulu' });\n\n      db.find({}).sort({ name: 1 }).exec(function (err, docs) {\n        _.pluck(docs, 'name')[0].should.equal('zulu');\n        _.pluck(docs, 'name')[1].should.equal('alpha');\n        _.pluck(docs, 'name')[2].should.equal('charlie');\n\n        delete db.compareStrings;\n        db.find({}).sort({ name: 1 }).exec(function (err, docs) {\n          _.pluck(docs, 'name')[0].should.equal('alpha');\n          _.pluck(docs, 'name')[1].should.equal('charlie');\n          _.pluck(docs, 'name')[2].should.equal('zulu');\n\n          done();\n        });\n      });\n    });\n\n    it('With an empty collection', function (done) {\n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function(err) { return cb(err); })\n        }\n      , function (cb) {\n    var cursor = new Cursor(d);\n    cursor.sort({ age: 1 });\n    cursor.exec(function (err, docs) {\n      assert.isNull(err);\n      docs.length.should.equal(0);\n      cb();\n    });\n      }\n      ], done);\n    });\n\n    it('Ability to chain sorting and exec', function (done) {\n      var i;\n      async.waterfall([\n        function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).exec(function (err, docs) {\n            assert.isNull(err);\n            // Results are in ascending order\n            for (i = 0; i < docs.length - 1; i += 1) {\n              assert(docs[i].age < docs[i + 1].age)\n            }\n            cb();\n          });\n        }\n      , function (cb) {\n    var cursor = new Cursor(d);\n    cursor.sort({ age: -1 }).exec(function (err, docs) {\n      assert.isNull(err);\n      // Results are in descending order\n      for (i = 0; i < docs.length - 1; i += 1) {\n        assert(docs[i].age > docs[i + 1].age)\n      }\n      cb();\n    });\n      }\n      ], done);\n    });\n\n    it('Using limit and sort', function (done) {\n      var i;\n      async.waterfall([\n        function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).limit(3).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(3);\n            docs[0].age.should.equal(5);\n            docs[1].age.should.equal(23);\n            docs[2].age.should.equal(52);\n            cb();\n          });\n        }\n      , function (cb) {\n    var cursor = new Cursor(d);\n    cursor.sort({ age: -1 }).limit(2).exec(function (err, docs) {\n      assert.isNull(err);\n      docs.length.should.equal(2);\n      docs[0].age.should.equal(89);\n      docs[1].age.should.equal(57);\n      cb();\n    });\n      }\n      ], done);\n    });\n\n    it('Using a limit higher than total number of docs shouldnt cause an error', function (done) {\n      var i;\n      async.waterfall([\n        function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).limit(7).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(5);\n            docs[0].age.should.equal(5);\n            docs[1].age.should.equal(23);\n            docs[2].age.should.equal(52);\n            docs[3].age.should.equal(57);\n            docs[4].age.should.equal(89);\n            cb();\n          });\n        }\n      ], done);\n    });\n\n    it('Using limit and skip with sort', function (done) {\n      var i;\n      async.waterfall([\n        function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).limit(1).skip(2).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(1);\n            docs[0].age.should.equal(52);\n            cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).limit(3).skip(1).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(3);\n            docs[0].age.should.equal(23);\n            docs[1].age.should.equal(52);\n            docs[2].age.should.equal(57);\n            cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: -1 }).limit(2).skip(2).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(2);\n            docs[0].age.should.equal(52);\n            docs[1].age.should.equal(23);\n            cb();\n          });\n        }\n      ], done);\n    });\n    \n    it('Using too big a limit and a skip with sort', function (done) {\n      var i;    \n      async.waterfall([\n        function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).limit(8).skip(2).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(3);\n            docs[0].age.should.equal(52);\n            docs[1].age.should.equal(57);\n            docs[2].age.should.equal(89);\n            cb();\n          });\n        }\n      ], done);\n    });\n\n    it('Using too big a skip with sort should return no result', function (done) {\n      var i;    \n      async.waterfall([\n        function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).skip(5).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(0);\n            cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).skip(7).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(0);\n            cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).limit(3).skip(7).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(0);\n            cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d);\n          cursor.sort({ age: 1 }).limit(6).skip(7).exec(function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(0);\n            cb();\n          });\n        }\n      ], done);\n    });\n    \n    it('Sorting strings', function (done) {\n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function (err) {\n            if (err) { return cb(err); }\n\n            d.insert({ name: 'jako'}, function () {\n              d.insert({ name: 'jakeb' }, function () {\n                d.insert({ name: 'sue' }, function () {\n                  return cb();\n                });\n              });            \n            });\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ name: 1 }).exec(function (err, docs) {\n            docs.length.should.equal(3);\n            docs[0].name.should.equal('jakeb');\n            docs[1].name.should.equal('jako');\n            docs[2].name.should.equal('sue');\n            return cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ name: -1 }).exec(function (err, docs) {\n            docs.length.should.equal(3);\n            docs[0].name.should.equal('sue');\n            docs[1].name.should.equal('jako');\n            docs[2].name.should.equal('jakeb');\n            return cb();\n          });\n        }\n      ], done);\n    });\n    \n    it('Sorting nested fields with dates', function (done) {\n      var doc1, doc2, doc3;\n      \n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function (err) {\n            if (err) { return cb(err); }\n\n            d.insert({ event: { recorded: new Date(400) } }, function (err, _doc1) {\n              doc1 = _doc1;\n              d.insert({ event: { recorded: new Date(60000) } }, function (err, _doc2) {\n                doc2 = _doc2;\n                d.insert({ event: { recorded: new Date(32) } }, function (err, _doc3) {\n                  doc3 = _doc3;\n                  return cb();\n                });\n              });            \n            });\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ \"event.recorded\": 1 }).exec(function (err, docs) {\n            docs.length.should.equal(3);\n            docs[0]._id.should.equal(doc3._id);\n            docs[1]._id.should.equal(doc1._id);\n            docs[2]._id.should.equal(doc2._id);\n            return cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ \"event.recorded\": -1 }).exec(function (err, docs) {\n            docs.length.should.equal(3);\n            docs[0]._id.should.equal(doc2._id);\n            docs[1]._id.should.equal(doc1._id);\n            docs[2]._id.should.equal(doc3._id);\n            return cb();\n          });\n        }\n      ], done);\n    });\n    \n    it('Sorting when some fields are undefined', function (done) {      \n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function (err) {\n            if (err) { return cb(err); }\n\n            d.insert({ name: 'jako', other: 2 }, function () {\n              d.insert({ name: 'jakeb', other: 3 }, function () {\n                d.insert({ name: 'sue' }, function () {\n                  d.insert({ name: 'henry', other: 4 }, function () {\n                    return cb();\n                  });\n                });\n              });            \n            });\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ other: 1 }).exec(function (err, docs) {\n            docs.length.should.equal(4);\n            docs[0].name.should.equal('sue');\n            assert.isUndefined(docs[0].other);\n            docs[1].name.should.equal('jako');\n            docs[1].other.should.equal(2);\n            docs[2].name.should.equal('jakeb');\n            docs[2].other.should.equal(3);\n            docs[3].name.should.equal('henry');\n            docs[3].other.should.equal(4);\n            return cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, { name: { $in: [ 'suzy', 'jakeb', 'jako' ] } });\n          cursor.sort({ other: -1 }).exec(function (err, docs) {\n            docs.length.should.equal(2);\n            docs[0].name.should.equal('jakeb');\n            docs[0].other.should.equal(3);\n            docs[1].name.should.equal('jako');\n            docs[1].other.should.equal(2);\n            return cb();\n          });\n        }\n      ], done);\n    });\n    \n    it('Sorting when all fields are undefined', function (done) {      \n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function (err) {\n            if (err) { return cb(err); }\n\n            d.insert({ name: 'jako'}, function () {\n              d.insert({ name: 'jakeb' }, function () {\n                d.insert({ name: 'sue' }, function () {\n                  return cb();\n                });\n              });            \n            });\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ other: 1 }).exec(function (err, docs) {\n            docs.length.should.equal(3);\n            return cb();\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, { name: { $in: [ 'sue', 'jakeb', 'jakob' ] } });\n          cursor.sort({ other: -1 }).exec(function (err, docs) {\n            docs.length.should.equal(2);\n            return cb();\n          });\n        }\n      ], done);\n    });\n\n    it('Multiple consecutive sorts', function(done) {\n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function (err) {\n            if (err) { return cb(err); }\n\n            d.insert({ name: 'jako', age: 43, nid: 1 }, function () {\n              d.insert({ name: 'jakeb', age: 43, nid: 2 }, function () {\n                d.insert({ name: 'sue', age: 12, nid: 3 }, function () {\n                  d.insert({ name: 'zoe', age: 23, nid: 4 }, function () {\n                    d.insert({ name: 'jako', age: 35, nid: 5 }, function () {\n                      return cb();\n                    });\n                  });\n                });\n              });            \n            });\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ name: 1, age: -1 }).exec(function (err, docs) {\n            docs.length.should.equal(5);\n            \n            docs[0].nid.should.equal(2);\n            docs[1].nid.should.equal(1);\n            docs[2].nid.should.equal(5);\n            docs[3].nid.should.equal(3);\n            docs[4].nid.should.equal(4);\n            return cb();\n          });\n        }\n        , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ name: 1, age: 1 }).exec(function (err, docs) {\n            docs.length.should.equal(5);\n            \n            docs[0].nid.should.equal(2);\n            docs[1].nid.should.equal(5);\n            docs[2].nid.should.equal(1);\n            docs[3].nid.should.equal(3);\n            docs[4].nid.should.equal(4);\n            return cb();\n          });\n        }\n        , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ age: 1, name: 1 }).exec(function (err, docs) {\n            docs.length.should.equal(5);\n            \n            docs[0].nid.should.equal(3);\n            docs[1].nid.should.equal(4);\n            docs[2].nid.should.equal(5);\n            docs[3].nid.should.equal(2);\n            docs[4].nid.should.equal(1);\n            return cb();\n          });\n        }\n        , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ age: 1, name: -1 }).exec(function (err, docs) {\n            docs.length.should.equal(5);\n            \n            docs[0].nid.should.equal(3);\n            docs[1].nid.should.equal(4);\n            docs[2].nid.should.equal(5);\n            docs[3].nid.should.equal(1);\n            docs[4].nid.should.equal(2);\n            return cb();\n          });\n        }\n      ], done);    });\n\n    it('Similar data, multiple consecutive sorts', function(done) {\n      var i, j, id\n        , companies = [ 'acme', 'milkman', 'zoinks' ]\n        , entities = []\n        ;\n    \n      async.waterfall([\n        function (cb) {\n          d.remove({}, { multi: true }, function (err) {\n            if (err) { return cb(err); }\n            \n            id = 1;\n            for (i = 0; i < companies.length; i++) {\n              for (j = 5; j <= 100; j += 5) {\n                entities.push({\n                  company: companies[i],\n                  cost: j,\n                  nid: id\n                });\n                id++;\n              }\n            }\n\n            async.each(entities, function(entity, callback) {\n              d.insert(entity, function() {\n                callback();\n              });\n            }, function(err) {\n              return cb();\n            });\n          });\n        }\n      , function (cb) {\n          var cursor = new Cursor(d, {});\n          cursor.sort({ company: 1, cost: 1 }).exec(function (err, docs) {\n            docs.length.should.equal(60);\n\n            for (var i = 0; i < docs.length; i++) {\n              docs[i].nid.should.equal(i+1);\n            };\n            return cb();\n          });\n        }\n      ], done);    });\n\n  });   // ===== End of 'Sorting' =====\n\n\n  describe('Projections', function () {\n    var doc1, doc2, doc3, doc4, doc0;\n\n\n    beforeEach(function (done) {\n      // We don't know the order in which docs wil be inserted but we ensure correctness by testing both sort orders\n      d.insert({ age: 5, name: 'Jo', planet: 'B', toys: { bebe: true, ballon: 'much' } }, function (err, _doc0) {\n        doc0 = _doc0;\n        d.insert({ age: 57, name: 'Louis', planet: 'R', toys: { ballon: 'yeah', bebe: false } }, function (err, _doc1) {\n          doc1 = _doc1;\n          d.insert({ age: 52, name: 'Grafitti', planet: 'C', toys: { bebe: 'kind of' } }, function (err, _doc2) {\n            doc2 = _doc2;\n            d.insert({ age: 23, name: 'LM', planet: 'S' }, function (err, _doc3) {\n              doc3 = _doc3;\n              d.insert({ age: 89, planet: 'Earth' }, function (err, _doc4) {\n                doc4 = _doc4;\n                return done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Takes all results if no projection or empty object given', function (done) {\n      var cursor = new Cursor(d, {});\n      cursor.sort({ age: 1 });   // For easier finding\n      cursor.exec(function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(5);\n        assert.deepEqual(docs[0], doc0);\n        assert.deepEqual(docs[1], doc3);\n        assert.deepEqual(docs[2], doc2);\n        assert.deepEqual(docs[3], doc1);\n        assert.deepEqual(docs[4], doc4);\n\n        cursor.projection({});\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(5);\n          assert.deepEqual(docs[0], doc0);\n          assert.deepEqual(docs[1], doc3);\n          assert.deepEqual(docs[2], doc2);\n          assert.deepEqual(docs[3], doc1);\n          assert.deepEqual(docs[4], doc4);\n\n          done();\n        });\n      });\n    });\n\n    it('Can take only the expected fields', function (done) {\n      var cursor = new Cursor(d, {});\n      cursor.sort({ age: 1 });   // For easier finding\n      cursor.projection({ age: 1, name: 1 });\n      cursor.exec(function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(5);\n        // Takes the _id by default\n        assert.deepEqual(docs[0], { age: 5, name: 'Jo', _id: doc0._id });\n        assert.deepEqual(docs[1], { age: 23, name: 'LM', _id: doc3._id });\n        assert.deepEqual(docs[2], { age: 52, name: 'Grafitti', _id: doc2._id });\n        assert.deepEqual(docs[3], { age: 57, name: 'Louis', _id: doc1._id });\n        assert.deepEqual(docs[4], { age: 89, _id: doc4._id });   // No problems if one field to take doesn't exist\n\n        cursor.projection({ age: 1, name: 1, _id: 0 });\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(5);\n          assert.deepEqual(docs[0], { age: 5, name: 'Jo' });\n          assert.deepEqual(docs[1], { age: 23, name: 'LM' });\n          assert.deepEqual(docs[2], { age: 52, name: 'Grafitti' });\n          assert.deepEqual(docs[3], { age: 57, name: 'Louis' });\n          assert.deepEqual(docs[4], { age: 89 });   // No problems if one field to take doesn't exist\n\n          done();\n        });\n      });\n    });\n\n    it('Can omit only the expected fields', function (done) {\n      var cursor = new Cursor(d, {});\n      cursor.sort({ age: 1 });   // For easier finding\n      cursor.projection({ age: 0, name: 0 });\n      cursor.exec(function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(5);\n        // Takes the _id by default\n        assert.deepEqual(docs[0], { planet: 'B', _id: doc0._id, toys: { bebe: true, ballon: 'much' } });\n        assert.deepEqual(docs[1], { planet: 'S', _id: doc3._id });\n        assert.deepEqual(docs[2], { planet: 'C', _id: doc2._id, toys: { bebe: 'kind of' } });\n        assert.deepEqual(docs[3], { planet: 'R', _id: doc1._id, toys: { bebe: false, ballon: 'yeah' } });\n        assert.deepEqual(docs[4], { planet: 'Earth', _id: doc4._id });\n\n        cursor.projection({ age: 0, name: 0, _id: 0 });\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(5);\n          assert.deepEqual(docs[0], { planet: 'B', toys: { bebe: true, ballon: 'much' } });\n          assert.deepEqual(docs[1], { planet: 'S' });\n          assert.deepEqual(docs[2], { planet: 'C', toys: { bebe: 'kind of' } });\n          assert.deepEqual(docs[3], { planet: 'R', toys: { bebe: false, ballon: 'yeah' } });\n          assert.deepEqual(docs[4], { planet: 'Earth' });\n\n          done();\n        });\n      });\n    });\n\n    it('Cannot use both modes except for _id', function (done) {\n      var cursor = new Cursor(d, {});\n      cursor.sort({ age: 1 });   // For easier finding\n      cursor.projection({ age: 1, name: 0 });\n      cursor.exec(function (err, docs) {\n        assert.isNotNull(err);\n        assert.isUndefined(docs);\n\n        cursor.projection({ age: 1, _id: 0 });\n        cursor.exec(function (err, docs) {\n          assert.isNull(err);\n          assert.deepEqual(docs[0], { age: 5 });\n          assert.deepEqual(docs[1], { age: 23 });\n          assert.deepEqual(docs[2], { age: 52 });\n          assert.deepEqual(docs[3], { age: 57 });\n          assert.deepEqual(docs[4], { age: 89 });\n\n          cursor.projection({ age: 0, toys: 0, planet: 0, _id: 1 });\n          cursor.exec(function (err, docs) {\n            assert.isNull(err);\n            assert.deepEqual(docs[0], { name: 'Jo', _id: doc0._id });\n            assert.deepEqual(docs[1], { name: 'LM', _id: doc3._id });\n            assert.deepEqual(docs[2], { name: 'Grafitti', _id: doc2._id });\n            assert.deepEqual(docs[3], { name: 'Louis', _id: doc1._id });\n            assert.deepEqual(docs[4], { _id: doc4._id });\n\n            done();\n          });\n        });\n      });\n    });\n\n    it(\"Projections on embedded documents - omit type\", function (done) {\n      var cursor = new Cursor(d, {});\n      cursor.sort({ age: 1 });   // For easier finding\n      cursor.projection({ name: 0, planet: 0, 'toys.bebe': 0, _id: 0 });\n      cursor.exec(function (err, docs) {\n        assert.deepEqual(docs[0], { age: 5, toys: { ballon: 'much' } });\n        assert.deepEqual(docs[1], { age: 23 });\n        assert.deepEqual(docs[2], { age: 52, toys: {} });\n        assert.deepEqual(docs[3], { age: 57, toys: { ballon: 'yeah' } });\n        assert.deepEqual(docs[4], { age: 89 });\n\n        done();\n      });\n    });\n\n    it(\"Projections on embedded documents - pick type\", function (done) {\n      var cursor = new Cursor(d, {});\n      cursor.sort({ age: 1 });   // For easier finding\n      cursor.projection({ name: 1, 'toys.ballon': 1, _id: 0 });\n      cursor.exec(function (err, docs) {\n        assert.deepEqual(docs[0], { name: 'Jo', toys: { ballon: 'much' } });\n        assert.deepEqual(docs[1], { name: 'LM' });\n        assert.deepEqual(docs[2], { name: 'Grafitti' });\n        assert.deepEqual(docs[3], { name: 'Louis', toys: { ballon: 'yeah' } });\n        assert.deepEqual(docs[4], {});\n\n        done();\n      });\n    });\n\n  });   // ==== End of 'Projections' ====\n\n});\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "test/customUtil.test.js",
    "content": "var should = require('chai').should()\n  , assert = require('chai').assert\n  , customUtils = require('../lib/customUtils')\n  , fs = require('fs')\n  ;\n\n\ndescribe('customUtils', function () {\n\n  describe('uid', function () {\n\n    it('Generates a string of the expected length', function () {\n      customUtils.uid(3).length.should.equal(3);\n      customUtils.uid(16).length.should.equal(16);\n      customUtils.uid(42).length.should.equal(42);\n      customUtils.uid(1000).length.should.equal(1000);\n    });\n\n    // Very small probability of conflict\n    it('Generated uids should not be the same', function () {\n      customUtils.uid(56).should.not.equal(customUtils.uid(56));\n    });\n\n  });\n\n});\n"
  },
  {
    "path": "test/db.test.js",
    "content": "var should = require('chai').should()\n  , assert = require('chai').assert\n  , testDb = 'workspace/test.db'\n  , fs = require('fs')\n  , path = require('path')\n  , _ = require('underscore')\n  , async = require('async')\n  , model = require('../lib/model')\n  , Datastore = require('../lib/datastore')\n  , Persistence = require('../lib/persistence')\n  , reloadTimeUpperBound = 60;   // In ms, an upper bound for the reload time used to check createdAt and updatedAt\n  ;\n\n\ndescribe('Database', function () {\n  var d;\n\n  beforeEach(function (done) {\n    d = new Datastore({ filename: testDb });\n    d.filename.should.equal(testDb);\n    d.inMemoryOnly.should.equal(false);\n\n    async.waterfall([\n      function (cb) {\n        Persistence.ensureDirectoryExists(path.dirname(testDb), function () {\n          fs.exists(testDb, function (exists) {\n            if (exists) {\n              fs.unlink(testDb, cb);\n            } else { return cb(); }\n          });\n        });\n      }\n    , function (cb) {\n        d.loadDatabase(function (err) {\n          assert.isNull(err);\n          d.getAllData().length.should.equal(0);\n          return cb();\n        });\n      }\n    ], done);\n  });\n\n  it('Constructor compatibility with v0.6-', function () {\n    var dbef = new Datastore('somefile');\n    dbef.filename.should.equal('somefile');\n    dbef.inMemoryOnly.should.equal(false);\n\n    var dbef = new Datastore('');\n    assert.isNull(dbef.filename);\n    dbef.inMemoryOnly.should.equal(true);\n\n    var dbef = new Datastore();\n    assert.isNull(dbef.filename);\n    dbef.inMemoryOnly.should.equal(true);\n  });\n\n  describe('Autoloading', function () {\n\n    it('Can autoload a database and query it right away', function (done) {\n      var fileStr = model.serialize({ _id: '1', a: 5, planet: 'Earth' }) + '\\n' + model.serialize({ _id: '2', a: 5, planet: 'Mars' }) + '\\n'\n        , autoDb = 'workspace/auto.db'\n        , db\n        ;\n\n      fs.writeFileSync(autoDb, fileStr, 'utf8');\n      db = new Datastore({ filename: autoDb, autoload: true })\n\n      db.find({}, function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(2);\n        done();\n      });\n    });\n\n    it('Throws if autoload fails', function (done) {\n      var fileStr = model.serialize({ _id: '1', a: 5, planet: 'Earth' }) + '\\n' + model.serialize({ _id: '2', a: 5, planet: 'Mars' }) + '\\n' + '{\"$$indexCreated\":{\"fieldName\":\"a\",\"unique\":true}}'\n        , autoDb = 'workspace/auto.db'\n        , db\n        ;\n\n      fs.writeFileSync(autoDb, fileStr, 'utf8');\n\n      // Check the loadDatabase generated an error\n      function onload (err) {\n        err.errorType.should.equal('uniqueViolated');\n        done();\n      }\n\n      db = new Datastore({ filename: autoDb, autoload: true, onload: onload })\n\n      db.find({}, function (err, docs) {\n        done(new Error(\"Find should not be executed since autoload failed\"));\n      });\n    });\n\n  });\n\n  describe('Insert', function () {\n\n    it('Able to insert a document in the database, setting an _id if none provided, and retrieve it even after a reload', function (done) {\n      d.find({}, function (err, docs) {\n        docs.length.should.equal(0);\n\n        d.insert({ somedata: 'ok' }, function (err) {\n          // The data was correctly updated\n          d.find({}, function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(1);\n            Object.keys(docs[0]).length.should.equal(2);\n            docs[0].somedata.should.equal('ok');\n            assert.isDefined(docs[0]._id);\n\n            // After a reload the data has been correctly persisted\n            d.loadDatabase(function (err) {\n              d.find({}, function (err, docs) {\n                assert.isNull(err);\n                docs.length.should.equal(1);\n                Object.keys(docs[0]).length.should.equal(2);\n                docs[0].somedata.should.equal('ok');\n                assert.isDefined(docs[0]._id);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can insert multiple documents in the database', function (done) {\n      d.find({}, function (err, docs) {\n        docs.length.should.equal(0);\n\n        d.insert({ somedata: 'ok' }, function (err) {\n          d.insert({ somedata: 'another' }, function (err) {\n            d.insert({ somedata: 'again' }, function (err) {\n              d.find({}, function (err, docs) {\n                docs.length.should.equal(3);\n                _.pluck(docs, 'somedata').should.contain('ok');\n                _.pluck(docs, 'somedata').should.contain('another');\n                _.pluck(docs, 'somedata').should.contain('again');\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can insert and get back from DB complex objects with all primitive and secondary types', function (done) {\n      var da = new Date()\n        , obj = { a: ['ee', 'ff', 42], date: da, subobj: { a: 'b', b: 'c' } }\n        ;\n\n      d.insert(obj, function (err) {\n        d.findOne({}, function (err, res) {\n          assert.isNull(err);\n          res.a.length.should.equal(3);\n          res.a[0].should.equal('ee');\n          res.a[1].should.equal('ff');\n          res.a[2].should.equal(42);\n          res.date.getTime().should.equal(da.getTime());\n          res.subobj.a.should.equal('b');\n          res.subobj.b.should.equal('c');\n\n          done();\n        });\n      });\n    });\n\n    it('If an object returned from the DB is modified and refetched, the original value should be found', function (done) {\n      d.insert({ a: 'something' }, function () {\n        d.findOne({}, function (err, doc) {\n          doc.a.should.equal('something');\n          doc.a = 'another thing';\n          doc.a.should.equal('another thing');\n\n          // Re-fetching with findOne should yield the persisted value\n          d.findOne({}, function (err, doc) {\n            doc.a.should.equal('something');\n            doc.a = 'another thing';\n            doc.a.should.equal('another thing');\n\n            // Re-fetching with find should yield the persisted value\n            d.find({}, function (err, docs) {\n              docs[0].a.should.equal('something');\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it('Cannot insert a doc that has a field beginning with a $ sign', function (done) {\n      d.insert({ $something: 'atest' }, function (err) {\n        assert.isDefined(err);\n        done();\n      });\n    });\n\n    it('If an _id is already given when we insert a document, use that instead of generating a random one', function (done) {\n      d.insert({ _id: 'test', stuff: true }, function (err, newDoc) {\n        if (err) { return done(err); }\n\n        newDoc.stuff.should.equal(true);\n        newDoc._id.should.equal('test');\n\n        d.insert({ _id: 'test', otherstuff: 42 }, function (err) {\n          err.errorType.should.equal('uniqueViolated');\n\n          done();\n        });\n      });\n    });\n\n    it('Modifying the insertedDoc after an insert doesnt change the copy saved in the database', function (done) {\n      d.insert({ a: 2, hello: 'world' }, function (err, newDoc) {\n        newDoc.hello = 'changed';\n\n        d.findOne({ a: 2 }, function (err, doc) {\n          doc.hello.should.equal('world');\n          done();\n        });\n      });\n    });\n\n    it('Can insert an array of documents at once', function (done) {\n      var docs = [{ a: 5, b: 'hello' }, { a: 42, b: 'world' }];\n\n      d.insert(docs, function (err) {\n        d.find({}, function (err, docs) {\n          var data;\n\n          docs.length.should.equal(2);\n          _.find(docs, function (doc) { return doc.a === 5; }).b.should.equal('hello');\n          _.find(docs, function (doc) { return doc.a === 42; }).b.should.equal('world');\n\n          // The data has been persisted correctly\n          data = _.filter(fs.readFileSync(testDb, 'utf8').split('\\n'), function (line) { return line.length > 0; });\n          data.length.should.equal(2);\n          model.deserialize(data[0]).a.should.equal(5);\n          model.deserialize(data[0]).b.should.equal('hello');\n          model.deserialize(data[1]).a.should.equal(42);\n          model.deserialize(data[1]).b.should.equal('world');\n\n          done();\n        });\n      });\n    });\n\n    it('If a bulk insert violates a constraint, all changes are rolled back', function (done) {\n      var docs = [{ a: 5, b: 'hello' }, { a: 42, b: 'world' }, { a: 5, b: 'bloup' }, { a: 7 }];\n\n      d.ensureIndex({ fieldName: 'a', unique: true }, function () {   // Important to specify callback here to make sure filesystem synced\n        d.insert(docs, function (err) {\n          err.errorType.should.equal('uniqueViolated');\n\n          d.find({}, function (err, docs) {\n            // Datafile only contains index definition\n            var datafileContents = model.deserialize(fs.readFileSync(testDb, 'utf8'));\n            assert.deepEqual(datafileContents, { $$indexCreated: { fieldName: 'a', unique: true } });\n\n            docs.length.should.equal(0);\n\n            done();\n          });\n        });\n      });\n    });\n\n    it(\"If timestampData option is set, a createdAt field is added and persisted\", function (done) {\n      var newDoc = { hello: 'world' }, beginning = Date.now();\n      d = new Datastore({ filename: testDb, timestampData: true, autoload: true });\n      d.find({}, function (err, docs) {\n        assert.isNull(err);\n        docs.length.should.equal(0);\n\n        d.insert(newDoc, function (err, insertedDoc) {\n          // No side effect on given input\n          assert.deepEqual(newDoc, { hello: 'world' });\n          // Insert doc has two new fields, _id and createdAt\n          insertedDoc.hello.should.equal('world');\n          assert.isDefined(insertedDoc.createdAt);\n          assert.isDefined(insertedDoc.updatedAt);\n          insertedDoc.createdAt.should.equal(insertedDoc.updatedAt);\n          assert.isDefined(insertedDoc._id);\n          Object.keys(insertedDoc).length.should.equal(4);\n          assert.isBelow(Math.abs(insertedDoc.createdAt.getTime() - beginning), reloadTimeUpperBound);   // No more than 30ms should have elapsed (worst case, if there is a flush)\n\n          // Modifying results of insert doesn't change the cache\n          insertedDoc.bloup = \"another\";\n          Object.keys(insertedDoc).length.should.equal(5);\n\n          d.find({}, function (err, docs) {\n            docs.length.should.equal(1);\n            assert.deepEqual(newDoc, { hello: 'world' });\n            assert.deepEqual({ hello: 'world', _id: insertedDoc._id, createdAt: insertedDoc.createdAt, updatedAt: insertedDoc.updatedAt }, docs[0]);\n\n            // All data correctly persisted on disk\n            d.loadDatabase(function () {\n              d.find({}, function (err, docs) {\n                docs.length.should.equal(1);\n                assert.deepEqual(newDoc, { hello: 'world' });\n                assert.deepEqual({ hello: 'world', _id: insertedDoc._id, createdAt: insertedDoc.createdAt, updatedAt: insertedDoc.updatedAt }, docs[0]);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it(\"If timestampData option not set, don't create a createdAt and a updatedAt field\", function (done) {\n      d.insert({ hello: 'world' }, function (err, insertedDoc) {\n        Object.keys(insertedDoc).length.should.equal(2);\n        assert.isUndefined(insertedDoc.createdAt);\n        assert.isUndefined(insertedDoc.updatedAt);\n\n        d.find({}, function (err, docs) {\n          docs.length.should.equal(1);\n          assert.deepEqual(docs[0], insertedDoc);\n\n          done();\n        });\n      });\n    });\n\n    it(\"If timestampData is set but createdAt is specified by user, don't change it\", function (done) {\n      var newDoc = { hello: 'world', createdAt: new Date(234) }, beginning = Date.now();\n      d = new Datastore({ filename: testDb, timestampData: true, autoload: true });\n      d.insert(newDoc, function (err, insertedDoc) {\n        Object.keys(insertedDoc).length.should.equal(4);\n        insertedDoc.createdAt.getTime().should.equal(234);   // Not modified\n        assert.isBelow(insertedDoc.updatedAt.getTime() - beginning, reloadTimeUpperBound);   // Created\n\n        d.find({}, function (err, docs) {\n          assert.deepEqual(insertedDoc, docs[0]);\n\n          d.loadDatabase(function () {\n            d.find({}, function (err, docs) {\n              assert.deepEqual(insertedDoc, docs[0]);\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it(\"If timestampData is set but updatedAt is specified by user, don't change it\", function (done) {\n      var newDoc = { hello: 'world', updatedAt: new Date(234) }, beginning = Date.now();\n      d = new Datastore({ filename: testDb, timestampData: true, autoload: true });\n      d.insert(newDoc, function (err, insertedDoc) {\n        Object.keys(insertedDoc).length.should.equal(4);\n        insertedDoc.updatedAt.getTime().should.equal(234);   // Not modified\n        assert.isBelow(insertedDoc.createdAt.getTime() - beginning, reloadTimeUpperBound);   // Created\n\n        d.find({}, function (err, docs) {\n          assert.deepEqual(insertedDoc, docs[0]);\n\n          d.loadDatabase(function () {\n            d.find({}, function (err, docs) {\n              assert.deepEqual(insertedDoc, docs[0]);\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it('Can insert a doc with id 0', function (done) {\n      d.insert({ _id: 0, hello: 'world' }, function (err, doc) {\n        doc._id.should.equal(0);\n        doc.hello.should.equal('world');\n        done();\n      });\n    });\n\n    /**\n     * Complicated behavior here. Basically we need to test that when a user function throws an exception, it is not caught\n     * in NeDB and the callback called again, transforming a user error into a NeDB error.\n     *\n     * So we need a way to check that the callback is called only once and the exception thrown is indeed the client exception\n     * Mocha's exception handling mechanism interferes with this since it already registers a listener on uncaughtException\n     * which we need to use since findOne is not called in the same turn of the event loop (so no try/catch)\n     * So we remove all current listeners, put our own which when called will register the former listeners (incl. Mocha's) again.\n     *\n     * Note: maybe using an in-memory only NeDB would give us an easier solution\n     */\n    it('If the callback throws an uncaught exception, do not catch it inside findOne, this is userspace concern', function (done) {\n      var tryCount = 0\n        , currentUncaughtExceptionHandlers = process.listeners('uncaughtException')\n        , i\n        ;\n\n      process.removeAllListeners('uncaughtException');\n\n      process.on('uncaughtException', function MINE (ex) {\n        process.removeAllListeners('uncaughtException');\n\n        for (i = 0; i < currentUncaughtExceptionHandlers.length; i += 1) {\n          process.on('uncaughtException', currentUncaughtExceptionHandlers[i]);\n        }\n\n        ex.message.should.equal('SOME EXCEPTION');\n        done();\n      });\n\n      d.insert({ a: 5 }, function () {\n        d.findOne({ a : 5}, function (err, doc) {\n          if (tryCount === 0) {\n            tryCount += 1;\n            throw new Error('SOME EXCEPTION');\n          } else {\n            done(new Error('Callback was called twice'));\n          }\n        });\n      });\n    });\n\n  });   // ==== End of 'Insert' ==== //\n\n\n  describe('#getCandidates', function () {\n\n    it('Can use an index to get docs with a basic match', function (done) {\n      d.ensureIndex({ fieldName: 'tf' }, function (err) {\n        d.insert({ tf: 4 }, function (err, _doc1) {\n          d.insert({ tf: 6 }, function () {\n            d.insert({ tf: 4, an: 'other' }, function (err, _doc2) {\n              d.insert({ tf: 9 }, function () {\n                d.getCandidates({ r: 6, tf: 4 }, function (err, data) {\n                  var doc1 = _.find(data, function (d) { return d._id === _doc1._id; })\n                    , doc2 = _.find(data, function (d) { return d._id === _doc2._id; })\n                    ;\n\n                  data.length.should.equal(2);\n                  assert.deepEqual(doc1, { _id: doc1._id, tf: 4 });\n                  assert.deepEqual(doc2, { _id: doc2._id, tf: 4, an: 'other' });\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can use an index to get docs with a $in match', function (done) {\n      d.ensureIndex({ fieldName: 'tf' }, function (err) {\n        d.insert({ tf: 4 }, function (err) {\n          d.insert({ tf: 6 }, function (err, _doc1) {\n            d.insert({ tf: 4, an: 'other' }, function (err) {\n              d.insert({ tf: 9 }, function (err, _doc2) {\n                d.getCandidates({ r: 6, tf: { $in: [6, 9, 5] } }, function (err, data) {\n                  var doc1 = _.find(data, function (d) { return d._id === _doc1._id; })\n                    , doc2 = _.find(data, function (d) { return d._id === _doc2._id; })\n                    ;\n\n                  data.length.should.equal(2);\n                  assert.deepEqual(doc1, { _id: doc1._id, tf: 6 });\n                  assert.deepEqual(doc2, { _id: doc2._id, tf: 9 });\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('If no index can be used, return the whole database', function (done) {\n      d.ensureIndex({ fieldName: 'tf' }, function (err) {\n        d.insert({ tf: 4 }, function (err, _doc1) {\n          d.insert({ tf: 6 }, function (err, _doc2) {\n            d.insert({ tf: 4, an: 'other' }, function (err, _doc3) {\n              d.insert({ tf: 9 }, function (err, _doc4) {\n                d.getCandidates({ r: 6, notf: { $in: [6, 9, 5] } }, function (err, data) {\n                  var doc1 = _.find(data, function (d) { return d._id === _doc1._id; })\n                    , doc2 = _.find(data, function (d) { return d._id === _doc2._id; })\n                    , doc3 = _.find(data, function (d) { return d._id === _doc3._id; })\n                    , doc4 = _.find(data, function (d) { return d._id === _doc4._id; })\n                    ;\n\n                  data.length.should.equal(4);\n                  assert.deepEqual(doc1, { _id: doc1._id, tf: 4 });\n                  assert.deepEqual(doc2, { _id: doc2._id, tf: 6 });\n                  assert.deepEqual(doc3, { _id: doc3._id, tf: 4, an: 'other' });\n                  assert.deepEqual(doc4, { _id: doc4._id, tf: 9 });\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can use indexes for comparison matches', function (done) {\n      d.ensureIndex({ fieldName: 'tf' }, function (err) {\n        d.insert({ tf: 4 }, function (err, _doc1) {\n          d.insert({ tf: 6 }, function (err, _doc2) {\n            d.insert({ tf: 4, an: 'other' }, function (err, _doc3) {\n              d.insert({ tf: 9 }, function (err, _doc4) {\n                d.getCandidates({ r: 6, tf: { $lte: 9, $gte: 6 } }, function (err, data) {\n                  var doc2 = _.find(data, function (d) { return d._id === _doc2._id; })\n                    , doc4 = _.find(data, function (d) { return d._id === _doc4._id; })\n                    ;\n\n                  data.length.should.equal(2);\n                  assert.deepEqual(doc2, { _id: doc2._id, tf: 6 });\n                  assert.deepEqual(doc4, { _id: doc4._id, tf: 9 });\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it(\"Can set a TTL index that expires documents\", function (done) {\n      d.ensureIndex({ fieldName: 'exp', expireAfterSeconds: 0.2 }, function () {\n        d.insert({ hello: 'world', exp: new Date() }, function () {\n          setTimeout(function () {\n            d.findOne({}, function (err, doc) {\n              assert.isNull(err);\n              doc.hello.should.equal('world');\n\n              setTimeout(function () {\n                d.findOne({}, function (err, doc) {\n                  assert.isNull(err);\n                  assert.isNull(doc);\n\n                  d.on('compaction.done', function () {\n                    // After compaction, no more mention of the document, correctly removed\n                    var datafileContents = fs.readFileSync(testDb, 'utf8');\n                    datafileContents.split('\\n').length.should.equal(2);\n                    assert.isNull(datafileContents.match(/world/));\n\n                    // New datastore on same datafile is empty\n                    var d2 = new Datastore({ filename: testDb, autoload: true });\n                    d2.findOne({}, function (err, doc) {\n                      assert.isNull(err);\n                      assert.isNull(doc);\n\n                      done();\n                    });\n                  });\n\n                  d.persistence.compactDatafile();\n                });\n              }, 101);\n            });\n          }, 100);\n        });\n      });\n    });\n\n    it(\"TTL indexes can expire multiple documents and only what needs to be expired\", function (done) {\n      d.ensureIndex({ fieldName: 'exp', expireAfterSeconds: 0.2 }, function () {\n        d.insert({ hello: 'world1', exp: new Date() }, function () {\n          d.insert({ hello: 'world2', exp: new Date() }, function () {\n            d.insert({ hello: 'world3', exp: new Date((new Date()).getTime() + 100) }, function () {\n              setTimeout(function () {\n                d.find({}, function (err, docs) {\n                  assert.isNull(err);\n                  docs.length.should.equal(3);\n\n                  setTimeout(function () {\n                    d.find({}, function (err, docs) {\n                      assert.isNull(err);\n                      docs.length.should.equal(1);\n                      docs[0].hello.should.equal('world3');\n\n                      setTimeout(function () {\n                        d.find({}, function (err, docs) {\n                          assert.isNull(err);\n                          docs.length.should.equal(0);\n\n                          done();\n                        });\n                      }, 101);\n                    });\n                  }, 101);\n                });\n              }, 100);\n            });\n          });\n        });\n      });\n    });\n\n    it(\"Document where indexed field is absent or not a date are ignored\", function (done) {\n      d.ensureIndex({ fieldName: 'exp', expireAfterSeconds: 0.2 }, function () {\n        d.insert({ hello: 'world1', exp: new Date() }, function () {\n          d.insert({ hello: 'world2', exp: \"not a date\" }, function () {\n            d.insert({ hello: 'world3' }, function () {\n              setTimeout(function () {\n                d.find({}, function (err, docs) {\n                  assert.isNull(err);\n                  docs.length.should.equal(3);\n\n                  setTimeout(function () {\n                    d.find({}, function (err, docs) {\n                      assert.isNull(err);\n                      docs.length.should.equal(2);\n\n\n                      docs[0].hello.should.not.equal('world1');\n                      docs[1].hello.should.not.equal('world1');\n\n                      done();\n                    });\n                  }, 101);\n                });\n              }, 100);\n            });\n          });\n        });\n      });\n    });\n\n  });   // ==== End of '#getCandidates' ==== //\n\n\n  describe('Find', function () {\n\n    it('Can find all documents if an empty query is used', function (done) {\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err) {\n          d.insert({ somedata: 'another', plus: 'additional data' }, function (err) {\n            d.insert({ somedata: 'again' }, function (err) { return cb(err); });\n          });\n        });\n      }\n      , function (cb) {   // Test with empty object\n        d.find({}, function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(3);\n          _.pluck(docs, 'somedata').should.contain('ok');\n          _.pluck(docs, 'somedata').should.contain('another');\n          _.find(docs, function (d) { return d.somedata === 'another' }).plus.should.equal('additional data');\n          _.pluck(docs, 'somedata').should.contain('again');\n          return cb();\n        });\n      }\n      ], done);\n    });\n\n    it('Can find all documents matching a basic query', function (done) {\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err) {\n          d.insert({ somedata: 'again', plus: 'additional data' }, function (err) {\n            d.insert({ somedata: 'again' }, function (err) { return cb(err); });\n          });\n        });\n      }\n      , function (cb) {   // Test with query that will return docs\n        d.find({ somedata: 'again' }, function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(2);\n          _.pluck(docs, 'somedata').should.not.contain('ok');\n          return cb();\n        });\n      }\n      , function (cb) {   // Test with query that doesn't match anything\n        d.find({ somedata: 'nope' }, function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(0);\n          return cb();\n        });\n      }\n      ], done);\n    });\n\n    it('Can find one document matching a basic query and return null if none is found', function (done) {\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err) {\n          d.insert({ somedata: 'again', plus: 'additional data' }, function (err) {\n            d.insert({ somedata: 'again' }, function (err) { return cb(err); });\n          });\n        });\n      }\n      , function (cb) {   // Test with query that will return docs\n        d.findOne({ somedata: 'ok' }, function (err, doc) {\n          assert.isNull(err);\n          Object.keys(doc).length.should.equal(2);\n          doc.somedata.should.equal('ok');\n          assert.isDefined(doc._id);\n          return cb();\n        });\n      }\n      , function (cb) {   // Test with query that doesn't match anything\n        d.findOne({ somedata: 'nope' }, function (err, doc) {\n          assert.isNull(err);\n          assert.isNull(doc);\n          return cb();\n        });\n      }\n      ], done);\n    });\n\n    it('Can find dates and objects (non JS-native types)', function (done) {\n      var date1 = new Date(1234543)\n        , date2 = new Date(9999)\n        ;\n\n      d.insert({ now: date1, sth: { name: 'nedb' } }, function () {\n        d.findOne({ now: date1 }, function (err, doc) {\n          assert.isNull(err);\n          doc.sth.name.should.equal('nedb');\n\n          d.findOne({ now: date2 }, function (err, doc) {\n            assert.isNull(err);\n            assert.isNull(doc);\n\n            d.findOne({ sth: { name: 'nedb' } }, function (err, doc) {\n              assert.isNull(err);\n              doc.sth.name.should.equal('nedb');\n\n              d.findOne({ sth: { name: 'other' } }, function (err, doc) {\n                assert.isNull(err);\n                assert.isNull(doc);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can use dot-notation to query subfields', function (done) {\n      d.insert({ greeting: { english: 'hello' } }, function () {\n        d.findOne({ \"greeting.english\": 'hello' }, function (err, doc) {\n          assert.isNull(err);\n          doc.greeting.english.should.equal('hello');\n\n          d.findOne({ \"greeting.english\": 'hellooo' }, function (err, doc) {\n            assert.isNull(err);\n            assert.isNull(doc);\n\n            d.findOne({ \"greeting.englis\": 'hello' }, function (err, doc) {\n              assert.isNull(err);\n              assert.isNull(doc);\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it('Array fields match if any element matches', function (done) {\n      d.insert({ fruits: ['pear', 'apple', 'banana'] }, function (err, doc1) {\n        d.insert({ fruits: ['coconut', 'orange', 'pear'] }, function (err, doc2) {\n          d.insert({ fruits: ['banana'] }, function (err, doc3) {\n            d.find({ fruits: 'pear' }, function (err, docs) {\n              assert.isNull(err);\n              docs.length.should.equal(2);\n              _.pluck(docs, '_id').should.contain(doc1._id);\n              _.pluck(docs, '_id').should.contain(doc2._id);\n\n              d.find({ fruits: 'banana' }, function (err, docs) {\n                assert.isNull(err);\n                docs.length.should.equal(2);\n                _.pluck(docs, '_id').should.contain(doc1._id);\n                _.pluck(docs, '_id').should.contain(doc3._id);\n\n                d.find({ fruits: 'doesntexist' }, function (err, docs) {\n                  assert.isNull(err);\n                  docs.length.should.equal(0);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Returns an error if the query is not well formed', function (done) {\n      d.insert({ hello: 'world' }, function () {\n        d.find({ $or: { hello: 'world' } }, function (err, docs) {\n          assert.isDefined(err);\n          assert.isUndefined(docs);\n\n          d.findOne({ $or: { hello: 'world' } }, function (err, doc) {\n            assert.isDefined(err);\n            assert.isUndefined(doc);\n\n            done();\n          });\n        });\n      });\n    });\n\n    it('Changing the documents returned by find or findOne do not change the database state', function (done) {\n      d.insert({ a: 2, hello: 'world' }, function () {\n        d.findOne({ a: 2 }, function (err, doc) {\n          doc.hello = 'changed';\n\n          d.findOne({ a: 2 }, function (err, doc) {\n            doc.hello.should.equal('world');\n\n            d.find({ a: 2 }, function (err, docs) {\n              docs[0].hello = 'changed';\n\n              d.findOne({ a: 2 }, function (err, doc) {\n                doc.hello.should.equal('world');\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n    \n    it('Can use sort, skip and limit if the callback is not passed to find but to exec', function (done) {\n      d.insert({ a: 2, hello: 'world' }, function () {\n        d.insert({ a: 24, hello: 'earth' }, function () {\n          d.insert({ a: 13, hello: 'blueplanet' }, function () {\n            d.insert({ a: 15, hello: 'home' }, function () {\n              d.find({}).sort({ a: 1 }).limit(2).exec(function (err, docs) {\n                assert.isNull(err);\n                docs.length.should.equal(2);\n                docs[0].hello.should.equal('world');\n                docs[1].hello.should.equal('blueplanet');\n                done();\n              });\n            });\n          });\n        });      \n      });\n    });\n\n     it('Can use sort and skip if the callback is not passed to findOne but to exec', function (done) {\n      d.insert({ a: 2, hello: 'world' }, function () {\n        d.insert({ a: 24, hello: 'earth' }, function () {\n          d.insert({ a: 13, hello: 'blueplanet' }, function () {\n            d.insert({ a: 15, hello: 'home' }, function () {\n              // No skip no query\n              d.findOne({}).sort({ a: 1 }).exec(function (err, doc) {\n                assert.isNull(err);\n                doc.hello.should.equal('world');\n                \n                // A query\n                d.findOne({ a: { $gt: 14 } }).sort({ a: 1 }).exec(function (err, doc) {\n                  assert.isNull(err);\n                  doc.hello.should.equal('home');\n\n                  // And a skip\n                  d.findOne({ a: { $gt: 14 } }).sort({ a: 1 }).skip(1).exec(function (err, doc) {\n                    assert.isNull(err);\n                    doc.hello.should.equal('earth');\n\n                    // No result\n                    d.findOne({ a: { $gt: 14 } }).sort({ a: 1 }).skip(2).exec(function (err, doc) {\n                      assert.isNull(err);\n                      assert.isNull(doc);\n\n                      done();\n                    });\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can use projections in find, normal or cursor way', function (done) {\n      d.insert({ a: 2, hello: 'world' }, function (err, doc0) {\n        d.insert({ a: 24, hello: 'earth' }, function (err, doc1) {\n          d.find({ a: 2 }, { a: 0, _id: 0 }, function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(1);\n            assert.deepEqual(docs[0], { hello: 'world' });\n\n            d.find({ a: 2 }, { a: 0, _id: 0 }).exec(function (err, docs) {\n              assert.isNull(err);\n              docs.length.should.equal(1);\n              assert.deepEqual(docs[0], { hello: 'world' });\n\n              // Can't use both modes at once if not _id\n              d.find({ a: 2 }, { a: 0, hello: 1 }, function (err, docs) {\n                assert.isNotNull(err);\n                assert.isUndefined(docs);\n\n                d.find({ a: 2 }, { a: 0, hello: 1 }).exec(function (err, docs) {\n                  assert.isNotNull(err);\n                  assert.isUndefined(docs);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can use projections in findOne, normal or cursor way', function (done) {\n      d.insert({ a: 2, hello: 'world' }, function (err, doc0) {\n        d.insert({ a: 24, hello: 'earth' }, function (err, doc1) {\n          d.findOne({ a: 2 }, { a: 0, _id: 0 }, function (err, doc) {\n            assert.isNull(err);\n            assert.deepEqual(doc, { hello: 'world' });\n\n            d.findOne({ a: 2 }, { a: 0, _id: 0 }).exec(function (err, doc) {\n              assert.isNull(err);\n              assert.deepEqual(doc, { hello: 'world' });\n\n              // Can't use both modes at once if not _id\n              d.findOne({ a: 2 }, { a: 0, hello: 1 }, function (err, doc) {\n                assert.isNotNull(err);\n                assert.isUndefined(doc);\n\n                d.findOne({ a: 2 }, { a: 0, hello: 1 }).exec(function (err, doc) {\n                  assert.isNotNull(err);\n                  assert.isUndefined(doc);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n  });   // ==== End of 'Find' ==== //\n\n  describe('Count', function() {\n\n    it('Count all documents if an empty query is used', function (done) {\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err) {\n          d.insert({ somedata: 'another', plus: 'additional data' }, function (err) {\n            d.insert({ somedata: 'again' }, function (err) { return cb(err); });\n          });\n        });\n      }\n      , function (cb) {   // Test with empty object\n        d.count({}, function (err, docs) {\n          assert.isNull(err);\n          docs.should.equal(3);\n          return cb();\n        });\n      }\n      ], done);\n    });\n\n    it('Count all documents matching a basic query', function (done) {\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err) {\n          d.insert({ somedata: 'again', plus: 'additional data' }, function (err) {\n            d.insert({ somedata: 'again' }, function (err) { return cb(err); });\n          });\n        });\n      }\n      , function (cb) {   // Test with query that will return docs\n        d.count({ somedata: 'again' }, function (err, docs) {\n          assert.isNull(err);\n          docs.should.equal(2);\n          return cb();\n        });\n      }\n      , function (cb) {   // Test with query that doesn't match anything\n        d.count({ somedata: 'nope' }, function (err, docs) {\n          assert.isNull(err);\n          docs.should.equal(0);\n          return cb();\n        });\n      }\n      ], done);\n    });\n\n    it('Array fields match if any element matches', function (done) {\n      d.insert({ fruits: ['pear', 'apple', 'banana'] }, function (err, doc1) {\n        d.insert({ fruits: ['coconut', 'orange', 'pear'] }, function (err, doc2) {\n          d.insert({ fruits: ['banana'] }, function (err, doc3) {\n            d.count({ fruits: 'pear' }, function (err, docs) {\n              assert.isNull(err);\n              docs.should.equal(2);\n\n              d.count({ fruits: 'banana' }, function (err, docs) {\n                assert.isNull(err);\n                docs.should.equal(2);\n\n                d.count({ fruits: 'doesntexist' }, function (err, docs) {\n                  assert.isNull(err);\n                  docs.should.equal(0);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Returns an error if the query is not well formed', function (done) {\n      d.insert({ hello: 'world' }, function () {\n        d.count({ $or: { hello: 'world' } }, function (err, docs) {\n          assert.isDefined(err);\n          assert.isUndefined(docs);\n\n          done();\n        });\n      });\n    });\n\n  });\n\n  describe('Update', function () {\n\n    it(\"If the query doesn't match anything, database is not modified\", function (done) {\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err) {\n          d.insert({ somedata: 'again', plus: 'additional data' }, function (err) {\n            d.insert({ somedata: 'another' }, function (err) { return cb(err); });\n          });\n        });\n      }\n      , function (cb) {   // Test with query that doesn't match anything\n        d.update({ somedata: 'nope' }, { newDoc: 'yes' }, { multi: true }, function (err, n) {\n          assert.isNull(err);\n          n.should.equal(0);\n\n          d.find({}, function (err, docs) {\n            var doc1 = _.find(docs, function (d) { return d.somedata === 'ok'; })\n              , doc2 = _.find(docs, function (d) { return d.somedata === 'again'; })\n              , doc3 = _.find(docs, function (d) { return d.somedata === 'another'; })\n              ;\n\n            docs.length.should.equal(3);\n            assert.isUndefined(_.find(docs, function (d) { return d.newDoc === 'yes'; }));\n\n            assert.deepEqual(doc1, { _id: doc1._id, somedata: 'ok' });\n            assert.deepEqual(doc2, { _id: doc2._id, somedata: 'again', plus: 'additional data' });\n            assert.deepEqual(doc3, { _id: doc3._id, somedata: 'another' });\n\n            return cb();\n          });\n        });\n      }\n      ], done);\n    });\n\n    it(\"If timestampData option is set, update the updatedAt field\", function (done) {\n      var beginning = Date.now();\n      d = new Datastore({ filename: testDb, autoload: true, timestampData: true });\n      d.insert({ hello: 'world' }, function (err, insertedDoc) {\n        assert.isBelow(insertedDoc.updatedAt.getTime() - beginning, reloadTimeUpperBound);\n        assert.isBelow(insertedDoc.createdAt.getTime() - beginning, reloadTimeUpperBound);\n        Object.keys(insertedDoc).length.should.equal(4);\n\n        // Wait 100ms before performing the update\n        setTimeout(function () {\n          var step1 = Date.now();\n          d.update({ _id: insertedDoc._id }, { $set: { hello: 'mars' } }, {}, function () {\n            d.find({ _id: insertedDoc._id }, function (err, docs) {\n              docs.length.should.equal(1);\n              Object.keys(docs[0]).length.should.equal(4);\n              docs[0]._id.should.equal(insertedDoc._id);\n              docs[0].createdAt.should.equal(insertedDoc.createdAt);\n              docs[0].hello.should.equal('mars');\n              assert.isAbove(docs[0].updatedAt.getTime() - beginning, 99);   // updatedAt modified\n              assert.isBelow(docs[0].updatedAt.getTime() - step1, reloadTimeUpperBound);   // updatedAt modified\n\n              done();\n            });\n          })\n        }, 100);\n      });\n    });\n\n    it(\"Can update multiple documents matching the query\", function (done) {\n      var id1, id2, id3;\n\n      // Test DB state after update and reload\n      function testPostUpdateState (cb) {\n        d.find({}, function (err, docs) {\n          var doc1 = _.find(docs, function (d) { return d._id === id1; })\n            , doc2 = _.find(docs, function (d) { return d._id === id2; })\n            , doc3 = _.find(docs, function (d) { return d._id === id3; })\n            ;\n\n          docs.length.should.equal(3);\n\n          Object.keys(doc1).length.should.equal(2);\n          doc1.somedata.should.equal('ok');\n          doc1._id.should.equal(id1);\n\n          Object.keys(doc2).length.should.equal(2);\n          doc2.newDoc.should.equal('yes');\n          doc2._id.should.equal(id2);\n\n          Object.keys(doc3).length.should.equal(2);\n          doc3.newDoc.should.equal('yes');\n          doc3._id.should.equal(id3);\n\n          return cb();\n        });\n      }\n\n      // Actually launch the tests\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err, doc1) {\n          id1 = doc1._id;\n          d.insert({ somedata: 'again', plus: 'additional data' }, function (err, doc2) {\n            id2 = doc2._id;\n            d.insert({ somedata: 'again' }, function (err, doc3) {\n              id3 = doc3._id;\n              return cb(err);\n            });\n          });\n        });\n      }\n      , function (cb) {\n        d.update({ somedata: 'again' }, { newDoc: 'yes' }, { multi: true }, function (err, n) {\n          assert.isNull(err);\n          n.should.equal(2);\n          return cb();\n        });\n      }\n      , async.apply(testPostUpdateState)\n      , function (cb) {\n        d.loadDatabase(function (err) { cb(err); });\n      }\n      , async.apply(testPostUpdateState)\n      ], done);\n    });\n\n    it(\"Can update only one document matching the query\", function (done) {\n      var id1, id2, id3;\n\n      // Test DB state after update and reload\n      function testPostUpdateState (cb) {\n        d.find({}, function (err, docs) {\n          var doc1 = _.find(docs, function (d) { return d._id === id1; })\n            , doc2 = _.find(docs, function (d) { return d._id === id2; })\n            , doc3 = _.find(docs, function (d) { return d._id === id3; })\n            ;\n\n          docs.length.should.equal(3);\n\n          assert.deepEqual(doc1, { somedata: 'ok', _id: doc1._id });\n\n          // doc2 or doc3 was modified. Since we sort on _id and it is random\n          // it can be either of two situations\n          try {\n            assert.deepEqual(doc2, { newDoc: 'yes', _id: doc2._id });\n            assert.deepEqual(doc3, { somedata: 'again', _id: doc3._id });\n          } catch (e) {\n            assert.deepEqual(doc2, { somedata: 'again', plus: 'additional data', _id: doc2._id });\n            assert.deepEqual(doc3, { newDoc: 'yes', _id: doc3._id });\n          }\n\n          return cb();\n        });\n      }\n\n      // Actually launch the test\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err, doc1) {\n          id1 = doc1._id;\n          d.insert({ somedata: 'again', plus: 'additional data' }, function (err, doc2) {\n            id2 = doc2._id;\n            d.insert({ somedata: 'again' }, function (err, doc3) {\n              id3 = doc3._id;\n              return cb(err);\n            });\n          });\n        });\n      }\n      , function (cb) {   // Test with query that doesn't match anything\n        d.update({ somedata: 'again' }, { newDoc: 'yes' }, { multi: false }, function (err, n) {\n          assert.isNull(err);\n          n.should.equal(1);\n          return cb();\n        });\n      }\n      , async.apply(testPostUpdateState)\n      , function (cb) {\n        d.loadDatabase(function (err) { return cb(err); });\n      }\n      , async.apply(testPostUpdateState)   // The persisted state has been updated\n      ], done);\n    });\n\n    describe('Upserts', function () {\n\n      it('Can perform upserts if needed', function (done) {\n        d.update({ impossible: 'db is empty anyway' }, { newDoc: true }, {}, function (err, nr, upsert) {\n          assert.isNull(err);\n          nr.should.equal(0);\n          assert.isUndefined(upsert);\n\n          d.find({}, function (err, docs) {\n            docs.length.should.equal(0);   // Default option for upsert is false\n\n            d.update({ impossible: 'db is empty anyway' }, { something: \"created ok\" }, { upsert: true }, function (err, nr, newDoc) {\n              assert.isNull(err);\n              nr.should.equal(1);\n              newDoc.something.should.equal(\"created ok\");\n              assert.isDefined(newDoc._id);\n\n              d.find({}, function (err, docs) {\n                docs.length.should.equal(1);   // Default option for upsert is false\n                docs[0].something.should.equal(\"created ok\");\n                \n                // Modifying the returned upserted document doesn't modify the database\n                newDoc.newField = true;\n                d.find({}, function (err, docs) {\n                  docs[0].something.should.equal(\"created ok\");\n                  assert.isUndefined(docs[0].newField);\n                \n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n      \n      it('If the update query is a normal object with no modifiers, it is the doc that will be upserted', function (done) {\n        d.update({ $or: [{ a: 4 }, { a: 5 }] }, { hello: 'world', bloup: 'blap' }, { upsert: true }, function (err) {\n          d.find({}, function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(1);\n            var doc = docs[0];\n            Object.keys(doc).length.should.equal(3);\n            doc.hello.should.equal('world');\n            doc.bloup.should.equal('blap');\n            done();\n          });\n        });\n      });\n      \n      it('If the update query contains modifiers, it is applied to the object resulting from removing all operators from the find query 1', function (done) {\n        d.update({ $or: [{ a: 4 }, { a: 5 }] }, { $set: { hello: 'world' }, $inc: { bloup: 3 } }, { upsert: true }, function (err) {\n          d.find({ hello: 'world' }, function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(1);\n            var doc = docs[0];\n            Object.keys(doc).length.should.equal(3);\n            doc.hello.should.equal('world');\n            doc.bloup.should.equal(3);\n            done();\n          });\n        });\n      });\n      \n      it('If the update query contains modifiers, it is applied to the object resulting from removing all operators from the find query 2', function (done) {\n        d.update({ $or: [{ a: 4 }, { a: 5 }], cac: 'rrr' }, { $set: { hello: 'world' }, $inc: { bloup: 3 } }, { upsert: true }, function (err) {\n          d.find({ hello: 'world' }, function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(1);\n            var doc = docs[0];\n            Object.keys(doc).length.should.equal(4);\n            doc.cac.should.equal('rrr');\n            doc.hello.should.equal('world');\n            doc.bloup.should.equal(3);\n            done();\n          });\n        });\n      });\n      \n      it('Performing upsert with badly formatted fields yields a standard error not an exception', function(done) {\n        d.update({_id: '1234'}, { $set: { $$badfield: 5 }}, { upsert: true }, function(err, doc) {\n          assert.isDefined(err);\n          done();\n        })\n      });\n\n\n    });   // ==== End of 'Upserts' ==== //\n\n    it('Cannot perform update if the update query is not either registered-modifiers-only or copy-only, or contain badly formatted fields', function (done) {\n      d.insert({ something: 'yup' }, function () {\n        d.update({}, { boom: { $badfield: 5 } }, { multi: false }, function (err) {\n          assert.isDefined(err);\n\n          d.update({}, { boom: { \"bad.field\": 5 } }, { multi: false }, function (err) {\n            assert.isDefined(err);\n\n            d.update({}, { $inc: { test: 5 }, mixed: 'rrr' }, { multi: false }, function (err) {\n              assert.isDefined(err);\n\n              d.update({}, { $inexistent: { test: 5 } }, { multi: false }, function (err) {\n                assert.isDefined(err);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Can update documents using multiple modifiers', function (done) {\n      var id;\n\n      d.insert({ something: 'yup', other: 40 }, function (err, newDoc) {\n        id = newDoc._id;\n\n        d.update({}, { $set: { something: 'changed' }, $inc: { other: 10 } }, { multi: false }, function (err, nr) {\n          assert.isNull(err);\n          nr.should.equal(1);\n\n          d.findOne({ _id: id }, function (err, doc) {\n            Object.keys(doc).length.should.equal(3);\n            doc._id.should.equal(id);\n            doc.something.should.equal('changed');\n            doc.other.should.equal(50);\n\n            done();\n          });\n        });\n      });\n    });\n\n    it('Can upsert a document even with modifiers', function (done) {\n      d.update({ bloup: 'blap' }, { $set: { hello: 'world' } }, { upsert: true }, function (err, nr, newDoc) {\n        assert.isNull(err);\n        nr.should.equal(1);\n        newDoc.bloup.should.equal('blap');\n        newDoc.hello.should.equal('world');\n        assert.isDefined(newDoc._id);\n\n        d.find({}, function (err, docs) {\n          docs.length.should.equal(1);\n          Object.keys(docs[0]).length.should.equal(3);\n          docs[0].hello.should.equal('world');\n          docs[0].bloup.should.equal('blap');\n          assert.isDefined(docs[0]._id);\n\n          done();\n        });\n      });\n    });\n\n    it('When using modifiers, the only way to update subdocs is with the dot-notation', function (done) {\n      d.insert({ bloup: { blip: \"blap\", other: true } }, function () {\n        // Correct methos\n        d.update({}, { $set: { \"bloup.blip\": \"hello\" } }, {}, function () {\n          d.findOne({}, function (err, doc) {\n            doc.bloup.blip.should.equal(\"hello\");\n            doc.bloup.other.should.equal(true);\n\n            // Wrong\n            d.update({}, { $set: { bloup: { blip: \"ola\" } } }, {}, function () {\n              d.findOne({}, function (err, doc) {\n                doc.bloup.blip.should.equal(\"ola\");\n                assert.isUndefined(doc.bloup.other);   // This information was lost\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Returns an error if the query is not well formed', function (done) {\n      d.insert({ hello: 'world' }, function () {\n        d.update({ $or: { hello: 'world' } }, { a: 1 }, {}, function (err, nr, upsert) {\n          assert.isDefined(err);\n          assert.isUndefined(nr);\n          assert.isUndefined(upsert);\n\n          done();\n        });\n      });\n    });\n\n    it('If an error is thrown by a modifier, the database state is not changed', function (done) {\n      d.insert({ hello: 'world' }, function (err, newDoc) {\n        d.update({}, { $inc: { hello: 4 } }, {}, function (err, nr) {\n          assert.isDefined(err);\n          assert.isUndefined(nr);\n\n          d.find({}, function (err, docs) {\n            assert.deepEqual(docs, [ { _id: newDoc._id, hello: 'world' } ]);\n\n            done();\n          });\n        });\n      });\n    });\n\n    it('Cant change the _id of a document', function (done) {\n      d.insert({ a: 2 }, function (err, newDoc) {\n        d.update({ a: 2 }, { a: 2, _id: 'nope' }, {}, function (err) {\n          assert.isDefined(err);\n\n          d.find({}, function (err, docs) {\n            docs.length.should.equal(1);\n            Object.keys(docs[0]).length.should.equal(2);\n            docs[0].a.should.equal(2);\n            docs[0]._id.should.equal(newDoc._id);\n\n            d.update({ a: 2 }, { $set: { _id: 'nope' } }, {}, function (err) {\n              assert.isDefined(err);\n\n              d.find({}, function (err, docs) {\n                docs.length.should.equal(1);\n                Object.keys(docs[0]).length.should.equal(2);\n                docs[0].a.should.equal(2);\n                docs[0]._id.should.equal(newDoc._id);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Non-multi updates are persistent', function (done) {\n      d.insert({ a:1, hello: 'world' }, function (err, doc1) {\n        d.insert({ a:2, hello: 'earth' }, function (err, doc2) {\n          d.update({ a: 2 }, { $set: { hello: 'changed' } }, {}, function (err) {\n            assert.isNull(err);\n\n            d.find({}, function (err, docs) {\n              docs.sort(function (a, b) { return a.a - b.a; });\n              docs.length.should.equal(2);\n              _.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'world' }).should.equal(true);\n              _.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);\n\n              // Even after a reload the database state hasn't changed\n              d.loadDatabase(function (err) {\n                assert.isNull(err);\n\n                d.find({}, function (err, docs) {\n                  docs.sort(function (a, b) { return a.a - b.a; });\n                  docs.length.should.equal(2);\n                  _.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'world' }).should.equal(true);\n                  _.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Multi updates are persistent', function (done) {\n      d.insert({ a:1, hello: 'world' }, function (err, doc1) {\n        d.insert({ a:2, hello: 'earth' }, function (err, doc2) {\n          d.insert({ a:5, hello: 'pluton' }, function (err, doc3) {\n            d.update({ a: { $in: [1, 2] } }, { $set: { hello: 'changed' } }, { multi: true }, function (err) {\n              assert.isNull(err);\n\n              d.find({}, function (err, docs) {\n                docs.sort(function (a, b) { return a.a - b.a; });\n                docs.length.should.equal(3);\n                _.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'changed' }).should.equal(true);\n                _.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);\n                _.isEqual(docs[2], { _id: doc3._id, a:5, hello: 'pluton' }).should.equal(true);\n\n                // Even after a reload the database state hasn't changed\n                d.loadDatabase(function (err) {\n                  assert.isNull(err);\n\n                  d.find({}, function (err, docs) {\n                    docs.sort(function (a, b) { return a.a - b.a; });\n                    docs.length.should.equal(3);\n                    _.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'changed' }).should.equal(true);\n                    _.isEqual(docs[1], { _id: doc2._id, a:2, hello: 'changed' }).should.equal(true);\n                    _.isEqual(docs[2], { _id: doc3._id, a:5, hello: 'pluton' }).should.equal(true);\n\n                    done();\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n    \n    it('Can update without the options arg (will use defaults then)', function (done) {\n      d.insert({ a:1, hello: 'world' }, function (err, doc1) {\n        d.insert({ a:2, hello: 'earth' }, function (err, doc2) {\n          d.insert({ a:5, hello: 'pluton' }, function (err, doc3) {\n            d.update({ a: 2 }, { $inc: { a: 10 } }, function (err, nr) {\n              assert.isNull(err);\n              nr.should.equal(1);\n              d.find({}, function (err, docs) {\n                var d1 = _.find(docs, function (doc) { return doc._id === doc1._id })\n                  , d2 = _.find(docs, function (doc) { return doc._id === doc2._id })\n                  , d3 = _.find(docs, function (doc) { return doc._id === doc3._id })\n                  ;\n                  \n                d1.a.should.equal(1);\n                d2.a.should.equal(12);\n                d3.a.should.equal(5);\n                \n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('If a multi update fails on one document, previous updates should be rolled back', function (done) {\n      d.ensureIndex({ fieldName: 'a' });\n      d.insert({ a: 4 }, function (err, doc1) {\n        d.insert({ a: 5 }, function (err, doc2) {\n          d.insert({ a: 'abc' }, function (err, doc3) {\n            // With this query, candidates are always returned in the order 4, 5, 'abc' so it's always the last one which fails\n            d.update({ a: { $in: [4, 5, 'abc'] } }, { $inc: { a: 10 } }, { multi: true }, function (err) {\n              assert.isDefined(err);\n\n              // No index modified\n              _.each(d.indexes, function (index) {\n                var docs = index.getAll()\n                  , d1 = _.find(docs, function (doc) { return doc._id === doc1._id })\n                  , d2 = _.find(docs, function (doc) { return doc._id === doc2._id })\n                  , d3 = _.find(docs, function (doc) { return doc._id === doc3._id })\n                  ;\n\n                // All changes rolled back, including those that didn't trigger an error\n                d1.a.should.equal(4);\n                d2.a.should.equal(5);\n                d3.a.should.equal('abc');\n              });\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it('If an index constraint is violated by an update, all changes should be rolled back', function (done) {\n      d.ensureIndex({ fieldName: 'a', unique: true });\n      d.insert({ a: 4 }, function (err, doc1) {\n        d.insert({ a: 5 }, function (err, doc2) {\n          // With this query, candidates are always returned in the order 4, 5, 'abc' so it's always the last one which fails\n           d.update({ a: { $in: [4, 5, 'abc'] } }, { $set: { a: 10 } }, { multi: true }, function (err) {\n            assert.isDefined(err);\n\n            // Check that no index was modified\n            _.each(d.indexes, function (index) {\n              var docs = index.getAll()\n              , d1 = _.find(docs, function (doc) { return doc._id === doc1._id })\n              , d2 = _.find(docs, function (doc) { return doc._id === doc2._id })\n              ;\n\n              d1.a.should.equal(4);\n              d2.a.should.equal(5);\n            });\n\n            done();\n          });\n        });\n      });\n    });\n\n    it(\"If options.returnUpdatedDocs is true, return all matched docs\", function (done) {\n      d.insert([{ a: 4 }, { a: 5 }, { a: 6 }], function (err, docs) {\n        docs.length.should.equal(3);\n\n        d.update({ a: 7 }, { $set: { u: 1 } }, { multi: true, returnUpdatedDocs: true }, function (err, num, updatedDocs) {\n          num.should.equal(0);\n          updatedDocs.length.should.equal(0);\n\n          d.update({ a: 5 }, { $set: { u: 2 } }, { multi: true, returnUpdatedDocs: true }, function (err, num, updatedDocs) {\n            num.should.equal(1);\n            updatedDocs.length.should.equal(1);\n            updatedDocs[0].a.should.equal(5);\n            updatedDocs[0].u.should.equal(2);\n\n            d.update({ a: { $in: [4, 6] } }, { $set: { u: 3 } }, { multi: true, returnUpdatedDocs: true }, function (err, num, updatedDocs) {\n              num.should.equal(2);\n              updatedDocs.length.should.equal(2);\n              updatedDocs[0].u.should.equal(3);\n              updatedDocs[1].u.should.equal(3);\n              if (updatedDocs[0].a === 4) {\n                updatedDocs[0].a.should.equal(4);\n                updatedDocs[1].a.should.equal(6);\n              } else {\n                updatedDocs[0].a.should.equal(6);\n                updatedDocs[1].a.should.equal(4);\n              }\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it(\"createdAt property is unchanged and updatedAt correct after an update, even a complete document replacement\", function (done) {\n      var d2 = new Datastore({ inMemoryOnly: true, timestampData: true });\n      d2.insert({ a: 1 });\n      d2.findOne({ a: 1 }, function (err, doc) {\n        var createdAt = doc.createdAt.getTime();\n\n        // Modifying update\n        setTimeout(function () {\n          d2.update({ a: 1 }, { $set: { b: 2 } }, {});\n          d2.findOne({ a: 1 }, function (err, doc) {\n            doc.createdAt.getTime().should.equal(createdAt);\n            assert.isBelow(Date.now() - doc.updatedAt.getTime(), 5);\n\n            // Complete replacement\n            setTimeout(function () {\n              d2.update({ a: 1 }, { c: 3 }, {});\n              d2.findOne({ c: 3 }, function (err, doc) {\n                doc.createdAt.getTime().should.equal(createdAt);\n                assert.isBelow(Date.now() - doc.updatedAt.getTime(), 5);\n\n                done();\n              });\n            }, 20);\n          });\n        }, 20);\n      });\n    });\n\n\n    describe(\"Callback signature\", function () {\n\n      it(\"Regular update, multi false\", function (done) {\n        d.insert({ a: 1 });\n        d.insert({ a: 2 });\n\n        // returnUpdatedDocs set to false\n        d.update({ a: 1 }, { $set: { b: 20 } }, {}, function (err, numAffected, affectedDocuments, upsert) {\n          assert.isNull(err);\n          numAffected.should.equal(1);\n          assert.isUndefined(affectedDocuments);\n          assert.isUndefined(upsert);\n\n          // returnUpdatedDocs set to true\n          d.update({ a: 1 }, { $set: { b: 21 } }, { returnUpdatedDocs: true }, function (err, numAffected, affectedDocuments, upsert) {\n            assert.isNull(err);\n            numAffected.should.equal(1);\n            affectedDocuments.a.should.equal(1);\n            affectedDocuments.b.should.equal(21);\n            assert.isUndefined(upsert);\n\n            done();\n          });\n        });\n      });\n\n      it(\"Regular update, multi true\", function (done) {\n        d.insert({ a: 1 });\n        d.insert({ a: 2 });\n\n        // returnUpdatedDocs set to false\n        d.update({}, { $set: { b: 20 } }, { multi: true }, function (err, numAffected, affectedDocuments, upsert) {\n          assert.isNull(err);\n          numAffected.should.equal(2);\n          assert.isUndefined(affectedDocuments);\n          assert.isUndefined(upsert);\n\n          // returnUpdatedDocs set to true\n          d.update({}, { $set: { b: 21 } }, { multi: true, returnUpdatedDocs: true }, function (err, numAffected, affectedDocuments, upsert) {\n            assert.isNull(err);\n            numAffected.should.equal(2);\n            affectedDocuments.length.should.equal(2);\n            assert.isUndefined(upsert);\n\n            done();\n          });\n        });\n      });\n\n      it(\"Upsert\", function (done) {\n        d.insert({ a: 1 });\n        d.insert({ a: 2 });\n\n        // Upsert flag not set\n        d.update({ a: 3 }, { $set: { b: 20 } }, {}, function (err, numAffected, affectedDocuments, upsert) {\n          assert.isNull(err);\n          numAffected.should.equal(0);\n          assert.isUndefined(affectedDocuments);\n          assert.isUndefined(upsert);\n\n          // Upsert flag set\n          d.update({ a: 3 }, { $set: { b: 21 } }, { upsert: true }, function (err, numAffected, affectedDocuments, upsert) {\n            assert.isNull(err);\n            numAffected.should.equal(1);\n            affectedDocuments.a.should.equal(3);\n            affectedDocuments.b.should.equal(21);\n            upsert.should.equal(true);\n\n            d.find({}, function (err, docs) {\n              docs.length.should.equal(3);\n              done();\n            });\n          });\n        });\n      });\n\n\n    });   // ==== End of 'Update - Callback signature' ==== //\n\n  });   // ==== End of 'Update' ==== //\n\n\n  describe('Remove', function () {\n\n    it('Can remove multiple documents', function (done) {\n      var id1, id2, id3;\n\n      // Test DB status\n      function testPostUpdateState (cb) {\n        d.find({}, function (err, docs) {\n          docs.length.should.equal(1);\n\n          Object.keys(docs[0]).length.should.equal(2);\n          docs[0]._id.should.equal(id1);\n          docs[0].somedata.should.equal('ok');\n\n          return cb();\n        });\n      }\n\n      // Actually launch the test\n      async.waterfall([\n      function (cb) {\n        d.insert({ somedata: 'ok' }, function (err, doc1) {\n          id1 = doc1._id;\n          d.insert({ somedata: 'again', plus: 'additional data' }, function (err, doc2) {\n            id2 = doc2._id;\n            d.insert({ somedata: 'again' }, function (err, doc3) {\n              id3 = doc3._id;\n              return cb(err);\n            });\n          });\n        });\n      }\n      , function (cb) {   // Test with query that doesn't match anything\n        d.remove({ somedata: 'again' }, { multi: true }, function (err, n) {\n          assert.isNull(err);\n          n.should.equal(2);\n          return cb();\n        });\n      }\n      , async.apply(testPostUpdateState)\n      , function (cb) {\n        d.loadDatabase(function (err) { return cb(err); });\n      }\n      , async.apply(testPostUpdateState)\n      ], done);\n    });\n\n    // This tests concurrency issues\n    it('Remove can be called multiple times in parallel and everything that needs to be removed will be', function (done) {\n      d.insert({ planet: 'Earth' }, function () {\n        d.insert({ planet: 'Mars' }, function () {\n          d.insert({ planet: 'Saturn' }, function () {\n            d.find({}, function (err, docs) {\n              docs.length.should.equal(3);\n\n              // Remove two docs simultaneously\n              var toRemove = ['Mars', 'Saturn'];\n              async.each(toRemove, function(planet, cb) {\n                d.remove({ planet: planet }, function (err) { return cb(err); });\n              }, function (err) {\n                d.find({}, function (err, docs) {\n                  docs.length.should.equal(1);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Returns an error if the query is not well formed', function (done) {\n      d.insert({ hello: 'world' }, function () {\n        d.remove({ $or: { hello: 'world' } }, {}, function (err, nr, upsert) {\n          assert.isDefined(err);\n          assert.isUndefined(nr);\n          assert.isUndefined(upsert);\n\n          done();\n        });\n      });\n    });\n\n    it('Non-multi removes are persistent', function (done) {\n      d.insert({ a:1, hello: 'world' }, function (err, doc1) {\n        d.insert({ a:2, hello: 'earth' }, function (err, doc2) {\n          d.insert({ a:3, hello: 'moto' }, function (err, doc3) {\n            d.remove({ a: 2 }, {}, function (err) {\n              assert.isNull(err);\n\n              d.find({}, function (err, docs) {\n                docs.sort(function (a, b) { return a.a - b.a; });\n                docs.length.should.equal(2);\n                _.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'world' }).should.equal(true);\n                _.isEqual(docs[1], { _id: doc3._id, a:3, hello: 'moto' }).should.equal(true);\n\n                // Even after a reload the database state hasn't changed\n                d.loadDatabase(function (err) {\n                  assert.isNull(err);\n\n                  d.find({}, function (err, docs) {\n                    docs.sort(function (a, b) { return a.a - b.a; });\n                    docs.length.should.equal(2);\n                    _.isEqual(docs[0], { _id: doc1._id, a:1, hello: 'world' }).should.equal(true);\n                    _.isEqual(docs[1], { _id: doc3._id, a:3, hello: 'moto' }).should.equal(true);\n\n                    done();\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it('Multi removes are persistent', function (done) {\n      d.insert({ a:1, hello: 'world' }, function (err, doc1) {\n        d.insert({ a:2, hello: 'earth' }, function (err, doc2) {\n          d.insert({ a:3, hello: 'moto' }, function (err, doc3) {\n            d.remove({ a: { $in: [1, 3] } }, { multi: true }, function (err) {\n              assert.isNull(err);\n\n              d.find({}, function (err, docs) {\n                docs.length.should.equal(1);\n                _.isEqual(docs[0], { _id: doc2._id, a:2, hello: 'earth' }).should.equal(true);\n\n                // Even after a reload the database state hasn't changed\n                d.loadDatabase(function (err) {\n                  assert.isNull(err);\n\n                  d.find({}, function (err, docs) {\n                    docs.length.should.equal(1);\n                    _.isEqual(docs[0], { _id: doc2._id, a:2, hello: 'earth' }).should.equal(true);\n\n                    done();\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n    \n    it('Can remove without the options arg (will use defaults then)', function (done) {\n      d.insert({ a:1, hello: 'world' }, function (err, doc1) {\n        d.insert({ a:2, hello: 'earth' }, function (err, doc2) {\n          d.insert({ a:5, hello: 'pluton' }, function (err, doc3) {\n            d.remove({ a: 2 }, function (err, nr) {\n              assert.isNull(err);\n              nr.should.equal(1);\n              d.find({}, function (err, docs) {\n                var d1 = _.find(docs, function (doc) { return doc._id === doc1._id })\n                  , d2 = _.find(docs, function (doc) { return doc._id === doc2._id })\n                  , d3 = _.find(docs, function (doc) { return doc._id === doc3._id })\n                  ;\n                  \n                d1.a.should.equal(1);\n                assert.isUndefined(d2);\n                d3.a.should.equal(5);\n                \n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n  });   // ==== End of 'Remove' ==== //\n\n\n  describe('Using indexes', function () {\n\n    describe('ensureIndex and index initialization in database loading', function () {\n\n      it('ensureIndex can be called right after a loadDatabase and be initialized and filled correctly', function (done) {\n        var now = new Date()\n          , rawData = model.serialize({ _id: \"aaa\", z: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n                      model.serialize({ _id: \"bbb\", z: \"2\", hello: 'world' }) + '\\n' +\n                      model.serialize({ _id: \"ccc\", z: \"3\", nested: { today: now } })\n          ;\n\n        d.getAllData().length.should.equal(0);\n\n        fs.writeFile(testDb, rawData, 'utf8', function () {\n          d.loadDatabase(function () {\n            d.getAllData().length.should.equal(3);\n\n            assert.deepEqual(Object.keys(d.indexes), ['_id']);\n\n            d.ensureIndex({ fieldName: 'z' });\n            d.indexes.z.fieldName.should.equal('z');\n            d.indexes.z.unique.should.equal(false);\n            d.indexes.z.sparse.should.equal(false);\n            d.indexes.z.tree.getNumberOfKeys().should.equal(3);\n            d.indexes.z.tree.search('1')[0].should.equal(d.getAllData()[0]);\n            d.indexes.z.tree.search('2')[0].should.equal(d.getAllData()[1]);\n            d.indexes.z.tree.search('3')[0].should.equal(d.getAllData()[2]);\n\n            done();\n          });\n        });\n      });\n      \n      it('ensureIndex can be called twice on the same field, the second call will ahve no effect', function (done) {\n        Object.keys(d.indexes).length.should.equal(1);\n        Object.keys(d.indexes)[0].should.equal(\"_id\");\n      \n        d.insert({ planet: \"Earth\" }, function () {\n          d.insert({ planet: \"Mars\" }, function () {\n            d.find({}, function (err, docs) {\n              docs.length.should.equal(2);\n              \n              d.ensureIndex({ fieldName: \"planet\" }, function (err) {\n                assert.isNull(err);\n                Object.keys(d.indexes).length.should.equal(2);\n                Object.keys(d.indexes)[0].should.equal(\"_id\");   \n                Object.keys(d.indexes)[1].should.equal(\"planet\");   \n\n                d.indexes.planet.getAll().length.should.equal(2);\n                \n                // This second call has no effect, documents don't get inserted twice in the index\n                d.ensureIndex({ fieldName: \"planet\" }, function (err) {\n                  assert.isNull(err);\n                  Object.keys(d.indexes).length.should.equal(2);\n                  Object.keys(d.indexes)[0].should.equal(\"_id\");   \n                  Object.keys(d.indexes)[1].should.equal(\"planet\");   \n\n                  d.indexes.planet.getAll().length.should.equal(2);                \n                  \n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n\n      it('ensureIndex can be called after the data set was modified and the index still be correct', function (done) {\n        var rawData = model.serialize({ _id: \"aaa\", z: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n                      model.serialize({ _id: \"bbb\", z: \"2\", hello: 'world' })\n          ;\n\n        d.getAllData().length.should.equal(0);\n\n        fs.writeFile(testDb, rawData, 'utf8', function () {\n          d.loadDatabase(function () {\n            d.getAllData().length.should.equal(2);\n\n            assert.deepEqual(Object.keys(d.indexes), ['_id']);\n\n            d.insert({ z: \"12\", yes: 'yes' }, function (err, newDoc1) {\n              d.insert({ z: \"14\", nope: 'nope' }, function (err, newDoc2) {\n                d.remove({ z: \"2\" }, {}, function () {\n                  d.update({ z: \"1\" }, { $set: { 'yes': 'yep' } }, {}, function () {\n                    assert.deepEqual(Object.keys(d.indexes), ['_id']);\n\n                    d.ensureIndex({ fieldName: 'z' });\n                    d.indexes.z.fieldName.should.equal('z');\n                    d.indexes.z.unique.should.equal(false);\n                    d.indexes.z.sparse.should.equal(false);\n                    d.indexes.z.tree.getNumberOfKeys().should.equal(3);\n\n                    // The pointers in the _id and z indexes are the same\n                    d.indexes.z.tree.search('1')[0].should.equal(d.indexes._id.getMatching('aaa')[0]);\n                    d.indexes.z.tree.search('12')[0].should.equal(d.indexes._id.getMatching(newDoc1._id)[0]);\n                    d.indexes.z.tree.search('14')[0].should.equal(d.indexes._id.getMatching(newDoc2._id)[0]);\n\n                    // The data in the z index is correct\n                    d.find({}, function (err, docs) {\n                      var doc0 = _.find(docs, function (doc) { return doc._id === 'aaa'; })\n                        , doc1 = _.find(docs, function (doc) { return doc._id === newDoc1._id; })\n                        , doc2 = _.find(docs, function (doc) { return doc._id === newDoc2._id; })\n                        ;\n\n                      docs.length.should.equal(3);\n\n                      assert.deepEqual(doc0, { _id: \"aaa\", z: \"1\", a: 2, ages: [1, 5, 12], yes: 'yep' });\n                      assert.deepEqual(doc1, { _id: newDoc1._id, z: \"12\", yes: 'yes' });\n                      assert.deepEqual(doc2, { _id: newDoc2._id, z: \"14\", nope: 'nope' });\n\n                      done();\n                    });\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n\n      it('ensureIndex can be called before a loadDatabase and still be initialized and filled correctly', function (done) {\n        var now = new Date()\n          , rawData = model.serialize({ _id: \"aaa\", z: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n                      model.serialize({ _id: \"bbb\", z: \"2\", hello: 'world' }) + '\\n' +\n                      model.serialize({ _id: \"ccc\", z: \"3\", nested: { today: now } })\n          ;\n\n        d.getAllData().length.should.equal(0);\n\n        d.ensureIndex({ fieldName: 'z' });\n        d.indexes.z.fieldName.should.equal('z');\n        d.indexes.z.unique.should.equal(false);\n        d.indexes.z.sparse.should.equal(false);\n        d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n        fs.writeFile(testDb, rawData, 'utf8', function () {\n          d.loadDatabase(function () {\n            var doc1 = _.find(d.getAllData(), function (doc) { return doc.z === \"1\"; })\n              , doc2 = _.find(d.getAllData(), function (doc) { return doc.z === \"2\"; })\n              , doc3 = _.find(d.getAllData(), function (doc) { return doc.z === \"3\"; })\n              ;\n\n            d.getAllData().length.should.equal(3);\n\n            d.indexes.z.tree.getNumberOfKeys().should.equal(3);\n            d.indexes.z.tree.search('1')[0].should.equal(doc1);\n            d.indexes.z.tree.search('2')[0].should.equal(doc2);\n            d.indexes.z.tree.search('3')[0].should.equal(doc3);\n\n            done();\n          });\n        });\n      });\n\n      it('Can initialize multiple indexes on a database load', function (done) {\n        var now = new Date()\n          , rawData = model.serialize({ _id: \"aaa\", z: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n                      model.serialize({ _id: \"bbb\", z: \"2\", a: 'world' }) + '\\n' +\n                      model.serialize({ _id: \"ccc\", z: \"3\", a: { today: now } })\n          ;\n\n        d.getAllData().length.should.equal(0);\n        d.ensureIndex({ fieldName: 'z' }, function () {\n          d.ensureIndex({ fieldName: 'a' }, function () {\n            d.indexes.a.tree.getNumberOfKeys().should.equal(0);\n            d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n            fs.writeFile(testDb, rawData, 'utf8', function () {\n              d.loadDatabase(function (err) {\n                var doc1 = _.find(d.getAllData(), function (doc) { return doc.z === \"1\"; })\n                  , doc2 = _.find(d.getAllData(), function (doc) { return doc.z === \"2\"; })\n                  , doc3 = _.find(d.getAllData(), function (doc) { return doc.z === \"3\"; })\n                  ;\n\n                assert.isNull(err);\n                d.getAllData().length.should.equal(3);\n\n                d.indexes.z.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.z.tree.search('1')[0].should.equal(doc1);\n                d.indexes.z.tree.search('2')[0].should.equal(doc2);\n                d.indexes.z.tree.search('3')[0].should.equal(doc3);\n\n                d.indexes.a.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.a.tree.search(2)[0].should.equal(doc1);\n                d.indexes.a.tree.search('world')[0].should.equal(doc2);\n                d.indexes.a.tree.search({ today: now })[0].should.equal(doc3);\n\n                done();\n              });\n            });\n          });\n\n        });\n      });\n\n      it('If a unique constraint is not respected, database loading will not work and no data will be inserted', function (done) {\n        var now = new Date()\n          , rawData = model.serialize({ _id: \"aaa\", z: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n                      model.serialize({ _id: \"bbb\", z: \"2\", a: 'world' }) + '\\n' +\n                      model.serialize({ _id: \"ccc\", z: \"1\", a: { today: now } })\n          ;\n\n        d.getAllData().length.should.equal(0);\n\n        d.ensureIndex({ fieldName: 'z', unique: true });\n        d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n        fs.writeFile(testDb, rawData, 'utf8', function () {\n          d.loadDatabase(function (err) {\n            err.errorType.should.equal('uniqueViolated');\n            err.key.should.equal(\"1\");\n            d.getAllData().length.should.equal(0);\n            d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n            done();\n          });\n        });\n      });\n\n      it('If a unique constraint is not respected, ensureIndex will return an error and not create an index', function (done) {\n        d.insert({ a: 1, b: 4 }, function () {\n          d.insert({ a: 2, b: 45 }, function () {\n            d.insert({ a: 1, b: 3 }, function () {\n              d.ensureIndex({ fieldName: 'b' }, function (err) {\n                assert.isNull(err);\n\n                d.ensureIndex({ fieldName: 'a', unique: true }, function (err) {\n                  err.errorType.should.equal('uniqueViolated');\n                  assert.deepEqual(Object.keys(d.indexes), ['_id', 'b']);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n      \n      it('Can remove an index', function (done) {\n        d.ensureIndex({ fieldName: 'e' }, function (err) {\n          assert.isNull(err);\n          \n          Object.keys(d.indexes).length.should.equal(2);\n          assert.isNotNull(d.indexes.e);\n          \n          d.removeIndex(\"e\", function (err) {\n            assert.isNull(err);\n            Object.keys(d.indexes).length.should.equal(1);\n            assert.isUndefined(d.indexes.e); \n \n            done();\n          });\n        });\n      });\n\n    });   // ==== End of 'ensureIndex and index initialization in database loading' ==== //\n\n    \n    describe('Indexing newly inserted documents', function () {\n\n      it('Newly inserted documents are indexed', function (done) {\n        d.ensureIndex({ fieldName: 'z' });\n        d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n        d.insert({ a: 2, z: 'yes' }, function (err, newDoc) {\n          d.indexes.z.tree.getNumberOfKeys().should.equal(1);\n          assert.deepEqual(d.indexes.z.getMatching('yes'), [newDoc]);\n\n          d.insert({ a: 5, z: 'nope' }, function (err, newDoc) {\n            d.indexes.z.tree.getNumberOfKeys().should.equal(2);\n            assert.deepEqual(d.indexes.z.getMatching('nope'), [newDoc]);\n\n            done();\n          });\n        });\n      });\n\n      it('If multiple indexes are defined, the document is inserted in all of them', function (done) {\n        d.ensureIndex({ fieldName: 'z' });\n        d.ensureIndex({ fieldName: 'ya' });\n        d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n        d.insert({ a: 2, z: 'yes', ya: 'indeed' }, function (err, newDoc) {\n          d.indexes.z.tree.getNumberOfKeys().should.equal(1);\n          d.indexes.ya.tree.getNumberOfKeys().should.equal(1);\n          assert.deepEqual(d.indexes.z.getMatching('yes'), [newDoc]);\n          assert.deepEqual(d.indexes.ya.getMatching('indeed'), [newDoc]);\n\n          d.insert({ a: 5, z: 'nope', ya: 'sure' }, function (err, newDoc2) {\n            d.indexes.z.tree.getNumberOfKeys().should.equal(2);\n            d.indexes.ya.tree.getNumberOfKeys().should.equal(2);\n            assert.deepEqual(d.indexes.z.getMatching('nope'), [newDoc2]);\n            assert.deepEqual(d.indexes.ya.getMatching('sure'), [newDoc2]);\n\n            done();\n          });\n        });\n      });\n\n      it('Can insert two docs at the same key for a non unique index', function (done) {\n        d.ensureIndex({ fieldName: 'z' });\n        d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n        d.insert({ a: 2, z: 'yes' }, function (err, newDoc) {\n          d.indexes.z.tree.getNumberOfKeys().should.equal(1);\n          assert.deepEqual(d.indexes.z.getMatching('yes'), [newDoc]);\n\n          d.insert({ a: 5, z: 'yes' }, function (err, newDoc2) {\n            d.indexes.z.tree.getNumberOfKeys().should.equal(1);\n            assert.deepEqual(d.indexes.z.getMatching('yes'), [newDoc, newDoc2]);\n\n            done();\n          });\n        });\n      });\n\n      it('If the index has a unique constraint, an error is thrown if it is violated and the data is not modified', function (done) {\n        d.ensureIndex({ fieldName: 'z', unique: true });\n        d.indexes.z.tree.getNumberOfKeys().should.equal(0);\n\n        d.insert({ a: 2, z: 'yes' }, function (err, newDoc) {\n          d.indexes.z.tree.getNumberOfKeys().should.equal(1);\n          assert.deepEqual(d.indexes.z.getMatching('yes'), [newDoc]);\n\n          d.insert({ a: 5, z: 'yes' }, function (err) {\n            err.errorType.should.equal('uniqueViolated');\n            err.key.should.equal('yes');\n\n            // Index didn't change\n            d.indexes.z.tree.getNumberOfKeys().should.equal(1);\n            assert.deepEqual(d.indexes.z.getMatching('yes'), [newDoc]);\n\n            // Data didn't change\n            assert.deepEqual(d.getAllData(), [newDoc]);\n            d.loadDatabase(function () {\n              d.getAllData().length.should.equal(1);\n              assert.deepEqual(d.getAllData()[0], newDoc);\n\n              done();\n            });\n          });\n        });\n      });\n\n      it('If an index has a unique constraint, other indexes cannot be modified when it raises an error', function (done) {\n        d.ensureIndex({ fieldName: 'nonu1' });\n        d.ensureIndex({ fieldName: 'uni', unique: true });\n        d.ensureIndex({ fieldName: 'nonu2' });\n\n        d.insert({ nonu1: 'yes', nonu2: 'yes2', uni: 'willfail' }, function (err, newDoc) {\n          assert.isNull(err);\n          d.indexes.nonu1.tree.getNumberOfKeys().should.equal(1);\n          d.indexes.uni.tree.getNumberOfKeys().should.equal(1);\n          d.indexes.nonu2.tree.getNumberOfKeys().should.equal(1);\n\n          d.insert({ nonu1: 'no', nonu2: 'no2', uni: 'willfail' }, function (err) {\n            err.errorType.should.equal('uniqueViolated');\n\n            // No index was modified\n            d.indexes.nonu1.tree.getNumberOfKeys().should.equal(1);\n            d.indexes.uni.tree.getNumberOfKeys().should.equal(1);\n            d.indexes.nonu2.tree.getNumberOfKeys().should.equal(1);\n\n            assert.deepEqual(d.indexes.nonu1.getMatching('yes'), [newDoc]);\n            assert.deepEqual(d.indexes.uni.getMatching('willfail'), [newDoc]);\n            assert.deepEqual(d.indexes.nonu2.getMatching('yes2'), [newDoc]);\n\n            done();\n          });\n        });\n      });\n\n      it('Unique indexes prevent you from inserting two docs where the field is undefined except if theyre sparse', function (done) {\n        d.ensureIndex({ fieldName: 'zzz', unique: true });\n        d.indexes.zzz.tree.getNumberOfKeys().should.equal(0);\n\n        d.insert({ a: 2, z: 'yes' }, function (err, newDoc) {\n          d.indexes.zzz.tree.getNumberOfKeys().should.equal(1);\n          assert.deepEqual(d.indexes.zzz.getMatching(undefined), [newDoc]);\n\n          d.insert({ a: 5, z: 'other' }, function (err) {\n            err.errorType.should.equal('uniqueViolated');\n            assert.isUndefined(err.key);\n\n            d.ensureIndex({ fieldName: 'yyy', unique: true, sparse: true });\n\n            d.insert({ a: 5, z: 'other', zzz: 'set' }, function (err) {\n              assert.isNull(err);\n              d.indexes.yyy.getAll().length.should.equal(0);   // Nothing indexed\n              d.indexes.zzz.getAll().length.should.equal(2);\n\n              done();\n            });\n          });\n        });\n      });\n\n      it('Insertion still works as before with indexing', function (done) {\n        d.ensureIndex({ fieldName: 'a' });\n        d.ensureIndex({ fieldName: 'b' });\n\n        d.insert({ a: 1, b: 'hello' }, function (err, doc1) {\n          d.insert({ a: 2, b: 'si' }, function (err, doc2) {\n            d.find({}, function (err, docs) {\n              assert.deepEqual(doc1, _.find(docs, function (d) { return d._id === doc1._id; }));\n              assert.deepEqual(doc2, _.find(docs, function (d) { return d._id === doc2._id; }));\n\n              done();\n            });\n          });\n        });\n      });\n\n      it('All indexes point to the same data as the main index on _id', function (done) {\n        d.ensureIndex({ fieldName: 'a' });\n\n        d.insert({ a: 1, b: 'hello' }, function (err, doc1) {\n          d.insert({ a: 2, b: 'si' }, function (err, doc2) {\n            d.find({}, function (err, docs) {\n              docs.length.should.equal(2);\n              d.getAllData().length.should.equal(2);\n\n              d.indexes._id.getMatching(doc1._id).length.should.equal(1);\n              d.indexes.a.getMatching(1).length.should.equal(1);\n              d.indexes._id.getMatching(doc1._id)[0].should.equal(d.indexes.a.getMatching(1)[0]);\n\n              d.indexes._id.getMatching(doc2._id).length.should.equal(1);\n              d.indexes.a.getMatching(2).length.should.equal(1);\n              d.indexes._id.getMatching(doc2._id)[0].should.equal(d.indexes.a.getMatching(2)[0]);\n\n              done();\n            });\n          });\n        });\n      });\n\n      it('If a unique constraint is violated, no index is changed, including the main one', function (done) {\n        d.ensureIndex({ fieldName: 'a', unique: true });\n\n        d.insert({ a: 1, b: 'hello' }, function (err, doc1) {\n          d.insert({ a: 1, b: 'si' }, function (err) {\n            assert.isDefined(err);\n\n            d.find({}, function (err, docs) {\n              docs.length.should.equal(1);\n              d.getAllData().length.should.equal(1);\n\n              d.indexes._id.getMatching(doc1._id).length.should.equal(1);\n              d.indexes.a.getMatching(1).length.should.equal(1);\n              d.indexes._id.getMatching(doc1._id)[0].should.equal(d.indexes.a.getMatching(1)[0]);\n\n              d.indexes.a.getMatching(2).length.should.equal(0);\n\n              done();\n            });\n          });\n        });\n      });\n\n    });   // ==== End of 'Indexing newly inserted documents' ==== //\n\n    describe('Updating indexes upon document update', function () {\n\n      it('Updating docs still works as before with indexing', function (done) {\n        d.ensureIndex({ fieldName: 'a' });\n\n        d.insert({ a: 1, b: 'hello' }, function (err, _doc1) {\n          d.insert({ a: 2, b: 'si' }, function (err, _doc2) {\n            d.update({ a: 1 }, { $set: { a: 456, b: 'no' } }, {}, function (err, nr) {\n              var data = d.getAllData()\n                , doc1 = _.find(data, function (doc) { return doc._id === _doc1._id; })\n                , doc2 = _.find(data, function (doc) { return doc._id === _doc2._id; })\n                ;\n\n              assert.isNull(err);\n              nr.should.equal(1);\n\n              data.length.should.equal(2);\n              assert.deepEqual(doc1, { a: 456, b: 'no', _id: _doc1._id });\n              assert.deepEqual(doc2, { a: 2, b: 'si', _id: _doc2._id });\n\n              d.update({}, { $inc: { a: 10 }, $set: { b: 'same' } }, { multi: true }, function (err, nr) {\n                var data = d.getAllData()\n                  , doc1 = _.find(data, function (doc) { return doc._id === _doc1._id; })\n                  , doc2 = _.find(data, function (doc) { return doc._id === _doc2._id; })\n                  ;\n\n                assert.isNull(err);\n                nr.should.equal(2);\n\n                data.length.should.equal(2);\n                assert.deepEqual(doc1, { a: 466, b: 'same', _id: _doc1._id });\n                assert.deepEqual(doc2, { a: 12, b: 'same', _id: _doc2._id });\n\n                done();\n              });\n            });\n          });\n        });\n      });\n\n      it('Indexes get updated when a document (or multiple documents) is updated', function (done) {\n        d.ensureIndex({ fieldName: 'a' });\n        d.ensureIndex({ fieldName: 'b' });\n\n        d.insert({ a: 1, b: 'hello' }, function (err, doc1) {\n          d.insert({ a: 2, b: 'si' }, function (err, doc2) {\n            // Simple update\n            d.update({ a: 1 }, { $set: { a: 456, b: 'no' } }, {}, function (err, nr) {\n              assert.isNull(err);\n              nr.should.equal(1);\n\n              d.indexes.a.tree.getNumberOfKeys().should.equal(2);\n              d.indexes.a.getMatching(456)[0]._id.should.equal(doc1._id);\n              d.indexes.a.getMatching(2)[0]._id.should.equal(doc2._id);\n\n              d.indexes.b.tree.getNumberOfKeys().should.equal(2);\n              d.indexes.b.getMatching('no')[0]._id.should.equal(doc1._id);\n              d.indexes.b.getMatching('si')[0]._id.should.equal(doc2._id);\n\n              // The same pointers are shared between all indexes\n              d.indexes.a.tree.getNumberOfKeys().should.equal(2);\n              d.indexes.b.tree.getNumberOfKeys().should.equal(2);\n              d.indexes._id.tree.getNumberOfKeys().should.equal(2);\n              d.indexes.a.getMatching(456)[0].should.equal(d.indexes._id.getMatching(doc1._id)[0]);\n              d.indexes.b.getMatching('no')[0].should.equal(d.indexes._id.getMatching(doc1._id)[0]);\n              d.indexes.a.getMatching(2)[0].should.equal(d.indexes._id.getMatching(doc2._id)[0]);\n              d.indexes.b.getMatching('si')[0].should.equal(d.indexes._id.getMatching(doc2._id)[0]);\n\n              // Multi update\n              d.update({}, { $inc: { a: 10 }, $set: { b: 'same' } }, { multi: true }, function (err, nr) {\n                assert.isNull(err);\n                nr.should.equal(2);\n\n                d.indexes.a.tree.getNumberOfKeys().should.equal(2);\n                d.indexes.a.getMatching(466)[0]._id.should.equal(doc1._id);\n                d.indexes.a.getMatching(12)[0]._id.should.equal(doc2._id);\n\n                d.indexes.b.tree.getNumberOfKeys().should.equal(1);\n                d.indexes.b.getMatching('same').length.should.equal(2);\n                _.pluck(d.indexes.b.getMatching('same'), '_id').should.contain(doc1._id);\n                _.pluck(d.indexes.b.getMatching('same'), '_id').should.contain(doc2._id);\n\n                // The same pointers are shared between all indexes\n                d.indexes.a.tree.getNumberOfKeys().should.equal(2);\n                d.indexes.b.tree.getNumberOfKeys().should.equal(1);\n                d.indexes.b.getAll().length.should.equal(2);\n                d.indexes._id.tree.getNumberOfKeys().should.equal(2);\n                d.indexes.a.getMatching(466)[0].should.equal(d.indexes._id.getMatching(doc1._id)[0]);\n                d.indexes.a.getMatching(12)[0].should.equal(d.indexes._id.getMatching(doc2._id)[0]);\n                // Can't test the pointers in b as their order is randomized, but it is the same as with a\n\n                done();\n              });\n            });\n          });\n        });\n      });\n\n      it('If a simple update violates a contraint, all changes are rolled back and an error is thrown', function (done) {\n        d.ensureIndex({ fieldName: 'a', unique: true });\n        d.ensureIndex({ fieldName: 'b', unique: true });\n        d.ensureIndex({ fieldName: 'c', unique: true });\n\n        d.insert({ a: 1, b: 10, c: 100 }, function (err, _doc1) {\n          d.insert({ a: 2, b: 20, c: 200 }, function (err, _doc2) {\n            d.insert({ a: 3, b: 30, c: 300 }, function (err, _doc3) {\n              // Will conflict with doc3\n              d.update({ a: 2 }, { $inc: { a: 10, c: 1000 }, $set: { b: 30 } }, {}, function (err) {\n                var data = d.getAllData()\n                  , doc1 = _.find(data, function (doc) { return doc._id === _doc1._id; })\n                  , doc2 = _.find(data, function (doc) { return doc._id === _doc2._id; })\n                  , doc3 = _.find(data, function (doc) { return doc._id === _doc3._id; })\n                  ;\n\n                err.errorType.should.equal('uniqueViolated');\n\n                // Data left unchanged\n                data.length.should.equal(3);\n                assert.deepEqual(doc1, { a: 1, b: 10, c: 100, _id: _doc1._id });\n                assert.deepEqual(doc2, { a: 2, b: 20, c: 200, _id: _doc2._id });\n                assert.deepEqual(doc3, { a: 3, b: 30, c: 300, _id: _doc3._id });\n\n                // All indexes left unchanged and pointing to the same docs\n                d.indexes.a.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.a.getMatching(1)[0].should.equal(doc1);\n                d.indexes.a.getMatching(2)[0].should.equal(doc2);\n                d.indexes.a.getMatching(3)[0].should.equal(doc3);\n\n                d.indexes.b.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.b.getMatching(10)[0].should.equal(doc1);\n                d.indexes.b.getMatching(20)[0].should.equal(doc2);\n                d.indexes.b.getMatching(30)[0].should.equal(doc3);\n\n                d.indexes.c.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.c.getMatching(100)[0].should.equal(doc1);\n                d.indexes.c.getMatching(200)[0].should.equal(doc2);\n                d.indexes.c.getMatching(300)[0].should.equal(doc3);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n\n      it('If a multi update violates a contraint, all changes are rolled back and an error is thrown', function (done) {\n        d.ensureIndex({ fieldName: 'a', unique: true });\n        d.ensureIndex({ fieldName: 'b', unique: true });\n        d.ensureIndex({ fieldName: 'c', unique: true });\n\n        d.insert({ a: 1, b: 10, c: 100 }, function (err, _doc1) {\n          d.insert({ a: 2, b: 20, c: 200 }, function (err, _doc2) {\n            d.insert({ a: 3, b: 30, c: 300 }, function (err, _doc3) {\n              // Will conflict with doc3\n              d.update({ a: { $in: [1, 2] } }, { $inc: { a: 10, c: 1000 }, $set: { b: 30 } }, { multi: true }, function (err) {\n                var data = d.getAllData()\n                  , doc1 = _.find(data, function (doc) { return doc._id === _doc1._id; })\n                  , doc2 = _.find(data, function (doc) { return doc._id === _doc2._id; })\n                  , doc3 = _.find(data, function (doc) { return doc._id === _doc3._id; })\n                  ;\n\n                err.errorType.should.equal('uniqueViolated');\n\n                // Data left unchanged\n                data.length.should.equal(3);\n                assert.deepEqual(doc1, { a: 1, b: 10, c: 100, _id: _doc1._id });\n                assert.deepEqual(doc2, { a: 2, b: 20, c: 200, _id: _doc2._id });\n                assert.deepEqual(doc3, { a: 3, b: 30, c: 300, _id: _doc3._id });\n\n                // All indexes left unchanged and pointing to the same docs\n                d.indexes.a.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.a.getMatching(1)[0].should.equal(doc1);\n                d.indexes.a.getMatching(2)[0].should.equal(doc2);\n                d.indexes.a.getMatching(3)[0].should.equal(doc3);\n\n                d.indexes.b.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.b.getMatching(10)[0].should.equal(doc1);\n                d.indexes.b.getMatching(20)[0].should.equal(doc2);\n                d.indexes.b.getMatching(30)[0].should.equal(doc3);\n\n                d.indexes.c.tree.getNumberOfKeys().should.equal(3);\n                d.indexes.c.getMatching(100)[0].should.equal(doc1);\n                d.indexes.c.getMatching(200)[0].should.equal(doc2);\n                d.indexes.c.getMatching(300)[0].should.equal(doc3);\n\n                done();\n              });\n            });\n          });\n        });\n      });\n\n    });   // ==== End of 'Updating indexes upon document update' ==== //\n\n    describe('Updating indexes upon document remove', function () {\n\n      it('Removing docs still works as before with indexing', function (done) {\n        d.ensureIndex({ fieldName: 'a' });\n\n        d.insert({ a: 1, b: 'hello' }, function (err, _doc1) {\n          d.insert({ a: 2, b: 'si' }, function (err, _doc2) {\n            d.insert({ a: 3, b: 'coin' }, function (err, _doc3) {\n              d.remove({ a: 1 }, {}, function (err, nr) {\n                var data = d.getAllData()\n                , doc2 = _.find(data, function (doc) { return doc._id === _doc2._id; })\n                , doc3 = _.find(data, function (doc) { return doc._id === _doc3._id; })\n                ;\n\n                assert.isNull(err);\n                nr.should.equal(1);\n\n                data.length.should.equal(2);\n                assert.deepEqual(doc2, { a: 2, b: 'si', _id: _doc2._id });\n                assert.deepEqual(doc3, { a: 3, b: 'coin', _id: _doc3._id });\n\n                d.remove({ a: { $in: [2, 3] } }, { multi: true }, function (err, nr) {\n                  var data = d.getAllData()\n                  ;\n\n                  assert.isNull(err);\n                  nr.should.equal(2);\n                  data.length.should.equal(0);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n\n      it('Indexes get updated when a document (or multiple documents) is removed', function (done) {\n        d.ensureIndex({ fieldName: 'a' });\n        d.ensureIndex({ fieldName: 'b' });\n\n        d.insert({ a: 1, b: 'hello' }, function (err, doc1) {\n          d.insert({ a: 2, b: 'si' }, function (err, doc2) {\n            d.insert({ a: 3, b: 'coin' }, function (err, doc3) {\n              // Simple remove\n              d.remove({ a: 1 }, {}, function (err, nr) {\n                assert.isNull(err);\n                nr.should.equal(1);\n\n                d.indexes.a.tree.getNumberOfKeys().should.equal(2);\n                d.indexes.a.getMatching(2)[0]._id.should.equal(doc2._id);\n                d.indexes.a.getMatching(3)[0]._id.should.equal(doc3._id);\n\n                d.indexes.b.tree.getNumberOfKeys().should.equal(2);\n                d.indexes.b.getMatching('si')[0]._id.should.equal(doc2._id);\n                d.indexes.b.getMatching('coin')[0]._id.should.equal(doc3._id);\n\n                // The same pointers are shared between all indexes\n                d.indexes.a.tree.getNumberOfKeys().should.equal(2);\n                d.indexes.b.tree.getNumberOfKeys().should.equal(2);\n                d.indexes._id.tree.getNumberOfKeys().should.equal(2);\n                d.indexes.a.getMatching(2)[0].should.equal(d.indexes._id.getMatching(doc2._id)[0]);\n                d.indexes.b.getMatching('si')[0].should.equal(d.indexes._id.getMatching(doc2._id)[0]);\n                d.indexes.a.getMatching(3)[0].should.equal(d.indexes._id.getMatching(doc3._id)[0]);\n                d.indexes.b.getMatching('coin')[0].should.equal(d.indexes._id.getMatching(doc3._id)[0]);\n\n                // Multi remove\n                d.remove({}, { multi: true }, function (err, nr) {\n                  assert.isNull(err);\n                  nr.should.equal(2);\n\n                  d.indexes.a.tree.getNumberOfKeys().should.equal(0);\n                  d.indexes.b.tree.getNumberOfKeys().should.equal(0);\n                  d.indexes._id.tree.getNumberOfKeys().should.equal(0);\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n\n    });   // ==== End of 'Updating indexes upon document remove' ==== //\n\n\n    describe('Persisting indexes', function () {\n\n      it('Indexes are persisted to a separate file and recreated upon reload', function (done) {\n        var persDb = \"workspace/persistIndexes.db\"\n          , db\n          ;\n\n        if (fs.existsSync(persDb)) { fs.writeFileSync(persDb, '', 'utf8'); }\n        db = new Datastore({ filename: persDb, autoload: true });\n\n        Object.keys(db.indexes).length.should.equal(1);\n        Object.keys(db.indexes)[0].should.equal(\"_id\");\n\n        db.insert({ planet: \"Earth\" }, function (err) {\n          assert.isNull(err);\n          db.insert({ planet: \"Mars\" }, function (err) {\n            assert.isNull(err);\n\n            db.ensureIndex({ fieldName: \"planet\" }, function (err) {\n              Object.keys(db.indexes).length.should.equal(2);\n              Object.keys(db.indexes)[0].should.equal(\"_id\");\n              Object.keys(db.indexes)[1].should.equal(\"planet\");\n              db.indexes._id.getAll().length.should.equal(2);\n              db.indexes.planet.getAll().length.should.equal(2);\n              db.indexes.planet.fieldName.should.equal(\"planet\");\n\n              // After a reload the indexes are recreated\n              db = new Datastore({ filename: persDb });\n              db.loadDatabase(function (err) {\n                assert.isNull(err);\n                Object.keys(db.indexes).length.should.equal(2);\n                Object.keys(db.indexes)[0].should.equal(\"_id\");\n                Object.keys(db.indexes)[1].should.equal(\"planet\");\n                db.indexes._id.getAll().length.should.equal(2);\n                db.indexes.planet.getAll().length.should.equal(2);\n                db.indexes.planet.fieldName.should.equal(\"planet\");\n\n                // After another reload the indexes are still there (i.e. they are preserved during autocompaction)\n                db = new Datastore({ filename: persDb });\n                db.loadDatabase(function (err) {\n                  assert.isNull(err);\n                  Object.keys(db.indexes).length.should.equal(2);\n                  Object.keys(db.indexes)[0].should.equal(\"_id\");\n                  Object.keys(db.indexes)[1].should.equal(\"planet\");\n                  db.indexes._id.getAll().length.should.equal(2);\n                  db.indexes.planet.getAll().length.should.equal(2);\n                  db.indexes.planet.fieldName.should.equal(\"planet\");\n\n                  done();\n                });\n              });\n            });\n          });\n        });\n      });\n\n      it('Indexes are persisted with their options and recreated even if some db operation happen between loads', function (done) {\n        var persDb = \"workspace/persistIndexes.db\"\n          , db\n        ;\n\n        if (fs.existsSync(persDb)) { fs.writeFileSync(persDb, '', 'utf8'); }\n        db = new Datastore({ filename: persDb, autoload: true });\n\n        Object.keys(db.indexes).length.should.equal(1);\n        Object.keys(db.indexes)[0].should.equal(\"_id\");\n\n        db.insert({ planet: \"Earth\" }, function (err) {\n          assert.isNull(err);\n          db.insert({ planet: \"Mars\" }, function (err) {\n            assert.isNull(err);\n\n            db.ensureIndex({ fieldName: \"planet\", unique: true, sparse: false }, function (err) {\n              Object.keys(db.indexes).length.should.equal(2);\n              Object.keys(db.indexes)[0].should.equal(\"_id\");\n              Object.keys(db.indexes)[1].should.equal(\"planet\");\n              db.indexes._id.getAll().length.should.equal(2);\n              db.indexes.planet.getAll().length.should.equal(2);\n              db.indexes.planet.unique.should.equal(true);\n              db.indexes.planet.sparse.should.equal(false);\n\n              db.insert({ planet: \"Jupiter\" }, function (err) {\n                assert.isNull(err);\n\n                // After a reload the indexes are recreated\n                db = new Datastore({ filename: persDb });\n                db.loadDatabase(function (err) {\n                  assert.isNull(err);\n                  Object.keys(db.indexes).length.should.equal(2);\n                  Object.keys(db.indexes)[0].should.equal(\"_id\");\n                  Object.keys(db.indexes)[1].should.equal(\"planet\");\n                  db.indexes._id.getAll().length.should.equal(3);\n                  db.indexes.planet.getAll().length.should.equal(3);\n                  db.indexes.planet.unique.should.equal(true);\n                  db.indexes.planet.sparse.should.equal(false);\n\n                  db.ensureIndex({ fieldName: 'bloup', unique: false, sparse: true }, function (err) {\n                    assert.isNull(err);\n                    Object.keys(db.indexes).length.should.equal(3);\n                    Object.keys(db.indexes)[0].should.equal(\"_id\");\n                    Object.keys(db.indexes)[1].should.equal(\"planet\");\n                    Object.keys(db.indexes)[2].should.equal(\"bloup\");\n                    db.indexes._id.getAll().length.should.equal(3);\n                    db.indexes.planet.getAll().length.should.equal(3);\n                    db.indexes.bloup.getAll().length.should.equal(0);\n                    db.indexes.planet.unique.should.equal(true);\n                    db.indexes.planet.sparse.should.equal(false);\n                    db.indexes.bloup.unique.should.equal(false);\n                    db.indexes.bloup.sparse.should.equal(true);\n\n                    // After another reload the indexes are still there (i.e. they are preserved during autocompaction)\n                    db = new Datastore({ filename: persDb });\n                    db.loadDatabase(function (err) {\n                      assert.isNull(err);\n                      Object.keys(db.indexes).length.should.equal(3);\n                      Object.keys(db.indexes)[0].should.equal(\"_id\");\n                      Object.keys(db.indexes)[1].should.equal(\"planet\");\n                      Object.keys(db.indexes)[2].should.equal(\"bloup\");\n                      db.indexes._id.getAll().length.should.equal(3);\n                      db.indexes.planet.getAll().length.should.equal(3);\n                      db.indexes.bloup.getAll().length.should.equal(0);\n                      db.indexes.planet.unique.should.equal(true);\n                      db.indexes.planet.sparse.should.equal(false);\n                      db.indexes.bloup.unique.should.equal(false);\n                      db.indexes.bloup.sparse.should.equal(true);\n\n                      done();\n                    });\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n\n      it('Indexes can also be removed and the remove persisted', function (done) {\n        var persDb = \"workspace/persistIndexes.db\"\n          , db\n        ;\n\n        if (fs.existsSync(persDb)) { fs.writeFileSync(persDb, '', 'utf8'); }\n        db = new Datastore({ filename: persDb, autoload: true });\n\n        Object.keys(db.indexes).length.should.equal(1);\n        Object.keys(db.indexes)[0].should.equal(\"_id\");\n\n        db.insert({ planet: \"Earth\" }, function (err) {\n          assert.isNull(err);\n          db.insert({ planet: \"Mars\" }, function (err) {\n            assert.isNull(err);\n\n            db.ensureIndex({ fieldName: \"planet\" }, function (err) {\n              assert.isNull(err);\n              db.ensureIndex({ fieldName: \"another\" }, function (err) {\n                assert.isNull(err);\n                Object.keys(db.indexes).length.should.equal(3);\n                Object.keys(db.indexes)[0].should.equal(\"_id\");\n                Object.keys(db.indexes)[1].should.equal(\"planet\");\n                Object.keys(db.indexes)[2].should.equal(\"another\");\n                db.indexes._id.getAll().length.should.equal(2);\n                db.indexes.planet.getAll().length.should.equal(2);\n                db.indexes.planet.fieldName.should.equal(\"planet\");\n\n                // After a reload the indexes are recreated\n                db = new Datastore({ filename: persDb });\n                db.loadDatabase(function (err) {\n                  assert.isNull(err);\n                  Object.keys(db.indexes).length.should.equal(3);\n                  Object.keys(db.indexes)[0].should.equal(\"_id\");\n                  Object.keys(db.indexes)[1].should.equal(\"planet\");  \n                  Object.keys(db.indexes)[2].should.equal(\"another\");\n                  db.indexes._id.getAll().length.should.equal(2);\n                  db.indexes.planet.getAll().length.should.equal(2);\n                  db.indexes.planet.fieldName.should.equal(\"planet\");\n\n                  // Index is removed\n                  db.removeIndex(\"planet\", function (err) {\n                    assert.isNull(err);\n                    Object.keys(db.indexes).length.should.equal(2);\n                    Object.keys(db.indexes)[0].should.equal(\"_id\");\n                    Object.keys(db.indexes)[1].should.equal(\"another\");\n                    db.indexes._id.getAll().length.should.equal(2);\n\n                    // After a reload indexes are preserved\n                    db = new Datastore({ filename: persDb });\n                    db.loadDatabase(function (err) {\n                      assert.isNull(err);\n                      Object.keys(db.indexes).length.should.equal(2);\n                      Object.keys(db.indexes)[0].should.equal(\"_id\");\n                      Object.keys(db.indexes)[1].should.equal(\"another\");\n                      db.indexes._id.getAll().length.should.equal(2);\n\n                      // After another reload the indexes are still there (i.e. they are preserved during autocompaction)\n                      db = new Datastore({ filename: persDb });\n                      db.loadDatabase(function (err) {\n                        assert.isNull(err);\n                        Object.keys(db.indexes).length.should.equal(2);\n                        Object.keys(db.indexes)[0].should.equal(\"_id\");\n                        Object.keys(db.indexes)[1].should.equal(\"another\");\n                        db.indexes._id.getAll().length.should.equal(2);\n\n                        done();\n                      });\n                    });\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n\n    });   // ==== End of 'Persisting indexes' ====\n\n    it('Results of getMatching should never contain duplicates', function (done) {\n      d.ensureIndex({ fieldName: 'bad' });\n      d.insert({ bad: ['a', 'b'] }, function () {\n        d.getCandidates({ bad: { $in: ['a', 'b'] } }, function (err, res) {\n          res.length.should.equal(1);\n          done();\n        });\n      });\n    });\n\n  });   // ==== End of 'Using indexes' ==== //\n\n\n});\n"
  },
  {
    "path": "test/executor.test.js",
    "content": "var should = require('chai').should()\n  , assert = require('chai').assert\n  , testDb = 'workspace/test.db'\n  , fs = require('fs')\n  , path = require('path')\n  , _ = require('underscore')\n  , async = require('async')\n  , model = require('../lib/model')\n  , Datastore = require('../lib/datastore')\n  , Persistence = require('../lib/persistence')\n  ;\n\n\n// Test that even if a callback throws an exception, the next DB operations will still be executed\n// We prevent Mocha from catching the exception we throw on purpose by remembering all current handlers, remove them and register them back after test ends\nfunction testThrowInCallback (d, done) {\n  var currentUncaughtExceptionHandlers = process.listeners('uncaughtException');\n\n  process.removeAllListeners('uncaughtException');\n\n  process.on('uncaughtException', function (err) {\n    // Do nothing with the error which is only there to test we stay on track\n  });\n\n  d.find({}, function (err) {\n    process.nextTick(function () {\n      d.insert({ bar: 1 }, function (err) {\n        process.removeAllListeners('uncaughtException');\n        for (var i = 0; i < currentUncaughtExceptionHandlers.length; i += 1) {\n          process.on('uncaughtException', currentUncaughtExceptionHandlers[i]);\n        }\n\n        done();\n      });\n    });\n\n    throw new Error('Some error');\n  });\n}\n\n// Test that if the callback is falsy, the next DB operations will still be executed\nfunction testFalsyCallback (d, done) {\n  d.insert({ a: 1 }, null);\n  process.nextTick(function () {\n    d.update({ a: 1 }, { a: 2 }, {}, null);\n    process.nextTick(function () {\n      d.update({ a: 2 }, { a: 1 }, null);\n      process.nextTick(function () {\n        d.remove({ a: 2 }, {}, null);\n        process.nextTick(function () {\n          d.remove({ a: 2 }, null);\n          process.nextTick(function () {\n            d.find({}, done);\n          });\n        });\n      });\n    });\n  });\n}\n\n// Test that operations are executed in the right order\n// We prevent Mocha from catching the exception we throw on purpose by remembering all current handlers, remove them and register them back after test ends\nfunction testRightOrder (d, done) {\n  var currentUncaughtExceptionHandlers = process.listeners('uncaughtException');\n\n  process.removeAllListeners('uncaughtException');\n\n  process.on('uncaughtException', function (err) {\n    // Do nothing with the error which is only there to test we stay on track\n  });\n\n  d.find({}, function (err, docs) {\n    docs.length.should.equal(0);\n\n    d.insert({ a: 1 }, function () {\n      d.update({ a: 1 }, { a: 2 }, {}, function () {\n        d.find({}, function (err, docs) {\n          docs[0].a.should.equal(2);\n\n          process.nextTick(function () {\n            d.update({ a: 2 }, { a: 3 }, {}, function () {\n              d.find({}, function (err, docs) {\n                docs[0].a.should.equal(3);\n\n                process.removeAllListeners('uncaughtException');\n                for (var i = 0; i < currentUncaughtExceptionHandlers.length; i += 1) {\n                  process.on('uncaughtException', currentUncaughtExceptionHandlers[i]);\n                }\n\n                done();\n              });\n            });\n          });\n\n          throw new Error('Some error');\n        });\n      });\n    });\n  });\n}\n\n// Note:  The following test does not have any assertion because it\n// is meant to address the deprecation warning:\n// (node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral.\n// see\nvar testEventLoopStarvation = function(d, done){\n   var times = 1001;\n   var i = 0;\n   while ( i <times) {\n      i++;\n     d.find({\"bogus\": \"search\"}, function (err, docs) {\n     });\n   }\n   done();\n};\n\n// Test that operations are executed in the right order even with no callback\nfunction testExecutorWorksWithoutCallback (d, done) {\n  d.insert({ a: 1 });\n  d.insert({ a: 2 }, false);\n  d.find({}, function (err, docs) {\n    docs.length.should.equal(2);\n    done();\n  });\n}\n\n\ndescribe('Executor', function () {\n\n  describe('With persistent database', function () {\n    var d;\n\n    beforeEach(function (done) {\n      d = new Datastore({ filename: testDb });\n      d.filename.should.equal(testDb);\n      d.inMemoryOnly.should.equal(false);\n\n      async.waterfall([\n        function (cb) {\n          Persistence.ensureDirectoryExists(path.dirname(testDb), function () {\n            fs.exists(testDb, function (exists) {\n              if (exists) {\n                fs.unlink(testDb, cb);\n              } else { return cb(); }\n            });\n          });\n        }\n      , function (cb) {\n          d.loadDatabase(function (err) {\n            assert.isNull(err);\n            d.getAllData().length.should.equal(0);\n            return cb();\n          });\n        }\n      ], done);\n    });\n\n    it('A throw in a callback doesnt prevent execution of next operations', function(done) {\n      testThrowInCallback(d, done);\n    });\n\n    it('A falsy callback doesnt prevent execution of next operations', function(done) {\n      testFalsyCallback(d, done);\n    });\n\n    it('Operations are executed in the right order', function(done) {\n      testRightOrder(d, done);\n    });\n\n    it('Does not starve event loop and raise warning when more than 1000 callbacks are in queue', function(done){\n      testEventLoopStarvation(d, done);\n    });\n\n    it('Works in the right order even with no supplied callback', function(done){\n      testExecutorWorksWithoutCallback(d, done);\n    });\n\n  });   // ==== End of 'With persistent database' ====\n\n\n  describe('With non persistent database', function () {\n    var d;\n\n    beforeEach(function (done) {\n      d = new Datastore({ inMemoryOnly: true });\n      d.inMemoryOnly.should.equal(true);\n\n      d.loadDatabase(function (err) {\n        assert.isNull(err);\n        d.getAllData().length.should.equal(0);\n        return done();\n      });\n    });\n\n    it('A throw in a callback doesnt prevent execution of next operations', function(done) {\n      testThrowInCallback(d, done);\n    });\n\n    it('A falsy callback doesnt prevent execution of next operations', function(done) {\n      testFalsyCallback(d, done);\n    });\n\n    it('Operations are executed in the right order', function(done) {\n      testRightOrder(d, done);\n    });\n\n    it('Works in the right order even with no supplied callback', function(done){\n      testExecutorWorksWithoutCallback(d, done);\n    });\n\n  });   // ==== End of 'With non persistent database' ====\n\n});\n"
  },
  {
    "path": "test/indexes.test.js",
    "content": "var Index = require('../lib/indexes')\n  , customUtils = require('../lib/customUtils')\n  , should = require('chai').should()\n  , assert = require('chai').assert\n  , _ = require('underscore')\n  , async = require('async')\n  , model = require('../lib/model')\n  ;\n\ndescribe('Indexes', function () {\n\n  describe('Insertion', function () {\n\n    it('Can insert pointers to documents in the index correctly when they have the field', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      // The underlying BST now has 3 nodes which contain the docs where it's expected\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('hello'), [{ a: 5, tf: 'hello' }]);\n      assert.deepEqual(idx.tree.search('world'), [{ a: 8, tf: 'world' }]);\n      assert.deepEqual(idx.tree.search('bloup'), [{ a: 2, tf: 'bloup' }]);\n\n      // The nodes contain pointers to the actual documents\n      idx.tree.search('world')[0].should.equal(doc2);\n      idx.tree.search('bloup')[0].a = 42;\n      doc3.a.should.equal(42);\n    });\n\n    it('Inserting twice for the same fieldName in a unique index will result in an error thrown', function () {\n      var idx = new Index({ fieldName: 'tf', unique: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        ;\n\n      idx.insert(doc1);\n      idx.tree.getNumberOfKeys().should.equal(1);\n      (function () { idx.insert(doc1); }).should.throw();\n    });\n\n    it('Inserting twice for a fieldName the docs dont have with a unique index results in an error thrown', function () {\n      var idx = new Index({ fieldName: 'nope', unique: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 5, tf: 'world' }\n        ;\n\n      idx.insert(doc1);\n      idx.tree.getNumberOfKeys().should.equal(1);\n      (function () { idx.insert(doc2); }).should.throw();\n    });\n\n    it('Inserting twice for a fieldName the docs dont have with a unique and sparse index will not throw, since the docs will be non indexed', function () {\n      var idx = new Index({ fieldName: 'nope', unique: true, sparse: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 5, tf: 'world' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.tree.getNumberOfKeys().should.equal(0);   // Docs are not indexed\n    });\n\n    it('Works with dot notation', function () {\n      var idx = new Index({ fieldName: 'tf.nested' })\n        , doc1 = { a: 5, tf: { nested: 'hello' } }\n        , doc2 = { a: 8, tf: { nested: 'world', additional: true } }\n        , doc3 = { a: 2, tf: { nested: 'bloup', age: 42 } }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      // The underlying BST now has 3 nodes which contain the docs where it's expected\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('hello'), [doc1]);\n      assert.deepEqual(idx.tree.search('world'), [doc2]);\n      assert.deepEqual(idx.tree.search('bloup'), [doc3]);\n\n      // The nodes contain pointers to the actual documents\n      idx.tree.search('bloup')[0].a = 42;\n      doc3.a.should.equal(42);\n    });\n\n    it('Can insert an array of documents', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        ;\n\n      idx.insert([doc1, doc2, doc3]);\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('hello'), [doc1]);\n      assert.deepEqual(idx.tree.search('world'), [doc2]);\n      assert.deepEqual(idx.tree.search('bloup'), [doc3]);\n    });\n\n    it('When inserting an array of elements, if an error is thrown all inserts need to be rolled back', function () {\n      var idx = new Index({ fieldName: 'tf', unique: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc2b = { a: 84, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        ;\n\n      try {\n        idx.insert([doc1, doc2, doc2b, doc3]);\n      } catch (e) {\n        e.errorType.should.equal('uniqueViolated');\n      }\n      idx.tree.getNumberOfKeys().should.equal(0);\n      assert.deepEqual(idx.tree.search('hello'), []);\n      assert.deepEqual(idx.tree.search('world'), []);\n      assert.deepEqual(idx.tree.search('bloup'), []);\n    });\n\n\n    describe('Array fields', function () {\n\n      it('Inserts one entry per array element in the index', function () {\n        var obj = { tf: ['aa', 'bb'], really: 'yeah' }\n          , obj2 = { tf: 'normal', yes: 'indeed' }\n          , idx = new Index({ fieldName: 'tf' })\n          ;\n\n        idx.insert(obj);\n        idx.getAll().length.should.equal(2);\n        idx.getAll()[0].should.equal(obj);\n        idx.getAll()[1].should.equal(obj);\n\n        idx.insert(obj2);\n        idx.getAll().length.should.equal(3);\n      });\n\n      it('Inserts one entry per array element in the index, type-checked', function () {\n        var obj = { tf: ['42', 42, new Date(42), 42], really: 'yeah' }\n          , idx = new Index({ fieldName: 'tf' })\n          ;\n\n        idx.insert(obj);\n        idx.getAll().length.should.equal(3);\n        idx.getAll()[0].should.equal(obj);\n        idx.getAll()[1].should.equal(obj);\n        idx.getAll()[2].should.equal(obj);\n      });\n\n      it('Inserts one entry per unique array element in the index, the unique constraint only holds across documents', function () {\n        var obj = { tf: ['aa', 'aa'], really: 'yeah' }\n          , obj2 = { tf: ['cc', 'yy', 'cc'], yes: 'indeed' }\n          , idx = new Index({ fieldName: 'tf', unique: true })\n          ;\n\n        idx.insert(obj);\n        idx.getAll().length.should.equal(1);\n        idx.getAll()[0].should.equal(obj);\n\n        idx.insert(obj2);\n        idx.getAll().length.should.equal(3);\n      });\n\n      it('The unique constraint holds across documents', function () {\n        var obj = { tf: ['aa', 'aa'], really: 'yeah' }\n          , obj2 = { tf: ['cc', 'aa', 'cc'], yes: 'indeed' }\n          , idx = new Index({ fieldName: 'tf', unique: true })\n          ;\n\n        idx.insert(obj);\n        idx.getAll().length.should.equal(1);\n        idx.getAll()[0].should.equal(obj);\n\n        (function () { idx.insert(obj2); }).should.throw();\n      });\n\n      it('When removing a document, remove it from the index at all unique array elements', function () {\n        var obj = { tf: ['aa', 'aa'], really: 'yeah' }\n          , obj2 = { tf: ['cc', 'aa', 'cc'], yes: 'indeed' }\n          , idx = new Index({ fieldName: 'tf' })\n          ;\n\n        idx.insert(obj);\n        idx.insert(obj2);\n        idx.getMatching('aa').length.should.equal(2);\n        idx.getMatching('aa').indexOf(obj).should.not.equal(-1);\n        idx.getMatching('aa').indexOf(obj2).should.not.equal(-1);\n        idx.getMatching('cc').length.should.equal(1);\n\n        idx.remove(obj2);\n        idx.getMatching('aa').length.should.equal(1);\n        idx.getMatching('aa').indexOf(obj).should.not.equal(-1);\n        idx.getMatching('aa').indexOf(obj2).should.equal(-1);\n        idx.getMatching('cc').length.should.equal(0);\n      });\n\n      it('If a unique constraint is violated when inserting an array key, roll back all inserts before the key', function () {\n        var obj = { tf: ['aa', 'bb'], really: 'yeah' }\n          , obj2 = { tf: ['cc', 'dd', 'aa', 'ee'], yes: 'indeed' }\n          , idx = new Index({ fieldName: 'tf', unique: true })\n          ;\n\n        idx.insert(obj);\n        idx.getAll().length.should.equal(2);\n        idx.getMatching('aa').length.should.equal(1);\n        idx.getMatching('bb').length.should.equal(1);\n        idx.getMatching('cc').length.should.equal(0);\n        idx.getMatching('dd').length.should.equal(0);\n        idx.getMatching('ee').length.should.equal(0);\n\n        (function () { idx.insert(obj2); }).should.throw();\n        idx.getAll().length.should.equal(2);\n        idx.getMatching('aa').length.should.equal(1);\n        idx.getMatching('bb').length.should.equal(1);\n        idx.getMatching('cc').length.should.equal(0);\n        idx.getMatching('dd').length.should.equal(0);\n        idx.getMatching('ee').length.should.equal(0);\n      });\n\n    });   // ==== End of 'Array fields' ==== //\n\n  });   // ==== End of 'Insertion' ==== //\n\n\n  describe('Removal', function () {\n\n    it('Can remove pointers from the index, even when multiple documents have the same key', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , doc4 = { a: 23, tf: 'world' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.insert(doc4);\n      idx.tree.getNumberOfKeys().should.equal(3);\n\n      idx.remove(doc1);\n      idx.tree.getNumberOfKeys().should.equal(2);\n      idx.tree.search('hello').length.should.equal(0);\n\n      idx.remove(doc2);\n      idx.tree.getNumberOfKeys().should.equal(2);\n      idx.tree.search('world').length.should.equal(1);\n      idx.tree.search('world')[0].should.equal(doc4);\n    });\n\n    it('If we have a sparse index, removing a non indexed doc has no effect', function () {\n      var idx = new Index({ fieldName: 'nope', sparse: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 5, tf: 'world' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.tree.getNumberOfKeys().should.equal(0);\n\n      idx.remove(doc1);\n      idx.tree.getNumberOfKeys().should.equal(0);\n    });\n\n    it('Works with dot notation', function () {\n      var idx = new Index({ fieldName: 'tf.nested' })\n        , doc1 = { a: 5, tf: { nested: 'hello' } }\n        , doc2 = { a: 8, tf: { nested: 'world', additional: true } }\n        , doc3 = { a: 2, tf: { nested: 'bloup', age: 42 } }\n        , doc4 = { a: 2, tf: { nested: 'world', fruits: ['apple', 'carrot'] } }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.insert(doc4);\n      idx.tree.getNumberOfKeys().should.equal(3);\n\n      idx.remove(doc1);\n      idx.tree.getNumberOfKeys().should.equal(2);\n      idx.tree.search('hello').length.should.equal(0);\n\n      idx.remove(doc2);\n      idx.tree.getNumberOfKeys().should.equal(2);\n      idx.tree.search('world').length.should.equal(1);\n      idx.tree.search('world')[0].should.equal(doc4);\n    });\n\n    it('Can remove an array of documents', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        ;\n\n      idx.insert([doc1, doc2, doc3]);\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.remove([doc1, doc3]);\n      idx.tree.getNumberOfKeys().should.equal(1);\n      assert.deepEqual(idx.tree.search('hello'), []);\n      assert.deepEqual(idx.tree.search('world'), [doc2]);\n      assert.deepEqual(idx.tree.search('bloup'), []);\n    });\n\n  });   // ==== End of 'Removal' ==== //\n\n\n  describe('Update', function () {\n\n    it('Can update a document whose key did or didnt change', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , doc4 = { a: 23, tf: 'world' }\n        , doc5 = { a: 1, tf: 'changed' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('world'), [doc2]);\n\n      idx.update(doc2, doc4);\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('world'), [doc4]);\n\n      idx.update(doc1, doc5);\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('hello'), []);\n      assert.deepEqual(idx.tree.search('changed'), [doc5]);\n    });\n\n    it('If a simple update violates a unique constraint, changes are rolled back and an error thrown', function () {\n      var idx = new Index({ fieldName: 'tf', unique: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , bad = { a: 23, tf: 'world' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('hello'), [doc1]);\n      assert.deepEqual(idx.tree.search('world'), [doc2]);\n      assert.deepEqual(idx.tree.search('bloup'), [doc3]);\n\n      try {\n        idx.update(doc3, bad);\n      } catch (e) {\n        e.errorType.should.equal('uniqueViolated');\n      }\n\n      // No change\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('hello'), [doc1]);\n      assert.deepEqual(idx.tree.search('world'), [doc2]);\n      assert.deepEqual(idx.tree.search('bloup'), [doc3]);\n    });\n\n    it('Can update an array of documents', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , doc1b = { a: 23, tf: 'world' }\n        , doc2b = { a: 1, tf: 'changed' }\n        , doc3b = { a: 44, tf: 'bloup' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.tree.getNumberOfKeys().should.equal(3);\n\n      idx.update([{ oldDoc: doc1, newDoc: doc1b }, { oldDoc: doc2, newDoc: doc2b }, { oldDoc: doc3, newDoc: doc3b }]);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('world')[0].should.equal(doc1b);\n      idx.getMatching('changed').length.should.equal(1);\n      idx.getMatching('changed')[0].should.equal(doc2b);\n      idx.getMatching('bloup').length.should.equal(1);\n      idx.getMatching('bloup')[0].should.equal(doc3b);\n    });\n\n    it('If a unique constraint is violated during an array-update, all changes are rolled back and an error thrown', function () {\n      var idx = new Index({ fieldName: 'tf', unique: true })\n        , doc0 = { a: 432, tf: 'notthistoo' }\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , doc1b = { a: 23, tf: 'changed' }\n        , doc2b = { a: 1, tf: 'changed' }   // Will violate the constraint (first try)\n        , doc2c = { a: 1, tf: 'notthistoo' }   // Will violate the constraint (second try)\n        , doc3b = { a: 44, tf: 'alsochanged' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.tree.getNumberOfKeys().should.equal(3);\n\n      try {\n        idx.update([{ oldDoc: doc1, newDoc: doc1b }, { oldDoc: doc2, newDoc: doc2b }, { oldDoc: doc3, newDoc: doc3b }]);\n      } catch (e) {\n        e.errorType.should.equal('uniqueViolated');\n      }\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('hello')[0].should.equal(doc1);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('world')[0].should.equal(doc2);\n      idx.getMatching('bloup').length.should.equal(1);\n      idx.getMatching('bloup')[0].should.equal(doc3);\n\n      try {\n        idx.update([{ oldDoc: doc1, newDoc: doc1b }, { oldDoc: doc2, newDoc: doc2b }, { oldDoc: doc3, newDoc: doc3b }]);\n      } catch (e) {\n        e.errorType.should.equal('uniqueViolated');\n      }\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('hello')[0].should.equal(doc1);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('world')[0].should.equal(doc2);\n      idx.getMatching('bloup').length.should.equal(1);\n      idx.getMatching('bloup')[0].should.equal(doc3);\n    });\n\n    it('If an update doesnt change a document, the unique constraint is not violated', function () {\n      var idx = new Index({ fieldName: 'tf', unique: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , noChange = { a: 8, tf: 'world' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('world'), [doc2]);\n\n      idx.update(doc2, noChange);   // No error thrown\n      idx.tree.getNumberOfKeys().should.equal(3);\n      assert.deepEqual(idx.tree.search('world'), [noChange]);\n    });\n\n    it('Can revert simple and batch updates', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , doc1b = { a: 23, tf: 'world' }\n        , doc2b = { a: 1, tf: 'changed' }\n        , doc3b = { a: 44, tf: 'bloup' }\n        , batchUpdate = [{ oldDoc: doc1, newDoc: doc1b }, { oldDoc: doc2, newDoc: doc2b }, { oldDoc: doc3, newDoc: doc3b }]\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.tree.getNumberOfKeys().should.equal(3);\n\n      idx.update(batchUpdate);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('world')[0].should.equal(doc1b);\n      idx.getMatching('changed').length.should.equal(1);\n      idx.getMatching('changed')[0].should.equal(doc2b);\n      idx.getMatching('bloup').length.should.equal(1);\n      idx.getMatching('bloup')[0].should.equal(doc3b);\n\n      idx.revertUpdate(batchUpdate);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('hello')[0].should.equal(doc1);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('world')[0].should.equal(doc2);\n      idx.getMatching('bloup').length.should.equal(1);\n      idx.getMatching('bloup')[0].should.equal(doc3);\n\n      // Now a simple update\n      idx.update(doc2, doc2b);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('hello')[0].should.equal(doc1);\n      idx.getMatching('changed').length.should.equal(1);\n      idx.getMatching('changed')[0].should.equal(doc2b);\n      idx.getMatching('bloup').length.should.equal(1);\n      idx.getMatching('bloup')[0].should.equal(doc3);\n\n      idx.revertUpdate(doc2, doc2b);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('hello')[0].should.equal(doc1);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('world')[0].should.equal(doc2);\n      idx.getMatching('bloup').length.should.equal(1);\n      idx.getMatching('bloup')[0].should.equal(doc3);\n    });\n\n  });   // ==== End of 'Update' ==== //\n\n\n  describe('Get matching documents', function () {\n\n    it('Get all documents where fieldName is equal to the given value, or an empty array if no match', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , doc4 = { a: 23, tf: 'world' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.insert(doc4);\n\n      assert.deepEqual(idx.getMatching('bloup'), [doc3]);\n      assert.deepEqual(idx.getMatching('world'), [doc2, doc4]);\n      assert.deepEqual(idx.getMatching('nope'), []);\n    });\n\n    it('Can get all documents for a given key in a unique index', function () {\n      var idx = new Index({ fieldName: 'tf', unique: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      assert.deepEqual(idx.getMatching('bloup'), [doc3]);\n      assert.deepEqual(idx.getMatching('world'), [doc2]);\n      assert.deepEqual(idx.getMatching('nope'), []);\n    });\n\n    it('Can get all documents for which a field is undefined', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 2, nottf: 'bloup' }\n        , doc3 = { a: 8, tf: 'world' }\n        , doc4 = { a: 7, nottf: 'yes' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      assert.deepEqual(idx.getMatching('bloup'), []);\n      assert.deepEqual(idx.getMatching('hello'), [doc1]);\n      assert.deepEqual(idx.getMatching('world'), [doc3]);\n      assert.deepEqual(idx.getMatching('yes'), []);\n      assert.deepEqual(idx.getMatching(undefined), [doc2]);\n\n      idx.insert(doc4);\n\n      assert.deepEqual(idx.getMatching('bloup'), []);\n      assert.deepEqual(idx.getMatching('hello'), [doc1]);\n      assert.deepEqual(idx.getMatching('world'), [doc3]);\n      assert.deepEqual(idx.getMatching('yes'), []);\n      assert.deepEqual(idx.getMatching(undefined), [doc2, doc4]);\n    });\n\n    it('Can get all documents for which a field is null', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 2, tf: null }\n        , doc3 = { a: 8, tf: 'world' }\n        , doc4 = { a: 7, tf: null }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      assert.deepEqual(idx.getMatching('bloup'), []);\n      assert.deepEqual(idx.getMatching('hello'), [doc1]);\n      assert.deepEqual(idx.getMatching('world'), [doc3]);\n      assert.deepEqual(idx.getMatching('yes'), []);\n      assert.deepEqual(idx.getMatching(null), [doc2]);\n\n      idx.insert(doc4);\n\n      assert.deepEqual(idx.getMatching('bloup'), []);\n      assert.deepEqual(idx.getMatching('hello'), [doc1]);\n      assert.deepEqual(idx.getMatching('world'), [doc3]);\n      assert.deepEqual(idx.getMatching('yes'), []);\n      assert.deepEqual(idx.getMatching(null), [doc2, doc4]);\n    });\n\n    it('Can get all documents for a given key in a sparse index, but not unindexed docs (= field undefined)', function () {\n      var idx = new Index({ fieldName: 'tf', sparse: true })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 2, nottf: 'bloup' }\n        , doc3 = { a: 8, tf: 'world' }\n        , doc4 = { a: 7, nottf: 'yes' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.insert(doc4);\n\n      assert.deepEqual(idx.getMatching('bloup'), []);\n      assert.deepEqual(idx.getMatching('hello'), [doc1]);\n      assert.deepEqual(idx.getMatching('world'), [doc3]);\n      assert.deepEqual(idx.getMatching('yes'), []);\n      assert.deepEqual(idx.getMatching(undefined), []);\n    });\n\n    it('Can get all documents whose key is in an array of keys', function () {\n      // For this test only we have to use objects with _ids as the array version of getMatching\n      // relies on the _id property being set, otherwise we have to use a quadratic algorithm\n      // or a fingerprinting algorithm, both solutions too complicated and slow given that live nedb\n      // indexes documents with _id always set\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello', _id: '1' }\n        , doc2 = { a: 2, tf: 'bloup', _id: '2' }\n        , doc3 = { a: 8, tf: 'world', _id: '3' }\n        , doc4 = { a: 7, tf: 'yes', _id: '4' }\n        , doc5 = { a: 7, tf: 'yes', _id: '5' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.insert(doc4);\n      idx.insert(doc5);\n\n      assert.deepEqual(idx.getMatching([]), []);\n      assert.deepEqual(idx.getMatching(['bloup']), [doc2]);\n      assert.deepEqual(idx.getMatching(['bloup', 'yes']), [doc2, doc4, doc5]);\n      assert.deepEqual(idx.getMatching(['hello', 'no']), [doc1]);\n      assert.deepEqual(idx.getMatching(['nope', 'no']), []);\n    });\n\n    it('Can get all documents whose key is between certain bounds', function () {\n      var idx = new Index({ fieldName: 'a' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 2, tf: 'bloup' }\n        , doc3 = { a: 8, tf: 'world' }\n        , doc4 = { a: 7, tf: 'yes' }\n        , doc5 = { a: 10, tf: 'yes' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n      idx.insert(doc4);\n      idx.insert(doc5);\n\n      assert.deepEqual(idx.getBetweenBounds({ $lt: 10, $gte: 5 }), [ doc1, doc4, doc3 ]);\n      assert.deepEqual(idx.getBetweenBounds({ $lte: 8 }), [ doc2, doc1, doc4, doc3 ]);\n      assert.deepEqual(idx.getBetweenBounds({ $gt: 7 }), [ doc3, doc5 ]);\n    });\n\n  });   // ==== End of 'Get matching documents' ==== //\n\n\n  describe('Resetting', function () {\n\n    it('Can reset an index without any new data, the index will be empty afterwards', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('bloup').length.should.equal(1);\n\n      idx.reset();\n      idx.tree.getNumberOfKeys().should.equal(0);\n      idx.getMatching('hello').length.should.equal(0);\n      idx.getMatching('world').length.should.equal(0);\n      idx.getMatching('bloup').length.should.equal(0);\n    });\n\n    it('Can reset an index and initialize it with one document', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , newDoc = { a: 555, tf: 'new' }\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('bloup').length.should.equal(1);\n\n      idx.reset(newDoc);\n      idx.tree.getNumberOfKeys().should.equal(1);\n      idx.getMatching('hello').length.should.equal(0);\n      idx.getMatching('world').length.should.equal(0);\n      idx.getMatching('bloup').length.should.equal(0);\n      idx.getMatching('new')[0].a.should.equal(555);\n    });\n\n    it('Can reset an index and initialize it with an array of documents', function () {\n      var idx = new Index({ fieldName: 'tf' })\n        , doc1 = { a: 5, tf: 'hello' }\n        , doc2 = { a: 8, tf: 'world' }\n        , doc3 = { a: 2, tf: 'bloup' }\n        , newDocs = [{ a: 555, tf: 'new' }, { a: 666, tf: 'again' }]\n        ;\n\n      idx.insert(doc1);\n      idx.insert(doc2);\n      idx.insert(doc3);\n\n      idx.tree.getNumberOfKeys().should.equal(3);\n      idx.getMatching('hello').length.should.equal(1);\n      idx.getMatching('world').length.should.equal(1);\n      idx.getMatching('bloup').length.should.equal(1);\n\n      idx.reset(newDocs);\n      idx.tree.getNumberOfKeys().should.equal(2);\n      idx.getMatching('hello').length.should.equal(0);\n      idx.getMatching('world').length.should.equal(0);\n      idx.getMatching('bloup').length.should.equal(0);\n      idx.getMatching('new')[0].a.should.equal(555);\n      idx.getMatching('again')[0].a.should.equal(666);\n    });\n\n  });   // ==== End of 'Resetting' ==== //\n\n  it('Get all elements in the index', function () {\n    var idx = new Index({ fieldName: 'a' })\n      , doc1 = { a: 5, tf: 'hello' }\n      , doc2 = { a: 8, tf: 'world' }\n      , doc3 = { a: 2, tf: 'bloup' }\n      ;\n\n    idx.insert(doc1);\n    idx.insert(doc2);\n    idx.insert(doc3);\n\n    assert.deepEqual(idx.getAll(), [{ a: 2, tf: 'bloup' }, { a: 5, tf: 'hello' }, { a: 8, tf: 'world' }]);\n  });\n\n\n});\n"
  },
  {
    "path": "test/mocha.opts",
    "content": "--reporter spec\n--timeout 30000"
  },
  {
    "path": "test/model.test.js",
    "content": "var model = require('../lib/model')\n  , should = require('chai').should()\n  , assert = require('chai').assert\n  , expect = require('chai').expect\n  , _ = require('underscore')\n  , async = require('async')\n  , util = require('util')\n  , Datastore = require('../lib/datastore')\n  , fs = require('fs')\n  ;\n\n\ndescribe('Model', function () {\n\n  describe('Serialization, deserialization', function () {\n\n    it('Can serialize and deserialize strings', function () {\n      var a, b, c;\n\n      a = { test: \"Some string\" };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      b.indexOf('\\n').should.equal(-1);\n      c.test.should.equal(\"Some string\");\n\n      // Even if a property is a string containing a new line, the serialized\n      // version doesn't. The new line must still be there upon deserialization\n      a = { test: \"With a new\\nline\" };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      c.test.should.equal(\"With a new\\nline\");\n      a.test.indexOf('\\n').should.not.equal(-1);\n      b.indexOf('\\n').should.equal(-1);\n      c.test.indexOf('\\n').should.not.equal(-1);\n    });\n\n    it('Can serialize and deserialize booleans', function () {\n      var a, b, c;\n\n      a = { test: true };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      b.indexOf('\\n').should.equal(-1);\n      c.test.should.equal(true);\n    });\n\n    it('Can serialize and deserialize numbers', function () {\n      var a, b, c;\n\n      a = { test: 5 };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      b.indexOf('\\n').should.equal(-1);\n      c.test.should.equal(5);\n    });\n\n    it('Can serialize and deserialize null', function () {\n      var a, b, c;\n\n      a = { test: null };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      b.indexOf('\\n').should.equal(-1);\n      assert.isNull(a.test);\n    });\n\n    it('undefined fields are removed when serialized', function() {\n      var a = { bloup: undefined, hello: 'world' }\n        , b = model.serialize(a)\n        , c = model.deserialize(b)\n        ;\n\n      Object.keys(c).length.should.equal(1);\n      c.hello.should.equal('world');\n      assert.isUndefined(c.bloup);\n    });\n\n    it('Can serialize and deserialize a date', function () {\n      var a, b, c\n        , d = new Date();\n\n      a = { test: d };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      b.indexOf('\\n').should.equal(-1);\n      b.should.equal('{\"test\":{\"$$date\":' + d.getTime() + '}}');\n      util.isDate(c.test).should.equal(true);\n      c.test.getTime().should.equal(d.getTime());\n    });\n\n    it('Can serialize and deserialize sub objects', function () {\n      var a, b, c\n        , d = new Date();\n\n      a = { test: { something: 39, also: d, yes: { again: 'yes' } } };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      b.indexOf('\\n').should.equal(-1);\n      c.test.something.should.equal(39);\n      c.test.also.getTime().should.equal(d.getTime());\n      c.test.yes.again.should.equal('yes');\n    });\n\n    it('Can serialize and deserialize sub arrays', function () {\n      var a, b, c\n        , d = new Date();\n\n      a = { test: [ 39, d, { again: 'yes' } ] };\n      b = model.serialize(a);\n      c = model.deserialize(b);\n      b.indexOf('\\n').should.equal(-1);\n      c.test[0].should.equal(39);\n      c.test[1].getTime().should.equal(d.getTime());\n      c.test[2].again.should.equal('yes');\n    });\n\n    it('Reject field names beginning with a $ sign or containing a dot, except the four edge cases', function () {\n      var a1 = { $something: 'totest' }\n        , a2 = { \"with.dot\": 'totest' }\n        , e1 = { $$date: 4321 }\n        , e2 = { $$deleted: true }\n        , e3 = { $$indexCreated: \"indexName\" }\n        , e4 = { $$indexRemoved: \"indexName\" }\n        , b;\n\n      // Normal cases\n      (function () { b = model.serialize(a1); }).should.throw();\n      (function () { b = model.serialize(a2); }).should.throw();\n\n      // Edge cases\n      b = model.serialize(e1);\n      b = model.serialize(e2);\n      b = model.serialize(e3);\n      b = model.serialize(e4);\n    });\n\n    it('Can serialize string fields with a new line without breaking the DB', function (done) {\n      var db1, db2\n        , badString = \"world\\r\\nearth\\nother\\rline\"\n      ;\n\n      if (fs.existsSync('workspace/test1.db')) { fs.unlinkSync('workspace/test1.db'); }\n      fs.existsSync('workspace/test1.db').should.equal(false);\n      db1 = new Datastore({ filename: 'workspace/test1.db' });\n\n      db1.loadDatabase(function (err) {\n        assert.isNull(err);\n        db1.insert({ hello: badString }, function (err) {\n          assert.isNull(err);\n\n          db2 = new Datastore({ filename: 'workspace/test1.db' });\n          db2.loadDatabase(function (err) {\n            assert.isNull(err);\n            db2.find({}, function (err, docs) {\n              assert.isNull(err);\n              docs.length.should.equal(1);\n              docs[0].hello.should.equal(badString);\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it('Can accept objects whose keys are numbers', function () {\n      var o = { 42: true };\n\n      var s = model.serialize(o);\n    });\n\n  });   // ==== End of 'Serialization, deserialization' ==== //\n\n\n  describe('Object checking', function () {\n\n    it('Field names beginning with a $ sign are forbidden', function () {\n      assert.isDefined(model.checkObject);\n\n      (function () {\n        model.checkObject({ $bad: true });\n      }).should.throw();\n\n      (function () {\n        model.checkObject({ some: 42, nested: { again: \"no\", $worse: true } });\n      }).should.throw();\n\n      // This shouldn't throw since \"$actuallyok\" is not a field name\n      model.checkObject({ some: 42, nested: [ 5, \"no\", \"$actuallyok\", true ] });\n\n      (function () {\n        model.checkObject({ some: 42, nested: [ 5, \"no\", \"$actuallyok\", true, { $hidden: \"useless\" } ] });\n      }).should.throw();\n    });\n\n    it('Field names cannot contain a .', function () {\n      assert.isDefined(model.checkObject);\n\n      (function () {\n        model.checkObject({ \"so.bad\": true });\n      }).should.throw();\n\n      // Recursive behaviour testing done in the above test on $ signs\n    });\n\n    it('Properties with a null value dont trigger an error', function () {\n      var obj = { prop: null };\n\n      model.checkObject(obj);\n    });\n\n    it('Can check if an object is a primitive or not', function () {\n      model.isPrimitiveType(5).should.equal(true);\n      model.isPrimitiveType('sdsfdfs').should.equal(true);\n      model.isPrimitiveType(0).should.equal(true);\n      model.isPrimitiveType(true).should.equal(true);\n      model.isPrimitiveType(false).should.equal(true);\n      model.isPrimitiveType(new Date()).should.equal(true);\n      model.isPrimitiveType([]).should.equal(true);\n      model.isPrimitiveType([3, 'try']).should.equal(true);\n      model.isPrimitiveType(null).should.equal(true);\n\n      model.isPrimitiveType({}).should.equal(false);\n      model.isPrimitiveType({ a: 42 }).should.equal(false);\n    });\n\n  });   // ==== End of 'Object checking' ==== //\n\n\n  describe('Deep copying', function () {\n\n    it('Should be able to deep copy any serializable model', function () {\n      var d = new Date()\n        , obj = { a: ['ee', 'ff', 42], date: d, subobj: { a: 'b', b: 'c' } }\n        , res = model.deepCopy(obj);\n        ;\n\n      res.a.length.should.equal(3);\n      res.a[0].should.equal('ee');\n      res.a[1].should.equal('ff');\n      res.a[2].should.equal(42);\n      res.date.getTime().should.equal(d.getTime());\n      res.subobj.a.should.equal('b');\n      res.subobj.b.should.equal('c');\n\n      obj.a.push('ggg');\n      obj.date = 'notadate';\n      obj.subobj = [];\n\n      // Even if the original object is modified, the copied one isn't\n      res.a.length.should.equal(3);\n      res.a[0].should.equal('ee');\n      res.a[1].should.equal('ff');\n      res.a[2].should.equal(42);\n      res.date.getTime().should.equal(d.getTime());\n      res.subobj.a.should.equal('b');\n      res.subobj.b.should.equal('c');\n    });\n\n    it('Should deep copy the contents of an array', function () {\n      var a = [{ hello: 'world' }]\n        , b = model.deepCopy(a)\n      ;\n\n      b[0].hello.should.equal('world');\n      b[0].hello = 'another';\n      b[0].hello.should.equal('another');\n      a[0].hello.should.equal('world');\n    });\n\n    it('Without the strictKeys option, everything gets deep copied', function () {\n      var a = { a: 4, $e: 'rrr', 'eee.rt': 42, nested: { yes: 1, 'tt.yy': 2, $nopenope: 3 }, array: [{ 'rr.hh': 1 }, { yes: true }, { $yes: false }] }\n        , b = model.deepCopy(a)\n      ;\n\n      assert.deepEqual(a, b);\n    });\n\n    it('With the strictKeys option, only valid keys gets deep copied', function () {\n      var a = { a: 4, $e: 'rrr', 'eee.rt': 42, nested: { yes: 1, 'tt.yy': 2, $nopenope: 3 }, array: [{ 'rr.hh': 1 }, { yes: true }, { $yes: false }] }\n        , b = model.deepCopy(a, true)\n      ;\n\n      assert.deepEqual(b, { a: 4, nested: { yes: 1 }, array: [{}, { yes: true }, {}] });\n    });\n\n  });   // ==== End of 'Deep copying' ==== //\n\n\n  describe('Modifying documents', function () {\n\n    it('Queries not containing any modifier just replace the document by the contents of the query but keep its _id', function () {\n      var obj = { some: 'thing', _id: 'keepit' }\n        , updateQuery = { replace: 'done', bloup: [ 1, 8] }\n        , t\n        ;\n\n      t = model.modify(obj, updateQuery);\n      t.replace.should.equal('done');\n      t.bloup.length.should.equal(2);\n      t.bloup[0].should.equal(1);\n      t.bloup[1].should.equal(8);\n\n      assert.isUndefined(t.some);\n      t._id.should.equal('keepit');\n    });\n\n    it('Throw an error if trying to change the _id field in a copy-type modification', function () {\n      var obj = { some: 'thing', _id: 'keepit' }\n        , updateQuery = { replace: 'done', bloup: [ 1, 8], _id: 'donttryit' }\n        ;\n\n      expect(function () {\n        model.modify(obj, updateQuery);\n      }).to.throw(\"You cannot change a document's _id\");\n\n      updateQuery._id = 'keepit';\n      model.modify(obj, updateQuery);   // No error thrown\n    });\n\n    it('Throw an error if trying to use modify in a mixed copy+modify way', function () {\n      var obj = { some: 'thing' }\n        , updateQuery = { replace: 'me', $modify: 'metoo' };\n\n      expect(function () {\n        model.modify(obj, updateQuery);\n      }).to.throw(\"You cannot mix modifiers and normal fields\");\n    });\n\n    it('Throw an error if trying to use an inexistent modifier', function () {\n      var obj = { some: 'thing' }\n        , updateQuery = { $set: { it: 'exists' }, $modify: 'not this one' };\n\n      expect(function () {\n        model.modify(obj, updateQuery);\n      }).to.throw(/^Unknown modifier .modify/);\n    });\n\n    it('Throw an error if a modifier is used with a non-object argument', function () {\n      var obj = { some: 'thing' }\n        , updateQuery = { $set: 'this exists' };\n\n      expect(function () {\n        model.modify(obj, updateQuery);\n      }).to.throw(/Modifier .set's argument must be an object/);\n    });\n\n    describe('$set modifier', function () {\n      it('Can change already set fields without modfifying the underlying object', function () {\n        var obj = { some: 'thing', yup: 'yes', nay: 'noes' }\n          , updateQuery = { $set: { some: 'changed', nay: 'yes indeed' } }\n          , modified = model.modify(obj, updateQuery);\n\n        Object.keys(modified).length.should.equal(3);\n        modified.some.should.equal('changed');\n        modified.yup.should.equal('yes');\n        modified.nay.should.equal('yes indeed');\n\n        Object.keys(obj).length.should.equal(3);\n        obj.some.should.equal('thing');\n        obj.yup.should.equal('yes');\n        obj.nay.should.equal('noes');\n      });\n\n      it('Creates fields to set if they dont exist yet', function () {\n        var obj = { yup: 'yes' }\n          , updateQuery = { $set: { some: 'changed', nay: 'yes indeed' } }\n          , modified = model.modify(obj, updateQuery);\n\n        Object.keys(modified).length.should.equal(3);\n        modified.some.should.equal('changed');\n        modified.yup.should.equal('yes');\n        modified.nay.should.equal('yes indeed');\n      });\n\n      it('Can set sub-fields and create them if necessary', function () {\n        var obj = { yup: { subfield: 'bloup' } }\n          , updateQuery = { $set: { \"yup.subfield\": 'changed', \"yup.yop\": 'yes indeed', \"totally.doesnt.exist\": 'now it does' } }\n          , modified = model.modify(obj, updateQuery);\n\n        _.isEqual(modified, { yup: { subfield: 'changed', yop: 'yes indeed' }, totally: { doesnt: { exist: 'now it does' } } }).should.equal(true);\n      });\n\n      it(\"Doesn't replace a falsy field by an object when recursively following dot notation\", function () {\n        var obj = { nested: false }\n          , updateQuery = { $set: { \"nested.now\": 'it is' } }\n          , modified = model.modify(obj, updateQuery);\n\n        assert.deepEqual(modified, { nested: false });   // Object not modified as the nested field doesn't exist\n      });\n    });   // End of '$set modifier'\n\n    describe('$unset modifier', function () {\n\n      it('Can delete a field, not throwing an error if the field doesnt exist', function () {\n        var obj, updateQuery, modified;\n\n        obj = { yup: 'yes', other: 'also' }\n        updateQuery = { $unset: { yup: true } }\n        modified = model.modify(obj, updateQuery);\n        assert.deepEqual(modified, { other: 'also' });\n\n        obj = { yup: 'yes', other: 'also' }\n        updateQuery = { $unset: { nope: true } }\n        modified = model.modify(obj, updateQuery);\n        assert.deepEqual(modified, obj);\n\n        obj = { yup: 'yes', other: 'also' }\n        updateQuery = { $unset: { nope: true, other: true } }\n        modified = model.modify(obj, updateQuery);\n        assert.deepEqual(modified, { yup: 'yes' });\n      });\n\n      it('Can unset sub-fields and entire nested documents', function () {\n        var obj, updateQuery, modified;\n\n        obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } }\n        updateQuery = { $unset: { nested: true } }\n        modified = model.modify(obj, updateQuery);\n        assert.deepEqual(modified, { yup: 'yes' });\n\n        obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } }\n        updateQuery = { $unset: { 'nested.a': true } }\n        modified = model.modify(obj, updateQuery);\n        assert.deepEqual(modified, { yup: 'yes', nested: { b: 'yeah' } });\n\n        obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } }\n        updateQuery = { $unset: { 'nested.a': true, 'nested.b': true } }\n        modified = model.modify(obj, updateQuery);\n        assert.deepEqual(modified, { yup: 'yes', nested: {} });\n      });\n\n      it(\"When unsetting nested fields, should not create an empty parent to nested field\", function () {\n        var obj = model.modify({ argh: true }, { $unset: { 'bad.worse': true } });\n        assert.deepEqual(obj, { argh: true });\n\n        obj = model.modify({ argh: true, bad: { worse: 'oh' } }, { $unset: { 'bad.worse': true } });\n        assert.deepEqual(obj, { argh: true, bad: {} });\n\n        obj = model.modify({ argh: true, bad: {} }, { $unset: { 'bad.worse': true } });\n        assert.deepEqual(obj, { argh: true, bad: {} });\n      });\n\n    });   // End of '$unset modifier'\n\n    describe('$inc modifier', function () {\n      it('Throw an error if you try to use it with a non-number or on a non number field', function () {\n        (function () {\n          var obj = { some: 'thing', yup: 'yes', nay: 2 }\n            , updateQuery = { $inc: { nay: 'notanumber' } }\n            , modified = model.modify(obj, updateQuery);\n        }).should.throw();\n\n        (function () {\n          var obj = { some: 'thing', yup: 'yes', nay: 'nope' }\n            , updateQuery = { $inc: { nay: 1 } }\n            , modified = model.modify(obj, updateQuery);\n        }).should.throw();\n      });\n\n      it('Can increment number fields or create and initialize them if needed', function () {\n        var obj = { some: 'thing', nay: 40 }\n          , modified;\n\n        modified = model.modify(obj, { $inc: { nay: 2 } });\n        _.isEqual(modified, { some: 'thing', nay: 42 }).should.equal(true);\n\n        // Incidentally, this tests that obj was not modified\n        modified = model.modify(obj, { $inc: { inexistent: -6 } });\n        _.isEqual(modified, { some: 'thing', nay: 40, inexistent: -6 }).should.equal(true);\n      });\n\n      it('Works recursively', function () {\n        var obj = { some: 'thing', nay: { nope: 40 } }\n          , modified;\n\n        modified = model.modify(obj, { $inc: { \"nay.nope\": -2, \"blip.blop\": 123 } });\n        _.isEqual(modified, { some: 'thing', nay: { nope: 38 }, blip: { blop: 123 } }).should.equal(true);\n      });\n    });   // End of '$inc modifier'\n\n    describe('$push modifier', function () {\n\n      it('Can push an element to the end of an array', function () {\n        var obj = { arr: ['hello'] }\n          , modified;\n\n        modified = model.modify(obj, { $push: { arr: 'world' } });\n        assert.deepEqual(modified, { arr: ['hello', 'world'] });\n      });\n\n      it('Can push an element to a non-existent field and will create the array', function () {\n        var obj = {}\n          , modified;\n\n        modified = model.modify(obj, { $push: { arr: 'world' } });\n        assert.deepEqual(modified, { arr: ['world'] });\n      });\n\n      it('Can push on nested fields', function () {\n        var obj = { arr: { nested: ['hello'] } }\n          , modified;\n\n        modified = model.modify(obj, { $push: { \"arr.nested\": 'world' } });\n        assert.deepEqual(modified, { arr: { nested: ['hello', 'world'] } });\n\n        obj = { arr: { a: 2 }};\n        modified = model.modify(obj, { $push: { \"arr.nested\": 'world' } });\n        assert.deepEqual(modified, { arr: { a: 2, nested: ['world'] } });\n      });\n\n      it('Throw if we try to push to a non-array', function () {\n        var obj = { arr: 'hello' }\n          , modified;\n\n        (function () {\n          modified = model.modify(obj, { $push: { arr: 'world' } });\n        }).should.throw();\n\n        obj = { arr: { nested: 45 } };\n        (function () {\n          modified = model.modify(obj, { $push: { \"arr.nested\": 'world' } });\n        }).should.throw();\n      });\n\n      it('Can use the $each modifier to add multiple values to an array at once', function () {\n        var obj = { arr: ['hello'] }\n          , modified;\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'] } } });\n        assert.deepEqual(modified, { arr: ['hello', 'world', 'earth', 'everything'] });\n\n        (function () {\n          modified = model.modify(obj, { $push: { arr: { $each: 45 } } });\n        }).should.throw();\n\n        (function () {\n          modified = model.modify(obj, { $push: { arr: { $each: ['world'], unauthorized: true } } });\n        }).should.throw();\n      });\n\n      it('Can use the $slice modifier to limit the number of array elements', function () {\n        var obj = { arr: ['hello'] }\n          , modified;\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 1 } } });\n        assert.deepEqual(modified, { arr: ['hello'] });\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: -1 } } });\n        assert.deepEqual(modified, { arr: ['everything'] });\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 0 } } });\n        assert.deepEqual(modified, { arr: [] });\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 2 } } });\n        assert.deepEqual(modified, { arr: ['hello', 'world'] });\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: -2 } } });\n        assert.deepEqual(modified, { arr: ['earth', 'everything'] });\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: -20 } } });\n        assert.deepEqual(modified, { arr: ['hello', 'world', 'earth', 'everything'] });\n\n        modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 20 } } });\n        assert.deepEqual(modified, { arr: ['hello', 'world', 'earth', 'everything'] });\n\n        modified = model.modify(obj, { $push: { arr: { $each: [], $slice: 1 } } });\n        assert.deepEqual(modified, { arr: ['hello'] });\n\n        // $each not specified, but $slice is\n        modified = model.modify(obj, { $push: { arr: { $slice: 1 } } });\n        assert.deepEqual(modified, { arr: ['hello'] });\n\n        (function () {\n          modified = model.modify(obj, { $push: { arr: { $slice: 1, unauthorized: true } } });\n        }).should.throw();\n\n        (function () {\n          modified = model.modify(obj, { $push: { arr: { $each: [], unauthorized: true } } });\n        }).should.throw();\n      });\n\n    });   // End of '$push modifier'\n\n    describe('$addToSet modifier', function () {\n\n      it('Can add an element to a set', function () {\n        var obj = { arr: ['hello'] }\n          , modified;\n\n        modified = model.modify(obj, { $addToSet: { arr: 'world' } });\n        assert.deepEqual(modified, { arr: ['hello', 'world'] });\n\n        obj = { arr: ['hello'] };\n        modified = model.modify(obj, { $addToSet: { arr: 'hello' } });\n        assert.deepEqual(modified, { arr: ['hello'] });\n      });\n\n      it('Can add an element to a non-existent set and will create the array', function () {\n        var obj = { arr: [] }\n          , modified;\n\n        modified = model.modify(obj, { $addToSet: { arr: 'world' } });\n        assert.deepEqual(modified, { arr: ['world'] });\n      });\n\n      it('Throw if we try to addToSet to a non-array', function () {\n        var obj = { arr: 'hello' }\n          , modified;\n\n        (function () {\n          modified = model.modify(obj, { $addToSet: { arr: 'world' } });\n        }).should.throw();\n      });\n\n      it('Use deep-equality to check whether we can add a value to a set', function () {\n        var obj = { arr: [ { b: 2 } ] }\n          , modified;\n\n        modified = model.modify(obj, { $addToSet: { arr: { b: 3 } } });\n        assert.deepEqual(modified, { arr: [{ b: 2 }, { b: 3 }] });\n\n        obj = { arr: [ { b: 2 } ] }\n        modified = model.modify(obj, { $addToSet: { arr: { b: 2 } } });\n        assert.deepEqual(modified, { arr: [{ b: 2 }] });\n      });\n\n      it('Can use the $each modifier to add multiple values to a set at once', function () {\n        var obj = { arr: ['hello'] }\n          , modified;\n\n        modified = model.modify(obj, { $addToSet: { arr: { $each: ['world', 'earth', 'hello', 'earth'] } } });\n        assert.deepEqual(modified, { arr: ['hello', 'world', 'earth'] });\n\n        (function () {\n          modified = model.modify(obj, { $addToSet: { arr: { $each: 45 } } });\n        }).should.throw();\n\n        (function () {\n          modified = model.modify(obj, { $addToSet: { arr: { $each: ['world'], unauthorized: true } } });\n        }).should.throw();\n      });\n\n    });   // End of '$addToSet modifier'\n\n    describe('$pop modifier', function () {\n\n      it('Throw if called on a non array, a non defined field or a non integer', function () {\n        var obj = { arr: 'hello' }\n          , modified;\n\n        (function () {\n          modified = model.modify(obj, { $pop: { arr: 1 } });\n        }).should.throw();\n\n        obj = { bloup: 'nope' };\n        (function () {\n          modified = model.modify(obj, { $pop: { arr: 1 } });\n        }).should.throw();\n\n        obj = { arr: [1, 4, 8] };\n        (function () {\n          modified = model.modify(obj, { $pop: { arr: true } });\n        }).should.throw();\n      });\n\n      it('Can remove the first and last element of an array', function () {\n        var obj\n          , modified;\n\n        obj = { arr: [1, 4, 8] };\n        modified = model.modify(obj, { $pop: { arr: 1 } });\n        assert.deepEqual(modified, { arr: [1, 4] });\n\n        obj = { arr: [1, 4, 8] };\n        modified = model.modify(obj, { $pop: { arr: -1 } });\n        assert.deepEqual(modified, { arr: [4, 8] });\n\n        // Empty arrays are not changed\n        obj = { arr: [] };\n        modified = model.modify(obj, { $pop: { arr: 1 } });\n        assert.deepEqual(modified, { arr: [] });\n        modified = model.modify(obj, { $pop: { arr: -1 } });\n        assert.deepEqual(modified, { arr: [] });\n      });\n\n    });   // End of '$pop modifier'\n\n    describe('$pull modifier', function () {\n\n      it('Can remove an element from a set', function () {\n        var obj = { arr: ['hello', 'world'] }\n          , modified;\n\n        modified = model.modify(obj, { $pull: { arr: 'world' } });\n        assert.deepEqual(modified, { arr: ['hello'] });\n\n        obj = { arr: ['hello'] };\n        modified = model.modify(obj, { $pull: { arr: 'world' } });\n        assert.deepEqual(modified, { arr: ['hello'] });\n      });\n\n      it('Can remove multiple matching elements', function () {\n        var obj = { arr: ['hello', 'world', 'hello', 'world'] }\n          , modified;\n\n        modified = model.modify(obj, { $pull: { arr: 'world' } });\n        assert.deepEqual(modified, { arr: ['hello', 'hello'] });\n      });\n\n      it('Throw if we try to pull from a non-array', function () {\n        var obj = { arr: 'hello' }\n          , modified;\n\n        (function () {\n          modified = model.modify(obj, { $pull: { arr: 'world' } });\n        }).should.throw();\n      });\n\n      it('Use deep-equality to check whether we can remove a value from a set', function () {\n        var obj = { arr: [{ b: 2 }, { b: 3 }] }\n          , modified;\n\n        modified = model.modify(obj, { $pull: { arr: { b: 3 } } });\n        assert.deepEqual(modified, { arr: [ { b: 2 } ] });\n\n        obj = { arr: [ { b: 2 } ] }\n        modified = model.modify(obj, { $pull: { arr: { b: 3 } } });\n        assert.deepEqual(modified, { arr: [{ b: 2 }] });\n      });\n\n      it('Can use any kind of nedb query with $pull', function () {\n        var obj = { arr: [4, 7, 12, 2], other: 'yup' }\n          , modified\n        ;\n\n        modified = model.modify(obj, { $pull: { arr: { $gte: 5 } } });\n        assert.deepEqual(modified, { arr: [4, 2], other: 'yup' });\n\n        obj = { arr: [{ b: 4 }, { b: 7 }, { b: 1 }], other: 'yeah' };\n        modified = model.modify(obj, { $pull: { arr: { b: { $gte: 5} } } });\n        assert.deepEqual(modified, { arr: [{ b: 4 }, { b: 1 }], other: 'yeah' });\n      });\n\n    });   // End of '$pull modifier'\n\n    describe('$max modifier', function () {\n      it('Will set the field to the updated value if value is greater than current one, without modifying the original object', function () {\n        var obj = { some:'thing', number: 10 }\n            , updateQuery = { $max: { number:12 } }\n            , modified = model.modify(obj, updateQuery);\n\n        modified.should.deep.equal({ some: 'thing', number: 12 });\n        obj.should.deep.equal({ some: 'thing', number: 10 });\n      });\n\n      it('Will not update the field if new value is smaller than current one', function () {\n        var obj = { some:'thing', number: 10 }\n            , updateQuery = { $max: { number: 9 } }\n            , modified = model.modify(obj, updateQuery);\n\n        modified.should.deep.equal({ some:'thing', number:10 });\n      });\n\n      it('Will create the field if it does not exist', function () {\n        var obj = { some: 'thing' }\n            , updateQuery = { $max: { number: 10 } }\n            , modified = model.modify(obj, updateQuery);\n\n        modified.should.deep.equal({ some: 'thing', number: 10 });\n      });\n\n      it('Works on embedded documents', function () {\n        var obj = { some: 'thing', somethingElse: { number:10 } }\n            , updateQuery = { $max: { 'somethingElse.number': 12 } }\n            , modified = model.modify(obj,updateQuery);\n\n        modified.should.deep.equal({ some: 'thing', somethingElse: { number:12 } });\n      });\n    });// End of '$max modifier'\n\n    describe('$min modifier', function () {\n      it('Will set the field to the updated value if value is smaller than current one, without modifying the original object', function () {\n        var obj = { some:'thing', number: 10 }\n            , updateQuery = { $min: { number: 8 } }\n            , modified = model.modify(obj, updateQuery);\n\n        modified.should.deep.equal({ some: 'thing', number: 8 });\n        obj.should.deep.equal({ some: 'thing', number: 10 });\n      });\n\n      it('Will not update the field if new value is greater than current one', function () {\n        var obj = { some: 'thing', number: 10 }\n            , updateQuery = { $min: { number: 12 } }\n            , modified = model.modify(obj, updateQuery);\n\n        modified.should.deep.equal({ some: 'thing', number: 10 });\n      });\n\n      it('Will create the field if it does not exist', function () {\n        var obj = { some: 'thing' }\n            , updateQuery = { $min: { number: 10 } }\n            , modified = model.modify(obj, updateQuery);\n\n        modified.should.deep.equal({ some: 'thing', number: 10 });\n      });\n\n      it('Works on embedded documents', function () {\n        var obj = { some: 'thing', somethingElse: { number: 10 } }\n            , updateQuery = { $min: { 'somethingElse.number': 8 } }\n            , modified = model.modify(obj, updateQuery);\n\n        modified.should.deep.equal({ some: 'thing', somethingElse: { number: 8 } } );\n      });\n    });// End of '$min modifier'\n\n  });   // ==== End of 'Modifying documents' ==== //\n\n\n  describe('Comparing things', function () {\n\n    it('undefined is the smallest', function () {\n      var otherStuff = [null, \"string\", \"\", -1, 0, 5.3, 12, true, false, new Date(12345), {}, { hello: 'world' }, [], ['quite', 5]];\n\n      model.compareThings(undefined, undefined).should.equal(0);\n\n      otherStuff.forEach(function (stuff) {\n        model.compareThings(undefined, stuff).should.equal(-1);\n        model.compareThings(stuff, undefined).should.equal(1);\n      });\n    });\n\n    it('Then null', function () {\n      var otherStuff = [\"string\", \"\", -1, 0, 5.3, 12, true, false, new Date(12345), {}, { hello: 'world' }, [], ['quite', 5]];\n\n      model.compareThings(null, null).should.equal(0);\n\n      otherStuff.forEach(function (stuff) {\n        model.compareThings(null, stuff).should.equal(-1);\n        model.compareThings(stuff, null).should.equal(1);\n      });\n    });\n\n    it('Then numbers', function () {\n      var otherStuff = [\"string\", \"\", true, false, new Date(4312), {}, { hello: 'world' }, [], ['quite', 5]]\n        , numbers = [-12, 0, 12, 5.7];\n\n      model.compareThings(-12, 0).should.equal(-1);\n      model.compareThings(0, -3).should.equal(1);\n      model.compareThings(5.7, 2).should.equal(1);\n      model.compareThings(5.7, 12.3).should.equal(-1);\n      model.compareThings(0, 0).should.equal(0);\n      model.compareThings(-2.6, -2.6).should.equal(0);\n      model.compareThings(5, 5).should.equal(0);\n\n      otherStuff.forEach(function (stuff) {\n        numbers.forEach(function (number) {\n          model.compareThings(number, stuff).should.equal(-1);\n          model.compareThings(stuff, number).should.equal(1);\n        });\n      });\n    });\n\n    it('Then strings', function () {\n      var otherStuff = [true, false, new Date(4321), {}, { hello: 'world' }, [], ['quite', 5]]\n        , strings = ['', 'string', 'hello world'];\n\n      model.compareThings('', 'hey').should.equal(-1);\n      model.compareThings('hey', '').should.equal(1);\n      model.compareThings('hey', 'hew').should.equal(1);\n      model.compareThings('hey', 'hey').should.equal(0);\n\n      otherStuff.forEach(function (stuff) {\n        strings.forEach(function (string) {\n          model.compareThings(string, stuff).should.equal(-1);\n          model.compareThings(stuff, string).should.equal(1);\n        });\n      });\n    });\n\n    it('Then booleans', function () {\n      var otherStuff = [new Date(4321), {}, { hello: 'world' }, [], ['quite', 5]]\n        , bools = [true, false];\n\n      model.compareThings(true, true).should.equal(0);\n      model.compareThings(false, false).should.equal(0);\n      model.compareThings(true, false).should.equal(1);\n      model.compareThings(false, true).should.equal(-1);\n\n      otherStuff.forEach(function (stuff) {\n        bools.forEach(function (bool) {\n          model.compareThings(bool, stuff).should.equal(-1);\n          model.compareThings(stuff, bool).should.equal(1);\n        });\n      });\n    });\n\n    it('Then dates', function () {\n      var otherStuff = [{}, { hello: 'world' }, [], ['quite', 5]]\n        , dates = [new Date(-123), new Date(), new Date(5555), new Date(0)]\n        , now = new Date();\n\n      model.compareThings(now, now).should.equal(0);\n      model.compareThings(new Date(54341), now).should.equal(-1);\n      model.compareThings(now, new Date(54341)).should.equal(1);\n      model.compareThings(new Date(0), new Date(-54341)).should.equal(1);\n      model.compareThings(new Date(123), new Date(4341)).should.equal(-1);\n\n      otherStuff.forEach(function (stuff) {\n        dates.forEach(function (date) {\n          model.compareThings(date, stuff).should.equal(-1);\n          model.compareThings(stuff, date).should.equal(1);\n        });\n      });\n    });\n\n    it('Then arrays', function () {\n      var otherStuff = [{}, { hello: 'world' }]\n        , arrays = [[], ['yes'], ['hello', 5]]\n        ;\n\n      model.compareThings([], []).should.equal(0);\n      model.compareThings(['hello'], []).should.equal(1);\n      model.compareThings([], ['hello']).should.equal(-1);\n      model.compareThings(['hello'], ['hello', 'world']).should.equal(-1);\n      model.compareThings(['hello', 'earth'], ['hello', 'world']).should.equal(-1);\n      model.compareThings(['hello', 'zzz'], ['hello', 'world']).should.equal(1);\n      model.compareThings(['hello', 'world'], ['hello', 'world']).should.equal(0);\n\n      otherStuff.forEach(function (stuff) {\n        arrays.forEach(function (array) {\n          model.compareThings(array, stuff).should.equal(-1);\n          model.compareThings(stuff, array).should.equal(1);\n        });\n      });\n    });\n\n    it('And finally objects', function () {\n      model.compareThings({}, {}).should.equal(0);\n      model.compareThings({ a: 42 }, { a: 312}).should.equal(-1);\n      model.compareThings({ a: '42' }, { a: '312'}).should.equal(1);\n      model.compareThings({ a: 42, b: 312 }, { b: 312, a: 42 }).should.equal(0);\n      model.compareThings({ a: 42, b: 312, c: 54 }, { b: 313, a: 42 }).should.equal(-1);\n    });\n\n    it('Can specify custom string comparison function', function () {\n      model.compareThings('hello', 'bloup', function (a, b) { return a < b ? -1 : 1; }).should.equal(1);\n      model.compareThings('hello', 'bloup', function (a, b) { return a > b ? -1 : 1; }).should.equal(-1);\n    });\n\n  });   // ==== End of 'Comparing things' ==== //\n\n\n  describe('Querying', function () {\n\n    describe('Comparing things', function () {\n\n      it('Two things of different types cannot be equal, two identical native things are equal', function () {\n        var toTest = [null, 'somestring', 42, true, new Date(72998322), { hello: 'world' }]\n          , toTestAgainst = [null, 'somestring', 42, true, new Date(72998322), { hello: 'world' }]   // Use another array so that we don't test pointer equality\n          , i, j\n          ;\n\n        for (i = 0; i < toTest.length; i += 1) {\n          for (j = 0; j < toTestAgainst.length; j += 1) {\n            model.areThingsEqual(toTest[i], toTestAgainst[j]).should.equal(i === j);\n          }\n        }\n      });\n\n      it('Can test native types null undefined string number boolean date equality', function () {\n        var toTest = [null, undefined, 'somestring', 42, true, new Date(72998322), { hello: 'world' }]\n          , toTestAgainst = [undefined, null, 'someotherstring', 5, false, new Date(111111), { hello: 'mars' }]\n          , i\n          ;\n\n        for (i = 0; i < toTest.length; i += 1) {\n          model.areThingsEqual(toTest[i], toTestAgainst[i]).should.equal(false);\n        }\n      });\n\n      it('If one side is an array or undefined, comparison fails', function () {\n        var toTestAgainst = [null, undefined, 'somestring', 42, true, new Date(72998322), { hello: 'world' }]\n          , i\n          ;\n\n        for (i = 0; i < toTestAgainst.length; i += 1) {\n          model.areThingsEqual([1, 2, 3], toTestAgainst[i]).should.equal(false);\n          model.areThingsEqual(toTestAgainst[i], []).should.equal(false);\n\n          model.areThingsEqual(undefined, toTestAgainst[i]).should.equal(false);\n          model.areThingsEqual(toTestAgainst[i], undefined).should.equal(false);\n        }\n      });\n\n      it('Can test objects equality', function () {\n        model.areThingsEqual({ hello: 'world' }, {}).should.equal(false);\n        model.areThingsEqual({ hello: 'world' }, { hello: 'mars' }).should.equal(false);\n        model.areThingsEqual({ hello: 'world' }, { hello: 'world', temperature: 42 }).should.equal(false);\n        model.areThingsEqual({ hello: 'world', other: { temperature: 42 }}, { hello: 'world', other: { temperature: 42 }}).should.equal(true);\n      });\n\n    });\n\n\n    describe('Getting a fields value in dot notation', function () {\n\n      it('Return first-level and nested values', function () {\n        model.getDotValue({ hello: 'world' }, 'hello').should.equal('world');\n        model.getDotValue({ hello: 'world', type: { planet: true, blue: true } }, 'type.planet').should.equal(true);\n      });\n\n      it('Return undefined if the field cannot be found in the object', function () {\n        assert.isUndefined(model.getDotValue({ hello: 'world' }, 'helloo'));\n        assert.isUndefined(model.getDotValue({ hello: 'world', type: { planet: true } }, 'type.plane'));\n      });\n      \n      it(\"Can navigate inside arrays with dot notation, and return the array of values in that case\", function () {\n        var dv;\n        \n        // Simple array of subdocuments\n        dv = model.getDotValue({ planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] }, 'planets.name');\n        assert.deepEqual(dv, ['Earth', 'Mars', 'Pluton']);\n        \n        // Nested array of subdocuments\n        dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } }, 'data.planets.number');\n        assert.deepEqual(dv, [3, 2, 9]);\n        \n        // Nested array in a subdocument of an array (yay, inception!)\n        // TODO: make sure MongoDB doesn't flatten the array (it wouldn't make sense)\n        dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', numbers: [ 1, 3 ] }, { name: 'Mars', numbers: [ 7 ] }, { name: 'Pluton', numbers: [ 9, 5, 1 ] } ] } }, 'data.planets.numbers');\n        assert.deepEqual(dv, [[ 1, 3 ], [ 7 ], [ 9, 5, 1 ]]);\n      });\n      \n      it(\"Can get a single value out of an array using its index\", function () {\n        var dv;\n        \n        // Simple index in dot notation\n        dv = model.getDotValue({ planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] }, 'planets.1');\n        assert.deepEqual(dv, { name: 'Mars', number: 2 });\n\n        // Out of bounds index\n        dv = model.getDotValue({ planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] }, 'planets.3');\n        assert.isUndefined(dv);\n\n        // Index in nested array\n        dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } }, 'data.planets.2');\n        assert.deepEqual(dv, { name: 'Pluton', number: 9 });\n        \n        // Dot notation with index in the middle\n        dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } }, 'data.planets.0.name');\n        dv.should.equal('Earth');\n      });\n\n    });\n\n\n    describe('Field equality', function () {\n\n      it('Can find documents with simple fields', function () {\n        model.match({ test: 'yeah' }, { test: 'yea' }).should.equal(false);\n        model.match({ test: 'yeah' }, { test: 'yeahh' }).should.equal(false);\n        model.match({ test: 'yeah' }, { test: 'yeah' }).should.equal(true);\n      });\n\n      it('Can find documents with the dot-notation', function () {\n        model.match({ test: { ooo: 'yeah' } }, { \"test.ooo\": 'yea' }).should.equal(false);\n        model.match({ test: { ooo: 'yeah' } }, { \"test.oo\": 'yeah' }).should.equal(false);\n        model.match({ test: { ooo: 'yeah' } }, { \"tst.ooo\": 'yeah' }).should.equal(false);\n        model.match({ test: { ooo: 'yeah' } }, { \"test.ooo\": 'yeah' }).should.equal(true);\n      });\n\n      it('Cannot find undefined', function () {\n        model.match({ test: undefined }, { test: undefined }).should.equal(false);\n        model.match({ test: { pp: undefined } }, { \"test.pp\": undefined }).should.equal(false);\n      });\n\n      it('Nested objects are deep-equality matched and not treated as sub-queries', function () {\n        model.match({ a: { b: 5 } }, { a: { b: 5 } }).should.equal(true);\n        model.match({ a: { b: 5, c: 3 } }, { a: { b: 5 } }).should.equal(false);\n\n        model.match({ a: { b: 5 } }, { a: { b: { $lt: 10 } } }).should.equal(false);\n        (function () { model.match({ a: { b: 5 } }, { a: { $or: [ { b: 10 }, { b: 5 } ] } }) }).should.throw();\n      });\n      \n      it(\"Can match for field equality inside an array with the dot notation\", function () {\n        model.match({ a: true, b: [ 'node', 'embedded', 'database' ] }, { 'b.1': 'node' }).should.equal(false);\n        model.match({ a: true, b: [ 'node', 'embedded', 'database' ] }, { 'b.1': 'embedded' }).should.equal(true);\n        model.match({ a: true, b: [ 'node', 'embedded', 'database' ] }, { 'b.1': 'database' }).should.equal(false);\n      })\n\n    });\n\n\n    describe('Regular expression matching', function () {\n\n      it('Matching a non-string to a regular expression always yields false', function () {\n        var d = new Date()\n          , r = new RegExp(d.getTime());\n\n        model.match({ test: true }, { test: /true/ }).should.equal(false);\n        model.match({ test: null }, { test: /null/ }).should.equal(false);\n        model.match({ test: 42 }, { test: /42/ }).should.equal(false);\n        model.match({ test: d }, { test: r }).should.equal(false);\n      });\n\n      it('Can match strings using basic querying', function () {\n        model.match({ test: 'true' }, { test: /true/ }).should.equal(true);\n        model.match({ test: 'babaaaar' }, { test: /aba+r/ }).should.equal(true);\n        model.match({ test: 'babaaaar' }, { test: /^aba+r/ }).should.equal(false);\n        model.match({ test: 'true' }, { test: /t[ru]e/ }).should.equal(false);\n      });\n\n      it('Can match strings using the $regex operator', function () {\n        model.match({ test: 'true' }, { test: { $regex: /true/ } }).should.equal(true);\n        model.match({ test: 'babaaaar' }, { test: { $regex: /aba+r/ } }).should.equal(true);\n        model.match({ test: 'babaaaar' }, { test: { $regex: /^aba+r/ } }).should.equal(false);\n        model.match({ test: 'true' }, { test: { $regex: /t[ru]e/ } }).should.equal(false);\n      });\n\n      it('Will throw if $regex operator is used with a non regex value', function () {\n        (function () {\n          model.match({ test: 'true' }, { test: { $regex: 42 } })\n        }).should.throw();\n\n        (function () {\n          model.match({ test: 'true' }, { test: { $regex: 'true' } })\n        }).should.throw();\n      });\n\n      it('Can use the $regex operator in cunjunction with other operators', function () {\n        model.match({ test: 'helLo' }, { test: { $regex: /ll/i, $nin: ['helL', 'helLop'] } }).should.equal(true);\n        model.match({ test: 'helLo' }, { test: { $regex: /ll/i, $nin: ['helLo', 'helLop'] } }).should.equal(false);\n      });\n\n      it('Can use dot-notation', function () {\n        model.match({ test: { nested: 'true' } }, { 'test.nested': /true/ }).should.equal(true);\n        model.match({ test: { nested: 'babaaaar' } }, { 'test.nested': /^aba+r/ }).should.equal(false);\n\n        model.match({ test: { nested: 'true' } }, { 'test.nested': { $regex: /true/ } }).should.equal(true);\n        model.match({ test: { nested: 'babaaaar' } }, { 'test.nested': { $regex: /^aba+r/ } }).should.equal(false);\n      });\n\n    });\n\n\n    describe('$lt', function () {\n\n      it('Cannot compare a field to an object, an array, null or a boolean, it will return false', function () {\n        model.match({ a: 5 }, { a: { $lt: { a: 6 } } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $lt: [6, 7] } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $lt: null } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $lt: true } }).should.equal(false);\n      });\n\n      it('Can compare numbers, with or without dot notation', function () {\n        model.match({ a: 5 }, { a: { $lt: 6 } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $lt: 5 } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $lt: 4 } }).should.equal(false);\n\n        model.match({ a: { b: 5 } }, { \"a.b\": { $lt: 6 } }).should.equal(true);\n        model.match({ a: { b: 5 } }, { \"a.b\": { $lt: 3 } }).should.equal(false);\n      });\n\n      it('Can compare strings, with or without dot notation', function () {\n        model.match({ a: \"nedb\" }, { a: { $lt: \"nedc\" } }).should.equal(true);\n        model.match({ a: \"nedb\" }, { a: { $lt: \"neda\" } }).should.equal(false);\n\n        model.match({ a: { b: \"nedb\" } }, { \"a.b\": { $lt: \"nedc\" } }).should.equal(true);\n        model.match({ a: { b: \"nedb\" } }, { \"a.b\": { $lt: \"neda\" } }).should.equal(false);\n      });\n\n      it('If field is an array field, a match means a match on at least one element', function () {\n        model.match({ a: [5, 10] }, { a: { $lt: 4 } }).should.equal(false);\n        model.match({ a: [5, 10] }, { a: { $lt: 6 } }).should.equal(true);\n        model.match({ a: [5, 10] }, { a: { $lt: 11 } }).should.equal(true);\n      });\n\n      it('Works with dates too', function () {\n        model.match({ a: new Date(1000) }, { a: { $gte: new Date(1001) } }).should.equal(false);\n        model.match({ a: new Date(1000) }, { a: { $lt: new Date(1001) } }).should.equal(true);\n      });\n\n    });\n\n\n    // General behaviour is tested in the block about $lt. Here we just test operators work\n    describe('Other comparison operators: $lte, $gt, $gte, $ne, $in, $exists', function () {\n\n      it('$lte', function () {\n        model.match({ a: 5 }, { a: { $lte: 6 } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $lte: 5 } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $lte: 4 } }).should.equal(false);\n      });\n\n      it('$gt', function () {\n        model.match({ a: 5 }, { a: { $gt: 6 } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $gt: 5 } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $gt: 4 } }).should.equal(true);\n      });\n\n      it('$gte', function () {\n        model.match({ a: 5 }, { a: { $gte: 6 } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $gte: 5 } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $gte: 4 } }).should.equal(true);\n      });\n\n      it('$ne', function () {\n        model.match({ a: 5 }, { a: { $ne: 4 } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $ne: 5 } }).should.equal(false);\n        model.match({ a: 5 }, { b: { $ne: 5 } }).should.equal(true);\n        model.match({ a: false }, { a: { $ne: false } }).should.equal(false);\n      });\n\n      it('$in', function () {\n        model.match({ a: 5 }, { a: { $in: [6, 8, 9] } }).should.equal(false);\n        model.match({ a: 6 }, { a: { $in: [6, 8, 9] } }).should.equal(true);\n        model.match({ a: 7 }, { a: { $in: [6, 8, 9] } }).should.equal(false);\n        model.match({ a: 8 }, { a: { $in: [6, 8, 9] } }).should.equal(true);\n        model.match({ a: 9 }, { a: { $in: [6, 8, 9] } }).should.equal(true);\n\n        (function () { model.match({ a: 5 }, { a: { $in: 5 } }); }).should.throw();\n      });\n\n      it('$nin', function () {\n        model.match({ a: 5 }, { a: { $nin: [6, 8, 9] } }).should.equal(true);\n        model.match({ a: 6 }, { a: { $nin: [6, 8, 9] } }).should.equal(false);\n        model.match({ a: 7 }, { a: { $nin: [6, 8, 9] } }).should.equal(true);\n        model.match({ a: 8 }, { a: { $nin: [6, 8, 9] } }).should.equal(false);\n        model.match({ a: 9 }, { a: { $nin: [6, 8, 9] } }).should.equal(false);\n\n        // Matches if field doesn't exist\n        model.match({ a: 9 }, { b: { $nin: [6, 8, 9] } }).should.equal(true);\n\n        (function () { model.match({ a: 5 }, { a: { $in: 5 } }); }).should.throw();\n      });\n\n      it('$exists', function () {\n        model.match({ a: 5 }, { a: { $exists: 1 } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $exists: true } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $exists: new Date() } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $exists: '' } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $exists: [] } }).should.equal(true);\n        model.match({ a: 5 }, { a: { $exists: {} } }).should.equal(true);\n\n        model.match({ a: 5 }, { a: { $exists: 0 } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $exists: false } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $exists: null } }).should.equal(false);\n        model.match({ a: 5 }, { a: { $exists: undefined } }).should.equal(false);\n\n        model.match({ a: 5 }, { b: { $exists: true } }).should.equal(false);\n\n        model.match({ a: 5 }, { b: { $exists: false } }).should.equal(true);\n      });\n\n    });\n\n\n    describe('Comparing on arrays', function () {\n\n      it(\"Can perform a direct array match\", function () {\n        model.match({ planets: ['Earth', 'Mars', 'Pluto'], something: 'else' }, { planets: ['Earth', 'Mars'] }).should.equal(false);\n        model.match({ planets: ['Earth', 'Mars', 'Pluto'], something: 'else' }, { planets: ['Earth', 'Mars', 'Pluto'] }).should.equal(true);\n        model.match({ planets: ['Earth', 'Mars', 'Pluto'], something: 'else' }, { planets: ['Earth', 'Pluto', 'Mars'] }).should.equal(false);\n      });\n\n      it('Can query on the size of an array field', function () {\n        // Non nested documents\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $size: 0 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $size: 1 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $size: 2 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $size: 3 } }).should.equal(true);\n\n        // Nested documents\n        model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { \"description.satellites\": { $size: 0 } }).should.equal(false);\n        model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { \"description.satellites\": { $size: 1 } }).should.equal(false);\n        model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { \"description.satellites\": { $size: 2 } }).should.equal(true);\n        model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { \"description.satellites\": { $size: 3 } }).should.equal(false);\n\n        // Using a projected array\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.names\": { $size: 0 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.names\": { $size: 1 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.names\": { $size: 2 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.names\": { $size: 3 } }).should.equal(true);\n      });\n\n      it('$size operator works with empty arrays', function () {\n        model.match({ childrens: [] }, { \"childrens\": { $size: 0 } }).should.equal(true);\n        model.match({ childrens: [] }, { \"childrens\": { $size: 2 } }).should.equal(false);\n        model.match({ childrens: [] }, { \"childrens\": { $size: 3 } }).should.equal(false);\n      });\n\n      it('Should throw an error if a query operator is used without comparing to an integer', function () {\n        (function () { model.match({ a: [1, 5] }, { a: { $size: 1.4 } }); }).should.throw();\n        (function () { model.match({ a: [1, 5] }, { a: { $size: 'fdf' } }); }).should.throw();\n        (function () { model.match({ a: [1, 5] }, { a: { $size: { $lt: 5 } } }); }).should.throw();\n      });\n\n      it('Using $size operator on a non-array field should prevent match but not throw', function () {\n        model.match({ a: 5 }, { a: { $size: 1 } }).should.equal(false);\n      });\n\n      it('Can use $size several times in the same matcher', function () {\n        model.match({ childrens: [ 'Riri', 'Fifi', 'Loulou' ] }, { \"childrens\": { $size: 3, $size: 3 } }).should.equal(true);\n        model.match({ childrens: [ 'Riri', 'Fifi', 'Loulou' ] }, { \"childrens\": { $size: 3, $size: 4 } }).should.equal(false);   // Of course this can never be true\n      });\n\n      it('Can query array documents with multiple simultaneous conditions', function () {\n        // Non nested documents\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $elemMatch: { name: \"Dewey\", age: 7 } } }).should.equal(true);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $elemMatch: { name: \"Dewey\", age: 12 } } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $elemMatch: { name: \"Louie\", age: 3 } } }).should.equal(false);\n\n        // Nested documents\n        model.match({ outer: { childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] } }, { \"outer.childrens\": { $elemMatch: { name: \"Dewey\", age: 7 } } }).should.equal(true);\n        model.match({ outer: { childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] } }, { \"outer.childrens\": { $elemMatch: { name: \"Dewey\", age: 12 } } }).should.equal(false);\n        model.match({ outer: { childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] } }, { \"outer.childrens\": { $elemMatch: { name: \"Louie\", age: 3 } } }).should.equal(false);\n\n      });\n\n      it('$elemMatch operator works with empty arrays', function () {\n        model.match({ childrens: [] }, { \"childrens\": { $elemMatch: { name: \"Mitsos\" } } }).should.equal(false);\n        model.match({ childrens: [] }, { \"childrens\": { $elemMatch: {} } }).should.equal(false);\n      });\n\n      it('Can use more complex comparisons inside nested query documents', function () {\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $elemMatch: { name: \"Dewey\", age: { $gt: 6, $lt: 8 } } } }).should.equal(true);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $elemMatch: { name: \"Dewey\", age: { $in: [ 6, 7, 8 ] } } } } ).should.equal(true);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $elemMatch: { name: \"Dewey\", age: { $gt: 6, $lt: 7 } } } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens\": { $elemMatch: { name: \"Louie\", age: { $gt: 6, $lte: 7 } } } }).should.equal(false);\n      });\n    });\n\n\n    describe('Logical operators $or, $and, $not', function () {\n\n      it('Any of the subqueries should match for an $or to match', function () {\n        model.match({ hello: 'world' }, { $or: [ { hello: 'pluton' }, { hello: 'world' } ] }).should.equal(true);\n        model.match({ hello: 'pluton' }, { $or: [ { hello: 'pluton' }, { hello: 'world' } ] }).should.equal(true);\n        model.match({ hello: 'nope' }, { $or: [ { hello: 'pluton' }, { hello: 'world' } ] }).should.equal(false);\n        model.match({ hello: 'world', age: 15 }, { $or: [ { hello: 'pluton' }, { age: { $lt: 20 } } ] }).should.equal(true);\n        model.match({ hello: 'world', age: 15 }, { $or: [ { hello: 'pluton' }, { age: { $lt: 10 } } ] }).should.equal(false);\n      });\n\n      it('All of the subqueries should match for an $and to match', function () {\n        model.match({ hello: 'world', age: 15 }, { $and: [ { age: 15 }, { hello: 'world' } ] }).should.equal(true);\n        model.match({ hello: 'world', age: 15 }, { $and: [ { age: 16 }, { hello: 'world' } ] }).should.equal(false);\n        model.match({ hello: 'world', age: 15 }, { $and: [ { hello: 'world' }, { age: { $lt: 20 } } ] }).should.equal(true);\n        model.match({ hello: 'world', age: 15 }, { $and: [ { hello: 'pluton' }, { age: { $lt: 20 } } ] }).should.equal(false);\n      });\n\n      it('Subquery should not match for a $not to match', function () {\n        model.match({ a: 5, b: 10 }, { a: 5 }).should.equal(true);\n        model.match({ a: 5, b: 10 }, { $not: { a: 5 } }).should.equal(false);\n      });\n\n      it('Logical operators are all top-level, only other logical operators can be above', function () {\n        (function () { model.match({ a: { b: 7 } }, { a: { $or: [ { b: 5 }, { b: 7 } ] } })}).should.throw();\n        model.match({ a: { b: 7 } }, { $or: [ { \"a.b\": 5 }, { \"a.b\": 7 } ] }).should.equal(true);\n      });\n\n      it('Logical operators can be combined as long as they are on top of the decision tree', function () {\n        model.match({ a: 5, b: 7, c: 12 }, { $or: [ { $and: [ { a: 5 }, { b: 8 } ] }, { $and: [{ a: 5 }, { c : { $lt: 40 } }] } ] }).should.equal(true);\n        model.match({ a: 5, b: 7, c: 12 }, { $or: [ { $and: [ { a: 5 }, { b: 8 } ] }, { $and: [{ a: 5 }, { c : { $lt: 10 } }] } ] }).should.equal(false);\n      });\n\n      it('Should throw an error if a logical operator is used without an array or if an unknown logical operator is used', function () {\n        (function () { model.match({ a: 5 }, { $or: { a: 5, a: 6 } }); }).should.throw();\n        (function () { model.match({ a: 5 }, { $and: { a: 5, a: 6 } }); }).should.throw();\n        (function () { model.match({ a: 5 }, { $unknown: [ { a: 5 } ] }); }).should.throw();\n      });\n\n    });\n\n\n    describe('Comparison operator $where', function () {\n\n      it('Function should match and not match correctly', function () {\n        model.match({ a: 4}, { $where: function () { return this.a === 4; } }).should.equal(true);\n        model.match({ a: 4}, { $where: function () { return this.a === 5; } }).should.equal(false);\n      });\n\n      it('Should throw an error if the $where function is not, in fact, a function', function () {\n        (function () { model.match({ a: 4 }, { $where: 'not a function' }); }).should.throw();\n      });\n\n      it('Should throw an error if the $where function returns a non-boolean', function () {\n        (function () { model.match({ a: 4 }, { $where: function () { return 'not a boolean'; } }); }).should.throw();\n      });\n      \n      it('Should be able to do the complex matching it must be used for', function () {\n        var checkEmail = function() {\n          if (!this.firstName || !this.lastName) { return false; }\n          return this.firstName.toLowerCase() + \".\" + this.lastName.toLowerCase() + \"@gmail.com\" === this.email;\n        };\n        model.match({ firstName: \"John\", lastName: \"Doe\", email: \"john.doe@gmail.com\" }, { $where: checkEmail }).should.equal(true);\n        model.match({ firstName: \"john\", lastName: \"doe\", email: \"john.doe@gmail.com\" }, { $where: checkEmail }).should.equal(true);\n        model.match({ firstName: \"Jane\", lastName: \"Doe\", email: \"john.doe@gmail.com\" }, { $where: checkEmail }).should.equal(false);\n        model.match({ firstName: \"John\", lastName: \"Deere\", email: \"john.doe@gmail.com\" }, { $where: checkEmail }).should.equal(false);\n        model.match({ lastName: \"Doe\", email: \"john.doe@gmail.com\" }, { $where: checkEmail }).should.equal(false);\n      });\n\n    });\n\n\n    describe('Array fields', function () {\n\n      it('Field equality', function () {\n        model.match({ tags: ['node', 'js', 'db'] }, { tags: 'python' }).should.equal(false);\n        model.match({ tags: ['node', 'js', 'db'] }, { tagss: 'js' }).should.equal(false);\n        model.match({ tags: ['node', 'js', 'db'] }, { tags: 'js' }).should.equal(true);\n        model.match({ tags: ['node', 'js', 'db'] }, { tags: 'js', tags: 'node' }).should.equal(true);\n\n        // Mixed matching with array and non array\n        model.match({ tags: ['node', 'js', 'db'], nedb: true }, { tags: 'js', nedb: true }).should.equal(true);\n\n        // Nested matching\n        model.match({ number: 5, data: { tags: ['node', 'js', 'db'] } }, { \"data.tags\": 'js' }).should.equal(true);\n        model.match({ number: 5, data: { tags: ['node', 'js', 'db'] } }, { \"data.tags\": 'j' }).should.equal(false);\n      });\n\n      it('With one comparison operator', function () {\n        model.match({ ages: [3, 7, 12] }, { ages: { $lt: 2 } }).should.equal(false);\n        model.match({ ages: [3, 7, 12] }, { ages: { $lt: 3 } }).should.equal(false);\n        model.match({ ages: [3, 7, 12] }, { ages: { $lt: 4 } }).should.equal(true);\n        model.match({ ages: [3, 7, 12] }, { ages: { $lt: 8 } }).should.equal(true);\n        model.match({ ages: [3, 7, 12] }, { ages: { $lt: 13 } }).should.equal(true);\n      });\n\n      it('Works with arrays that are in subdocuments', function () {\n        model.match({ children: { ages: [3, 7, 12] } }, { \"children.ages\": { $lt: 2 } }).should.equal(false);\n        model.match({ children: { ages: [3, 7, 12] } }, { \"children.ages\": { $lt: 3 } }).should.equal(false);\n        model.match({ children: { ages: [3, 7, 12] } }, { \"children.ages\": { $lt: 4 } }).should.equal(true);\n        model.match({ children: { ages: [3, 7, 12] } }, { \"children.ages\": { $lt: 8 } }).should.equal(true);\n        model.match({ children: { ages: [3, 7, 12] } }, { \"children.ages\": { $lt: 13 } }).should.equal(true);\n      });\n\n      it('Can query inside arrays thanks to dot notation', function () {\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.age\": { $lt: 2 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.age\": { $lt: 3 } }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.age\": { $lt: 4 } }).should.equal(true);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.age\": { $lt: 8 } }).should.equal(true);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.age\": { $lt: 13 } }).should.equal(true);\n        \n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.name\": 'Louis' }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.name\": 'Louie' }).should.equal(true);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.name\": 'Lewi' }).should.equal(false);\n      });\n      \n      it('Can query for a specific element inside arrays thanks to dot notation', function () {\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.0.name\": 'Louie' }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.1.name\": 'Louie' }).should.equal(false);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.2.name\": 'Louie' }).should.equal(true);\n        model.match({ childrens: [ { name: \"Huey\", age: 3 }, { name: \"Dewey\", age: 7 }, { name: \"Louie\", age: 12 } ] }, { \"childrens.3.name\": 'Louie' }).should.equal(false);\n      });\n      \n      it('A single array-specific operator and the query is treated as array specific', function () {\n        (function () { model.match({ childrens: [ 'Riri', 'Fifi', 'Loulou' ] }, { \"childrens\": { \"Fifi\": true, $size: 3 } })}).should.throw();\n      });\n      \n      it('Can mix queries on array fields and non array filds with array specific operators', function () {\n        model.match({ uncle: 'Donald', nephews: [ 'Riri', 'Fifi', 'Loulou' ] }, { nephews: { $size: 2 }, uncle: 'Donald' }).should.equal(false);\n        model.match({ uncle: 'Donald', nephews: [ 'Riri', 'Fifi', 'Loulou' ] }, { nephews: { $size: 3 }, uncle: 'Donald' }).should.equal(true);\n        model.match({ uncle: 'Donald', nephews: [ 'Riri', 'Fifi', 'Loulou' ] }, { nephews: { $size: 4 }, uncle: 'Donald' }).should.equal(false);\n\n        model.match({ uncle: 'Donals', nephews: [ 'Riri', 'Fifi', 'Loulou' ] }, { nephews: { $size: 3 }, uncle: 'Picsou' }).should.equal(false);\n        model.match({ uncle: 'Donald', nephews: [ 'Riri', 'Fifi', 'Loulou' ] }, { nephews: { $size: 3 }, uncle: 'Donald' }).should.equal(true);\n        model.match({ uncle: 'Donald', nephews: [ 'Riri', 'Fifi', 'Loulou' ] }, { nephews: { $size: 3 }, uncle: 'Daisy' }).should.equal(false);\n      });\n      \n    });\n\n  });   // ==== End of 'Querying' ==== //\n\n});\n"
  },
  {
    "path": "test/persistence.test.js",
    "content": "var should = require('chai').should()\n  , assert = require('chai').assert\n  , testDb = 'workspace/test.db'\n  , fs = require('fs')\n  , path = require('path')\n  , _ = require('underscore')\n  , async = require('async')\n  , model = require('../lib/model')\n  , customUtils = require('../lib/customUtils')\n  , Datastore = require('../lib/datastore')\n  , Persistence = require('../lib/persistence')\n  , storage = require('../lib/storage')\n  , child_process = require('child_process')\n;\n\n\ndescribe('Persistence', function () {\n  var d;\n\n  beforeEach(function (done) {\n    d = new Datastore({ filename: testDb });\n    d.filename.should.equal(testDb);\n    d.inMemoryOnly.should.equal(false);\n\n    async.waterfall([\n      function (cb) {\n        Persistence.ensureDirectoryExists(path.dirname(testDb), function () {\n          fs.exists(testDb, function (exists) {\n            if (exists) {\n              fs.unlink(testDb, cb);\n            } else { return cb(); }\n          });\n        });\n      }\n    , function (cb) {\n  d.loadDatabase(function (err) {\n    assert.isNull(err);\n    d.getAllData().length.should.equal(0);\n    return cb();\n  });\n    }\n    ], done);\n  });\n\n  it('Every line represents a document', function () {\n    var now = new Date()\n      , rawData = model.serialize({ _id: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n    model.serialize({ _id: \"2\", hello: 'world' }) + '\\n' +\n    model.serialize({ _id: \"3\", nested: { today: now } })\n      , treatedData = d.persistence.treatRawData(rawData).data\n    ;\n\n    treatedData.sort(function (a, b) { return a._id - b._id; });\n    treatedData.length.should.equal(3);\n    _.isEqual(treatedData[0], { _id: \"1\", a: 2, ages: [1, 5, 12] }).should.equal(true);\n    _.isEqual(treatedData[1], { _id: \"2\", hello: 'world' }).should.equal(true);\n    _.isEqual(treatedData[2], { _id: \"3\", nested: { today: now } }).should.equal(true);\n  });\n\n  it('Badly formatted lines have no impact on the treated data', function () {\n    var now = new Date()\n      , rawData = model.serialize({ _id: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n    'garbage\\n' +\n    model.serialize({ _id: \"3\", nested: { today: now } })\n      , treatedData = d.persistence.treatRawData(rawData).data\n    ;\n\n    treatedData.sort(function (a, b) { return a._id - b._id; });\n    treatedData.length.should.equal(2);\n    _.isEqual(treatedData[0], { _id: \"1\", a: 2, ages: [1, 5, 12] }).should.equal(true);\n    _.isEqual(treatedData[1], { _id: \"3\", nested: { today: now } }).should.equal(true);\n  });\n\n  it('Well formatted lines that have no _id are not included in the data', function () {\n    var now = new Date()\n      , rawData = model.serialize({ _id: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n    model.serialize({ _id: \"2\", hello: 'world' }) + '\\n' +\n    model.serialize({ nested: { today: now } })\n      , treatedData = d.persistence.treatRawData(rawData).data\n    ;\n\n    treatedData.sort(function (a, b) { return a._id - b._id; });\n    treatedData.length.should.equal(2);\n    _.isEqual(treatedData[0], { _id: \"1\", a: 2, ages: [1, 5, 12] }).should.equal(true);\n    _.isEqual(treatedData[1], { _id: \"2\", hello: 'world' }).should.equal(true);\n  });\n\n  it('If two lines concern the same doc (= same _id), the last one is the good version', function () {\n    var now = new Date()\n      , rawData = model.serialize({ _id: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n    model.serialize({ _id: \"2\", hello: 'world' }) + '\\n' +\n    model.serialize({ _id: \"1\", nested: { today: now } })\n      , treatedData = d.persistence.treatRawData(rawData).data\n    ;\n\n    treatedData.sort(function (a, b) { return a._id - b._id; });\n    treatedData.length.should.equal(2);\n    _.isEqual(treatedData[0], { _id: \"1\", nested: { today: now } }).should.equal(true);\n    _.isEqual(treatedData[1], { _id: \"2\", hello: 'world' }).should.equal(true);\n  });\n\n  it('If a doc contains $$deleted: true, that means we need to remove it from the data', function () {\n    var now = new Date()\n      , rawData = model.serialize({ _id: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n    model.serialize({ _id: \"2\", hello: 'world' }) + '\\n' +\n    model.serialize({ _id: \"1\", $$deleted: true }) + '\\n' +\n    model.serialize({ _id: \"3\", today: now })\n      , treatedData = d.persistence.treatRawData(rawData).data\n    ;\n\n    treatedData.sort(function (a, b) { return a._id - b._id; });\n    treatedData.length.should.equal(2);\n    _.isEqual(treatedData[0], { _id: \"2\", hello: 'world' }).should.equal(true);\n    _.isEqual(treatedData[1], { _id: \"3\", today: now }).should.equal(true);\n  });\n\n  it('If a doc contains $$deleted: true, no error is thrown if the doc wasnt in the list before', function () {\n    var now = new Date()\n      , rawData = model.serialize({ _id: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n    model.serialize({ _id: \"2\", $$deleted: true }) + '\\n' +\n    model.serialize({ _id: \"3\", today: now })\n      , treatedData = d.persistence.treatRawData(rawData).data\n    ;\n\n    treatedData.sort(function (a, b) { return a._id - b._id; });\n    treatedData.length.should.equal(2);\n    _.isEqual(treatedData[0], { _id: \"1\", a: 2, ages: [1, 5, 12] }).should.equal(true);\n    _.isEqual(treatedData[1], { _id: \"3\", today: now }).should.equal(true);\n  });\n\n  it('If a doc contains $$indexCreated, no error is thrown during treatRawData and we can get the index options', function () {\n    var now = new Date()\n      , rawData = model.serialize({ _id: \"1\", a: 2, ages: [1, 5, 12] }) + '\\n' +\n    model.serialize({ $$indexCreated: { fieldName: \"test\", unique: true } }) + '\\n' +\n    model.serialize({ _id: \"3\", today: now })\n      , treatedData = d.persistence.treatRawData(rawData).data\n      , indexes = d.persistence.treatRawData(rawData).indexes\n    ;\n\n    Object.keys(indexes).length.should.equal(1);\n    assert.deepEqual(indexes.test, { fieldName: \"test\", unique: true });\n\n    treatedData.sort(function (a, b) { return a._id - b._id; });\n    treatedData.length.should.equal(2);\n    _.isEqual(treatedData[0], { _id: \"1\", a: 2, ages: [1, 5, 12] }).should.equal(true);\n    _.isEqual(treatedData[1], { _id: \"3\", today: now }).should.equal(true);\n  });\n\n  it('Compact database on load', function (done) {\n    d.insert({ a: 2 }, function () {\n      d.insert({ a: 4 }, function () {\n        d.remove({ a: 2 }, {}, function () {\n          // Here, the underlying file is 3 lines long for only one document\n          var data = fs.readFileSync(d.filename, 'utf8').split('\\n')\n            , filledCount = 0;\n\n          data.forEach(function (item) { if (item.length > 0) { filledCount += 1; } });\n          filledCount.should.equal(3);\n\n          d.loadDatabase(function (err) {\n            assert.isNull(err);\n\n            // Now, the file has been compacted and is only 1 line long\n            var data = fs.readFileSync(d.filename, 'utf8').split('\\n')\n              , filledCount = 0;\n\n            data.forEach(function (item) { if (item.length > 0) { filledCount += 1; } });\n            filledCount.should.equal(1);\n\n            done();\n          });\n        })\n      });\n    });\n  });\n\n  it('Calling loadDatabase after the data was modified doesnt change its contents', function (done) {\n    d.loadDatabase(function () {\n      d.insert({ a: 1 }, function (err) {\n        assert.isNull(err);\n        d.insert({ a: 2 }, function (err) {\n          var data = d.getAllData()\n            , doc1 = _.find(data, function (doc) { return doc.a === 1; })\n            , doc2 = _.find(data, function (doc) { return doc.a === 2; })\n          ;\n          assert.isNull(err);\n          data.length.should.equal(2);\n          doc1.a.should.equal(1);\n          doc2.a.should.equal(2);\n\n          d.loadDatabase(function (err) {\n            var data = d.getAllData()\n              , doc1 = _.find(data, function (doc) { return doc.a === 1; })\n              , doc2 = _.find(data, function (doc) { return doc.a === 2; })\n            ;\n            assert.isNull(err);\n            data.length.should.equal(2);\n            doc1.a.should.equal(1);\n            doc2.a.should.equal(2);\n\n            done();\n          });\n        });\n      });\n    });\n  });\n\n  it('Calling loadDatabase after the datafile was removed will reset the database', function (done) {\n    d.loadDatabase(function () {\n      d.insert({ a: 1 }, function (err) {\n        assert.isNull(err);\n        d.insert({ a: 2 }, function (err) {\n          var data = d.getAllData()\n            , doc1 = _.find(data, function (doc) { return doc.a === 1; })\n            , doc2 = _.find(data, function (doc) { return doc.a === 2; })\n          ;\n          assert.isNull(err);\n          data.length.should.equal(2);\n          doc1.a.should.equal(1);\n          doc2.a.should.equal(2);\n\n          fs.unlink(testDb, function (err) {\n            assert.isNull(err);\n            d.loadDatabase(function (err) {\n              assert.isNull(err);\n              d.getAllData().length.should.equal(0);\n\n              done();\n            });\n          });\n        });\n      });\n    });\n  });\n\n  it('Calling loadDatabase after the datafile was modified loads the new data', function (done) {\n    d.loadDatabase(function () {\n      d.insert({ a: 1 }, function (err) {\n        assert.isNull(err);\n        d.insert({ a: 2 }, function (err) {\n          var data = d.getAllData()\n            , doc1 = _.find(data, function (doc) { return doc.a === 1; })\n            , doc2 = _.find(data, function (doc) { return doc.a === 2; })\n          ;\n          assert.isNull(err);\n          data.length.should.equal(2);\n          doc1.a.should.equal(1);\n          doc2.a.should.equal(2);\n\n          fs.writeFile(testDb, '{\"a\":3,\"_id\":\"aaa\"}', 'utf8', function (err) {\n            assert.isNull(err);\n            d.loadDatabase(function (err) {\n              var data = d.getAllData()\n                , doc1 = _.find(data, function (doc) { return doc.a === 1; })\n                , doc2 = _.find(data, function (doc) { return doc.a === 2; })\n                , doc3 = _.find(data, function (doc) { return doc.a === 3; })\n              ;\n              assert.isNull(err);\n              data.length.should.equal(1);\n              doc3.a.should.equal(3);\n              assert.isUndefined(doc1);\n              assert.isUndefined(doc2);\n\n              done();\n            });\n          });\n        });\n      });\n    });\n  });\n\n  it(\"When treating raw data, refuse to proceed if too much data is corrupt, to avoid data loss\", function (done) {\n    var corruptTestFilename = 'workspace/corruptTest.db'\n      , fakeData = '{\"_id\":\"one\",\"hello\":\"world\"}\\n' + 'Some corrupt data\\n' + '{\"_id\":\"two\",\"hello\":\"earth\"}\\n' + '{\"_id\":\"three\",\"hello\":\"you\"}\\n'\n      , d\n    ;\n    fs.writeFileSync(corruptTestFilename, fakeData, \"utf8\");\n\n    // Default corruptAlertThreshold\n    d = new Datastore({ filename: corruptTestFilename });\n    d.loadDatabase(function (err) {\n      assert.isDefined(err);\n      assert.isNotNull(err);\n\n      fs.writeFileSync(corruptTestFilename, fakeData, \"utf8\");\n      d = new Datastore({ filename: corruptTestFilename, corruptAlertThreshold: 1 });\n      d.loadDatabase(function (err) {\n        assert.isNull(err);\n\n        fs.writeFileSync(corruptTestFilename, fakeData, \"utf8\");\n        d = new Datastore({ filename: corruptTestFilename, corruptAlertThreshold: 0 });\n        d.loadDatabase(function (err) {\n          assert.isDefined(err);\n          assert.isNotNull(err);\n\n          done();\n        });\n      });\n    });\n  });\n\n  it(\"Can listen to compaction events\", function (done) {\n    d.on('compaction.done', function () {\n      d.removeAllListeners('compaction.done');   // Tidy up for next tests\n      done();\n    });\n\n    d.persistence.compactDatafile();\n  });\n\n\n  describe('Serialization hooks', function () {\n    var as = function (s) { return \"before_\" + s + \"_after\"; }\n      , bd = function (s) { return s.substring(7, s.length - 6); }\n\n    it(\"Declaring only one hook will throw an exception to prevent data loss\", function (done) {\n      var hookTestFilename = 'workspace/hookTest.db'\n      storage.ensureFileDoesntExist(hookTestFilename, function () {\n        fs.writeFileSync(hookTestFilename, \"Some content\", \"utf8\");\n\n        (function () {\n          new Datastore({ filename: hookTestFilename, autoload: true\n                        , afterSerialization: as\n          });\n        }).should.throw();\n\n        // Data file left untouched\n        fs.readFileSync(hookTestFilename, \"utf8\").should.equal(\"Some content\");\n\n        (function () {\n          new Datastore({ filename: hookTestFilename, autoload: true\n                        , beforeDeserialization: bd\n          });\n        }).should.throw();\n\n        // Data file left untouched\n        fs.readFileSync(hookTestFilename, \"utf8\").should.equal(\"Some content\");\n\n        done();\n      });\n    });\n\n    it(\"Declaring two hooks that are not reverse of one another will cause an exception to prevent data loss\", function (done) {\n      var hookTestFilename = 'workspace/hookTest.db'\n      storage.ensureFileDoesntExist(hookTestFilename, function () {\n        fs.writeFileSync(hookTestFilename, \"Some content\", \"utf8\");\n\n        (function () {\n          new Datastore({ filename: hookTestFilename, autoload: true\n                        , afterSerialization: as\n                        , beforeDeserialization: function (s) { return s; }\n          });\n        }).should.throw();\n\n        // Data file left untouched\n        fs.readFileSync(hookTestFilename, \"utf8\").should.equal(\"Some content\");\n\n        done();\n      });\n    });\n\n    it(\"A serialization hook can be used to transform data before writing new state to disk\", function (done) {\n      var hookTestFilename = 'workspace/hookTest.db'\n      storage.ensureFileDoesntExist(hookTestFilename, function () {\n        var d = new Datastore({ filename: hookTestFilename, autoload: true\n          , afterSerialization: as\n          , beforeDeserialization: bd\n        })\n        ;\n\n        d.insert({ hello: \"world\" }, function () {\n          var _data = fs.readFileSync(hookTestFilename, 'utf8')\n            , data = _data.split('\\n')\n            , doc0 = bd(data[0])\n          ;\n\n          data.length.should.equal(2);\n\n          data[0].substring(0, 7).should.equal('before_');\n          data[0].substring(data[0].length - 6).should.equal('_after');\n\n          doc0 = model.deserialize(doc0);\n          Object.keys(doc0).length.should.equal(2);\n          doc0.hello.should.equal('world');\n\n          d.insert({ p: 'Mars' }, function () {\n            var _data = fs.readFileSync(hookTestFilename, 'utf8')\n              , data = _data.split('\\n')\n              , doc0 = bd(data[0])\n              , doc1 = bd(data[1])\n            ;\n\n            data.length.should.equal(3);\n\n            data[0].substring(0, 7).should.equal('before_');\n            data[0].substring(data[0].length - 6).should.equal('_after');\n            data[1].substring(0, 7).should.equal('before_');\n            data[1].substring(data[1].length - 6).should.equal('_after');\n\n            doc0 = model.deserialize(doc0);\n            Object.keys(doc0).length.should.equal(2);\n            doc0.hello.should.equal('world');\n\n            doc1 = model.deserialize(doc1);\n            Object.keys(doc1).length.should.equal(2);\n            doc1.p.should.equal('Mars');\n\n            d.ensureIndex({ fieldName: 'idefix' }, function () {\n              var _data = fs.readFileSync(hookTestFilename, 'utf8')\n                , data = _data.split('\\n')\n                , doc0 = bd(data[0])\n                , doc1 = bd(data[1])\n                , idx = bd(data[2])\n              ;\n\n              data.length.should.equal(4);\n\n              data[0].substring(0, 7).should.equal('before_');\n              data[0].substring(data[0].length - 6).should.equal('_after');\n              data[1].substring(0, 7).should.equal('before_');\n              data[1].substring(data[1].length - 6).should.equal('_after');\n\n              doc0 = model.deserialize(doc0);\n              Object.keys(doc0).length.should.equal(2);\n              doc0.hello.should.equal('world');\n\n              doc1 = model.deserialize(doc1);\n              Object.keys(doc1).length.should.equal(2);\n              doc1.p.should.equal('Mars');\n\n              idx = model.deserialize(idx);\n              assert.deepEqual(idx, { '$$indexCreated': { fieldName: 'idefix' } });\n\n              done();\n            });\n          });\n        });\n      });\n    });\n\n    it(\"Use serialization hook when persisting cached database or compacting\", function (done) {\n      var hookTestFilename = 'workspace/hookTest.db'\n      storage.ensureFileDoesntExist(hookTestFilename, function () {\n        var d = new Datastore({ filename: hookTestFilename, autoload: true\n          , afterSerialization: as\n          , beforeDeserialization: bd\n        })\n        ;\n\n        d.insert({ hello: \"world\" }, function () {\n          d.update({ hello: \"world\" }, { $set: { hello: \"earth\" } }, {}, function () {\n            d.ensureIndex({ fieldName: 'idefix' }, function () {\n              var _data = fs.readFileSync(hookTestFilename, 'utf8')\n                , data = _data.split('\\n')\n                , doc0 = bd(data[0])\n                , doc1 = bd(data[1])\n                , idx = bd(data[2])\n                , _id\n              ;\n\n              data.length.should.equal(4);\n\n              doc0 = model.deserialize(doc0);\n              Object.keys(doc0).length.should.equal(2);\n              doc0.hello.should.equal('world');\n\n              doc1 = model.deserialize(doc1);\n              Object.keys(doc1).length.should.equal(2);\n              doc1.hello.should.equal('earth');\n\n              doc0._id.should.equal(doc1._id);\n              _id = doc0._id;\n\n              idx = model.deserialize(idx);\n              assert.deepEqual(idx, { '$$indexCreated': { fieldName: 'idefix' } });\n\n              d.persistence.persistCachedDatabase(function () {\n                var _data = fs.readFileSync(hookTestFilename, 'utf8')\n                  , data = _data.split('\\n')\n                  , doc0 = bd(data[0])\n                  , idx = bd(data[1])\n                ;\n\n                data.length.should.equal(3);\n\n                doc0 = model.deserialize(doc0);\n                Object.keys(doc0).length.should.equal(2);\n                doc0.hello.should.equal('earth');\n\n                doc0._id.should.equal(_id);\n\n                idx = model.deserialize(idx);\n                assert.deepEqual(idx, { '$$indexCreated': { fieldName: 'idefix', unique: false, sparse: false } });\n\n                done();\n              });\n            });\n          });\n        });\n      });\n    });\n\n    it(\"Deserialization hook is correctly used when loading data\", function (done) {\n      var hookTestFilename = 'workspace/hookTest.db'\n      storage.ensureFileDoesntExist(hookTestFilename, function () {\n        var d = new Datastore({ filename: hookTestFilename, autoload: true\n          , afterSerialization: as\n          , beforeDeserialization: bd\n        })\n        ;\n\n        d.insert({ hello: \"world\" }, function (err, doc) {\n          var _id = doc._id;\n          d.insert({ yo: \"ya\" }, function () {\n            d.update({ hello: \"world\" }, { $set: { hello: \"earth\" } }, {}, function () {\n              d.remove({ yo: \"ya\" }, {}, function () {\n                d.ensureIndex({ fieldName: 'idefix' }, function () {\n                  var _data = fs.readFileSync(hookTestFilename, 'utf8')\n                    , data = _data.split('\\n')\n                  ;\n\n                  data.length.should.equal(6);\n\n                  // Everything is deserialized correctly, including deletes and indexes\n                  var d = new Datastore({ filename: hookTestFilename\n                    , afterSerialization: as\n                    , beforeDeserialization: bd\n                  })\n                  ;\n                  d.loadDatabase(function () {\n                    d.find({}, function (err, docs) {\n                      docs.length.should.equal(1);\n                      docs[0].hello.should.equal(\"earth\");\n                      docs[0]._id.should.equal(_id);\n\n                      Object.keys(d.indexes).length.should.equal(2);\n                      Object.keys(d.indexes).indexOf(\"idefix\").should.not.equal(-1);\n\n                      done();\n                    });\n                  });\n                });\n              });\n            });\n          });\n        });\n      });\n    });\n\n  });   // ==== End of 'Serialization hooks' ==== //\n\n  describe('Prevent dataloss when persisting data', function () {\n\n    it('Creating a datastore with in memory as true and a bad filename wont cause an error', function () {\n      new Datastore({ filename: 'workspace/bad.db~', inMemoryOnly: true });\n    })\n\n    it('Creating a persistent datastore with a bad filename will cause an error', function () {\n      (function () { new Datastore({ filename: 'workspace/bad.db~' }); }).should.throw();\n    })\n\n    it('If no file exists, ensureDatafileIntegrity creates an empty datafile', function (done) {\n      var p = new Persistence({ db: { inMemoryOnly: false, filename: 'workspace/it.db' } });\n\n      if (fs.existsSync('workspace/it.db')) { fs.unlinkSync('workspace/it.db'); }\n      if (fs.existsSync('workspace/it.db~')) { fs.unlinkSync('workspace/it.db~'); }\n\n      fs.existsSync('workspace/it.db').should.equal(false);\n      fs.existsSync('workspace/it.db~').should.equal(false);\n\n      storage.ensureDatafileIntegrity(p.filename, function (err) {\n        assert.isNull(err);\n\n        fs.existsSync('workspace/it.db').should.equal(true);\n        fs.existsSync('workspace/it.db~').should.equal(false);\n\n        fs.readFileSync('workspace/it.db', 'utf8').should.equal('');\n\n        done();\n      });\n    });\n\n    it('If only datafile exists, ensureDatafileIntegrity will use it', function (done) {\n      var p = new Persistence({ db: { inMemoryOnly: false, filename: 'workspace/it.db' } });\n\n      if (fs.existsSync('workspace/it.db')) { fs.unlinkSync('workspace/it.db'); }\n      if (fs.existsSync('workspace/it.db~')) { fs.unlinkSync('workspace/it.db~'); }\n\n      fs.writeFileSync('workspace/it.db', 'something', 'utf8');\n\n      fs.existsSync('workspace/it.db').should.equal(true);\n      fs.existsSync('workspace/it.db~').should.equal(false);\n\n      storage.ensureDatafileIntegrity(p.filename, function (err) {\n        assert.isNull(err);\n\n        fs.existsSync('workspace/it.db').should.equal(true);\n        fs.existsSync('workspace/it.db~').should.equal(false);\n\n        fs.readFileSync('workspace/it.db', 'utf8').should.equal('something');\n\n        done();\n      });\n    });\n\n    it('If temp datafile exists and datafile doesnt, ensureDatafileIntegrity will use it (cannot happen except upon first use)', function (done) {\n      var p = new Persistence({ db: { inMemoryOnly: false, filename: 'workspace/it.db' } });\n\n      if (fs.existsSync('workspace/it.db')) { fs.unlinkSync('workspace/it.db'); }\n      if (fs.existsSync('workspace/it.db~')) { fs.unlinkSync('workspace/it.db~~'); }\n\n      fs.writeFileSync('workspace/it.db~', 'something', 'utf8');\n\n      fs.existsSync('workspace/it.db').should.equal(false);\n      fs.existsSync('workspace/it.db~').should.equal(true);\n\n      storage.ensureDatafileIntegrity(p.filename, function (err) {\n        assert.isNull(err);\n\n        fs.existsSync('workspace/it.db').should.equal(true);\n        fs.existsSync('workspace/it.db~').should.equal(false);\n\n        fs.readFileSync('workspace/it.db', 'utf8').should.equal('something');\n\n        done();\n      });\n    });\n\n    // Technically it could also mean the write was successful but the rename wasn't, but there is in any case no guarantee that the data in the temp file is whole so we have to discard the whole file\n    it('If both temp and current datafiles exist, ensureDatafileIntegrity will use the datafile, as it means that the write of the temp file failed', function (done) {\n      var theDb = new Datastore({ filename: 'workspace/it.db' });\n\n      if (fs.existsSync('workspace/it.db')) { fs.unlinkSync('workspace/it.db'); }\n      if (fs.existsSync('workspace/it.db~')) { fs.unlinkSync('workspace/it.db~'); }\n\n      fs.writeFileSync('workspace/it.db', '{\"_id\":\"0\",\"hello\":\"world\"}', 'utf8');\n      fs.writeFileSync('workspace/it.db~', '{\"_id\":\"0\",\"hello\":\"other\"}', 'utf8');\n\n      fs.existsSync('workspace/it.db').should.equal(true);\n      fs.existsSync('workspace/it.db~').should.equal(true);\n\n      storage.ensureDatafileIntegrity(theDb.persistence.filename, function (err) {\n        assert.isNull(err);\n\n        fs.existsSync('workspace/it.db').should.equal(true);\n        fs.existsSync('workspace/it.db~').should.equal(true);\n\n        fs.readFileSync('workspace/it.db', 'utf8').should.equal('{\"_id\":\"0\",\"hello\":\"world\"}');\n\n        theDb.loadDatabase(function (err) {\n          assert.isNull(err);\n          theDb.find({}, function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(1);\n            docs[0].hello.should.equal(\"world\");\n            fs.existsSync('workspace/it.db').should.equal(true);\n            fs.existsSync('workspace/it.db~').should.equal(false);\n            done();\n          });\n        });\n      });\n    });\n\n    it('persistCachedDatabase should update the contents of the datafile and leave a clean state', function (done) {\n      d.insert({ hello: 'world' }, function () {\n        d.find({}, function (err, docs) {\n          docs.length.should.equal(1);\n\n          if (fs.existsSync(testDb)) { fs.unlinkSync(testDb); }\n          if (fs.existsSync(testDb + '~')) { fs.unlinkSync(testDb + '~'); }\n          fs.existsSync(testDb).should.equal(false);\n\n          fs.writeFileSync(testDb + '~', 'something', 'utf8');\n          fs.existsSync(testDb + '~').should.equal(true);\n\n          d.persistence.persistCachedDatabase(function (err) {\n            var contents = fs.readFileSync(testDb, 'utf8');\n            assert.isNull(err);\n            fs.existsSync(testDb).should.equal(true);\n            fs.existsSync(testDb + '~').should.equal(false);\n            if (!contents.match(/^{\"hello\":\"world\",\"_id\":\"[0-9a-zA-Z]{16}\"}\\n$/)) {\n              throw new Error(\"Datafile contents not as expected\");\n            }\n            done();\n          });\n        });\n      });\n    });\n\n    it('After a persistCachedDatabase, there should be no temp or old filename', function (done) {\n      d.insert({ hello: 'world' }, function () {\n        d.find({}, function (err, docs) {\n          docs.length.should.equal(1);\n\n          if (fs.existsSync(testDb)) { fs.unlinkSync(testDb); }\n          if (fs.existsSync(testDb + '~')) { fs.unlinkSync(testDb + '~'); }\n          fs.existsSync(testDb).should.equal(false);\n          fs.existsSync(testDb + '~').should.equal(false);\n\n          fs.writeFileSync(testDb + '~', 'bloup', 'utf8');\n          fs.existsSync(testDb + '~').should.equal(true);\n\n          d.persistence.persistCachedDatabase(function (err) {\n            var contents = fs.readFileSync(testDb, 'utf8');\n            assert.isNull(err);\n            fs.existsSync(testDb).should.equal(true);\n            fs.existsSync(testDb + '~').should.equal(false);\n            if (!contents.match(/^{\"hello\":\"world\",\"_id\":\"[0-9a-zA-Z]{16}\"}\\n$/)) {\n              throw new Error(\"Datafile contents not as expected\");\n            }\n            done();\n          });\n        });\n      });\n    });\n\n    it('persistCachedDatabase should update the contents of the datafile and leave a clean state even if there is a temp datafile', function (done) {\n      d.insert({ hello: 'world' }, function () {\n        d.find({}, function (err, docs) {\n          docs.length.should.equal(1);\n\n          if (fs.existsSync(testDb)) { fs.unlinkSync(testDb); }\n          fs.writeFileSync(testDb + '~', 'blabla', 'utf8');\n          fs.existsSync(testDb).should.equal(false);\n          fs.existsSync(testDb + '~').should.equal(true);\n\n          d.persistence.persistCachedDatabase(function (err) {\n            var contents = fs.readFileSync(testDb, 'utf8');\n            assert.isNull(err);\n            fs.existsSync(testDb).should.equal(true);\n            fs.existsSync(testDb + '~').should.equal(false);\n            if (!contents.match(/^{\"hello\":\"world\",\"_id\":\"[0-9a-zA-Z]{16}\"}\\n$/)) {\n              throw new Error(\"Datafile contents not as expected\");\n            }\n            done();\n          });\n        });\n      });\n    });\n\n    it('persistCachedDatabase should update the contents of the datafile and leave a clean state even if there is a temp datafile', function (done) {\n      var dbFile = 'workspace/test2.db', theDb;\n\n      if (fs.existsSync(dbFile)) { fs.unlinkSync(dbFile); }\n      if (fs.existsSync(dbFile + '~')) { fs.unlinkSync(dbFile + '~'); }\n\n      theDb = new Datastore({ filename: dbFile });\n\n      theDb.loadDatabase(function (err) {\n        var contents = fs.readFileSync(dbFile, 'utf8');\n        assert.isNull(err);\n        fs.existsSync(dbFile).should.equal(true);\n        fs.existsSync(dbFile + '~').should.equal(false);\n        if (contents != \"\") {\n          throw new Error(\"Datafile contents not as expected\");\n        }\n        done();\n      });\n    });\n\n    it('Persistence works as expected when everything goes fine', function (done) {\n      var dbFile = 'workspace/test2.db', theDb, theDb2, doc1, doc2;\n\n      async.waterfall([\n          async.apply(storage.ensureFileDoesntExist, dbFile)\n        , async.apply(storage.ensureFileDoesntExist, dbFile + '~')\n        , function (cb) {\n          theDb = new Datastore({ filename: dbFile });\n          theDb.loadDatabase(cb);\n        }\n        , function (cb) {\n          theDb.find({}, function (err, docs) {\n            assert.isNull(err);\n            docs.length.should.equal(0);\n            return cb();\n          });\n        }\n      , function (cb) {\n        theDb.insert({ a: 'hello' }, function (err, _doc1) {\n        assert.isNull(err);\n          doc1 = _doc1;\n          theDb.insert({ a: 'world' }, function (err, _doc2) {\n            assert.isNull(err);\n            doc2 = _doc2;\n            return cb();\n          });\n        });\n      }\n      , function (cb) {\n        theDb.find({}, function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(2);\n          _.find(docs, function (item) { return item._id === doc1._id }).a.should.equal('hello');\n          _.find(docs, function (item) { return item._id === doc2._id }).a.should.equal('world');\n          return cb();\n        });\n      }\n      , function (cb) {\n        theDb.loadDatabase(cb);\n      }\n      , function (cb) {   // No change\n        theDb.find({}, function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(2);\n          _.find(docs, function (item) { return item._id === doc1._id }).a.should.equal('hello');\n          _.find(docs, function (item) { return item._id === doc2._id }).a.should.equal('world');\n          return cb();\n        });\n      }\n      , function (cb) {\n        fs.existsSync(dbFile).should.equal(true);\n        fs.existsSync(dbFile + '~').should.equal(false);\n        return cb();\n      }\n      , function (cb) {\n        theDb2 = new Datastore({ filename: dbFile });\n        theDb2.loadDatabase(cb);\n      }\n      , function (cb) {   // No change in second db\n        theDb2.find({}, function (err, docs) {\n          assert.isNull(err);\n          docs.length.should.equal(2);\n          _.find(docs, function (item) { return item._id === doc1._id }).a.should.equal('hello');\n          _.find(docs, function (item) { return item._id === doc2._id }).a.should.equal('world');\n          return cb();\n        });\n      }\n      , function (cb) {\n        fs.existsSync(dbFile).should.equal(true);\n        fs.existsSync(dbFile + '~').should.equal(false);\n        return cb();\n      }\n      ], done);\n    });\n\n    // The child process will load the database with the given datafile, but the fs.writeFile function\n    // is rewritten to crash the process before it finished (after 5000 bytes), to ensure data was not lost\n    it('If system crashes during a loadDatabase, the former version is not lost', function (done) {\n      var N = 500, toWrite = \"\", i, doc_i;\n\n      // Ensuring the state is clean\n      if (fs.existsSync('workspace/lac.db')) { fs.unlinkSync('workspace/lac.db'); }\n      if (fs.existsSync('workspace/lac.db~')) { fs.unlinkSync('workspace/lac.db~'); }\n\n      // Creating a db file with 150k records (a bit long to load)\n      for (i = 0; i < N; i += 1) {\n        toWrite += model.serialize({ _id: 'anid_' + i, hello: 'world' }) + '\\n';\n      }\n      fs.writeFileSync('workspace/lac.db', toWrite, 'utf8');\n\n      var datafileLength = fs.readFileSync('workspace/lac.db', 'utf8').length;\n\n      // Loading it in a separate process that we will crash before finishing the loadDatabase\n      child_process.fork('test_lac/loadAndCrash.test').on('exit', function (code) {\n        code.should.equal(1);   // See test_lac/loadAndCrash.test.js\n\n        fs.existsSync('workspace/lac.db').should.equal(true);\n        fs.existsSync('workspace/lac.db~').should.equal(true);\n        fs.readFileSync('workspace/lac.db', 'utf8').length.should.equal(datafileLength);\n        fs.readFileSync('workspace/lac.db~', 'utf8').length.should.equal(5000);\n\n        // Reload database without a crash, check that no data was lost and fs state is clean (no temp file)\n        var db = new Datastore({ filename: 'workspace/lac.db' });\n        db.loadDatabase(function (err) {\n          assert.isNull(err);\n\n          fs.existsSync('workspace/lac.db').should.equal(true);\n          fs.existsSync('workspace/lac.db~').should.equal(false);\n          fs.readFileSync('workspace/lac.db', 'utf8').length.should.equal(datafileLength);\n\n          db.find({}, function (err, docs) {\n            docs.length.should.equal(N);\n            for (i = 0; i < N; i += 1) {\n              doc_i = _.find(docs, function (d) { return d._id === 'anid_' + i; });\n              assert.isDefined(doc_i);\n              assert.deepEqual({ hello: 'world', _id: 'anid_' + i }, doc_i);\n            }\n            return done();\n          });\n        });\n      });\n    });\n\n    // Not run on Windows as there is no clean way to set maximum file descriptors. Not an issue as the code itself is tested.\n    it(\"Cannot cause EMFILE errors by opening too many file descriptors\", function (done) {\n      if (process.platform === 'win32' || process.platform === 'win64') { return done(); }\n      child_process.execFile('test_lac/openFdsLaunch.sh', function (err, stdout, stderr) {\n        if (err) { return done(err); }\n\n        // The subprocess will not output anything to stdout unless part of the test fails\n        if (stdout.length !== 0) {\n          return done(stdout);\n        } else {\n          return done();\n        }\n      });\n    });\n\n  });   // ==== End of 'Prevent dataloss when persisting data' ====\n\n\n  describe('ensureFileDoesntExist', function () {\n\n    it('Doesnt do anything if file already doesnt exist', function (done) {\n      storage.ensureFileDoesntExist('workspace/nonexisting', function (err) {\n        assert.isNull(err);\n        fs.existsSync('workspace/nonexisting').should.equal(false);\n        done();\n      });\n    });\n\n    it('Deletes file if it exists', function (done) {\n      fs.writeFileSync('workspace/existing', 'hello world', 'utf8');\n      fs.existsSync('workspace/existing').should.equal(true);\n\n      storage.ensureFileDoesntExist('workspace/existing', function (err) {\n        assert.isNull(err);\n        fs.existsSync('workspace/existing').should.equal(false);\n        done();\n      });\n    });\n\n  });   // ==== End of 'ensureFileDoesntExist' ====\n\n\n});\n"
  },
  {
    "path": "test_lac/loadAndCrash.test.js",
    "content": "/**\n * Load and modify part of fs to ensure writeFile will crash after writing 5000 bytes\n */\nvar fs = require('fs');\n\nfunction rethrow() {\n  // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and\n  // is fairly slow to generate.\n  if (DEBUG) {\n    var backtrace = new Error();\n    return function(err) {\n      if (err) {\n        backtrace.stack = err.name + ': ' + err.message +\n                          backtrace.stack.substr(backtrace.name.length);\n        throw backtrace;\n      }\n    };\n  }\n\n  return function(err) {\n    if (err) {\n      throw err;  // Forgot a callback but don't know where? Use NODE_DEBUG=fs\n    }\n  };\n}\n\nfunction maybeCallback(cb) {\n  return typeof cb === 'function' ? cb : rethrow();\n}\n\nfunction isFd(path) {\n  return (path >>> 0) === path;\n}\n\nfunction assertEncoding(encoding) {\n  if (encoding && !Buffer.isEncoding(encoding)) {\n    throw new Error('Unknown encoding: ' + encoding);\n  }\n}\n\nvar onePassDone = false;\nfunction writeAll(fd, isUserFd, buffer, offset, length, position, callback_) {\n  var callback = maybeCallback(arguments[arguments.length - 1]);\n\n  if (onePassDone) { process.exit(1); }   // Crash on purpose before rewrite done\n  var l = Math.min(5000, length);   // Force write by chunks of 5000 bytes to ensure data will be incomplete on crash\n\n  // write(fd, buffer, offset, length, position, callback)\n  fs.write(fd, buffer, offset, l, position, function(writeErr, written) {\n    if (writeErr) {\n      if (isUserFd) {\n        if (callback) callback(writeErr);\n      } else {\n        fs.close(fd, function() {\n          if (callback) callback(writeErr);\n        });\n      }\n    } else {\n      onePassDone = true;\n      if (written === length) {\n        if (isUserFd) {\n          if (callback) callback(null);\n        } else {\n          fs.close(fd, callback);\n        }\n      } else {\n        offset += written;\n        length -= written;\n        if (position !== null) {\n          position += written;\n        }\n        writeAll(fd, isUserFd, buffer, offset, length, position, callback);\n      }\n    }\n  });\n}\n\nfs.writeFile = function(path, data, options, callback_) {\n  var callback = maybeCallback(arguments[arguments.length - 1]);\n\n  if (!options || typeof options === 'function') {\n    options = { encoding: 'utf8', mode: 438, flag: 'w' }; // Mode 438 == 0o666 (compatibility with older Node releases)\n  } else if (typeof options === 'string') {\n    options = { encoding: options, mode: 438, flag: 'w' }; // Mode 438 == 0o666 (compatibility with older Node releases)\n  } else if (typeof options !== 'object') {\n    throwOptionsError(options);\n  }\n\n  assertEncoding(options.encoding);\n\n  var flag = options.flag || 'w';\n\n  if (isFd(path)) {\n    writeFd(path, true);\n    return;\n  }\n\n  fs.open(path, flag, options.mode, function(openErr, fd) {\n    if (openErr) {\n      if (callback) callback(openErr);\n    } else {\n      writeFd(fd, false);\n    }\n  });\n\n  function writeFd(fd, isUserFd) {\n    var buffer = (data instanceof Buffer) ? data : new Buffer('' + data,\n        options.encoding || 'utf8');\n    var position = /a/.test(flag) ? null : 0;\n\n    writeAll(fd, isUserFd, buffer, 0, buffer.length, position, callback);\n  }\n};\n\n\n\n\n// End of fs modification\nvar Nedb = require('../lib/datastore.js')\n  , db = new Nedb({ filename: 'workspace/lac.db' })\n  ;\n\ndb.loadDatabase();\n"
  },
  {
    "path": "test_lac/openFds.test.js",
    "content": "var fs = require('fs')\n  , child_process = require('child_process')\n  , async = require('async')\n  , Nedb = require('../lib/datastore')\n  , db = new Nedb({ filename: './workspace/openfds.db', autoload: true })\n  , N = 64   // Half the allowed file descriptors\n  , i, fds\n  ;\n\nfunction multipleOpen (filename, N, callback) {\n  async.whilst( function () { return i < N; }\n              , function (cb) {\n                fs.open(filename, 'r', function (err, fd) {\n                  i += 1;\n                  if (fd) { fds.push(fd); }\n                  return cb(err);\n                });\n              }\n              , callback);\n}\n\nasync.waterfall([\n  // Check that ulimit has been set to the correct value\n  function (cb) {\n    i = 0;\n    fds = [];\n    multipleOpen('./test_lac/openFdsTestFile', 2 * N + 1, function (err) {\n      if (!err) { console.log(\"No error occured while opening a file too many times\"); }\n      fds.forEach(function (fd) { fs.closeSync(fd); });\n      return cb();\n    })\n  }\n, function (cb) {\n    i = 0;\n    fds = [];\n    multipleOpen('./test_lac/openFdsTestFile2', N, function (err) {\n      if (err) { console.log('An unexpected error occured when opening file not too many times: ' + err); }\n      fds.forEach(function (fd) { fs.closeSync(fd); });\n      return cb();\n    })\n  }\n  // Then actually test NeDB persistence\n, function () {\n    db.remove({}, { multi: true }, function (err) {\n      if (err) { console.log(err); }\n      db.insert({ hello: 'world' }, function (err) {\n        if (err) { console.log(err); }\n\n        i = 0;\n        async.whilst( function () { return i < 2 * N  + 1; }\n                    , function (cb) {\n                        db.persistence.persistCachedDatabase(function (err) {\n                          if (err) { return cb(err); }\n                          i += 1;\n                          return cb();\n                        });\n                      }\n                    , function (err) {\n                      if (err) { console.log(\"Got unexpected error during one peresistence operation: \" + err); }\n                      }\n                    );\n\n      });\n    });\n  }\n]);\n\n"
  },
  {
    "path": "test_lac/openFdsLaunch.sh",
    "content": "ulimit -n 128\nnode ./test_lac/openFds.test.js\n"
  },
  {
    "path": "test_lac/openFdsTestFile",
    "content": "Random stuff\n"
  },
  {
    "path": "test_lac/openFdsTestFile2",
    "content": "Some other random stuff\n"
  }
]