[
  {
    "path": ".gitignore",
    "content": "node_modules"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - 0.10\n\nservices:\n  - mongodb\n\nbranches:\n  only:\n    - master"
  },
  {
    "path": "CHANGELOG.md",
    "content": "\n2.6.0 / 2015-10-21\n==================\n\n  * [dist, contribs] bumped v, added @t27 to contribs\n  * Merge pull request #37 from t27/master\n  * Added an update call to update the URL or data of a preexisting hash\n  * Merge pull request #34 from datermine/patch-2\n  * Fix bug with missing update var & unnecessary update.\n  * [docs, changelog] updated\n  * [dist, bump] add @jperkelens to contributors, bump v\n  * Merge pull request #33 from jperkelens/master\n  * Only connects if current state is disconnected\n\n2.5.2 / 2015-09-04\n==================\n\n  * Merge pull request #33 from jperkelens/master\n  * Only connects if current state is disconnected\n\n2.5.1 / 2015-09-02\n==================\n\n  * Merge pull request #32 from romanmt/mongo-v-bump\n  * Adding romanmt as a contributor\n  * Merge pull request #31 from romanmt/mongo-v-bump\n  * Bump mongoose version in order to support mongo 3.0 auth\n\n2.5.0 / 2015-02-25\n==================\n\n  * Merge pull request #29 from matmar10/master\n  * resolves issue #30 - remove unique index on URL; create a new document when existing URL and new hash is specified\n  * Reproduces issue #30 - Specifying hash has no effect for pre-existing URL\n  * add test case for specifying hash; resolves #28\n\n2.4.0 / 2014-09-06\n==================\n\n  * Merge pull request #26 from pwmckenna/patch-1\n  * Expose the hash as part of the api\n  * Merge pull request #24 from knownasilya/patch-1\n  * Fix author link\n\n2.3.0 / 2014-07-01 \n==================\n\n * [dist] bump\n * [shields/badges/whatever] deps\n * [node] bump travis and package reqs to .10.x\n * [package, contribs] added @nippe\n * [minor, license] remove line, derp!\n * Merge pull request #23 from nippe/master\n * Removed an extra promise layer\n * Update README.md\n * Delete paige.config\n\n2.2.0 / 2013-11-22 \n==================\n\n * [contrib] added @pwmckenna\n * [minor] format\n * Merge pull request #22 from pwmckenna/patch-1\n * Update short.js\n\n2.1.0 / 2013-11-06 \n==================\n\n * Merge pull request #20 from lbj96347/master\n * [fix]fix hits feature\n * Merge pull request #19 from bitdeli-chef/master\n * Add a Bitdeli badge to README\n\n2.0.0 / 2013-08-01 \n==================\n\n * [dist] release 2.0.0\n * Merge branch 'develop'\n * [promises] use node-promises my my I hate callbacks\n * Merge branch 'promises' into develop\n * [refactor] node-promise full integration and detailed sha1 hahs refactor\n * [promises] dont use callbacks\n * [docs] update for new api\n * [rewrite]\n * [model] cleanup\n * [license] updated YYYY\n * [travis, hasher] updated travis for just 0.8.x, added short-id using a genuine sha1 sum for a short url\n\n1.7.0 / 2012-10-25 \n==================\n\n  * [dist] version bump\n  * [test] updated mongoose and reflected within tests\n  * [package] reference makefile in scripts\n  * [Makefile] use Makefile \"make test\" (who does not love bash?) ALONG WITH \"npm test\"\n  * [deps] update mongoose and vows to latest\n  * [node] bump version\n  * [minor] code cleanup and segmentation\n\n1.6.0 / 2012-06-27 \n==================\n\n  * [node] 0.6.0+\n\n\n1.5.1 / 2012-06-22 \n==================\n\n  * [docs] add latest contributors [@cbrammer, @lynchseattle] to README\n  * [deps] bunp mongoose to latest\n  * [docs] stylize\n  * [dictatorship] dont <= node engine version, prep for 0.8.x\n  * [syntax] i prefer **/ over */ now, corrected\n  * [gitignore] added\n  * [email] have author match address in contributors, thanks @isaacs\n  * [node] test for 0.4.0\n\n1.5.0 / 2012-03-22 \n==================\n\n  * [deps] bump mongoose to 2.5.13\n  * [package] updated contributors\n  * Merge pull request #17 from lynchseattle/master\n  * Support for nodejs 0.6.11\n  * Added support for passing in custom data in the options when creating a new URL. This will store any meta-information on that URL that you might want to track. A possible use for this would be an ecommerce store with a shortened URL, but you might want to track that this URL was generated for a specific micro-site or even a specific customer.\n\n1.4.7 / 2012-03-22 \n==================\n\n  * [package] added bugs\n  * [package] added \"homepage\"\n  * [deps] bump mongoose to 2.5.12\n\n1.4.6 / 2012-03-18 \n==================\n\n  * [dist] version bump\n  * [tests] run all in /test incase of contrib\n  * [docs] contribute\n  * [node] engine req bump to 0.6.13\n  * [cleanup] remove examples/, single file already in README\n  * [cleanup] mmhmmm\n  * [docs] updated for 1.4.5\n\n1.4.5 / 2012-03-17 \n==================\n\n  * [comments]\n  * [merge] fix conflicts, remove statics\n  * Merge branch 'ifit-master'\n  * [merge] fix conflicts\n  * Create Connection Option\n  * [docs] rebuilt\n  * [comments] update style for docs\n  * [deps] bump mongoose version to 2.5.10\n  * [engine] prep for 0.8.0, req 0.6.12+\n\n1.4.4 / 2012-03-05 \n==================\n\n  * [tests] data validity\n  * [tests] added short.retrieve\n  * [npm registry] search for bit.ly?\n  * [deps] bump vows to 0.6.2\n  * [tests] spring cleaning\n  * [docs] &&\n  * [deps] removed Makefile (use npm test now)\n  * [npm] use `npm test` vs. Makefile for single command\n  * [package] 0.6.X\n\n1.4.3 / 2012-02-18 \n==================\n\n  * [dist] version bump\n  * [engine] prepare for 0.8.0, bump required engine\n  * [minor] formating\n  * dont benchmark without tracking\n\n1.4.2 / 2012-01-29 \n==================\n\n  * [minor] update basic example\n  * remove full express example\n  * for full example please see @thinkroth 's work\n  * Merge pull request #15 from hudgins/master\n  * Fix for retrieve(hash, callback) throwing due to null options.\n\n1.4.1 / 2012-01-23 \n==================\n\n  * [API] short.list()\n\n1.4.0 / 2012-01-20 \n==================\n\n  * Added atomic logging (thinkroth/master) / options.hash\n\n1.3.1 / 2012-01-18 \n==================\n\n  * [docs] update\n  * update npmignore for benchmarks and docs\n  * nicely generated docs by paige\n  * setup `paige` : `[sudo] npm install paige -g\n  * use contributors full name\n  * hanging commas, exports\n  * [refactor]\n  * /lib/short.js hanging commas\n  * hanging commas\n  * [tests] god I love those hanging commas :P\n  * basic benchmarking\n  * [tests] use Makefile so that we can add benchmarking also\n  * [tests] use benchmark.js\n\n1.3.0 / 2012-01-10 \n==================\n\n  * [docs] updated mongoose.connection events\n  * Merge pull request #12 from thinkroth/master\n  * Added unique tracking\n  * Merge pull request #11 from thinkroth/master\n  * Removed duplicate mongo query\n  * Merge pull request #10 from thinkroth/master\n  * Added length option\n\n1.2.1 / 2012-01-06 \n==================\n\n  * Merge pull request #9 from thinkroth/master\n  * Fixed recursion error\n\n1.2.0 / 2012-01-04 \n==================\n\n  * retrieve was broken in most recent api change\n\n1.1.4 / 2012-01-01 \n==================\n\n  * version bump\n  * change usage for examples\n  * remove full example, segment out to bkln.me\n  * description, notes on migrating\n  * opacity in github\n  * formating\n  * dont test 0.8.0, which doesnt exist (yet) :P\n  * changelog\n\n1.1.3 / 2011-12-28 \n==================\n\n  * version bump, new email address\n  * formating\n  * smaller module footprint\n  * node api.js vs. API.js\n  * comment duplicate\n  * include .gitignore\n  * changelog for 1.1.2\n\n1.1.2 / 2011-12-27 \n==================\n\n  * updated npm test info to align with .npmignore\n  * compacted the npm module size with .npmignore\n  * added a .npmignore file\n  * gunio whitespace robot added ignores for already ignored (globally) .DS_Store files\n  * check for valid urls\n  * travis using 0.4.x - 0.8.x\n  * readme notes on version 1.0.0 plus more descriptive\n  * HTML meta tags\n  * add \"fork me on github\" image to bkln.me\"\n\n1.1.1 / 2011-12-25 \n==================\n\n  * version bump\n  * use 1.1.1 now with examples\n  * remove debug logging\n  * remove complete license from readme, only specify type and owner\n  * Changed findByHash to use findOne\n  * changelog for 1.0.0\n  * remove `base-converter` as a dependency\n  * new base 62 URL hasher\n  * new API\n  * new exports method, expose hasher method\n  * description\n\n1.1.0 / 2011-12-23 \n==================\n\n  * version bump, using findOne vs. find, better speed [kevin]\n  * Merge pull request #8 from thinkroth/master\n  * package minor\n  * Changed findByHash to use findOne\n  * final\n  * facepalm!\n  * travis?\n  * minor fix\n\n1.0.0 / 2011-12-23 \n==================\n\n  * remove require(base-converter)\n  * complete example uses short 1.0.0 now\n  * version bump, updated complete example\n  * updated API with docs also updated\n  * keywords in package.json\n  * remove `base-converter` as a dependency\n  * new test for short.hasher\n  * new base 62 URL hasher\n  * Merge branch 'develop'\n  * travis ci will only test master\n  * new API\n  * code cleanup, emphasis in README\n  * new exports method, expose hasher method\n  * roth, thats his last name\n  * use v0.4.3 on /examples/bkln.me\n  * description\n\n0.4.3 / 2011-12-22 \n==================\n\n  * mongoose.connection.on(open|error)\n  * changes to work with nodejitsu, and display ENV information /env\n  * production NODE_ENV\n  * updated example to expose ShortModel and retrieve all Shortened URLs\n  * comments\n\n0.4.2 / 2011-12-22 \n==================\n\n  * expose `ShortURL` mongoose model\n  * use exports vs. function/module.exports\n  * use request and response vs. req and res for clarity\n\n0.4.1 / 2011-12-22 \n==================\n\n  * mongoose isnt actually required by bkln.me example directly, remove dep\n  * updated required mongoose version to 2.4.8\n  * version bump\n  * larger node range to support nodejitsu\n  * travis for 0.4-0.8\n  * use 0.4.1 (incoming) which will suport 0.4.11 >= 0.8.0\n  * bump required `short` version to 0.4.0 for bkln.me\n  * rename name for deploy to bkln\n  * index to app for package.json/nodejitsu\n  * setup for nodejitsu\n  * rename MONGO_DB to MONGO_DB_SHORT for nodejitsu deploy\n  * rename complete example to bkln.me\n  * improvements in the readme\n  * readme formating\n  * pull requests section on README\n  * added kevin to readme via contributors, added license and test `npm test` to readme also\n\n0.4.0 / 2011-12-22 \n==================\n\n  * added `Kevin` (@thinkroth) as a contributor\n  * more comments, cleaned up code\n  * comments\n  * Merge pull request #7 from thinkroth/master\n  * Optimized write process\n  * Merge pull request #6 from thinkroth/master\n  * bump required node version to 0.6.0 align travis with that spec also\n  * Optimized checkExists query\n\n0.3.0 / 2011-12-20 \n==================\n\n  * working example README\n  * working complete example :P\n  * added CoreJS Client side script, edited to intergrate alongside testing\n  * rename for integration of two similar git repos\n\n0.2.8 / 2011-12-18 \n==================\n\n  * Added gun.io whitespace changes, version bump\n  * Merge pull request #4 from GunioRobot/clean\n  * Remove whitespace [Gun.io WhitespaceBot]\n  * license\n  * new readme format that i have kind of fallen in love with\n  * formating, bump travis up to 0.8.0\n  * neatification++\n  * formating, module version bumps\n  * tests\n  * version bump 2.2.4\n  * Merge pull request #3 from thinkroth/master\n  * Added express example to readme\n  * [dist] version bump to 0.2.3\n  * Merge pull request #2 from thinkroth/master\n  * Extended short url ending to 7 digits\n  * [dist] version bump\n  * travis in readme\n  * travis f t w\n  * no more sys warnings from node-base-converter, version bumps there and mongoose\n  * more engines\n  * major bug fix, regression when entry point went from /index to /lib/short, fixed in package as well as a doc minor improvement\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2011-2014, Edward Hotchkiss.\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\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "\n# short [![Build Status](https://secure.travis-ci.org/edwardhotchkiss/short.png)](http://travis-ci.org/edwardhotchkiss/short) [![Dependency Status](https://david-dm.org/edwardhotchkiss/short.png?theme=shields.io)](https://david-dm.org/edwardhotchkiss/short)\n\n[![NPM](https://nodei.co/npm/short.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/short/)\n\n> Node.js URL Shortener backed by Mongoose.js\n\n_**No Callbacks, just Promises!**_\n\n## Installation\n\n```bash\n$ npm install short\n```\n\n***\n\n## Basic API Usage\n\n**Generates a Shortened URL Doc, then retrieves it for demo:**\n\n```javascript\nvar shortURLPromise\n  , short = require('../lib/short');\n\n// connect to mongodb\nshort.connect('mongodb://localhost/short');\n\nshort.connection.on('error', function(error) {\n  throw new Error(error);\n});\n\n// promise to generate a shortened URL.\nvar shortURLPromise = short.generate({\n  URL : 'http://nodejs.org/'\n});\n\n// gets back the short url document, and then retrieves it\nshortURLPromise.then(function(mongodbDoc) {\n  console.log('>> created short URL:');\n  console.log(mongodbDoc);\n  console.log('>> retrieving short URL: %s', mongodbDoc.hash);\n  short.retrieve(mongodbDoc.hash).then(function(result) {\n    console.log('>> retrieve result:');\n    console.log(result);\n    process.exit(0);\n  }, function(error) {\n    if (error) {\n      throw new Error(error);\n    }\n  });\n}, function(error) {\n  if (error) {\n    throw new Error(error);\n  }\n});\n```\n\n**Listing all Shortened URLs in DB:**\n\n```javascript\nvar listURLsPromise\n  , short = require('../lib/short');\n\n// connect to mongodb\nshort.connect('mongodb://localhost/short');\n\nshort.connection.on('error', function(error) {\n  throw new Error(error);\n});\n\n// promise to retrieve all shortened URLs\nlistURLsPromise = short.list();\n\n// output all resulting shortened url db docs\nlistURLsPromise.then(function(URLsDocument) {\n  console.log('>> listing (%d) Shortened URLS:', URLsDocument.length);\n  console.log(URLsDocument);\n  process.exit(0);\n}, function(error) {\n  if (error) {\n    throw new Error(error);\n  }\n});\n```\n\n**Updating the URL or the data fields of an existing Short URL hash**\n\n```javascript\n// Basically, update works like this\nvar updatePromise = short.update(hash, updateData);\n// hash => Short url hashcode generated using short.generate()\n// updateData => An object consisting of the new URL and/or the new data object. \n//               If a key already exists in the current data object, it's value is updated, \n//               otherwise, it is added and saved to the data object\n\n//This function returns a promise which on resolution returns the new updated object as an argument.\n```\nHere's some working code. `hash` is assumed to be given \n```javascript\n// The basic Initialisation, Connection, Short URL generation and \n// retrieval remains the same as depicted in previous examples\n\n// the variable hash contains the short url hash code generated using short.generate()\nvar updatePromise = short.update(hash,{\n  URL : 'http://www.youtube.com/watch?v=qvsgGtivCgs',\n  data: {\n    'type' : 'movie-trailer',\n    'movie': 'Back To The Future'\n  }\n});\nupdatePromise.then(function(ShortURLObject) {\n  console.log('New URL:', ShortURLObject.URL, '\\nNew data:', ShortURLObject.data);\n}, function(error) {\n  console.log('Error', error);\n});\n```\n\n## Contribute\n\n  1. Fork\n  2. Clone forked repository\n  3. Add some sweet code\n  4. Tests still passing? Run tests with `npm test`\n  5. Add a test if adding a feature\n  6. Pull Request\n  7. **Instant Karma!**\n\n## License (MIT)\n\nCopyright (c) 2011-2013, Edward Hotchkiss.\n\n### Author: [Edward Hotchkiss][0]\n\n[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/edwardhotchkiss/short/trend.png)](https://bitdeli.com/free \"Bitdeli Badge\")\n\n[0]: http://edwardhotchkiss.com/\n"
  },
  {
    "path": "examples/generate-retrieve.js",
    "content": "\n/**\n * @example generates a shortened url, then fetches it\n * back from mongodb data store\n */\n\nvar shortURLPromise\n  , short = require('../lib/short');\n\n// connect to mongodb\nshort.connect('mongodb://localhost/short');\n\nshort.connection.on('error', function(error) {\n  throw new Error(error);\n});\n\n// promise to generate a shortened URL.\nvar shortURLPromise = short.generate({\n  URL : 'http://nodejs.org/'\n});\n\n// gets back the short url document, and then retrieves it\nshortURLPromise.then(function(mongodbDoc) {\n  console.log('>> created short URL:');\n  console.log(mongodbDoc);\n  console.log('>> retrieving short URL: %s', mongodbDoc.hash);\n  short.retrieve(mongodbDoc.hash).then(function(result) {\n    console.log('>> retrieve result:');\n    console.log(result);\n    process.exit(0);\n  }, function(error) {\n    if (error) {\n      throw new Error(error);\n    }\n  });\n}, function(error) {\n  if (error) {\n    throw new Error(error);\n  }\n});\n"
  },
  {
    "path": "examples/list-all.js",
    "content": "\n/**\n * @example lists all shortened urls in db\n */\n\nvar listURLsPromise\n  , short = require('../lib/short');\n\n// connect to mongodb\nshort.connect('mongodb://localhost/short');\n\nshort.connection.on('error', function(error) {\n  throw new Error(error);\n});\n\n// promise to retrieve all shortened URLs\nlistURLsPromise = short.list();\n\n// output all resulting shortened url db docs\nlistURLsPromise.then(function(URLsDocument) {\n  console.log('>> listing (%d) Shortened URLS:', URLsDocument.length);\n  console.log(URLsDocument);\n  process.exit(0);\n}, function(error) {\n  if (error) {\n    throw new Error(error);\n  }\n});\n"
  },
  {
    "path": "lib/short.js",
    "content": "/**\n * @list dependencies\n */\n\nvar ID = require('short-id')\n  , mongoose = require('mongoose')\n  , Promise = require('node-promise').Promise\n  , ShortURL = require('../models/ShortURL').ShortURL;\n\n/**\n * @configure short-id\n */\n\nID.configure({\n  length: 6,\n  algorithm: 'sha1',\n  salt: Math.random\n});\n\n/**\n * @method connect\n * @param {String} mongdb Mongo DB String to connect to\n */\n\nexports.connect = function(mongodb) {\n  if (mongoose.connection.readyState === 0)\n    mongoose.connect(mongodb);\n\n  exports.connection = mongoose.connection;\n};\n\n/**\n * @method generate\n * @param {Object} options Must at least include a `URL` attribute\n */\n\nexports.generate = function(document) {\n  var generatePromise\n    , promise = new Promise();\n\n  document['data'] = document.data || null;\n\n  // hash was specified, so we should always honor it\n  if (document.hasOwnProperty('hash')) {\n    generatePromise = ShortURL.create(document);\n  } else {\n    document['hash'] = ID.store(document.URL);\n    generatePromise = ShortURL.findOrCreate({URL : document.URL}, document, {});\n  }\n\n  generatePromise.then(function(ShortURLObject) {\n    promise.resolve(ShortURLObject);\n  }, function(error) {\n    promise.reject(error, true);\n  });\n\n  return promise;\n};\n\n/**\n * @method retrieve\n * @param {Object} options Must at least include a `hash` attribute\n */\n\nexports.retrieve = function(hash) {\n  var promise = new Promise();\n  var query = { hash : hash }\n    , update = { $inc: { hits: 1 } }\n    , options = { multi: true };\n  var retrievePromise = ShortURL.findOne(query);\n  ShortURL.update( query, update , options , function (){ } );\n  retrievePromise.then(function(ShortURLObject) {\n    if (ShortURLObject && ShortURLObject !== null) {\n      promise.resolve(ShortURLObject);\n    } else {\n      promise.reject(new Error('MongoDB - Cannot find Document'), true);\n    };\n  }, function(error) {\n    promise.reject(error, true);\n  });\n  return promise;\n};\n\n/**\n * @method update\n * @param {String} hash - must include a `hash` attribute\n * @param {Object} updates - must include either a `URL` or `data` attribute\n */\n\nexports.update = function(hash, updates) {\n  var promise = new Promise();\n  ShortURL.findOne({hash: hash}, function(err, doc) {\n    if (updates.URL) {\n      doc.URL = updates.URL;\n    }\n    if (updates.data) {\n      doc.data = extend(doc.data, updates.data);\n      doc.markModified('data'); //Required by mongoose, as data is of Mixed type\n    }\n    doc.save(function(err, updatedObj, numAffected) {\n      if (err) {\n        promise.reject(new Error('MongoDB - Cannot save updates'), true);\n      } else {\n        promise.resolve(updatedObj);\n      }\n    });\n  });\n  return promise;\n};\n\n/**\n * @method hits\n * @param {Object} options Must at least include a `hash` attribute\n */\n\nexports.hits = function(hash) {\n  var promise = new Promise();\n  var query = { hash : hash }\n    , options = { multi: true };\n  var retrievePromise = ShortURL.findOne(query);\n  retrievePromise.then(function(ShortURLObject) {\n    if (ShortURLObject && ShortURLObject !== null) {\n      promise.resolve(ShortURLObject.hits);\n    } else {\n      promise.reject(new Error('MongoDB - Cannot find Document'), true);\n    };\n  }, function(error) {\n    promise.reject(error, true);\n  });\n  return promise;\n};\n\n/**\n * @method list\n * @description List all Shortened URLs\n */\n\nexports.list = function() {\n  return ShortURL.find({});\n};\n\n/**\n * @method extend\n * @description Private function to extend objects\n * @param {Object} original The original object to extend\n * @param {Object} updated The updates; new keys are added, existing updated\n */\n\nvar extend = function(original, updates) {\n  Object.keys(updates).forEach(function(key) {\n    original[key] = updates[key];\n  });\n  return original;\n};\n"
  },
  {
    "path": "models/ShortURL.js",
    "content": "\n/**\n * @model ShortURL\n */\n\nvar options\n  , ShortURLSchema\n  , mongoose = require('mongoose')\n  , wrapper = require('./prototype.js')\n  , Schema = mongoose.Schema\n  , ObjectId = Schema.ObjectId;\n\noptions = { \n  versionKey : false\n};\n\nShortURLSchema = new Schema({\n  id         : { type : ObjectId },\n  URL        : { type : String, unique: false },\n  hash       : { type : String, unique: true },\n  hits       : { type : Number, default: 0 },\n  data       : { type : Schema.Types.Mixed },\n  created_at : { type : Date, default: Date.now },\n}, options);\n\nexports.ShortURL = new wrapper.Model(mongoose.model('ShortURL', ShortURLSchema));\n"
  },
  {
    "path": "models/prototype.js",
    "content": "\n/**\n * @list dependencies\n */\n\nvar Promise = require('node-promise').Promise;\n\n/**\n * @description wrapper for models to return promises versus executing immediately\n */\n\nexports.Model = function(mongooseModel) {\n  this.baseModel = mongooseModel;\n};\n\n/**\n * @method find\n * @description wraps mongodb find with a promise\n */\n\nexports.Model.prototype.find = function(query, fields, options) {\n  var promise = new Promise();\n  this.baseModel.find(query, fields, options, function(error, result) {\n    if (error) {\n      promise.reject(error, true);\n    } else {\n      promise.resolve(result);\n    };\n  });\n  return promise;\n};\n\n/**\n * @method findOne\n * @description wraps mongodb findOne with a promise\n */\n\nexports.Model.prototype.findOne = function(query, fields, options) {\n  var promise = new Promise();\n  this.baseModel.findOne(query, fields, options, function(error, result) {\n    if (error) {\n      promise.reject(error, true);\n    } else {\n      promise.resolve(result);\n    };\n  });\n  return promise;\n};\n\n/**\n * @method update\n * @description wraps mongodb update with a promise\n */\n\nexports.Model.prototype.update = function(query, document, options) {\n  var promise = new Promise()\n  this.baseModel.update(query, document, options, function(error, affected) {\n    if (error) {\n      promise.reject(error, true);\n    } else {\n      if (affected === 0) {\n        promise.reject(new Error('MongoDB - Cannot find Document'), true);\n      } else {\n        promise.resolve();\n      };\n    };\n  });\n  return promise;\n};\n\n/**\n * @method create\n * @description wraps mongodb create with a promise\n */\n\nexports.Model.prototype.create = function(data) {\n  var promise = new Promise();\n  this.baseModel.create(data, function(error, result) {\n    if (error) {\n      if (error.message && error.message.match(/E11000/i)) {\n        promise.reject(new Error('Duplicate Key Error'), true);\n      } else {\n        promise.reject(error, true)\n      };\n    } else {\n      promise.resolve(result);\n    };\n  });\n  return promise;\n};\n\n/**\n * @method findOrCreate\n * @description searches for a document, otherwise creates it.\n */\n\nexports.Model.prototype.findOrCreate = function(query, document, options) {\n  var promise = new Promise()\n    , baseModel = this;\n  baseModel.findOne(query, function(error, result) {\n    if (error) {\n      if (error.message && error.message.match(/E11000/i)) {\n        promise.reject(new Error('Duplicate Key Error'), true);\n      } else {\n        promise.reject(error, true);\n      };\n    } else {\n      if (result && result !== null) {\n        promise.resolve(result);\n      } else {\n        var createPromise = baseModel.create(document);\n        createPromise.then(function(result) {\n          promise.resolve(result);\n        }, function(error) {\n          promise.reject(error, true);\n        });\n      }\n    };\n  });\n  return promise;\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\":\"short\",\n  \"version\":\"2.6.0\",\n  \"author\":\"Edward Hotchkiss <edward@edwardhotchkiss.com>\",\n  \"description\":\"Node.js URL Shortener backed by Mongoose.js\",\n  \"contributors\":[\n    { \"name\": \"Edward Hotchkiss\", \"email\": \"edward@edwardhotchkiss.com\" },\n    { \"name\": \"Kevin Roth\", \"github\": \"http://github.com/thinkroth\" },\n    { \"name\": \"Chase Brammer\", \"github\":\"https://github.com/cbrammer\" },\n    { \"name\": \"Chris Lynch\", \"github\":\"https://github.com/lynchseattle\" },\n    { \"name\": \"CashLee\", \"github\": \"https://github.com/lbj96347\" },\n    { \"name\": \"Patrick Williams\", \"github\": \"https://github.com/pwmckenna\" },\n    { \"name\": \"Niklas Nihlén\", \"github\": \"https://github.com/nippe\" },\n    { \"name\": \"Matt Roman\", \"github\": \"https://github.com/romanmt\" },\n    { \"name\": \"Jan Paul Erkelens\", \"github\": \"https://github.com/jperkelens\" },\n    { \"name\": \"Tarang Shah\", \"github\": \"https://github.com/t27\" }\n  ],\n  \"homepage\": \"http://edwardhotchkiss.github.com/short\",\n  \"repository\":{\n    \"type\":\"git\",\n    \"url\":\"git://github.com/edwardhotchkiss/short.git\"\n  },\n  \"keywords\":[\"short\",\"url\",\"shortener\",\"tiny\",\"uri\",\"vanity\",\"bit.ly\"],\n  \"main\":\"./lib/short\",\n  \"engines\":{\n    \"node\":\">=0.10.0\"\n  },\n  \"dependencies\":{\n    \"node-promise\":\"0.5.8\",\n    \"mongoose\":\"4.0.6\",\n    \"short-id\":\"0.1.0-1\"\n  },\n  \"devDependencies\":{\n    \"vows\":\"0.7.0\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/edwardhotchkiss/short/issues\"\n  },\n  \"license\":{\n    \"type\":\"MIT\",\n    \"url\":\"http://github.com/edwardhotchkiss/short/LICENSE\"\n  },\n  \"scripts\":{\n    \"test\":\"vows test/*.test.js --spec\"\n  }\n}"
  },
  {
    "path": "test/index.test.js",
    "content": "\n/**\n * @list dependencies\n */\n\nvar vows = require('vows')\n  , assert = require('assert')\n  , mongoose = require('mongoose')\n  , short = require('../lib/short');\n\nmongoose.set('debug', true);\n\n/**\n * @description connect to mongodb\n */\n\nshort.connect('mongodb://localhost/short');\n\n/**\n * @description add suites to vows\n */\n\nvows.describe('general module tests').addBatch({\n\n  'when instantiating short':{\n    topic: function(){\n      return short;\n    },\n    'short should be an object': function(topic) {\n      assert.isObject(topic);\n    }\n  },\n\n  'when creating a short url and then retrieving it':{\n    topic:function() {\n      var context = this;\n      var generatePromise = short.generate({ URL : 'http://nodejs.org/' });\n      generatePromise.then(function(ShortURLObject) {\n        var hash = ShortURLObject.hash\n          , retrievePromise = short.retrieve(hash);\n        retrievePromise.then(function(ShortURLObject) {\n          context.callback(null, ShortURLObject);\n        }, function(error) {\n          context.callback(error, null);\n        })\n      }, function(error) {\n        context.callback(error, null);\n      });\n    },\n    'there should be no errors':function(error, ShortURLObject) {\n      assert.isNull(error);\n    },\n    'shortURL should be defined':function(error, ShortURLObject) {\n      assert.isNotNull(ShortURLObject);\n    },\n    'shortURL should be an object':function(error, ShortURLObject) {\n      assert.isObject(ShortURLObject);\n    },\n    'and shortURL.URL should be \"http://nodejs.org/\"':function(error, ShortURLObject) {\n      assert.equal(ShortURLObject.URL, 'http://nodejs.org/');\n    }\n  },\n\n  'when creating a short url and specify the hash': {\n    topic: function () {\n      var\n        specifiedHash = 'google',\n        context = this;\n      short.generate({\n        hash: specifiedHash,\n        URL: 'https://www.google.com'\n      }).then(function (shortURLObject) {\n          context.callback(null, shortURLObject);\n        }, function (err) {\n          context.callback(err, null);\n        });\n    },\n    'and shortURL.URL should be \"https://www.google.com\"': function (err, shortURLObject) {\n      assert.equal(shortURLObject.URL, 'https://www.google.com');\n    },\n    'and shortURL.hash should match original hash': function (err, shortURLObject) {\n      assert.equal(shortURLObject.hash, 'google');\n    }\n  },\n\n  'when creating a short url for an existing url and specifying the hash': {\n    topic: function () {\n      var context = this, url = 'http://www.nyan.cat/';\n      short.generate({\n        URL: url\n      })\n        .then(function () {\n          return short.generate({\n            hash: 'nyan',\n            URL: url\n          });\n        })\n        .then(function (shortUrlObject) {\n          context.callback(null, shortUrlObject);\n        }, function (err) {\n          context.callback(err, null);\n        });\n    },\n    'shortURL.hash should match the specified hash': function (err, shortURLObject) {\n      assert.equal(shortURLObject.hash, 'nyan');\n    }\n  },\n\n  'when .list()ing Shortened URLs':{\n    topic: function() {\n      var context = this;\n      var listPromise = short.list();\n      listPromise.then(function(URLs) {\n        context.callback(null, URLs);\n      }, function(error) {\n        context.callback(error, null);\n      });\n    },\n    'there should be no errors':function(error, URLs) {\n      assert.isNull(error);\n    },\n    'URLs should be defined':function(error, URLs){\n      assert.isNotNull(URLs);\n    },\n    'and URLs should be an array of objects':function(error, URLs) {\n      assert.isArray(URLs);\n    }\n  },\n\n  'when creating a short url with data, updating and retrieving it':{\n    topic:function() {\n      var context = this;\n      var generatePromise = short.generate({\n        URL : 'https://www.youtube.com/watch?v=qvsgGtivCgs',\n        data: {\n          'type':'trailer'\n        }\n       });\n      generatePromise.then(function(ShortURLObject) {\n        var updatePromise = short.update(ShortURLObject.hash,{\n          URL : 'http://www.youtube.com/watch?v=qvsgGtivCgs',\n          data: {\n            'type' : 'movie-trailer',\n            'movie': 'Back To The Future'\n          }\n        });\n        updatePromise.then(function(updatedObject) {\n          retrievePromise = short.retrieve(updatedObject.hash);\n          retrievePromise.then(function(ShortURLObject) {\n            context.callback(null, ShortURLObject);\n          }, function(error) {\n            context.callback(error, null);\n          });\n        }, function(error) {\n          context.callback(error, null);\n        });\n      }, function(error) {\n        context.callback(error, null);\n      });\n    },\n    'there should be no errors':function(error, ShortURLObject) {\n      assert.isNull(error);\n    },\n    'shortURL should be defined':function(error, ShortURLObject) {\n      assert.isNotNull(ShortURLObject);\n    },\n    'shortURL should be an object':function(error, ShortURLObject) {\n      assert.isObject(ShortURLObject);\n    },\n    'shortURL.URL should be \"http://www.youtube.com/watch?v=qvsgGtivCgs\"':function(error, ShortURLObject) {\n      assert.equal(ShortURLObject.URL, 'http://www.youtube.com/watch?v=qvsgGtivCgs');\n    },\n    'shortURL.data.type should be movie-trailer':function(error, ShortURLObject) {\n      assert.equal(ShortURLObject.data.type, 'movie-trailer');\n    },\n    'shortURL.data.movie should be Back To The Future':function(error, ShortURLObject) {\n      assert.equal(ShortURLObject.data.movie, 'Back To The Future');\n    },\n  },\n\n}).export(module);\n"
  }
]