text: (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pouchdbFind = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
  'use strict';
  
  var upsert = _dereq_(4);
  var utils = _dereq_(5);
  var Promise = utils.Promise;
  
  function stringify(input) {
    if (!input) {
      return 'undefined'; // backwards compat for empty reduce
    }
    // for backwards compat with mapreduce, functions/strings are stringified
    // as-is. everything else is JSON-stringified.
    switch (typeof input) {
      case 'function':
        // e.g. a mapreduce map
        return input.toString();
      case 'string':
        // e.g. a mapreduce built-in _reduce function
        return input.toString();
      default:
        // e.g. a JSON object in the case of mango queries
        return JSON.stringify(input);
    }
  }
  
  module.exports = function (opts) {
    var sourceDB = opts.db;
    var viewName = opts.viewName;
    var mapFun = opts.map;
    var reduceFun = opts.reduce;
    var temporary = opts.temporary;
    var pluginName = opts.pluginName;
  
    // the "undefined" part is for backwards compatibility
    var viewSignature = stringify(mapFun) + stringify(reduceFun) +
      'undefined';
  
    if (!temporary && sourceDB._cachedViews) {
      var cachedView = sourceDB._cachedViews[viewSignature];
      if (cachedView) {
        return Promise.resolve(cachedView);
      }
    }
  
    return sourceDB.info().then(function (info) {
  
      var depDbName = info.db_name + '-mrview-' +
        (temporary ? 'temp' : utils.MD5(viewSignature));
  
      // save the view name in the source PouchDB so it can be cleaned up if necessary
      // (e.g. when the _design doc is deleted, remove all associated view data)
      function diffFunction(doc) {
        doc.views = doc.views || {};
        var fullViewName = viewName;
        if (fullViewName.indexOf('/') === -1) {
          fullViewName = viewName + '/' + viewName;
        }
        var depDbs = doc.views[fullViewName] = doc.views[fullViewName] || {};
        /* istanbul ignore if */
        if (depDbs[depDbName]) {
          return; // no update necessary
        }
        depDbs[depDbName] = true;
        return doc;
      }
      return upsert(sourceDB, '_local/' + pluginName, diffFunction).then(function () {
        return sourceDB.registerDependentDatabase(depDbName).then(function (res) {
          var db = res.db;
          db.auto_compaction = true;
          var view = {
            name: depDbName,
            db: db, 
            sourceDB: sourceDB,
            adapter: sourceDB.adapter,
            mapFun: mapFun,
            reduceFun: reduceFun
          };
          return view.db.get('_local/lastSeq')["catch"](function (err) {
            /* istanbul ignore if */
            if (err.status !== 404) {
              throw err;
            }
          }).then(function (lastSeqDoc) {
            view.seq = lastSeqDoc ? lastSeqDoc.seq : 0;
            if (!temporary) {
              sourceDB._cachedViews = sourceDB._cachedViews || {};
              sourceDB._cachedViews[viewSignature] = view;
              view.db.on('destroyed', function () {
                delete sourceDB._cachedViews[viewSignature];
              });
            }
            return view;
          });
        });
      });
    });
  };
  
  },{"4":4,"5":5}],2:[function(_dereq_,module,exports){
  (function (process){
  'use strict';
  
  var pouchCollate = _dereq_(27);
  var TaskQueue = _dereq_(3);
  var collate = pouchCollate.collate;
  var toIndexableString = pouchCollate.toIndexableString;
  var normalizeKey = pouchCollate.normalizeKey;
  var createView = _dereq_(1);
  var log;
  /* istanbul ignore else */
  if ((typeof console !== 'undefined') && (typeof console.log === 'function')) {
    log = Function.prototype.bind.call(console.log, console);
  } else {
    log = function () {};
  }
  var utils = _dereq_(5);
  var Promise = utils.Promise;
  var persistentQueues = {};
  var tempViewQueue = new TaskQueue();
  var CHANGES_BATCH_SIZE = 50;
  
  function QueryParseError(message) {
    this.status = 400;
    this.name = 'query_parse_error';
    this.message = message;
    this.error = true;
    try {
      Error.captureStackTrace(this, QueryParseError);
    } catch (e) {}
  }
  
  utils.inherits(QueryParseError, Error);
  
  function NotFoundError(message) {
    this.status = 404;
    this.name = 'not_found';
    this.message = message;
    this.error = true;
    try {
      Error.captureStackTrace(this, NotFoundError);
    } catch (e) {}
  }
  
  utils.inherits(NotFoundError, Error);
  
  function parseViewName(name) {
    // can be either 'ddocname/viewname' or just 'viewname'
    // (where the ddoc name is the same)
    return name.indexOf('/') === -1 ? [name, name] : name.split('/');
  }
  
  function isGenOne(changes) {
    // only return true if the current change is 1-
    // and there are no other leafs
    return changes.length === 1 && /^1-/.test(changes[0].rev);
  }
  
  function sortByKeyThenValue(x, y) {
    var keyCompare = collate(x.key, y.key);
    return keyCompare !== 0 ? keyCompare : collate(x.value, y.value);
  }
  
  function sliceResults(results, limit, skip) {
    skip = skip || 0;
    if (typeof limit === 'number') {
      return results.slice(skip, limit + skip);
    } else if (skip > 0) {
      return results.slice(skip);
    }
    return results;
  }
  
  function rowToDocId(row) {
    var val = row.value;
    // Users can explicitly specify a joined doc _id, or it
    // defaults to the doc _id that emitted the key/value.
    var docId = (val && typeof val === 'object' && val._id) || row.id;
    return docId;
  }
  
  function emitError(db, e) {
    try {
      db.emit('error', e);
    } catch (err) {
      console.error(
        'The user\'s map/reduce function threw an uncaught error.\n' +
        'You can debug this error by doing:\n' +
        'myDatabase.on(\'error\', function (err) { debugger; });\n' +
        'Please double-check your map/reduce function.');
      console.error(e);
    }
  }
  
  function tryCode(db, fun, args) {
    // emit an event if there was an error thrown by a map/reduce function.
    // putting try/catches in a single function also avoids deoptimizations.
    try {
      return {
        output : fun.apply(null, args)
      };
    } catch (e) {
      emitError(db, e);
      return {error: e};
    }
  }
  
  function checkQueryParseError(options, fun) {
    var startkeyName = options.descending ? 'endkey' : 'startkey';
    var endkeyName = options.descending ? 'startkey' : 'endkey';
  
    if (typeof options[startkeyName] !== 'undefined' &&
      typeof options[endkeyName] !== 'undefined' &&
      collate(options[startkeyName], options[endkeyName]) > 0) {
      throw new QueryParseError('No rows can match your key range, reverse your ' +
      'start_key and end_key or set {descending : true}');
    } else if (fun.reduce && options.reduce !== false) {
      if (options.include_docs) {
        throw new QueryParseError('{include_docs:true} is invalid for reduce');
      } else if (options.keys && options.keys.length > 1 &&
        !options.group && !options.group_level) {
        throw new QueryParseError('Multi-key fetches for reduce views must use {group: true}');
      }
    }
    if (options.group_level) {
      if (typeof options.group_level !== 'number') {
        throw new QueryParseError('Invalid value for integer: "' + options.group_level + '"');
      }
      if (options.group_level < 0) {
        throw new QueryParseError('Invalid value for positive integer: ' +
        '"' + options.group_level + '"');
      }
    }
  }
  
  function defaultsTo(value) {
    return function (reason) {
      /* istanbul ignore else */
      if (reason.status === 404) {
        return value;
      } else {
        throw reason;
      }
    };
  }
  
  function createIndexer(def) {
  
    var pluginName = def.name;
    var mapper = def.mapper;
    var reducer = def.reducer;
    var ddocValidator = def.ddocValidator;
  
  
    // returns a promise for a list of docs to update, based on the input docId.
    // the order doesn't matter, because post-3.2.0, bulkDocs
    // is an atomic operation in all three adapters.
    function getDocsToPersist(docId, view, docIdsToChangesAndEmits) {
      var metaDocId = '_local/doc_' + docId;
      var defaultMetaDoc = {_id: metaDocId, keys: []};
      var docData = docIdsToChangesAndEmits[docId];
      var indexableKeysToKeyValues = docData.indexableKeysToKeyValues;
      var changes = docData.changes;
  
      function getMetaDoc() {
        if (isGenOne(changes)) {
          // generation 1, so we can safely assume initial state
          // for performance reasons (avoids unnecessary GETs)
          return Promise.resolve(defaultMetaDoc);
        }
        return view.db.get(metaDocId)["catch"](defaultsTo(defaultMetaDoc));
      }
  
      function getKeyValueDocs(metaDoc) {
        if (!metaDoc.keys.length) {
          // no keys, no need for a lookup
          return Promise.resolve({rows: []});
        }
        return view.db.allDocs({
          keys: metaDoc.keys,
          include_docs: true
        });
      }
  
      function processKvDocs(metaDoc, kvDocsRes) {
        var kvDocs = [];
        var oldKeysMap = {};
  
        for (var i = 0, len = kvDocsRes.rows.length; i < len; i++) {
          var row = kvDocsRes.rows[i];
          var doc = row.doc;
          if (!doc) { // deleted
            continue;
          }
          kvDocs.push(doc);
          oldKeysMap[doc._id] = true;
          doc._deleted = !indexableKeysToKeyValues[doc._id];
          if (!doc._deleted) {
            var keyValue = indexableKeysToKeyValues[doc._id];
            if ('value' in keyValue) {
              doc.value = keyValue.value;
            }
          }
        }
  
        var newKeys = Object.keys(indexableKeysToKeyValues);
        newKeys.forEach(function (key) {
          if (!oldKeysMap[key]) {
            // new doc
            var kvDoc = {
              _id: key
            };
            var keyValue = indexableKeysToKeyValues[key];
            if ('value' in keyValue) {
              kvDoc.value = keyValue.value;
            }
            kvDocs.push(kvDoc);
          }
        });
        metaDoc.keys = utils.uniq(newKeys.concat(metaDoc.keys));
        kvDocs.push(metaDoc);
  
        return kvDocs;
      }
  
      return getMetaDoc().then(function (metaDoc) {
        return getKeyValueDocs(metaDoc).then(function (kvDocsRes) {
          return processKvDocs(metaDoc, kvDocsRes);
        });
      });
    }
  
    // updates all emitted key/value docs and metaDocs in the mrview database
    // for the given batch of documents from the source database
    function saveKeyValues(view, docIdsToChangesAndEmits, seq) {
      var seqDocId = '_local/lastSeq';
      return view.db.get(seqDocId)[
      "catch"](defaultsTo({_id: seqDocId, seq: 0}))
      .then(function (lastSeqDoc) {
        var docIds = Object.keys(docIdsToChangesAndEmits);
        return Promise.all(docIds.map(function (docId) {
          return getDocsToPersist(docId, view, docIdsToChangesAndEmits);
        })).then(function (listOfDocsToPersist) {
          var docsToPersist = utils.flatten(listOfDocsToPersist);
          lastSeqDoc.seq = seq;
          docsToPersist.push(lastSeqDoc);
          // write all docs in a single operation, update the seq once
          return view.db.bulkDocs({docs : docsToPersist});
        });
      });
    }
  
    function getQueue(view) {
      var viewName = typeof view === 'string' ? view : view.name;
      var queue = persistentQueues[viewName];
      if (!queue) {
        queue = persistentQueues[viewName] = new TaskQueue();
      }
      return queue;
    }
  
    function updateView(view) {
      return utils.sequentialize(getQueue(view), function () {
        return updateViewInQueue(view);
      })();
    }
  
    function updateViewInQueue(view) {
      // bind the emit function once
      var mapResults;
      var doc;
  
      function emit(key, value) {
        var output = {id: doc._id, key: normalizeKey(key)};
        // Don't explicitly store the value unless it's defined and non-null.
        // This saves on storage space, because often people don't use it.
        if (typeof value !== 'undefined' && value !== null) {
          output.value = normalizeKey(value);
        }
        mapResults.push(output);
      }
  
      var mapFun = mapper(view.mapFun, emit);
  
      var currentSeq = view.seq || 0;
  
      function processChange(docIdsToChangesAndEmits, seq) {
        return function () {
          return saveKeyValues(view, docIdsToChangesAndEmits, seq);
        };
      }
  
      var queue = new TaskQueue();
  
      return new Promise(function (resolve, reject) {
  
        function complete() {
          queue.finish().then(function () {
            view.seq = currentSeq;
            resolve();
          });
        }
  
        function processNextBatch() {
          view.sourceDB.changes({
            conflicts: true,
            include_docs: true,
            style: 'all_docs',
            since: currentSeq,
            limit: CHANGES_BATCH_SIZE
          }).on('complete', function (response) {
            var results = response.results;
            if (!results.length) {
              return complete();
            }
            var docIdsToChangesAndEmits = {};
            for (var i = 0, l = results.length; i < l; i++) {
              var change = results[i];
              if (change.doc._id[0] !== '_') {
                mapResults = [];
                doc = change.doc;
  
                if (!doc._deleted) {
                  tryCode(view.sourceDB, mapFun, [doc]);
                }
                mapResults.sort(sortByKeyThenValue);
  
                var indexableKeysToKeyValues = {};
                var lastKey;
                for (var j = 0, jl = mapResults.length; j < jl; j++) {
                  var obj = mapResults[j];
                  var complexKey = [obj.key, obj.id];
                  if (collate(obj.key, lastKey) === 0) {
                    complexKey.push(j); // dup key+id, so make it unique
                  }
                  var indexableKey = toIndexableString(complexKey);
                  indexableKeysToKeyValues[indexableKey] = obj;
                  lastKey = obj.key;
                }
                docIdsToChangesAndEmits[change.doc._id] = {
                  indexableKeysToKeyValues: indexableKeysToKeyValues,
                  changes: change.changes
                };
              }
              currentSeq = change.seq;
            }
            queue.add(processChange(docIdsToChangesAndEmits, currentSeq));
            if (results.length < CHANGES_BATCH_SIZE) {
              return complete();
            }
            return processNextBatch();
          }).on('error', onError);
          /* istanbul ignore next */
          function onError(err) {
            reject(err);
          }
        }
  
        processNextBatch();
      });
    }
  
    function reduceView(view, results, options) {
      if (options.group_level === 0) {
        delete options.group_level;
      }
  
      var shouldGroup = options.group || options.group_level;
  
      var reduceFun = reducer(view.reduceFun);
  
      var groups = [];
      var lvl = options.group_level;
      results.forEach(function (e) {
        var last = groups[groups.length - 1];
        var key = shouldGroup ? e.key : null;
  
        // only set group_level for array keys
        if (shouldGroup && Array.isArray(key) && typeof lvl === 'number') {
          key = key.length > lvl ? key.slice(0, lvl) : key;
        }
  
        if (last && collate(last.key[0][0], key) === 0) {
          last.key.push([key, e.id]);
          last.value.push(e.value);
          return;
        }
        groups.push({key: [
          [key, e.id]
        ], value: [e.value]});
      });
      for (var i = 0, len = groups.length; i < len; i++) {
        var e = groups[i];
        var reduceTry = tryCode(view.sourceDB, reduceFun, [e.key, e.value, false]);
        // TODO: can't do instanceof BuiltInError because this class is buried
        // in mapreduce.js
        if (reduceTry.error && /BuiltInError/.test(reduceTry.error.constructor)) {
          // CouchDB returns an error if a built-in errors out
          throw reduceTry.error;
        }
        // CouchDB just sets the value to null if a non-built-in errors out
        e.value = reduceTry.error ? null : reduceTry.output;
        e.key = e.key[0][0];
      }
      // no total_rows/offset when reducing
      return {rows: sliceResults(groups, options.limit, options.skip)};
    }
  
    function queryView(view, opts) {
      return utils.sequentialize(getQueue(view), function () {
        return queryViewInQueue(view, opts);
      })();
    }
  
    function queryViewInQueue(view, opts) {
      var totalRows;
      var shouldReduce = view.reduceFun && opts.reduce !== false;
      var skip = opts.skip || 0;
      if (typeof opts.keys !== 'undefined' && !opts.keys.length) {
        // equivalent query
        opts.limit = 0;
        delete opts.keys;
      }
  
      function fetchFromView(viewOpts) {
        viewOpts.include_docs = true;
        return view.db.allDocs(viewOpts).then(function (res) {
          totalRows = res.total_rows;
          return res.rows.map(function (result) {
  
            // implicit migration - in older versions of PouchDB,
            // we explicitly stored the doc as {id: ..., key: ..., value: ...}
            // this is tested in a migration test
            /* istanbul ignore next */
            if ('value' in result.doc && typeof result.doc.value === 'object' &&
                result.doc.value !== null) {
              var keys = Object.keys(result.doc.value).sort();
              // this detection method is not perfect, but it's unlikely the user
              // emitted a value which was an object with these 3 exact keys
              var expectedKeys = ['id', 'key', 'value'];
              if (!(keys < expectedKeys || keys > expectedKeys)) {
                return result.doc.value;
              }
            }
  
            var parsedKeyAndDocId = pouchCollate.parseIndexableString(result.doc._id);
            return {
              key: parsedKeyAndDocId[0],
              id: parsedKeyAndDocId[1],
              value: ('value' in result.doc ? result.doc.value : null)
            };
          });
        });
      }
  
      function onMapResultsReady(rows) {
        var finalResults;
        if (shouldReduce) {
          finalResults = reduceView(view, rows, opts);
        } else {
          finalResults = {
            total_rows: totalRows,
            offset: skip,
            rows: rows
          };
        }
        if (opts.include_docs) {
          var docIds = utils.uniq(rows.map(rowToDocId));
  
          return view.sourceDB.allDocs({
            keys: docIds,
            include_docs: true,
            conflicts: opts.conflicts,
            attachments: opts.attachments,
            binary: opts.binary
          }).then(function (allDocsRes) {
            var docIdsToDocs = {};
            allDocsRes.rows.forEach(function (row) {
              if (row.doc) {
                docIdsToDocs['$' + row.id] = row.doc;
              }
            });
            rows.forEach(function (row) {
              var docId = rowToDocId(row);
              var doc = docIdsToDocs['$' + docId];
              if (doc) {
                row.doc = doc;
              }
            });
            return finalResults;
          });
        } else {
          return finalResults;
        }
      }
  
      var flatten = function (array) {
        return array.reduce(function (prev, cur) {
          return prev.concat(cur);
        });
      };
  
      if (typeof opts.keys !== 'undefined') {
        var keys = opts.keys;
        var fetchPromises = keys.map(function (key) {
          var viewOpts = {
            startkey : toIndexableString([key]),
            endkey   : toIndexableString([key, {}])
          };
          return fetchFromView(viewOpts);
        });
        return Promise.all(fetchPromises).then(flatten).then(onMapResultsReady);
      } else { // normal query, no 'keys'
        var viewOpts = {
          descending : opts.descending
        };
        if (typeof opts.startkey !== 'undefined') {
          viewOpts.startkey = opts.descending ?
            toIndexableString([opts.startkey, {}]) :
            toIndexableString([opts.startkey]);
        }
        if (typeof opts.endkey !== 'undefined') {
          var inclusiveEnd = opts.inclusive_end !== false;
          if (opts.descending) {
            inclusiveEnd = !inclusiveEnd;
          }
  
          viewOpts.endkey = toIndexableString(inclusiveEnd ? [opts.endkey, {}] : [opts.endkey]);
        }
        if (typeof opts.key !== 'undefined') {
          var keyStart = toIndexableString([opts.key]);
          var keyEnd = toIndexableString([opts.key, {}]);
          if (viewOpts.descending) {
            viewOpts.endkey = keyStart;
            viewOpts.startkey = keyEnd;
          } else {
            viewOpts.startkey = keyStart;
            viewOpts.endkey = keyEnd;
          }
        }
        if (!shouldReduce) {
          if (typeof opts.limit === 'number') {
            viewOpts.limit = opts.limit;
          }
          viewOpts.skip = skip;
        }
        return fetchFromView(viewOpts).then(onMapResultsReady);
      }
    }
  
    function localViewCleanup(db) {
      return db.get('_local/' + pluginName).then(function (metaDoc) {
        var docsToViews = {};
        Object.keys(metaDoc.views).forEach(function (fullViewName) {
          var parts = parseViewName(fullViewName);
          var designDocName = '_design/' + parts[0];
          var viewName = parts[1];
          docsToViews[designDocName] = docsToViews[designDocName] || {};
          docsToViews[designDocName][viewName] = true;
        });
        var opts = {
          keys : Object.keys(docsToViews),
          include_docs : true
        };
        return db.allDocs(opts).then(function (res) {
          var viewsToStatus = {};
          res.rows.forEach(function (row) {
            var ddocName = row.key.substring(8);
            Object.keys(docsToViews[row.key]).forEach(function (viewName) {
              var fullViewName = ddocName + '/' + viewName;
              /* istanbul ignore if */
              if (!metaDoc.views[fullViewName]) {
                // new format, without slashes, to support PouchDB 2.2.0
                // migration test in pouchdb's browser.migration.js verifies this
                fullViewName = viewName;
              }
              var viewDBNames = Object.keys(metaDoc.views[fullViewName]);
              // design doc deleted, or view function nonexistent
              var statusIsGood = row.doc && row.doc.views && row.doc.views[viewName];
              viewDBNames.forEach(function (viewDBName) {
                viewsToStatus[viewDBName] = viewsToStatus[viewDBName] || statusIsGood;
              });
            });
          });
          var dbsToDelete = Object.keys(viewsToStatus).filter(function (viewDBName) {
            return !viewsToStatus[viewDBName];
          });
          var destroyPromises = dbsToDelete.map(function (viewDBName) {
            return utils.sequentialize(getQueue(viewDBName), function () {
              return new db.constructor(viewDBName, db.__opts).destroy();
            })();
          });
          return Promise.all(destroyPromises).then(function () {
            return {ok: true};
          });
        });
      }, defaultsTo({ok: true}));
    }
  
    function queryPromised(db, fun, opts) {
      if (typeof fun !== 'string') {
        // temp_view
        checkQueryParseError(opts, fun);
  
        var createViewOpts = {
          db : db,
          viewName : 'temp_view/temp_view',
          map : fun.map,
          reduce : fun.reduce,
          temporary : true,
          pluginName: pluginName
        };
        tempViewQueue.add(function () {
          return createView(createViewOpts).then(function (view) {
            function cleanup() {
              return view.db.destroy();
            }
            return utils.fin(updateView(view).then(function () {
              return queryView(view, opts);
            }), cleanup);
          });
        });
        return tempViewQueue.finish();
      } else {
        // persistent view
        var fullViewName = fun;
        var parts = parseViewName(fullViewName);
        var designDocName = parts[0];
        var viewName = parts[1];
        return db.get('_design/' + designDocName).then(function (doc) {
          var fun = doc.views && doc.views[viewName];
  
          if (!fun) {
            // basic validator; it's assumed that every subclass would want this
            throw new NotFoundError('ddoc ' + doc._id + ' has no view named ' +
              viewName);
          }
  
          ddocValidator(doc, viewName);
          checkQueryParseError(opts, fun);
  
          var createViewOpts = {
            db : db,
            viewName : fullViewName,
            map : fun.map,
            reduce : fun.reduce,
            pluginName: pluginName
          };
          return createView(createViewOpts).then(function (view) {
            if (opts.stale === 'ok' || opts.stale === 'update_after') {
              if (opts.stale === 'update_after') {
                process.nextTick(function () {
                  updateView(view);
                });
              }
              return queryView(view, opts);
            } else { // stale not ok
              return updateView(view).then(function () {
                return queryView(view, opts);
              });
            }
          });
        });
      }
    }
  
    var query = function (fun, opts, callback) {
      var db = this;
      if (typeof opts === 'function') {
        callback = opts;
        opts = {};
      }
      opts = utils.extend(true, {}, opts);
  
      if (typeof fun === 'function') {
        fun = {map : fun};
      }
  
      var promise = Promise.resolve().then(function () {
        return queryPromised(db, fun, opts);
      });
      utils.promisedCallback(promise, callback);
      return promise;
    };
  
    var viewCleanup = utils.callbackify(function () {
      var db = this;
      return localViewCleanup(db);
    });
  
    return {
      query: query,
      viewCleanup: viewCleanup
    };
  }
  
  module.exports = createIndexer;
  
  }).call(this,_dereq_(33))
  },{"1":1,"27":27,"3":3,"33":33,"5":5}],3:[function(_dereq_,module,exports){
  'use strict';
  /*
   * Simple task queue to sequentialize actions. Assumes callbacks will eventually fire (once).
   */
  
  var Promise = _dereq_(5).Promise;
  
  function TaskQueue() {
    this.promise = new Promise(function (fulfill) {fulfill(); });
  }
  TaskQueue.prototype.add = function (promiseFactory) {
    this.promise = this.promise["catch"](function () {
      // just recover
    }).then(function () {
      return promiseFactory();
    });
    return this.promise;
  };
  TaskQueue.prototype.finish = function () {
    return this.promise;
  };
  
  module.exports = TaskQueue;
  
  },{"5":5}],4:[function(_dereq_,module,exports){
  'use strict';
  
  var upsert = _dereq_(31).upsert;
  
  module.exports = function (db, doc, diffFun) {
    return upsert.apply(db, [doc, diffFun]);
  };
  },{"31":31}],5:[function(_dereq_,module,exports){
  (function (process){
  'use strict';
  /* istanbul ignore if */
  exports.Promise = _dereq_(30);
  
  exports.inherits = _dereq_(23);
  exports.extend = _dereq_(29);
  var argsarray = _dereq_(18);
  
  /* istanbul ignore next */
  exports.promisedCallback = function (promise, callback) {
    if (callback) {
      promise.then(function (res) {
        process.nextTick(function () {
          callback(null, res);
        });
      }, function (reason) {
        process.nextTick(function () {
          callback(reason);
        });
      });
    }
    return promise;
  };
  
  /* istanbul ignore next */
  exports.callbackify = function (fun) {
    return argsarray(function (args) {
      var cb = args.pop();
      var promise = fun.apply(this, args);
      if (typeof cb === 'function') {
        exports.promisedCallback(promise, cb);
      }
      return promise;
    });
  };
  
  // Promise finally util similar to Q.finally
  /* istanbul ignore next */
  exports.fin = function (promise, cb) {
    return promise.then(function (res) {
      var promise2 = cb();
      if (typeof promise2.then === 'function') {
        return promise2.then(function () {
          return res;
        });
      }
      return res;
    }, function (reason) {
      var promise2 = cb();
      if (typeof promise2.then === 'function') {
        return promise2.then(function () {
          throw reason;
        });
      }
      throw reason;
    });
  };
  
  exports.sequentialize = function (queue, promiseFactory) {
    return function () {
      var args = arguments;
      var that = this;
      return queue.add(function () {
        return promiseFactory.apply(that, args);
      });
    };
  };
  
  exports.flatten = function (arrs) {
    var res = [];
    for (var i = 0, len = arrs.length; i < len; i++) {
      res = res.concat(arrs[i]);
    }
    return res;
  };
  
  // uniq an array of strings, order not guaranteed
  // similar to underscore/lodash _.uniq
  exports.uniq = function (arr) {
    var map = {};
  
    for (var i = 0, len = arr.length; i < len; i++) {
      map['$' + arr[i]] = true;
    }
  
    var keys = Object.keys(map);
    var output = new Array(keys.length);
  
    for (i = 0, len = keys.length; i < len; i++) {
      output[i] = keys[i].substring(1);
    }
    return output;
  };
  
  var crypto = _dereq_(19);
  var Md5 = _dereq_(34);
  
  exports.MD5 = function (string) {
    /* istanbul ignore else */
    if (!process.browser) {
      return crypto.createHash('md5').update(string).digest('hex');
    } else {
      return Md5.hash(string);
    }
  };
  }).call(this,_dereq_(33))
  },{"18":18,"19":19,"23":23,"29":29,"30":30,"33":33,"34":34}],6:[function(_dereq_,module,exports){
  'use strict';
  
  var massageCreateIndexRequest = _dereq_(16);
  
  function createIndex(db, requestDef, callback) {
    requestDef = massageCreateIndexRequest(requestDef);
  
    db.request({
      method: 'POST',
      url: '_index',
      body: requestDef
    }, callback);
  }
  
  function find(db, requestDef, callback) {
    db.request({
      method: 'POST',
      url: '_find',
      body: requestDef
    }, callback);
  }
  
  function getIndexes(db, callback) {
    db.request({
      method: 'GET',
      url: '_index'
    }, callback);
  }
  
  function deleteIndex(db, indexDef, callback) {
  
  
    var ddoc = indexDef.ddoc;
    var type = indexDef.type || 'json';
    var name = indexDef.name;
  
    if (!ddoc) {
      return callback(new Error('you must provide an index\'s ddoc'));
    }
  
    if (!name) {
      return callback(new Error('you must provide an index\'s name'));
    }
  
    var url = '_index/' + [ddoc, type, name].map(encodeURIComponent).join('/');
  
    db.request({
      method: 'DELETE',
      url: url
    }, callback);
  }
  
  exports.createIndex = createIndex;
  exports.find = find;
  exports.getIndexes = getIndexes;
  exports.deleteIndex = deleteIndex;
  },{"16":16}],7:[function(_dereq_,module,exports){
  'use strict';
  
  var localUtils = _dereq_(15);
  var abstractMapReduce = _dereq_(2);
  var parseField = localUtils.parseField;
  
  //
  // One thing about these mappers:
  //
  // Per the advice of John-David Dalton (http://youtu.be/NthmeLEhDDM),
  // what you want to do in this case is optimize for the smallest possible
  // function, since that's the thing that gets run over and over again.
  //
  // This code would be a lot simpler if all the if/elses were inside
  // the function, but it would also be a lot less performant.
  //
  
  
  function createDeepMultiMapper(fields, emit) {
    return function (doc) {
      var toEmit = [];
      for (var i = 0, iLen = fields.length; i < iLen; i++) {
        var parsedField = parseField(fields[i]);
        var value = doc;
        for (var j = 0, jLen = parsedField.length; j < jLen; j++) {
          var key = parsedField[j];
          value = value[key];
          if (!value) {
            break;
          }
        }
        toEmit.push(value);
      }
      emit(toEmit);
    };
  }
  
  function createDeepSingleMapper(field, emit) {
    var parsedField = parseField(field);
    return function (doc) {
      var value = doc;
      for (var i = 0, len = parsedField.length; i < len; i++) {
        var key = parsedField[i];
        value = value[key];
        if (!value) {
          return; // do nothing
        }
      }
      emit(value);
    };
  }
  
  function createShallowSingleMapper(field, emit) {
    return function (doc) {
      emit(doc[field]);
    };
  }
  
  function createShallowMultiMapper(fields, emit) {
    return function (doc) {
      var toEmit = [];
      for (var i = 0, len = fields.length; i < len; i++) {
        toEmit.push(doc[fields[i]]);
      }
      emit(toEmit);
    };
  }
  
  function checkShallow(fields) {
    for (var i = 0, len = fields.length; i < len; i++) {
      var field = fields[i];
      if (field.indexOf('.') !== -1) {
        return false;
      }
    }
    return true;
  }
  
  function createMapper(fields, emit) {
    var isShallow = checkShallow(fields);
    var isSingle = fields.length === 1;
  
    // notice we try to optimize for the most common case,
    // i.e. single shallow indexes
    if (isShallow) {
      if (isSingle) {
        return createShallowSingleMapper(fields[0], emit);
      } else { // multi
        return createShallowMultiMapper(fields, emit);
      }
    } else { // deep
      if (isSingle) {
        return createDeepSingleMapper(fields[0], emit);
      } else { // multi
        return createDeepMultiMapper(fields, emit);
      }
    }
  }
  
  function mapper(mapFunDef, emit) {
    // mapFunDef is a list of fields
  
    var fields = Object.keys(mapFunDef.fields);
  
    return createMapper(fields, emit);
  }
  
  /* istanbul ignore next */
  function reducer(/*reduceFunDef*/) {
    throw new Error('reduce not supported');
  }
  
  function ddocValidator(ddoc, viewName) {
    var view = ddoc.views[viewName];
    // This doesn't actually need to be here apparently, but
    // I feel safer keeping it.
    /* istanbul ignore if */
    if (!view.map || !view.map.fields) {
      throw new Error('ddoc ' + ddoc._id +' with view ' + viewName +
        ' doesn\'t have map.fields defined. ' +
        'maybe it wasn\'t created by this plugin?');
    }
  }
  
  var abstractMapper = abstractMapReduce({
    name: 'indexes',
    mapper: mapper,
    reducer: reducer,
    ddocValidator: ddocValidator
  });
  
  module.exports = abstractMapper;
  },{"15":15,"2":2}],8:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  var log = utils.log;
  
  var pouchUpsert = _dereq_(31);
  var abstractMapper = _dereq_(7);
  var localUtils = _dereq_(15);
  var validateIndex = localUtils.validateIndex;
  var massageIndexDef = localUtils.massageIndexDef;
  var massageCreateIndexRequest = _dereq_(16);
  
  function upsert(db, docId, diffFun) {
    return pouchUpsert.upsert.call(db, docId, diffFun);
  }
  
  function createIndex(db, requestDef) {
    requestDef = massageCreateIndexRequest(requestDef);
    var originalIndexDef = utils.clone(requestDef.index);
    requestDef.index = massageIndexDef(requestDef.index);
  
    validateIndex(requestDef.index);
  
    var md5 = utils.MD5(JSON.stringify(requestDef));
  
    var viewName = requestDef.name || ('idx-' + md5);
  
    var ddocName = requestDef.ddoc || ('idx-' + md5);
    var ddocId = '_design/' + ddocName;
  
    var hasInvalidLanguage = false;
    var viewExists = false;
  
    function updateDdoc(doc) {
      if (doc._rev && doc.language !== 'query') {
        hasInvalidLanguage = true;
      }
      doc.language = 'query';
      doc.views = doc.views || {};
  
      viewExists = !!doc.views[viewName];
  
      doc.views[viewName] = {
        map: {
          fields: utils.mergeObjects(requestDef.index.fields)
        },
        reduce: '_count',
        options: {
          def: originalIndexDef
        }
      };
  
      return doc;
    }
  
    log('creating index', ddocId);
  
    return upsert(db, ddocId, updateDdoc).then(function () {
      if (hasInvalidLanguage) {
        throw new Error('invalid language for ddoc with id "' +
        ddocId +
        '" (should be "query")');
      }
    }).then(function () {
      // kick off a build
      // TODO: abstract-pouchdb-mapreduce should support auto-updating
      // TODO: should also use update_after, but pouchdb/pouchdb#3415 blocks me
      var signature = ddocName + '/' + viewName;
      return abstractMapper.query.call(db, signature, {
        limit: 0,
        reduce: false
      }).then(function () {
        return {
          id: ddocId,
          name: viewName,
          result: viewExists ? 'exists' : 'created'
        };
      });
    });
  }
  
  module.exports = createIndex;
  
  },{"15":15,"16":16,"17":17,"31":31,"7":7}],9:[function(_dereq_,module,exports){
  'use strict';
  
  var abstractMapper = _dereq_(7);
  var upsert = _dereq_(4);
  
  function deleteIndex(db, index) {
  
    if (!index.ddoc) {
      throw new Error('you must supply an index.ddoc when deleting');
    }
  
    if (!index.name) {
      throw new Error('you must supply an index.name when deleting');
    }
  
    var docId = index.ddoc;
    var viewName = index.name;
  
    function deltaFun (doc) {
      if (Object.keys(doc.views).length === 1 && doc.views[viewName]) {
        // only one view in this ddoc, delete the whole ddoc
        return {_id: docId, _deleted: true};
      }
      // more than one view here, just remove the view
      delete doc.views[viewName];
      return doc;
    }
  
    return upsert(db, docId, deltaFun).then(function () {
      return abstractMapper.viewCleanup.apply(db);
    }).then(function () {
      return {ok: true};
    });
  }
  
  module.exports = deleteIndex;
  },{"4":4,"7":7}],10:[function(_dereq_,module,exports){
  'use strict';
  
  //
  // Do an in-memory filtering of rows that aren't covered by the index.
  // E.g. if the user is asking for foo=1 and bar=2, but the index
  // only covers "foo", then this in-memory filter would take care of
  // "bar".
  //
  
  var isArray = _dereq_(24);
  var collate = _dereq_(27).collate;
  var localUtils = _dereq_(15);
  var isCombinationalField = localUtils.isCombinationalField;
  var getKey = localUtils.getKey;
  var getValue = localUtils.getValue;
  var parseField = localUtils.parseField;
  var utils = _dereq_(17);
  var getFieldFromDoc = utils.getFieldFromDoc;
  
  // create a comparator based on the sort object
  function createFieldSorter(sort) {
  
    function getFieldValuesAsArray(doc) {
      return sort.map(function (sorting) {
        var fieldName = getKey(sorting);
        var parsedField = parseField(fieldName);
        var docFieldValue = getFieldFromDoc(doc, parsedField);
        return docFieldValue;
      });
    }
  
    return function (aRow, bRow) {
      var aFieldValues = getFieldValuesAsArray(aRow.doc);
      var bFieldValues = getFieldValuesAsArray(bRow.doc);
      var collation = collate(aFieldValues, bFieldValues);
      if (collation !== 0) {
        return collation;
      }
      // this is what mango seems to do
      return utils.compare(aRow.doc._id, bRow.doc._id);
    };
  }
  
  function filterInMemoryFields (rows, requestDef, inMemoryFields) {
    rows = rows.filter(function (row) {
      return rowFilter(row.doc, requestDef.selector, inMemoryFields);
    });
  
    if (requestDef.sort) {
      // in-memory sort
      var fieldSorter = createFieldSorter(requestDef.sort);
      rows = rows.sort(fieldSorter);
      if (typeof requestDef.sort[0] !== 'string' &&
          getValue(requestDef.sort[0]) === 'desc') {
        rows = rows.reverse();
      }
    }
  
    if ('limit' in requestDef || 'skip' in requestDef) {
      // have to do the limit in-memory
      var skip = requestDef.skip || 0;
      var limit = ('limit' in requestDef ? requestDef.limit : rows.length) + skip;
      rows = rows.slice(skip, limit);
    }
    return rows;
  }
  
  function rowFilter (doc, selector, inMemoryFields) {
    return inMemoryFields.every(function (field) {
      var matcher = selector[field];
      var parsedField = parseField(field);
      var docFieldValue = getFieldFromDoc(doc, parsedField);
      if (isCombinationalField(field)) {
        return matchCominationalSelector(field, matcher, doc);
      }
  
      return matchSelector(matcher, doc, parsedField, docFieldValue);
    });
  }
  
  function matchSelector (matcher, doc, parsedField, docFieldValue) {
    if (!matcher) {
      // no filtering necessary; this field is just needed for sorting
      return true;
    }
  
    return Object.keys(matcher).every(function (userOperator) {
      var userValue = matcher[userOperator];
      return match(userOperator, doc, userValue, parsedField, docFieldValue);
    });
  }
  
  function matchCominationalSelector (field, matcher, doc) {
  
    if (field === '$or') {
      return matcher.some(function (orMatchers) {
        return rowFilter(doc, orMatchers, Object.keys(orMatchers));
      });
    }
  
    if (field === '$not') {
      return !rowFilter(doc, matcher, Object.keys(matcher));
    }
  
    //`$nor`
    return !matcher.find(function (orMatchers) {
      return rowFilter(doc, orMatchers, Object.keys(orMatchers));
    });
  
  }
  
  function match(userOperator, doc, userValue, parsedField, docFieldValue) {
    if (!matchers[userOperator]) {
      throw new Error('unknown operator "' + userOperator +
        '" - should be one of $eq, $lte, $lt, $gt, $gte, $exists, $ne, $in, ' +
        '$nin, $size, $mod, $regex, $elemMatch, $type or $all');
    }
    return matchers[userOperator](doc, userValue, parsedField, docFieldValue);
  }
  
  function fieldExists(docFieldValue) {
    return typeof docFieldValue !== 'undefined' && docFieldValue !== null;
  }
  
  function fieldIsNotUndefined(docFieldValue) {
    return typeof docFieldValue !== 'undefined';
  }
  
  function modField (docFieldValue, userValue) {
    var divisor = userValue[0];
    var mod = userValue[1];
    if (divisor === 0) {
      throw new Error('Bad divisor, cannot divide by zero');
    }
  
    if (parseInt(divisor, 10) !== divisor ) {
      throw new Error('Divisor is not an integer');
    }
  
    if (parseInt(mod, 10) !== mod ) {
      throw new Error('Modulus is not an integer');
    }
  
    if (parseInt(docFieldValue, 10) !== docFieldValue) {
      return false;
    }
  
    return docFieldValue % divisor === mod;
  }
  
  function arrayContainsValue (docFieldValue, userValue) {
    return userValue.some(function (val) {
      if (docFieldValue instanceof Array) {
        return docFieldValue.indexOf(val) > -1;
      }
  
      return docFieldValue === val;
    });
  }
  
  function arrayContainsAllValues (docFieldValue, userValue) {
    return userValue.every(function (val) {
      return docFieldValue.indexOf(val) > -1;
    });
  }
  
  function arraySize (docFieldValue, userValue) {
    return docFieldValue.length === userValue;
  }
  
  function regexMatch(docFieldValue, userValue) {
    var re = new RegExp(userValue);
  
    return re.test(docFieldValue);
  }
  
  function typeMatch(docFieldValue, userValue) {
  
    switch (userValue) {
      case 'null':
        return docFieldValue === null;
      case 'boolean':
        return typeof(docFieldValue) === 'boolean';
      case 'number':
        return typeof(docFieldValue) === 'number';
      case 'string':
        return typeof(docFieldValue) === 'string';
      case 'array':
        return docFieldValue instanceof Array;
      case 'object':
        return ({}).toString.call(docFieldValue) === '[object Object]';
    }
  
    throw new Error(userValue + ' not supported as a type.' +
                    'Please use one of object, string, array, number, boolean or null.');
  
  }
  
  var matchers = {
  
    '$elemMatch': function (doc, userValue, parsedField, docFieldValue) {
      if (!isArray(docFieldValue)) {
        return false;
      }
  
      if (docFieldValue.length === 0) {
        return false;
      }
  
      if (typeof docFieldValue[0] === 'object') {
        return docFieldValue.some(function (val) {
          return rowFilter(val, userValue, Object.keys(userValue));
        });
      }
  
      return docFieldValue.some(function (val) {
        return matchSelector(userValue, doc, parsedField, val);
      });
    },
  
    '$eq': function (doc, userValue, parsedField, docFieldValue) {
      return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) === 0;
    },
  
    '$gte': function (doc, userValue, parsedField, docFieldValue) {
      return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) >= 0;
    },
  
    '$gt': function (doc, userValue, parsedField, docFieldValue) {
      return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) > 0;
    },
  
    '$lte': function (doc, userValue, parsedField, docFieldValue) {
      return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) <= 0;
    },
  
    '$lt': function (doc, userValue, parsedField, docFieldValue) {
      return fieldIsNotUndefined(docFieldValue) && collate(docFieldValue, userValue) < 0;
    },
  
    '$exists': function (doc, userValue, parsedField, docFieldValue) {
      //a field that is null is still considered to exist
      if (userValue) {
        return fieldIsNotUndefined(docFieldValue);
      }
  
      return !fieldIsNotUndefined(docFieldValue);
    },
  
    '$mod': function (doc, userValue, parsedField, docFieldValue) {
      return fieldExists(docFieldValue) && modField(docFieldValue, userValue);
    },
  
    '$ne': function (doc, userValue, parsedField, docFieldValue) {
      return userValue.every(function (neValue) {
        return collate(docFieldValue, neValue) !== 0;
      });
    },
    '$in': function (doc, userValue, parsedField, docFieldValue) {
      return fieldExists(docFieldValue) && arrayContainsValue(docFieldValue, userValue);
    },
  
    '$nin': function (doc, userValue, parsedField, docFieldValue) {
      return fieldExists(docFieldValue) && !arrayContainsValue(docFieldValue, userValue);
    },
  
    '$size': function (doc, userValue, parsedField, docFieldValue) {
      return fieldExists(docFieldValue) && arraySize(docFieldValue, userValue);
    },
  
    '$all': function (doc, userValue, parsedField, docFieldValue) {
      return isArray(docFieldValue) && arrayContainsAllValues(docFieldValue, userValue);
    },
  
    '$regex': function (doc, userValue, parsedField, docFieldValue) {
      return fieldExists(docFieldValue) && regexMatch(docFieldValue, userValue);
    },
  
    '$type': function (doc, userValue, parsedField, docFieldValue) {
      return typeMatch(docFieldValue, userValue);
    }
  };
  
  module.exports = filterInMemoryFields;
  
  },{"15":15,"17":17,"24":24,"27":27}],11:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  var clone = utils.clone;
  var getIndexes = _dereq_(13);
  var collate = _dereq_(27).collate;
  var abstractMapper = _dereq_(7);
  var planQuery = _dereq_(12);
  var localUtils = _dereq_(15);
  var filterInMemoryFields = _dereq_(10);
  var massageSelector = localUtils.massageSelector;
  var massageSort = localUtils.massageSort;
  var getValue = localUtils.getValue;
  var validateFindRequest = localUtils.validateFindRequest;
  var validateSort = localUtils.validateSort;
  var reverseOptions = localUtils.reverseOptions;
  var filterInclusiveStart = localUtils.filterInclusiveStart;
  var Promise = utils.Promise;
  
  function indexToSignature(index) {
    // remove '_design/'
    return index.ddoc.substring(8) + '/' + index.name;
  }
  
  function doAllDocs(db, originalOpts) {
    var opts = clone(originalOpts);
  
    // CouchDB responds in weird ways when you provide a non-string to _id;
    // we mimic the behavior for consistency. See issue66 tests for details.
  
    if (opts.descending) {
      if ('endkey' in opts && typeof opts.endkey !== 'string') {
        opts.endkey = '';
      }
      if ('startkey' in opts && typeof opts.startkey !== 'string') {
        opts.limit = 0;
      }
    } else {
      if ('startkey' in opts && typeof opts.startkey !== 'string') {
        opts.startkey = '';
      }
      if ('endkey' in opts && typeof opts.endkey !== 'string') {
        opts.limit = 0;
      }
    }
    if ('key' in opts && typeof opts.key !== 'string') {
      opts.limit = 0;
    }
  
    return db.allDocs(opts);
  }
  
  function find(db, requestDef) {
  
    if (requestDef.selector) {
      requestDef.selector = massageSelector(requestDef.selector);
    }
    if (requestDef.sort) {
      requestDef.sort = massageSort(requestDef.sort);
    }
  
    validateFindRequest(requestDef);
  
    return getIndexes(db).then(function (getIndexesRes) {
  
      var queryPlan = planQuery(requestDef, getIndexesRes.indexes);
  
      var indexToUse = queryPlan.index;
  
      validateSort(requestDef, indexToUse);
  
      var opts = utils.extend(true, {
        include_docs: true,
        reduce: false
      }, queryPlan.queryOpts);
  
      if ('startkey' in opts && 'endkey' in opts &&
          collate(opts.startkey, opts.endkey) > 0) {
        // can't possibly return any results, startkey > endkey
        return {docs: []};
      }
  
      var isDescending = requestDef.sort &&
        typeof requestDef.sort[0] !== 'string' &&
        getValue(requestDef.sort[0]) === 'desc';
  
      if (isDescending) {
        // either all descending or all ascending
        opts.descending = true;
        opts = reverseOptions(opts);
      }
  
      if (!queryPlan.inMemoryFields.length) {
        // no in-memory filtering necessary, so we can let the
        // database do the limit/skip for us
        if ('limit' in requestDef) {
          opts.limit = requestDef.limit;
        }
        if ('skip' in requestDef) {
          opts.skip = requestDef.skip;
        }
      }
  
      return Promise.resolve().then(function () {
        if (indexToUse.name === '_all_docs') {
          return doAllDocs(db, opts);
        } else {
          var signature = indexToSignature(indexToUse);
          return abstractMapper.query.call(db, signature, opts);
        }
      }).then(function (res) {
  
        if (opts.inclusive_start === false) {
          // may have to manually filter the first one,
          // since couchdb has no true inclusive_start option
          res.rows = filterInclusiveStart(res.rows, opts.startkey, indexToUse);
        }
  
        if (queryPlan.inMemoryFields.length) {
          // need to filter some stuff in-memory
          res.rows = filterInMemoryFields(res.rows, requestDef, queryPlan.inMemoryFields);
        }
  
        var resp = {
          docs: res.rows.map(function (row) {
            var doc = row.doc;
            if (requestDef.fields) {
              return utils.pick(doc, requestDef.fields);
            }
            return doc;
          })
        };
  
        if (indexToUse.defaultUsed) {
          resp.warning = 'no matching index found, create an index to optimize query time';
        }
  
        return resp;
      });
    });
  }
  
  module.exports = find;
  
  },{"10":10,"12":12,"13":13,"15":15,"17":17,"27":27,"7":7}],12:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  var log = utils.log;
  var localUtils = _dereq_(15);
  var getKey = localUtils.getKey;
  var getValue = localUtils.getValue;
  var getUserFields = localUtils.getUserFields;
  
  // couchdb lowest collation value
  var COLLATE_LO = null;
  
  // couchdb highest collation value (TODO: well not really, but close enough amirite)
  var COLLATE_HI = {"\uffff": {}};
  
  // couchdb second-lowest collation value
  
  function checkFieldInIndex(index, field) {
    var indexFields = index.def.fields.map(getKey);
    for (var i = 0, len = indexFields.length; i < len; i++) {
      var indexField = indexFields[i];
      if (field === indexField) {
        return true;
      }
    }
    return false;
  }
  
  // so when you do e.g. $eq/$eq, we can do it entirely in the database.
  // but when you do e.g. $gt/$eq, the first part can be done
  // in the database, but the second part has to be done in-memory,
  // because $gt has forced us to lose precision.
  // so that's what this determines
  function userOperatorLosesPrecision(selector, field) {
    var matcher = selector[field];
    var userOperator = getKey(matcher);
  
    return userOperator !== '$eq';
  }
  
  // sort the user fields by their position in the index,
  // if they're in the index
  function sortFieldsByIndex(userFields, index) {
    var indexFields = index.def.fields.map(getKey);
  
    return userFields.slice().sort(function (a, b) {
      var aIdx = indexFields.indexOf(a);
      var bIdx = indexFields.indexOf(b);
      if (aIdx === -1) {
        aIdx = Number.MAX_VALUE;
      }
      if (bIdx === -1) {
        bIdx = Number.MAX_VALUE;
      }
      return utils.compare(aIdx, bIdx);
    });
  }
  
  // first pass to try to find fields that will need to be sorted in-memory
  function getBasicInMemoryFields(index, selector, userFields) {
  
    userFields = sortFieldsByIndex(userFields, index);
  
    // check if any of the user selectors lose precision
    var needToFilterInMemory = false;
    for (var i = 0, len = userFields.length; i < len; i++) {
      var field = userFields[i];
      if (needToFilterInMemory || !checkFieldInIndex(index, field)) {
        return userFields.slice(i);
      }
      if (i < len - 1 && userOperatorLosesPrecision(selector, field)) {
        needToFilterInMemory = true;
      }
    }
    return [];
  }
  
  function getInMemoryFieldsFromNe(selector) {
    var fields = [];
    Object.keys(selector).forEach(function (field) {
      var matcher = selector[field];
      Object.keys(matcher).forEach(function (operator) {
        if (operator === '$ne') {
          fields.push(field);
        }
      });
    });
    return fields;
  }
  
  function getInMemoryFields(coreInMemoryFields, index, selector, userFields) {
    var result = utils.flatten(
      // in-memory fields reported as necessary by the query planner
      coreInMemoryFields,
      // combine with another pass that checks for any we may have missed
      getBasicInMemoryFields(index, selector, userFields),
      // combine with another pass that checks for $ne's
      getInMemoryFieldsFromNe(selector)
    );
  
    return sortFieldsByIndex(utils.uniq(result), index);
  }
  
  // check that at least one field in the user's query is represented
  // in the index. order matters in the case of sorts
  function checkIndexFieldsMatch(indexFields, sortOrder, fields) {
    if (sortOrder) {
      // array has to be a strict subarray of index array. furthermore,
      // the sortOrder fields need to all be represented in the index
      var sortMatches = utils.oneArrayIsStrictSubArrayOfOther(sortOrder, indexFields);
      var selectorMatches = utils.oneArrayIsSubArrayOfOther(fields, indexFields);
  
      return sortMatches && selectorMatches;
    }
  
    // all of the user's specified fields still need to be
    // on the left side of the index array, although the order
    // doesn't matter
    return utils.oneSetIsSubArrayOfOther(fields, indexFields);
  }
  
  var logicalMatchers = ['$eq', '$gt', '$gte', '$lt', '$lte'];
  function isNonLogicalMatcher (matcher) {
    return logicalMatchers.indexOf(matcher) === -1;
  }
  
  // check all the index fields for usages of '$ne'
  // e.g. if the user queries {foo: {$ne: 'foo'}, bar: {$eq: 'bar'}},
  // then we can neither use an index on ['foo'] nor an index on
  // ['foo', 'bar'], but we can use an index on ['bar'] or ['bar', 'foo']
  function checkFieldsLogicallySound(indexFields, selector) {
    var firstField = indexFields[0];
    var matcher = selector[firstField];
  
    var hasLogicalOperator = Object.keys(matcher).some(function (matcherKey) {
      return !(isNonLogicalMatcher(matcherKey));
    });
  
    if (!hasLogicalOperator) {
      return false;
    }
  
    var isInvalidNe = Object.keys(matcher).length === 1 &&
      getKey(matcher) === '$ne';
  
    return !isInvalidNe;
  }
  
  function checkIndexMatches(index, sortOrder, fields, selector) {
  
    var indexFields = index.def.fields.map(getKey);
  
    var fieldsMatch = checkIndexFieldsMatch(indexFields, sortOrder, fields);
  
    if (!fieldsMatch) {
      return false;
    }
  
    return checkFieldsLogicallySound(indexFields, selector);
  }
  
  //
  // the algorithm is very simple:
  // take all the fields the user supplies, and if those fields
  // are a strict subset of the fields in some index,
  // then use that index
  //
  //
  function findMatchingIndexes(selector, userFields, sortOrder, indexes) {
  
    return indexes.reduce(function (res, index) {
      var indexMatches = checkIndexMatches(index, sortOrder, userFields, selector);
      if (indexMatches) {
        res.push(index);
      }
      return res;
    }, []);
  }
  
  // find the best index, i.e. the one that matches the most fields
  // in the user's query
  function findBestMatchingIndex(selector, userFields, sortOrder, indexes) {
  
    var matchingIndexes = findMatchingIndexes(selector, userFields, sortOrder, indexes);
  
    if (matchingIndexes.length === 0) {
      //return `all_docs` as a default index;
      //I'm assuming that _all_docs is always first
      var defaultIndex = indexes[0];
      defaultIndex.defaultUsed = true;
      return defaultIndex;
    }
    if (matchingIndexes.length === 1) {
      return matchingIndexes[0];
    }
  
    var userFieldsMap = utils.arrayToObject(userFields);
  
    function scoreIndex(index) {
      var indexFields = index.def.fields.map(getKey);
      var score = 0;
      for (var i = 0, len = indexFields.length; i < len; i++) {
        var indexField = indexFields[i];
        if (userFieldsMap[indexField]) {
          score++;
        }
      }
      return score;
    }
  
    return utils.max(matchingIndexes, scoreIndex);
  }
  
  function getSingleFieldQueryOptsFor(userOperator, userValue) {
    switch (userOperator) {
      case '$eq':
        return {key: userValue};
      case '$lte':
        return {endkey: userValue};
      case '$gte':
        return {startkey: userValue};
      case '$lt':
        return {
          endkey: userValue,
          inclusive_end: false
        };
      case '$gt':
        return {
          startkey: userValue,
          inclusive_start: false
        };
    }
  }
  
  function getSingleFieldCoreQueryPlan(selector, index) {
    var field = getKey(index.def.fields[0]);
    var matcher = selector[field];
    var inMemoryFields = [];
  
    var userOperators = Object.keys(matcher);
  
    var combinedOpts;
  
    userOperators.forEach(function (userOperator) {
  
      if (isNonLogicalMatcher(userOperator)) {
        inMemoryFields.push(field);
        return;
      }
  
      var userValue = matcher[userOperator];
  
      var newQueryOpts = getSingleFieldQueryOptsFor(userOperator, userValue);
  
      if (combinedOpts) {
        combinedOpts = utils.mergeObjects([combinedOpts, newQueryOpts]);
      } else {
        combinedOpts = newQueryOpts;
      }
    });
  
    return {
      queryOpts: combinedOpts,
      inMemoryFields: inMemoryFields
    };
  }
  
  function getMultiFieldCoreQueryPlan(userOperator, userValue) {
    switch (userOperator) {
      case '$eq':
        return {
          startkey: userValue,
          endkey: userValue
        };
      case '$lte':
        return {
          endkey: userValue
        };
      case '$gte':
        return {
          startkey: userValue
        };
      case '$lt':
        return {
          endkey: userValue,
          inclusive_end: false
        };
      case '$gt':
        return {
          startkey: userValue,
          inclusive_start: false
        };
    }
  }
  
  function getMultiFieldQueryOpts(selector, index) {
  
    var indexFields = index.def.fields.map(getKey);
  
    var inMemoryFields = [];
    var startkey = [];
    var endkey = [];
    var inclusiveStart;
    var inclusiveEnd;
  
  
    function finish(i) {
  
      if (inclusiveStart !== false) {
        startkey.push(COLLATE_LO);
      }
      if (inclusiveEnd !== false) {
        endkey.push(COLLATE_HI);
      }
      // keep track of the fields where we lost specificity,
      // and therefore need to filter in-memory
      inMemoryFields = indexFields.slice(i);
    }
  
    for (var i = 0, len = indexFields.length; i < len; i++) {
      var indexField = indexFields[i];
  
      var matcher = selector[indexField];
  
      if (!matcher) { // fewer fields in user query than in index
        finish(i);
        break;
      } else if (i > 0) {
        if ('$ne' in matcher) { // unusable $ne index
          finish(i);
          break;
        }
        var usingGtlt = (
          '$gt' in matcher || '$gte' in matcher ||
          '$lt' in matcher || '$lte' in matcher);
        var previousKeys = Object.keys(selector[indexFields[i - 1]]);
        var previousWasEq = utils.arrayEquals(previousKeys, ['$eq']);
        var previousWasSame = utils.arrayEquals(previousKeys, Object.keys(matcher));
        var gtltLostSpecificity = usingGtlt && !previousWasEq && !previousWasSame;
        if (gtltLostSpecificity) {
          finish(i);
          break;
        }
      }
  
      var userOperators = Object.keys(matcher);
  
      var combinedOpts = null;
  
      for (var j = 0; j < userOperators.length; j++) {
        var userOperator = userOperators[j];
        var userValue = matcher[userOperator];
  
        var newOpts = getMultiFieldCoreQueryPlan(userOperator, userValue);
  
        if (combinedOpts) {
          combinedOpts = utils.mergeObjects([combinedOpts, newOpts]);
        } else {
          combinedOpts = newOpts;
        }
      }
  
      startkey.push('startkey' in combinedOpts ? combinedOpts.startkey : COLLATE_LO);
      endkey.push('endkey' in combinedOpts ? combinedOpts.endkey : COLLATE_HI);
      if ('inclusive_start' in combinedOpts) {
        inclusiveStart = combinedOpts.inclusive_start;
      }
      if ('inclusive_end' in combinedOpts) {
        inclusiveEnd = combinedOpts.inclusive_end;
      }
    }
  
    var res = {
      startkey: startkey,
      endkey: endkey
    };
  
    if (typeof inclusiveStart !== 'undefined') {
      res.inclusive_start = inclusiveStart;
    }
    if (typeof inclusiveEnd !== 'undefined') {
      res.inclusive_end = inclusiveEnd;
    }
  
    return {
      queryOpts: res,
      inMemoryFields: inMemoryFields
    };
  }
  
  function getDefaultQueryPlan () {
    return {
      queryOpts: {startkey: null},
      //getInMemoryFields will do the work here later
      inMemoryFields: []
    };
  }
  
  function getCoreQueryPlan(selector, index) {
    if (index.defaultUsed) {
      return getDefaultQueryPlan(selector, index);
    }
  
    if (index.def.fields.length === 1) {
      // one field in index, so the value was indexed as a singleton
      return getSingleFieldCoreQueryPlan(selector, index);
    }
    // else index has multiple fields, so the value was indexed as an array
    return getMultiFieldQueryOpts(selector, index);
  }
  
  function planQuery(request, indexes) {
  
    log('planning query', request);
  
    var selector = request.selector;
    var sort = request.sort;
  
    var userFieldsRes = getUserFields(selector, sort);
  
    var userFields = userFieldsRes.fields;
    var sortOrder = userFieldsRes.sortOrder;
    var index = findBestMatchingIndex(selector, userFields, sortOrder, indexes);
  
    var coreQueryPlan = getCoreQueryPlan(selector, index);
    var queryOpts = coreQueryPlan.queryOpts;
    var coreInMemoryFields = coreQueryPlan.inMemoryFields;
  
    var inMemoryFields = getInMemoryFields(coreInMemoryFields, index, selector, userFields);
  
    var res = {
      queryOpts: queryOpts,
      index: index,
      inMemoryFields: inMemoryFields
    };
    log('query plan', res);
    return res;
  }
  
  module.exports = planQuery;
  
  },{"15":15,"17":17}],13:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  
  var localUtils = _dereq_(15);
  var massageIndexDef = localUtils.massageIndexDef;
  
  function getIndexes(db) {
    // just search through all the design docs and filter in-memory.
    // hopefully there aren't that many ddocs.
    return db.allDocs({
      startkey: '_design/',
      endkey: '_design/\uffff',
      include_docs: true
    }).then(function (allDocsRes) {
      var res = {
        indexes: [{
          ddoc: null,
          name: '_all_docs',
          type: 'special',
          def: {
            fields: [{_id: 'asc'}]
          }
        }]
      };
  
      res.indexes = utils.flatten(res.indexes, allDocsRes.rows.filter(function (row) {
        return row.doc.language === 'query';
      }).map(function (row) {
        var viewNames = row.doc.views !== undefined ? Object.keys(row.doc.views) : [];
  
        return viewNames.map(function (viewName) {
          var view = row.doc.views[viewName];
          return {
            ddoc: row.id,
            name: viewName,
            type: 'json',
            def: massageIndexDef(view.options.def)
          };
        });
      }));
  
      // these are sorted by view name for some reason
      res.indexes.sort(function (left, right) {
        return utils.compare(left.name, right.name);
      });
      res.total_rows = res.indexes.length;
      return res;
    });
  }
  
  module.exports = getIndexes;
  
  },{"15":15,"17":17}],14:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  var callbackify = utils.callbackify;
  
  exports.createIndex = callbackify(_dereq_(8));
  exports.find = callbackify(_dereq_(11));
  exports.getIndexes = callbackify(_dereq_(13));
  exports.deleteIndex = callbackify(_dereq_(9));
  },{"11":11,"13":13,"17":17,"8":8,"9":9}],15:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  var collate = _dereq_(27);
  
  function getKey(obj) {
    return Object.keys(obj)[0];
  }
  
  function getValue(obj) {
    return obj[getKey(obj)];
  }
  
  // normalize the "sort" value
  function massageSort(sort) {
    if (!Array.isArray(sort)) {
      throw new Error('invalid sort json - should be an array');
    }
    return sort.map(function (sorting) {
      if (typeof sorting === 'string') {
        var obj = {};
        obj[sorting] = 'asc';
        return obj;
      } else {
        return sorting;
      }
    });
  }
  
  var combinationFields = ['$or', '$nor', '$not'];
  function isCombinationalField (field) {
    return combinationFields.indexOf(field) > -1;
  }
  
  // collapse logically equivalent gt/gte values
  function mergeGtGte(operator, value, fieldMatchers) {
    if (typeof fieldMatchers.$eq !== 'undefined') {
      return; // do nothing
    }
    if (typeof fieldMatchers.$gte !== 'undefined') {
      if (operator === '$gte') {
        if (value > fieldMatchers.$gte) { // more specificity
          fieldMatchers.$gte = value;
        }
      } else { // operator === '$gt'
        if (value >= fieldMatchers.$gte) { // more specificity
          delete fieldMatchers.$gte;
          fieldMatchers.$gt = value;
        }
      }
    } else if (typeof fieldMatchers.$gt !== 'undefined') {
      if (operator === '$gte') {
        if (value > fieldMatchers.$gt) { // more specificity
          delete fieldMatchers.$gt;
          fieldMatchers.$gte = value;
        }
      } else { // operator === '$gt'
        if (value > fieldMatchers.$gt) { // more specificity
          fieldMatchers.$gt = value;
        }
      }
    } else {
      fieldMatchers[operator] = value;
    }
  }
  
  // collapse logically equivalent lt/lte values
  function mergeLtLte(operator, value, fieldMatchers) {
    if (typeof fieldMatchers.$eq !== 'undefined') {
      return; // do nothing
    }
    if (typeof fieldMatchers.$lte !== 'undefined') {
      if (operator === '$lte') {
        if (value < fieldMatchers.$lte) { // more specificity
          fieldMatchers.$lte = value;
        }
      } else { // operator === '$gt'
        if (value <= fieldMatchers.$lte) { // more specificity
          delete fieldMatchers.$lte;
          fieldMatchers.$lt = value;
        }
      }
    } else if (typeof fieldMatchers.$lt !== 'undefined') {
      if (operator === '$lte') {
        if (value < fieldMatchers.$lt) { // more specificity
          delete fieldMatchers.$lt;
          fieldMatchers.$lte = value;
        }
      } else { // operator === '$gt'
        if (value < fieldMatchers.$lt) { // more specificity
          fieldMatchers.$lt = value;
        }
      }
    } else {
      fieldMatchers[operator] = value;
    }
  }
  
  // combine $ne values into one array
  function mergeNe(value, fieldMatchers) {
    if ('$ne' in fieldMatchers) {
      // there are many things this could "not" be
      fieldMatchers.$ne.push(value);
    } else { // doesn't exist yet
      fieldMatchers.$ne = [value];
    }
  }
  
  // add $eq into the mix
  function mergeEq(value, fieldMatchers) {
    // these all have less specificity than the $eq
    // TODO: check for user errors here
    delete fieldMatchers.$gt;
    delete fieldMatchers.$gte;
    delete fieldMatchers.$lt;
    delete fieldMatchers.$lte;
    delete fieldMatchers.$ne;
    fieldMatchers.$eq = value;
  }
  
  // flatten an array of selectors joined by an $and operator
  function mergeAndedSelectors(selectors) {
  
    // sort to ensure that e.g. if the user specified
    // $and: [{$gt: 'a'}, {$gt: 'b'}], then it's collapsed into
    // just {$gt: 'b'}
    var res = {};
  
    selectors.forEach(function (selector) {
      Object.keys(selector).forEach(function (field) {
        var matcher = selector[field];
        if (typeof matcher !== 'object') {
          matcher = {$eq: matcher};
        }
  
        if (isCombinationalField(field)) {
          if (matcher instanceof Array) {
            res[field] = matcher.map(function (m) {
              return mergeAndedSelectors([m]);
            });
          } else {
            res[field] = mergeAndedSelectors([matcher]);
          }
        } else {
          var fieldMatchers = res[field] = res[field] || {};
          Object.keys(matcher).forEach(function (operator) {
            var value = matcher[operator];
  
            if (operator === '$gt' || operator === '$gte') {
              return mergeGtGte(operator, value, fieldMatchers);
            } else if (operator === '$lt' || operator === '$lte') {
              return mergeLtLte(operator, value, fieldMatchers);
            } else if (operator === '$ne') {
              return mergeNe(value, fieldMatchers);
            } else if (operator === '$eq') {
              return mergeEq(value, fieldMatchers);
            }
            fieldMatchers[operator] = value;
          });
        }
      });
    });
  
    return res;
  }
  
  //
  // normalize the selector
  //
  function massageSelector(input) {
    var result = utils.clone(input);
    var wasAnded = false;
    if ('$and' in result) {
      result = mergeAndedSelectors(result['$and']);
      wasAnded = true;
    }
  
    if ('$not' in result) {
      //This feels a little like forcing, but it will work for now,
      //I would like to come back to this and make the merging of selectors a little more generic
      result['$not'] = mergeAndedSelectors([result['$not']]);
    }
  
    var fields = Object.keys(result);
  
    for (var i = 0; i < fields.length; i++) {
      var field = fields[i];
      var matcher = result[field];
  
      if (typeof matcher !== 'object' || matcher === null) {
        matcher = {$eq: matcher};
      } else if ('$ne' in matcher && !wasAnded) {
        // I put these in an array, since there may be more than one
        // but in the "mergeAnded" operation, I already take care of that
        matcher.$ne = [matcher.$ne];
      }
      result[field] = matcher;
    }
  
    return result;
  }
  
  
  function massageIndexDef(indexDef) {
    indexDef.fields = indexDef.fields.map(function (field) {
      if (typeof field === 'string') {
        var obj = {};
        obj[field] = 'asc';
        return obj;
      }
      return field;
    });
    return indexDef;
  }
  
  function getKeyFromDoc(doc, index) {
    var res = [];
    for (var i = 0; i < index.def.fields.length; i++) {
      var field = getKey(index.def.fields[i]);
      res.push(doc[field]);
    }
    return res;
  }
  
  // have to do this manually because REASONS. I don't know why
  // CouchDB didn't implement inclusive_start
  function filterInclusiveStart(rows, targetValue, index) {
    var indexFields = index.def.fields;
    for (var i = 0, len = rows.length; i < len; i++) {
      var row = rows[i];
  
      // shave off any docs at the beginning that are <= the
      // target value
  
      var docKey = getKeyFromDoc(row.doc, index);
      if (indexFields.length === 1) {
        docKey = docKey[0]; // only one field, not multi-field
      } else { // more than one field in index
        // in the case where e.g. the user is searching {$gt: {a: 1}}
        // but the index is [a, b], then we need to shorten the doc key
        while (docKey.length > targetValue.length) {
          docKey.pop();
        }
      }
      //ABS as we just looking for values that don't match
      if (Math.abs(collate.collate(docKey, targetValue)) > 0) {
        // no need to filter any further; we're past the key
        break;
      }
    }
    return i > 0 ? rows.slice(i) : rows;
  }
  
  function reverseOptions(opts) {
    var newOpts = utils.clone(opts);
    delete newOpts.startkey;
    delete newOpts.endkey;
    delete newOpts.inclusive_start;
    delete newOpts.inclusive_end;
  
    if ('endkey' in opts) {
      newOpts.startkey = opts.endkey;
    }
    if ('startkey' in opts) {
      newOpts.endkey = opts.startkey;
    }
    if ('inclusive_start' in opts) {
      newOpts.inclusive_end = opts.inclusive_start;
    }
    if ('inclusive_end' in opts) {
      newOpts.inclusive_start = opts.inclusive_end;
    }
    return newOpts;
  }
  
  function validateIndex(index) {
    var ascFields = index.fields.filter(function (field) {
      return getValue(field) === 'asc';
    });
    if (ascFields.length !== 0 && ascFields.length !== index.fields.length) {
      throw new Error('unsupported mixed sorting');
    }
  }
  
  function validateSort (requestDef, index) {
    if (index.defaultUsed && requestDef.sort) {
      var noneIdSorts = requestDef.sort.filter(function (sortItem) {
        return Object.keys(sortItem)[0] !== '_id';
      }).map(function (sortItem) {
        return Object.keys(sortItem)[0];
      });
  
      if (noneIdSorts.length > 0) {
        throw new Error('Cannot sort on field(s) "' + noneIdSorts.join(',') +
        '" when using the default index');
      }
    }
  
    if (index.defaultUsed) {
      return;
    }
  }
  
  function validateFindRequest(requestDef) {
    if (typeof requestDef.selector !== 'object') {
      throw new Error('you must provide a selector when you find()');
    }
  
    /*var selectors = requestDef.selector['$and'] || [requestDef.selector];
    for (var i = 0; i < selectors.length; i++) {
      var selector = selectors[i];
      var keys = Object.keys(selector);
      if (keys.length === 0) {
        throw new Error('invalid empty selector');
      }
      //var selection = selector[keys[0]];
      /*if (Object.keys(selection).length !== 1) {
        throw new Error('invalid selector: ' + JSON.stringify(selection) +
          ' - it must have exactly one key/value');
      }
    }*/
  }
  
  // determine the maximum number of fields
  // we're going to need to query, e.g. if the user
  // has selection ['a'] and sorting ['a', 'b'], then we
  // need to use the longer of the two: ['a', 'b']
  function getUserFields(selector, sort) {
    var selectorFields = Object.keys(selector);
    var sortFields = sort? sort.map(getKey) : [];
    var userFields;
    if (selectorFields.length >= sortFields.length) {
      userFields = selectorFields;
    } else {
      userFields = sortFields;
    }
  
    if (sortFields.length === 0) {
      return {
        fields: userFields
      };
    }
  
    // sort according to the user's preferred sorting
    userFields = userFields.sort(function (left, right) {
      var leftIdx = sortFields.indexOf(left);
      if (leftIdx === -1) {
        leftIdx = Number.MAX_VALUE;
      }
      var rightIdx = sortFields.indexOf(right);
      if (rightIdx === -1) {
        rightIdx = Number.MAX_VALUE;
      }
      return leftIdx < rightIdx ? -1 : leftIdx > rightIdx ? 1 : 0;
    });
  
    return {
      fields: userFields,
      sortOrder: sort.map(getKey)
    };
  }
  
  module.exports = {
    getKey: getKey,
    getValue: getValue,
    massageSort: massageSort,
    massageSelector: massageSelector,
    validateIndex: validateIndex,
    validateFindRequest: validateFindRequest,
    validateSort: validateSort,
    reverseOptions: reverseOptions,
    filterInclusiveStart: filterInclusiveStart,
    massageIndexDef: massageIndexDef,
    parseField: utils.parseField,
    getUserFields: getUserFields,
    isCombinationalField: isCombinationalField
  };
  
  },{"17":17,"27":27}],16:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  var clone = utils.clone;
  
  // we restucture the supplied JSON considerably, because the official
  // Mango API is very particular about a lot of this stuff, but we like
  // to be liberal with what we accept in order to prevent mental
  // breakdowns in our users
  module.exports = function (requestDef) {
    requestDef = clone(requestDef);
  
    if (!requestDef.index) {
      requestDef.index = {};
    }
  
    ['type', 'name', 'ddoc'].forEach(function (key) {
      if (requestDef.index[key]) {
        requestDef[key] = requestDef.index[key];
        delete requestDef.index[key];
      }
    });
  
    if (requestDef.fields) {
      requestDef.index.fields = requestDef.fields;
      delete requestDef.fields;
    }
  
    if (!requestDef.type) {
      requestDef.type = 'json';
    }
    return requestDef;
  };
  },{"17":17}],17:[function(_dereq_,module,exports){
  (function (process){
  'use strict';
  
  var Promise = _dereq_(30);
  
  /* istanbul ignore next */
  exports.once = function (fun) {
    var called = false;
    return exports.getArguments(function (args) {
      if (called) {
        console.trace();
        throw new Error('once called  more than once');
      } else {
        called = true;
        fun.apply(this, args);
      }
    });
  };
  /* istanbul ignore next */
  exports.getArguments = function (fun) {
    return function () {
      var len = arguments.length;
      var args = new Array(len);
      var i = -1;
      while (++i < len) {
        args[i] = arguments[i];
      }
      return fun.call(this, args);
    };
  };
  /* istanbul ignore next */
  exports.toPromise = function (func) {
    //create the function we will be returning
    return exports.getArguments(function (args) {
      var self = this;
      var tempCB = (typeof args[args.length - 1] === 'function') ? args.pop() : false;
      // if the last argument is a function, assume its a callback
      var usedCB;
      if (tempCB) {
        // if it was a callback, create a new callback which calls it,
        // but do so async so we don't trap any errors
        usedCB = function (err, resp) {
          process.nextTick(function () {
            tempCB(err, resp);
          });
        };
      }
      var promise = new Promise(function (fulfill, reject) {
        try {
          var callback = exports.once(function (err, mesg) {
            if (err) {
              reject(err);
            } else {
              fulfill(mesg);
            }
          });
          // create a callback for this invocation
          // apply the function in the orig context
          args.push(callback);
          func.apply(self, args);
        } catch (e) {
          reject(e);
        }
      });
      // if there is a callback, call it back
      if (usedCB) {
        promise.then(function (result) {
          usedCB(null, result);
        }, usedCB);
      }
      promise.cancel = function () {
        return this;
      };
      return promise;
    });
  };
  
  exports.inherits = _dereq_(23);
  exports.Promise = Promise;
  
  exports.clone = function (obj) {
    return exports.extend(true, {}, obj);
  };
  
  exports.extend = _dereq_(29);
  
  exports.callbackify = function (fun) {
    return exports.getArguments(function (args) {
      var cb = args.pop();
      var promise = fun.apply(this, args);
      exports.promisedCallback(promise, cb);
      return promise;
    });
  };
  
  exports.promisedCallback = function (promise, callback) {
    promise.then(function (res) {
      process.nextTick(function () {
        callback(null, res);
      });
    }, function (reason) {
      process.nextTick(function () {
        callback(reason);
      });
    });
    return promise;
  };
  
  var crypto = _dereq_(19);
  var Md5 = _dereq_(34);
  
  exports.MD5 = function (string) {
    /* istanbul ignore else */
    if (!process.browser) {
      return crypto.createHash('md5').update(string).digest('hex');
    } else {
      return Md5.hash(string);
    }
  };
  
  exports.flatten = exports.getArguments(function (args) {
    var res = [];
    for (var i = 0, len = args.length; i < len; i++) {
      var subArr = args[i];
      if (Array.isArray(subArr)) {
        res = res.concat(exports.flatten.apply(null, subArr));
      } else {
        res.push(subArr);
      }
    }
    return res;
  });
  
  exports.mergeObjects = function (arr) {
    var res = {};
    for (var i = 0, len = arr.length; i < len; i++) {
      res = exports.extend(true, res, arr[i]);
    }
    return res;
  };
  
  // this would just be "return doc[field]", but fields
  // can be "deep" due to dot notation
  exports.getFieldFromDoc = function (doc, parsedField) {
    var value = doc;
    for (var i = 0, len = parsedField.length; i < len; i++) {
      var key = parsedField[i];
      value = value[key];
      if (!value) {
        break;
      }
    }
    return value;
  };
  
  exports.setFieldInDoc = function (doc, parsedField, value) {
    for (var i = 0, len = parsedField.length; i < len-1; i++) {
      var elem = parsedField[i];
      doc = doc[elem] = {};
    }
    doc[parsedField[len-1]] = value;
  };
  
  // Converts a string in dot notation to an array of its components, with backslash escaping
  exports.parseField = function (fieldName) {
    // fields may be deep (e.g. "foo.bar.baz"), so parse
    var fields = [];
    var current = '';
    for (var i = 0, len = fieldName.length; i < len; i++) {
      var ch = fieldName[i];
      if (ch === '.') {
        if (i > 0 && fieldName[i - 1] === '\\') { // escaped delimiter
          current = current.substring(0, current.length - 1) + '.';
        } else { // not escaped, so delimiter
          fields.push(current);
          current = '';
        }
      } else { // normal character
        current += ch;
      }
    }
    fields.push(current);
    return fields;
  };
  
  // Selects a list of fields defined in dot notation from one doc
  // and copies them to a new doc. Like underscore _.pick but supports nesting.
  exports.pick = function (obj, arr) {
    var res = {};
    for (var i = 0, len = arr.length; i < len; i++) {
      var parsedField = exports.parseField(arr[i]);
      var value = exports.getFieldFromDoc(obj, parsedField);
      if(typeof value !== 'undefined') {
        exports.setFieldInDoc(res, parsedField, value);
      }
    }
    return res;
  };
  
  // e.g. ['a'], ['a', 'b'] is true, but ['b'], ['a', 'b'] is false
  exports.oneArrayIsSubArrayOfOther = function (left, right) {
  
    for (var i = 0, len = Math.min(left.length, right.length); i < len; i++) {
      if (left[i] !== right[i]) {
        return false;
      }
    }
    return true;
  };
  
  // e.g.['a', 'b', 'c'], ['a', 'b'] is false
  exports.oneArrayIsStrictSubArrayOfOther = function (left, right) {
  
    if (left.length > right.length) {
      return false;
    }
  
    return exports.oneArrayIsSubArrayOfOther(left, right);
  };
  
  // same as above, but treat the left array as an unordered set
  // e.g. ['b', 'a'], ['a', 'b', 'c'] is true, but ['c'], ['a', 'b', 'c'] is false
  exports.oneSetIsSubArrayOfOther = function (left, right) {
    left = left.slice();
    for (var i = 0, len = right.length; i < len; i++) {
      var field = right[i];
      if (!left.length) {
        break;
      }
      var leftIdx = left.indexOf(field);
      if (leftIdx === -1) {
        return false;
      } else {
        left.splice(leftIdx, 1);
      }
    }
    return true;
  };
  
  exports.compare = function (left, right) {
    return left < right ? -1 : left > right ? 1 : 0;
  };
  
  exports.arrayToObject = function (arr) {
    var res = {};
    for (var i = 0, len = arr.length; i < len; i++) {
      res[arr[i]] = true;
    }
    return res;
  };
  
  exports.max = function (arr, fun) {
    var max = null;
    var maxScore = -1;
    for (var i = 0, len = arr.length; i < len; i++) {
      var element = arr[i];
      var score = fun(element);
      if (score > maxScore) {
        maxScore = score;
        max = element;
      }
    }
    return max;
  };
  
  exports.arrayEquals = function (arr1, arr2) {
    if (arr1.length !== arr2.length) {
      return false;
    }
    for (var i = 0, len = arr1.length; i < len; i++) {
      if (arr1[i] !== arr2[i]) {
        return false;
      }
    }
    return true;
  };
  
  exports.uniq = function(arr) {
    var obj = {};
    for (var i = 0; i < arr.length; i++) {
      obj['$' + arr[i]] = true;
    }
    return Object.keys(obj).map(function (key) {
      return key.substring(1);
    });
  };
  
  exports.log = _dereq_(20)('pouchdb:find');
  
  }).call(this,_dereq_(33))
  },{"19":19,"20":20,"23":23,"29":29,"30":30,"33":33,"34":34}],18:[function(_dereq_,module,exports){
  'use strict';
  
  module.exports = argsArray;
  
  function argsArray(fun) {
    return function () {
      var len = arguments.length;
      if (len) {
        var args = [];
        var i = -1;
        while (++i < len) {
          args[i] = arguments[i];
        }
        return fun.call(this, args);
      } else {
        return fun.call(this, []);
      }
    };
  }
  },{}],19:[function(_dereq_,module,exports){
  
  },{}],20:[function(_dereq_,module,exports){
  
  /**
   * This is the web browser implementation of `debug()`.
   *
   * Expose `debug()` as the module.
   */
  
  exports = module.exports = _dereq_(21);
  exports.log = log;
  exports.formatArgs = formatArgs;
  exports.save = save;
  exports.load = load;
  exports.useColors = useColors;
  exports.storage = 'undefined' != typeof chrome
                 && 'undefined' != typeof chrome.storage
                    ? chrome.storage.local
                    : localstorage();
  
  /**
   * Colors.
   */
  
  exports.colors = [
    'lightseagreen',
    'forestgreen',
    'goldenrod',
    'dodgerblue',
    'darkorchid',
    'crimson'
  ];
  
  /**
   * Currently only WebKit-based Web Inspectors, Firefox >= v31,
   * and the Firebug extension (any Firefox version) are known
   * to support "%c" CSS customizations.
   *
   * TODO: add a `localStorage` variable to explicitly enable/disable colors
   */
  
  function useColors() {
    // is webkit? http://stackoverflow.com/a/16459606/376773
    return ('WebkitAppearance' in document.documentElement.style) ||
      // is firebug? http://stackoverflow.com/a/398120/376773
      (window.console && (console.firebug || (console.exception && console.table))) ||
      // is firefox >= v31?
      // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
      (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
  }
  
  /**
   * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
   */
  
  exports.formatters.j = function(v) {
    return JSON.stringify(v);
  };
  
  
  /**
   * Colorize log arguments if enabled.
   *
   * @api public
   */
  
  function formatArgs() {
    var args = arguments;
    var useColors = this.useColors;
  
    args[0] = (useColors ? '%c' : '')
      + this.namespace
      + (useColors ? ' %c' : ' ')
      + args[0]
      + (useColors ? '%c ' : ' ')
      + '+' + exports.humanize(this.diff);
  
    if (!useColors) return args;
  
    var c = 'color: ' + this.color;
    args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
  
    // the final "%c" is somewhat tricky, because there could be other
    // arguments passed either before or after the %c, so we need to
    // figure out the correct index to insert the CSS into
    var index = 0;
    var lastC = 0;
    args[0].replace(/%[a-z%]/g, function(match) {
      if ('%%' === match) return;
      index++;
      if ('%c' === match) {
        // we only are interested in the *last* %c
        // (the user may have provided their own)
        lastC = index;
      }
    });
  
    args.splice(lastC, 0, c);
    return args;
  }
  
  /**
   * Invokes `console.log()` when available.
   * No-op when `console.log` is not a "function".
   *
   * @api public
   */
  
  function log() {
    // this hackery is required for IE8/9, where
    // the `console.log` function doesn't have 'apply'
    return 'object' === typeof console
      && console.log
      && Function.prototype.apply.call(console.log, console, arguments);
  }
  
  /**
   * Save `namespaces`.
   *
   * @param {String} namespaces
   * @api private
   */
  
  function save(namespaces) {
    try {
      if (null == namespaces) {
        exports.storage.removeItem('debug');
      } else {
        exports.storage.debug = namespaces;
      }
    } catch(e) {}
  }
  
  /**
   * Load `namespaces`.
   *
   * @return {String} returns the previously persisted debug modes
   * @api private
   */
  
  function load() {
    var r;
    try {
      r = exports.storage.debug;
    } catch(e) {}
    return r;
  }
  
  /**
   * Enable namespaces listed in `localStorage.debug` initially.
   */
  
  exports.enable(load());
  
  /**
   * Localstorage attempts to return the localstorage.
   *
   * This is necessary because safari throws
   * when a user disables cookies/localstorage
   * and you attempt to access it.
   *
   * @return {LocalStorage}
   * @api private
   */
  
  function localstorage(){
    try {
      return window.localStorage;
    } catch (e) {}
  }
  
  },{"21":21}],21:[function(_dereq_,module,exports){
  
  /**
   * This is the common logic for both the Node.js and web browser
   * implementations of `debug()`.
   *
   * Expose `debug()` as the module.
   */
  
  exports = module.exports = debug;
  exports.coerce = coerce;
  exports.disable = disable;
  exports.enable = enable;
  exports.enabled = enabled;
  exports.humanize = _dereq_(26);
  
  /**
   * The currently active debug mode names, and names to skip.
   */
  
  exports.names = [];
  exports.skips = [];
  
  /**
   * Map of special "%n" handling functions, for the debug "format" argument.
   *
   * Valid key names are a single, lowercased letter, i.e. "n".
   */
  
  exports.formatters = {};
  
  /**
   * Previously assigned color.
   */
  
  var prevColor = 0;
  
  /**
   * Previous log timestamp.
   */
  
  var prevTime;
  
  /**
   * Select a color.
   *
   * @return {Number}
   * @api private
   */
  
  function selectColor() {
    return exports.colors[prevColor++ % exports.colors.length];
  }
  
  /**
   * Create a debugger with the given `namespace`.
   *
   * @param {String} namespace
   * @return {Function}
   * @api public
   */
  
  function debug(namespace) {
  
    // define the `disabled` version
    function disabled() {
    }
    disabled.enabled = false;
  
    // define the `enabled` version
    function enabled() {
  
      var self = enabled;
  
      // set `diff` timestamp
      var curr = +new Date();
      var ms = curr - (prevTime || curr);
      self.diff = ms;
      self.prev = prevTime;
      self.curr = curr;
      prevTime = curr;
  
      // add the `color` if not set
      if (null == self.useColors) self.useColors = exports.useColors();
      if (null == self.color && self.useColors) self.color = selectColor();
  
      var args = Array.prototype.slice.call(arguments);
  
      args[0] = exports.coerce(args[0]);
  
      if ('string' !== typeof args[0]) {
        // anything else let's inspect with %o
        args = ['%o'].concat(args);
      }
  
      // apply any `formatters` transformations
      var index = 0;
      args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
        // if we encounter an escaped % then don't increase the array index
        if (match === '%%') return match;
        index++;
        var formatter = exports.formatters[format];
        if ('function' === typeof formatter) {
          var val = args[index];
          match = formatter.call(self, val);
  
          // now we need to remove `args[index]` since it's inlined in the `format`
          args.splice(index, 1);
          index--;
        }
        return match;
      });
  
      if ('function' === typeof exports.formatArgs) {
        args = exports.formatArgs.apply(self, args);
      }
      var logFn = enabled.log || exports.log || console.log.bind(console);
      logFn.apply(self, args);
    }
    enabled.enabled = true;
  
    var fn = exports.enabled(namespace) ? enabled : disabled;
  
    fn.namespace = namespace;
  
    return fn;
  }
  
  /**
   * Enables a debug mode by namespaces. This can include modes
   * separated by a colon and wildcards.
   *
   * @param {String} namespaces
   * @api public
   */
  
  function enable(namespaces) {
    exports.save(namespaces);
  
    var split = (namespaces || '').split(/[\s,]+/);
    var len = split.length;
  
    for (var i = 0; i < len; i++) {
      if (!split[i]) continue; // ignore empty strings
      namespaces = split[i].replace(/\*/g, '.*?');
      if (namespaces[0] === '-') {
        exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
      } else {
        exports.names.push(new RegExp('^' + namespaces + '$'));
      }
    }
  }
  
  /**
   * Disable debug output.
   *
   * @api public
   */
  
  function disable() {
    exports.enable('');
  }
  
  /**
   * Returns true if the given mode name is enabled, false otherwise.
   *
   * @param {String} name
   * @return {Boolean}
   * @api public
   */
  
  function enabled(name) {
    var i, len;
    for (i = 0, len = exports.skips.length; i < len; i++) {
      if (exports.skips[i].test(name)) {
        return false;
      }
    }
    for (i = 0, len = exports.names.length; i < len; i++) {
      if (exports.names[i].test(name)) {
        return true;
      }
    }
    return false;
  }
  
  /**
   * Coerce `val`.
   *
   * @param {Mixed} val
   * @return {Mixed}
   * @api private
   */
  
  function coerce(val) {
    if (val instanceof Error) return val.stack || val.message;
    return val;
  }
  
  },{"26":26}],22:[function(_dereq_,module,exports){
  (function (global){
  'use strict';
  var Mutation = global.MutationObserver || global.WebKitMutationObserver;
  
  var scheduleDrain;
  
  {
    if (Mutation) {
      var called = 0;
      var observer = new Mutation(nextTick);
      var element = global.document.createTextNode('');
      observer.observe(element, {
        characterData: true
      });
      scheduleDrain = function () {
        element.data = (called = ++called % 2);
      };
    } else if (!global.setImmediate && typeof global.MessageChannel !== 'undefined') {
      var channel = new global.MessageChannel();
      channel.port1.onmessage = nextTick;
      scheduleDrain = function () {
        channel.port2.postMessage(0);
      };
    } else if ('document' in global && 'onreadystatechange' in global.document.createElement('script')) {
      scheduleDrain = function () {
  
        // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
        // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
        var scriptEl = global.document.createElement('script');
        scriptEl.onreadystatechange = function () {
          nextTick();
  
          scriptEl.onreadystatechange = null;
          scriptEl.parentNode.removeChild(scriptEl);
          scriptEl = null;
        };
        global.document.documentElement.appendChild(scriptEl);
      };
    } else {
      scheduleDrain = function () {
        setTimeout(nextTick, 0);
      };
    }
  }
  
  var draining;
  var queue = [];
  //named nextTick for less confusing stack traces
  function nextTick() {
    draining = true;
    var i, oldQueue;
    var len = queue.length;
    while (len) {
      oldQueue = queue;
      queue = [];
      i = -1;
      while (++i < len) {
        oldQueue[i]();
      }
      len = queue.length;
    }
    draining = false;
  }
  
  module.exports = immediate;
  function immediate(task) {
    if (queue.push(task) === 1 && !draining) {
      scheduleDrain();
    }
  }
  
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  },{}],23:[function(_dereq_,module,exports){
  if (typeof Object.create === 'function') {
    // implementation from standard node.js 'util' module
    module.exports = function inherits(ctor, superCtor) {
      ctor.super_ = superCtor
      ctor.prototype = Object.create(superCtor.prototype, {
        constructor: {
          value: ctor,
          enumerable: false,
          writable: true,
          configurable: true
        }
      });
    };
  } else {
    // old school shim for old browsers
    module.exports = function inherits(ctor, superCtor) {
      ctor.super_ = superCtor
      var TempCtor = function () {}
      TempCtor.prototype = superCtor.prototype
      ctor.prototype = new TempCtor()
      ctor.prototype.constructor = ctor
    }
  }
  
  },{}],24:[function(_dereq_,module,exports){
  
  /**
   * isArray
   */
  
  var isArray = Array.isArray;
  
  /**
   * toString
   */
  
  var str = Object.prototype.toString;
  
  /**
   * Whether or not the given `val`
   * is an array.
   *
   * example:
   *
   *        isArray([]);
   *        // > true
   *        isArray(arguments);
   *        // > false
   *        isArray('');
   *        // > false
   *
   * @param {mixed} val
   * @return {bool}
   */
  
  module.exports = isArray || function (val) {
    return !! val && '[object Array]' == str.call(val);
  };
  
  },{}],25:[function(_dereq_,module,exports){
  'use strict';
  var immediate = _dereq_(22);
  
  /* istanbul ignore next */
  function INTERNAL() {}
  
  var handlers = {};
  
  var REJECTED = ['REJECTED'];
  var FULFILLED = ['FULFILLED'];
  var PENDING = ['PENDING'];
  
  module.exports = Promise;
  
  function Promise(resolver) {
    if (typeof resolver !== 'function') {
      throw new TypeError('resolver must be a function');
    }
    this.state = PENDING;
    this.queue = [];
    this.outcome = void 0;
    if (resolver !== INTERNAL) {
      safelyResolveThenable(this, resolver);
    }
  }
  
  Promise.prototype["catch"] = function (onRejected) {
    return this.then(null, onRejected);
  };
  Promise.prototype.then = function (onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
      typeof onRejected !== 'function' && this.state === REJECTED) {
      return this;
    }
    var promise = new this.constructor(INTERNAL);
    if (this.state !== PENDING) {
      var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
      unwrap(promise, resolver, this.outcome);
    } else {
      this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
    }
  
    return promise;
  };
  function QueueItem(promise, onFulfilled, onRejected) {
    this.promise = promise;
    if (typeof onFulfilled === 'function') {
      this.onFulfilled = onFulfilled;
      this.callFulfilled = this.otherCallFulfilled;
    }
    if (typeof onRejected === 'function') {
      this.onRejected = onRejected;
      this.callRejected = this.otherCallRejected;
    }
  }
  QueueItem.prototype.callFulfilled = function (value) {
    handlers.resolve(this.promise, value);
  };
  QueueItem.prototype.otherCallFulfilled = function (value) {
    unwrap(this.promise, this.onFulfilled, value);
  };
  QueueItem.prototype.callRejected = function (value) {
    handlers.reject(this.promise, value);
  };
  QueueItem.prototype.otherCallRejected = function (value) {
    unwrap(this.promise, this.onRejected, value);
  };
  
  function unwrap(promise, func, value) {
    immediate(function () {
      var returnValue;
      try {
        returnValue = func(value);
      } catch (e) {
        return handlers.reject(promise, e);
      }
      if (returnValue === promise) {
        handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
      } else {
        handlers.resolve(promise, returnValue);
      }
    });
  }
  
  handlers.resolve = function (self, value) {
    var result = tryCatch(getThen, value);
    if (result.status === 'error') {
      return handlers.reject(self, result.value);
    }
    var thenable = result.value;
  
    if (thenable) {
      safelyResolveThenable(self, thenable);
    } else {
      self.state = FULFILLED;
      self.outcome = value;
      var i = -1;
      var len = self.queue.length;
      while (++i < len) {
        self.queue[i].callFulfilled(value);
      }
    }
    return self;
  };
  handlers.reject = function (self, error) {
    self.state = REJECTED;
    self.outcome = error;
    var i = -1;
    var len = self.queue.length;
    while (++i < len) {
      self.queue[i].callRejected(error);
    }
    return self;
  };
  
  function getThen(obj) {
    // Make sure we only access the accessor once as required by the spec
    var then = obj && obj.then;
    if (obj && typeof obj === 'object' && typeof then === 'function') {
      return function appyThen() {
        then.apply(obj, arguments);
      };
    }
  }
  
  function safelyResolveThenable(self, thenable) {
    // Either fulfill, reject or reject with error
    var called = false;
    function onError(value) {
      if (called) {
        return;
      }
      called = true;
      handlers.reject(self, value);
    }
  
    function onSuccess(value) {
      if (called) {
        return;
      }
      called = true;
      handlers.resolve(self, value);
    }
  
    function tryToUnwrap() {
      thenable(onSuccess, onError);
    }
  
    var result = tryCatch(tryToUnwrap);
    if (result.status === 'error') {
      onError(result.value);
    }
  }
  
  function tryCatch(func, value) {
    var out = {};
    try {
      out.value = func(value);
      out.status = 'success';
    } catch (e) {
      out.status = 'error';
      out.value = e;
    }
    return out;
  }
  
  Promise.resolve = resolve;
  function resolve(value) {
    if (value instanceof this) {
      return value;
    }
    return handlers.resolve(new this(INTERNAL), value);
  }
  
  Promise.reject = reject;
  function reject(reason) {
    var promise = new this(INTERNAL);
    return handlers.reject(promise, reason);
  }
  
  Promise.all = all;
  function all(iterable) {
    var self = this;
    if (Object.prototype.toString.call(iterable) !== '[object Array]') {
      return this.reject(new TypeError('must be an array'));
    }
  
    var len = iterable.length;
    var called = false;
    if (!len) {
      return this.resolve([]);
    }
  
    var values = new Array(len);
    var resolved = 0;
    var i = -1;
    var promise = new this(INTERNAL);
  
    while (++i < len) {
      allResolver(iterable[i], i);
    }
    return promise;
    function allResolver(value, i) {
      self.resolve(value).then(resolveFromAll, function (error) {
        if (!called) {
          called = true;
          handlers.reject(promise, error);
        }
      });
      function resolveFromAll(outValue) {
        values[i] = outValue;
        if (++resolved === len && !called) {
          called = true;
          handlers.resolve(promise, values);
        }
      }
    }
  }
  
  Promise.race = race;
  function race(iterable) {
    var self = this;
    if (Object.prototype.toString.call(iterable) !== '[object Array]') {
      return this.reject(new TypeError('must be an array'));
    }
  
    var len = iterable.length;
    var called = false;
    if (!len) {
      return this.resolve([]);
    }
  
    var i = -1;
    var promise = new this(INTERNAL);
  
    while (++i < len) {
      resolver(iterable[i]);
    }
    return promise;
    function resolver(value) {
      self.resolve(value).then(function (response) {
        if (!called) {
          called = true;
          handlers.resolve(promise, response);
        }
      }, function (error) {
        if (!called) {
          called = true;
          handlers.reject(promise, error);
        }
      });
    }
  }
  
  },{"22":22}],26:[function(_dereq_,module,exports){
  /**
   * Helpers.
   */
  
  var s = 1000;
  var m = s * 60;
  var h = m * 60;
  var d = h * 24;
  var y = d * 365.25;
  
  /**
   * Parse or format the given `val`.
   *
   * Options:
   *
   *  - `long` verbose formatting [false]
   *
   * @param {String|Number} val
   * @param {Object} options
   * @return {String|Number}
   * @api public
   */
  
  module.exports = function(val, options){
    options = options || {};
    if ('string' == typeof val) return parse(val);
    return options["long"]
      ? long(val)
      : short(val);
  };
  
  /**
   * Parse the given `str` and return milliseconds.
   *
   * @param {String} str
   * @return {Number}
   * @api private
   */
  
  function parse(str) {
    str = '' + str;
    if (str.length > 10000) return;
    var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
    if (!match) return;
    var n = parseFloat(match[1]);
    var type = (match[2] || 'ms').toLowerCase();
    switch (type) {
      case 'years':
      case 'year':
      case 'yrs':
      case 'yr':
      case 'y':
        return n * y;
      case 'days':
      case 'day':
      case 'd':
        return n * d;
      case 'hours':
      case 'hour':
      case 'hrs':
      case 'hr':
      case 'h':
        return n * h;
      case 'minutes':
      case 'minute':
      case 'mins':
      case 'min':
      case 'm':
        return n * m;
      case 'seconds':
      case 'second':
      case 'secs':
      case 'sec':
      case 's':
        return n * s;
      case 'milliseconds':
      case 'millisecond':
      case 'msecs':
      case 'msec':
      case 'ms':
        return n;
    }
  }
  
  /**
   * Short format for `ms`.
   *
   * @param {Number} ms
   * @return {String}
   * @api private
   */
  
  function short(ms) {
    if (ms >= d) return Math.round(ms / d) + 'd';
    if (ms >= h) return Math.round(ms / h) + 'h';
    if (ms >= m) return Math.round(ms / m) + 'm';
    if (ms >= s) return Math.round(ms / s) + 's';
    return ms + 'ms';
  }
  
  /**
   * Long format for `ms`.
   *
   * @param {Number} ms
   * @return {String}
   * @api private
   */
  
  function long(ms) {
    return plural(ms, d, 'day')
      || plural(ms, h, 'hour')
      || plural(ms, m, 'minute')
      || plural(ms, s, 'second')
      || ms + ' ms';
  }
  
  /**
   * Pluralization helper.
   */
  
  function plural(ms, n, name) {
    if (ms < n) return;
    if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
    return Math.ceil(ms / n) + ' ' + name + 's';
  }
  
  },{}],27:[function(_dereq_,module,exports){
  'use strict';
  
  var MIN_MAGNITUDE = -324; // verified by -Number.MIN_VALUE
  var MAGNITUDE_DIGITS = 3; // ditto
  var SEP = ''; // set to '_' for easier debugging 
  
  var utils = _dereq_(28);
  
  exports.collate = function (a, b) {
  
    if (a === b) {
      return 0;
    }
  
    a = exports.normalizeKey(a);
    b = exports.normalizeKey(b);
  
    var ai = collationIndex(a);
    var bi = collationIndex(b);
    if ((ai - bi) !== 0) {
      return ai - bi;
    }
    if (a === null) {
      return 0;
    }
    switch (typeof a) {
      case 'number':
        return a - b;
      case 'boolean':
        return a === b ? 0 : (a < b ? -1 : 1);
      case 'string':
        return stringCollate(a, b);
    }
    return Array.isArray(a) ? arrayCollate(a, b) : objectCollate(a, b);
  };
  
  // couch considers null/NaN/Infinity/-Infinity === undefined,
  // for the purposes of mapreduce indexes. also, dates get stringified.
  exports.normalizeKey = function (key) {
    switch (typeof key) {
      case 'undefined':
        return null;
      case 'number':
        if (key === Infinity || key === -Infinity || isNaN(key)) {
          return null;
        }
        return key;
      case 'object':
        var origKey = key;
        if (Array.isArray(key)) {
          var len = key.length;
          key = new Array(len);
          for (var i = 0; i < len; i++) {
            key[i] = exports.normalizeKey(origKey[i]);
          }
        } else if (key instanceof Date) {
          return key.toJSON();
        } else if (key !== null) { // generic object
          key = {};
          for (var k in origKey) {
            if (origKey.hasOwnProperty(k)) {
              var val = origKey[k];
              if (typeof val !== 'undefined') {
                key[k] = exports.normalizeKey(val);
              }
            }
          }
        }
    }
    return key;
  };
  
  function indexify(key) {
    if (key !== null) {
      switch (typeof key) {
        case 'boolean':
          return key ? 1 : 0;
        case 'number':
          return numToIndexableString(key);
        case 'string':
          // We've to be sure that key does not contain \u0000
          // Do order-preserving replacements:
          // 0 -> 1, 1
          // 1 -> 1, 2
          // 2 -> 2, 2
          return key
            .replace(/\u0002/g, '\u0002\u0002')
            .replace(/\u0001/g, '\u0001\u0002')
            .replace(/\u0000/g, '\u0001\u0001');
        case 'object':
          var isArray = Array.isArray(key);
          var arr = isArray ? key : Object.keys(key);
          var i = -1;
          var len = arr.length;
          var result = '';
          if (isArray) {
            while (++i < len) {
              result += exports.toIndexableString(arr[i]);
            }
          } else {
            while (++i < len) {
              var objKey = arr[i];
              result += exports.toIndexableString(objKey) +
                  exports.toIndexableString(key[objKey]);
            }
          }
          return result;
      }
    }
    return '';
  }
  
  // convert the given key to a string that would be appropriate
  // for lexical sorting, e.g. within a database, where the
  // sorting is the same given by the collate() function.
  exports.toIndexableString = function (key) {
    var zero = '\u0000';
    key = exports.normalizeKey(key);
    return collationIndex(key) + SEP + indexify(key) + zero;
  };
  
  function parseNumber(str, i) {
    var originalIdx = i;
    var num;
    var zero = str[i] === '1';
    if (zero) {
      num = 0;
      i++;
    } else {
      var neg = str[i] === '0';
      i++;
      var numAsString = '';
      var magAsString = str.substring(i, i + MAGNITUDE_DIGITS);
      var magnitude = parseInt(magAsString, 10) + MIN_MAGNITUDE;
      if (neg) {
        magnitude = -magnitude;
      }
      i += MAGNITUDE_DIGITS;
      while (true) {
        var ch = str[i];
        if (ch === '\u0000') {
          break;
        } else {
          numAsString += ch;
        }
        i++;
      }
      numAsString = numAsString.split('.');
      if (numAsString.length === 1) {
        num = parseInt(numAsString, 10);
      } else {
        num = parseFloat(numAsString[0] + '.' + numAsString[1]);
      }
      if (neg) {
        num = num - 10;
      }
      if (magnitude !== 0) {
        // parseFloat is more reliable than pow due to rounding errors
        // e.g. Number.MAX_VALUE would return Infinity if we did
        // num * Math.pow(10, magnitude);
        num = parseFloat(num + 'e' + magnitude);
      }
    }
    return {num: num, length : i - originalIdx};
  }
  
  // move up the stack while parsing
  // this function moved outside of parseIndexableString for performance
  function pop(stack, metaStack) {
    var obj = stack.pop();
  
    if (metaStack.length) {
      var lastMetaElement = metaStack[metaStack.length - 1];
      if (obj === lastMetaElement.element) {
        // popping a meta-element, e.g. an object whose value is another object
        metaStack.pop();
        lastMetaElement = metaStack[metaStack.length - 1];
      }
      var element = lastMetaElement.element;
      var lastElementIndex = lastMetaElement.index;
      if (Array.isArray(element)) {
        element.push(obj);
      } else if (lastElementIndex === stack.length - 2) { // obj with key+value
        var key = stack.pop();
        element[key] = obj;
      } else {
        stack.push(obj); // obj with key only
      }
    }
  }
  
  exports.parseIndexableString = function (str) {
    var stack = [];
    var metaStack = []; // stack for arrays and objects
    var i = 0;
  
    while (true) {
      var collationIndex = str[i++];
      if (collationIndex === '\u0000') {
        if (stack.length === 1) {
          return stack.pop();
        } else {
          pop(stack, metaStack);
          continue;
        }
      }
      switch (collationIndex) {
        case '1':
          stack.push(null);
          break;
        case '2':
          stack.push(str[i] === '1');
          i++;
          break;
        case '3':
          var parsedNum = parseNumber(str, i);
          stack.push(parsedNum.num);
          i += parsedNum.length;
          break;
        case '4':
          var parsedStr = '';
          while (true) {
            var ch = str[i];
            if (ch === '\u0000') {
              break;
            }
            parsedStr += ch;
            i++;
          }
          // perform the reverse of the order-preserving replacement
          // algorithm (see above)
          parsedStr = parsedStr.replace(/\u0001\u0001/g, '\u0000')
            .replace(/\u0001\u0002/g, '\u0001')
            .replace(/\u0002\u0002/g, '\u0002');
          stack.push(parsedStr);
          break;
        case '5':
          var arrayElement = { element: [], index: stack.length };
          stack.push(arrayElement.element);
          metaStack.push(arrayElement);
          break;
        case '6':
          var objElement = { element: {}, index: stack.length };
          stack.push(objElement.element);
          metaStack.push(objElement);
          break;
        default:
          throw new Error(
            'bad collationIndex or unexpectedly reached end of input: ' + collationIndex);
      }
    }
  };
  
  function arrayCollate(a, b) {
    var len = Math.min(a.length, b.length);
    for (var i = 0; i < len; i++) {
      var sort = exports.collate(a[i], b[i]);
      if (sort !== 0) {
        return sort;
      }
    }
    return (a.length === b.length) ? 0 :
      (a.length > b.length) ? 1 : -1;
  }
  function stringCollate(a, b) {
    // See: https://github.com/daleharvey/pouchdb/issues/40
    // This is incompatible with the CouchDB implementation, but its the
    // best we can do for now
    return (a === b) ? 0 : ((a > b) ? 1 : -1);
  }
  function objectCollate(a, b) {
    var ak = Object.keys(a), bk = Object.keys(b);
    var len = Math.min(ak.length, bk.length);
    for (var i = 0; i < len; i++) {
      // First sort the keys
      var sort = exports.collate(ak[i], bk[i]);
      if (sort !== 0) {
        return sort;
      }
      // if the keys are equal sort the values
      sort = exports.collate(a[ak[i]], b[bk[i]]);
      if (sort !== 0) {
        return sort;
      }
  
    }
    return (ak.length === bk.length) ? 0 :
      (ak.length > bk.length) ? 1 : -1;
  }
  // The collation is defined by erlangs ordered terms
  // the atoms null, true, false come first, then numbers, strings,
  // arrays, then objects
  // null/undefined/NaN/Infinity/-Infinity are all considered null
  function collationIndex(x) {
    var id = ['boolean', 'number', 'string', 'object'];
    var idx = id.indexOf(typeof x);
    //false if -1 otherwise true, but fast!!!!1
    if (~idx) {
      if (x === null) {
        return 1;
      }
      if (Array.isArray(x)) {
        return 5;
      }
      return idx < 3 ? (idx + 2) : (idx + 3);
    }
    if (Array.isArray(x)) {
      return 5;
    }
  }
  
  // conversion:
  // x yyy zz...zz
  // x = 0 for negative, 1 for 0, 2 for positive
  // y = exponent (for negative numbers negated) moved so that it's >= 0
  // z = mantisse
  function numToIndexableString(num) {
  
    if (num === 0) {
      return '1';
    }
  
    // convert number to exponential format for easier and
    // more succinct string sorting
    var expFormat = num.toExponential().split(/e\+?/);
    var magnitude = parseInt(expFormat[1], 10);
  
    var neg = num < 0;
  
    var result = neg ? '0' : '2';
  
    // first sort by magnitude
    // it's easier if all magnitudes are positive
    var magForComparison = ((neg ? -magnitude : magnitude) - MIN_MAGNITUDE);
    var magString = utils.padLeft((magForComparison).toString(), '0', MAGNITUDE_DIGITS);
  
    result += SEP + magString;
  
    // then sort by the factor
    var factor = Math.abs(parseFloat(expFormat[0])); // [1..10)
    if (neg) { // for negative reverse ordering
      factor = 10 - factor;
    }
  
    var factorStr = factor.toFixed(20);
  
    // strip zeros from the end
    factorStr = factorStr.replace(/\.?0+$/, '');
  
    result += SEP + factorStr;
  
    return result;
  }
  
  },{"28":28}],28:[function(_dereq_,module,exports){
  'use strict';
  
  function pad(str, padWith, upToLength) {
    var padding = '';
    var targetLength = upToLength - str.length;
    while (padding.length < targetLength) {
      padding += padWith;
    }
    return padding;
  }
  
  exports.padLeft = function (str, padWith, upToLength) {
    var padding = pad(str, padWith, upToLength);
    return padding + str;
  };
  
  exports.padRight = function (str, padWith, upToLength) {
    var padding = pad(str, padWith, upToLength);
    return str + padding;
  };
  
  exports.stringLexCompare = function (a, b) {
  
    var aLen = a.length;
    var bLen = b.length;
  
    var i;
    for (i = 0; i < aLen; i++) {
      if (i === bLen) {
        // b is shorter substring of a
        return 1;
      }
      var aChar = a.charAt(i);
      var bChar = b.charAt(i);
      if (aChar !== bChar) {
        return aChar < bChar ? -1 : 1;
      }
    }
  
    if (aLen < bLen) {
      // a is shorter substring of b
      return -1;
    }
  
    return 0;
  };
  
  /*
   * returns the decimal form for the given integer, i.e. writes
   * out all the digits (in base-10) instead of using scientific notation
   */
  exports.intToDecimalForm = function (int) {
  
    var isNeg = int < 0;
    var result = '';
  
    do {
      var remainder = isNeg ? -Math.ceil(int % 10) : Math.floor(int % 10);
  
      result = remainder + result;
      int = isNeg ? Math.ceil(int / 10) : Math.floor(int / 10);
    } while (int);
  
  
    if (isNeg && result !== '0') {
      result = '-' + result;
    }
  
    return result;
  };
  },{}],29:[function(_dereq_,module,exports){
  "use strict";
  
  // Extends method
  // (taken from http://code.jquery.com/jquery-1.9.0.js)
  // Populate the class2type map
  var class2type = {};
  
  var types = [
    "Boolean", "Number", "String", "Function", "Array",
    "Date", "RegExp", "Object", "Error"
  ];
  for (var i = 0; i < types.length; i++) {
    var typename = types[i];
    class2type["[object " + typename + "]"] = typename.toLowerCase();
  }
  
  var core_toString = class2type.toString;
  var core_hasOwn = class2type.hasOwnProperty;
  
  function type(obj) {
    if (obj === null) {
      return String(obj);
    }
    return typeof obj === "object" || typeof obj === "function" ?
      class2type[core_toString.call(obj)] || "object" :
      typeof obj;
  }
  
  function isWindow(obj) {
    return obj !== null && obj === obj.window;
  }
  
  function isPlainObject(obj) {
    // Must be an Object.
    // Because of IE, we also have to check the presence of
    // the constructor property.
    // Make sure that DOM nodes and window objects don't pass through, as well
    if (!obj || type(obj) !== "object" || obj.nodeType || isWindow(obj)) {
      return false;
    }
  
    try {
      // Not own constructor property must be Object
      if (obj.constructor &&
        !core_hasOwn.call(obj, "constructor") &&
        !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
        return false;
      }
    } catch ( e ) {
      // IE8,9 Will throw exceptions on certain host objects #9897
      return false;
    }
  
    // Own properties are enumerated firstly, so to speed up,
    // if last one is own, then all properties are own.
    var key;
    for (key in obj) {}
  
    return key === undefined || core_hasOwn.call(obj, key);
  }
  
  
  function isFunction(obj) {
    return type(obj) === "function";
  }
  
  var isArray = Array.isArray || function (obj) {
    return type(obj) === "array";
  };
  
  function extend() {
    // originally extend() was recursive, but this ended up giving us
    // "call stack exceeded", so it's been unrolled to use a literal stack
    // (see https://github.com/pouchdb/pouchdb/issues/2543)
    var stack = [];
    var i = -1;
    var len = arguments.length;
    var args = new Array(len);
    while (++i < len) {
      args[i] = arguments[i];
    }
    var container = {};
    stack.push({args: args, result: {container: container, key: 'key'}});
    var next;
    while ((next = stack.pop())) {
      extendInner(stack, next.args, next.result);
    }
    return container.key;
  }
  
  function extendInner(stack, args, result) {
    var options, name, src, copy, copyIsArray, clone,
      target = args[0] || {},
      i = 1,
      length = args.length,
      deep = false,
      numericStringRegex = /\d+/,
      optionsIsArray;
  
    // Handle a deep copy situation
    if (typeof target === "boolean") {
      deep = target;
      target = args[1] || {};
      // skip the boolean and the target
      i = 2;
    }
  
    // Handle case when target is a string or something (possible in deep copy)
    if (typeof target !== "object" && !isFunction(target)) {
      target = {};
    }
  
    // extend jQuery itself if only one argument is passed
    if (length === i) {
      /* jshint validthis: true */
      target = this;
      --i;
    }
  
    for (; i < length; i++) {
      // Only deal with non-null/undefined values
      if ((options = args[i]) != null) {
        optionsIsArray = isArray(options);
        // Extend the base object
        for (name in options) {
          //if (options.hasOwnProperty(name)) {
          if (!(name in Object.prototype)) {
            if (optionsIsArray && !numericStringRegex.test(name)) {
              continue;
            }
  
            src = target[name];
            copy = options[name];
  
            // Prevent never-ending loop
            if (target === copy) {
              continue;
            }
  
            // Recurse if we're merging plain objects or arrays
            if (deep && copy && (isPlainObject(copy) ||
                (copyIsArray = isArray(copy)))) {
              if (copyIsArray) {
                copyIsArray = false;
                clone = src && isArray(src) ? src : [];
  
              } else {
                clone = src && isPlainObject(src) ? src : {};
              }
  
              // Never move original objects, clone them
              stack.push({
                args: [deep, clone, copy],
                result: {
                  container: target,
                  key: name
                }
              });
  
            // Don't bring in undefined values
            } else if (copy !== undefined) {
              if (!(isArray(options) && isFunction(copy))) {
                target[name] = copy;
              }
            }
          }
        }
      }
    }
  
    // "Return" the modified object by setting the key
    // on the given container
    result.container[result.key] = target;
  }
  
  
  module.exports = extend;
  
  
  
  },{}],30:[function(_dereq_,module,exports){
  'use strict';
  
  function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  
  var lie = _interopDefault(_dereq_(25));
  
  /* istanbul ignore next */
  var PouchPromise = typeof Promise === 'function' ? Promise : lie;
  
  module.exports = PouchPromise;
  },{"25":25}],31:[function(_dereq_,module,exports){
  'use strict';
  
  var PouchPromise = _dereq_(32);
  
  // this is essentially the "update sugar" function from daleharvey/pouchdb#1388
  // the diffFun tells us what delta to apply to the doc.  it either returns
  // the doc, or false if it doesn't need to do an update after all
  function upsertInner(db, docId, diffFun) {
    if (typeof docId !== 'string') {
      return PouchPromise.reject(new Error('doc id is required'));
    }
  
    return db.get(docId)["catch"](function (err) {
      /* istanbul ignore next */
      if (err.status !== 404) {
        throw err;
      }
      return {};
    }).then(function (doc) {
      // the user might change the _rev, so save it for posterity
      var docRev = doc._rev;
      var newDoc = diffFun(doc);
  
      if (!newDoc) {
        // if the diffFun returns falsy, we short-circuit as
        // an optimization
        return { updated: false, rev: docRev };
      }
  
      // users aren't allowed to modify these values,
      // so reset them here
      newDoc._id = docId;
      newDoc._rev = docRev;
      return tryAndPut(db, newDoc, diffFun);
    });
  }
  
  function tryAndPut(db, doc, diffFun) {
    return db.put(doc).then(function (res) {
      return {
        updated: true,
        rev: res.rev
      };
    }, function (err) {
      /* istanbul ignore next */
      if (err.status !== 409) {
        throw err;
      }
      return upsertInner(db, doc._id, diffFun);
    });
  }
  
  exports.upsert = function upsert(docId, diffFun, cb) {
    var db = this;
    var promise = upsertInner(db, docId, diffFun);
    if (typeof cb !== 'function') {
      return promise;
    }
    promise.then(function (resp) {
      cb(null, resp);
    }, cb);
  };
  
  exports.putIfNotExists = function putIfNotExists(docId, doc, cb) {
    var db = this;
  
    if (typeof docId !== 'string') {
      cb = doc;
      doc = docId;
      docId = doc._id;
    }
  
    var diffFun = function (existingDoc) {
      if (existingDoc._rev) {
        return false; // do nothing
      }
      return doc;
    };
  
    var promise = upsertInner(db, docId, diffFun);
    if (typeof cb !== 'function') {
      return promise;
    }
    promise.then(function (resp) {
      cb(null, resp);
    }, cb);
  };
  
  
  /* istanbul ignore next */
  if (typeof window !== 'undefined' && window.PouchDB) {
    window.PouchDB.plugin(exports);
  }
  
  },{"32":32}],32:[function(_dereq_,module,exports){
  arguments[4][30][0].apply(exports,arguments)
  },{"25":25,"30":30}],33:[function(_dereq_,module,exports){
  // shim for using process in browser
  
  var process = module.exports = {};
  
  // cached from whatever global is present so that test runners that stub it
  // don't break things.  But we need to wrap it in a try catch in case it is
  // wrapped in strict mode code which doesn't define any globals.  It's inside a
  // function because try/catches deoptimize in certain engines.
  
  var cachedSetTimeout;
  var cachedClearTimeout;
  
  (function () {
    try {
      cachedSetTimeout = setTimeout;
    } catch (e) {
      cachedSetTimeout = function () {
        throw new Error('setTimeout is not defined');
      }
    }
    try {
      cachedClearTimeout = clearTimeout;
    } catch (e) {
      cachedClearTimeout = function () {
        throw new Error('clearTimeout is not defined');
      }
    }
  } ())
  var queue = [];
  var draining = false;
  var currentQueue;
  var queueIndex = -1;
  
  function cleanUpNextTick() {
      if (!draining || !currentQueue) {
          return;
      }
      draining = false;
      if (currentQueue.length) {
          queue = currentQueue.concat(queue);
      } else {
          queueIndex = -1;
      }
      if (queue.length) {
          drainQueue();
      }
  }
  
  function drainQueue() {
      if (draining) {
          return;
      }
      var timeout = cachedSetTimeout(cleanUpNextTick);
      draining = true;
  
      var len = queue.length;
      while(len) {
          currentQueue = queue;
          queue = [];
          while (++queueIndex < len) {
              if (currentQueue) {
                  currentQueue[queueIndex].run();
              }
          }
          queueIndex = -1;
          len = queue.length;
      }
      currentQueue = null;
      draining = false;
      cachedClearTimeout(timeout);
  }
  
  process.nextTick = function (fun) {
      var args = new Array(arguments.length - 1);
      if (arguments.length > 1) {
          for (var i = 1; i < arguments.length; i++) {
              args[i - 1] = arguments[i];
          }
      }
      queue.push(new Item(fun, args));
      if (queue.length === 1 && !draining) {
          cachedSetTimeout(drainQueue, 0);
      }
  };
  
  // v8 likes predictible objects
  function Item(fun, array) {
      this.fun = fun;
      this.array = array;
  }
  Item.prototype.run = function () {
      this.fun.apply(null, this.array);
  };
  process.title = 'browser';
  process.browser = true;
  process.env = {};
  process.argv = [];
  process.version = ''; // empty string to avoid regexp issues
  process.versions = {};
  
  function noop() {}
  
  process.on = noop;
  process.addListener = noop;
  process.once = noop;
  process.off = noop;
  process.removeListener = noop;
  process.removeAllListeners = noop;
  process.emit = noop;
  
  process.binding = function (name) {
      throw new Error('process.binding is not supported');
  };
  
  process.cwd = function () { return '/' };
  process.chdir = function (dir) {
      throw new Error('process.chdir is not supported');
  };
  process.umask = function() { return 0; };
  
  },{}],34:[function(_dereq_,module,exports){
  /*jshint bitwise:false*/
  /*global unescape*/
  
  (function (factory) {
      if (typeof exports === 'object') {
          // Node/CommonJS
          module.exports = factory();
      } else if (typeof define === 'function' && define.amd) {
          // AMD
          define(factory);
      } else {
          // Browser globals (with support for web workers)
          var glob;
          try {
              glob = window;
          } catch (e) {
              glob = self;
          }
  
          glob.SparkMD5 = factory();
      }
  }(function (undefined) {
  
      'use strict';
  
      ////////////////////////////////////////////////////////////////////////////
  
      /*
       * Fastest md5 implementation around (JKM md5)
       * Credits: Joseph Myers
       *
       * @see http://www.myersdaily.org/joseph/javascript/md5-text.html
       * @see http://jsperf.com/md5-shootout/7
       */
  
      /* this function is much faster,
        so if possible we use it. Some IEs
        are the only ones I know of that
        need the idiotic second function,
        generated by an if clause.  */
      var add32 = function (a, b) {
          return (a + b) & 0xFFFFFFFF;
      },
  
      cmn = function (q, a, b, x, s, t) {
          a = add32(add32(a, q), add32(x, t));
          return add32((a << s) | (a >>> (32 - s)), b);
      },
  
      ff = function (a, b, c, d, x, s, t) {
          return cmn((b & c) | ((~b) & d), a, b, x, s, t);
      },
  
      gg = function (a, b, c, d, x, s, t) {
          return cmn((b & d) | (c & (~d)), a, b, x, s, t);
      },
  
      hh = function (a, b, c, d, x, s, t) {
          return cmn(b ^ c ^ d, a, b, x, s, t);
      },
  
      ii = function (a, b, c, d, x, s, t) {
          return cmn(c ^ (b | (~d)), a, b, x, s, t);
      },
  
      md5cycle = function (x, k) {
          var a = x[0],
              b = x[1],
              c = x[2],
              d = x[3];
  
          a = ff(a, b, c, d, k[0], 7, -680876936);
          d = ff(d, a, b, c, k[1], 12, -389564586);
          c = ff(c, d, a, b, k[2], 17, 606105819);
          b = ff(b, c, d, a, k[3], 22, -1044525330);
          a = ff(a, b, c, d, k[4], 7, -176418897);
          d = ff(d, a, b, c, k[5], 12, 1200080426);
          c = ff(c, d, a, b, k[6], 17, -1473231341);
          b = ff(b, c, d, a, k[7], 22, -45705983);
          a = ff(a, b, c, d, k[8], 7, 1770035416);
          d = ff(d, a, b, c, k[9], 12, -1958414417);
          c = ff(c, d, a, b, k[10], 17, -42063);
          b = ff(b, c, d, a, k[11], 22, -1990404162);
          a = ff(a, b, c, d, k[12], 7, 1804603682);
          d = ff(d, a, b, c, k[13], 12, -40341101);
          c = ff(c, d, a, b, k[14], 17, -1502002290);
          b = ff(b, c, d, a, k[15], 22, 1236535329);
  
          a = gg(a, b, c, d, k[1], 5, -165796510);
          d = gg(d, a, b, c, k[6], 9, -1069501632);
          c = gg(c, d, a, b, k[11], 14, 643717713);
          b = gg(b, c, d, a, k[0], 20, -373897302);
          a = gg(a, b, c, d, k[5], 5, -701558691);
          d = gg(d, a, b, c, k[10], 9, 38016083);
          c = gg(c, d, a, b, k[15], 14, -660478335);
          b = gg(b, c, d, a, k[4], 20, -405537848);
          a = gg(a, b, c, d, k[9], 5, 568446438);
          d = gg(d, a, b, c, k[14], 9, -1019803690);
          c = gg(c, d, a, b, k[3], 14, -187363961);
          b = gg(b, c, d, a, k[8], 20, 1163531501);
          a = gg(a, b, c, d, k[13], 5, -1444681467);
          d = gg(d, a, b, c, k[2], 9, -51403784);
          c = gg(c, d, a, b, k[7], 14, 1735328473);
          b = gg(b, c, d, a, k[12], 20, -1926607734);
  
          a = hh(a, b, c, d, k[5], 4, -378558);
          d = hh(d, a, b, c, k[8], 11, -2022574463);
          c = hh(c, d, a, b, k[11], 16, 1839030562);
          b = hh(b, c, d, a, k[14], 23, -35309556);
          a = hh(a, b, c, d, k[1], 4, -1530992060);
          d = hh(d, a, b, c, k[4], 11, 1272893353);
          c = hh(c, d, a, b, k[7], 16, -155497632);
          b = hh(b, c, d, a, k[10], 23, -1094730640);
          a = hh(a, b, c, d, k[13], 4, 681279174);
          d = hh(d, a, b, c, k[0], 11, -358537222);
          c = hh(c, d, a, b, k[3], 16, -722521979);
          b = hh(b, c, d, a, k[6], 23, 76029189);
          a = hh(a, b, c, d, k[9], 4, -640364487);
          d = hh(d, a, b, c, k[12], 11, -421815835);
          c = hh(c, d, a, b, k[15], 16, 530742520);
          b = hh(b, c, d, a, k[2], 23, -995338651);
  
          a = ii(a, b, c, d, k[0], 6, -198630844);
          d = ii(d, a, b, c, k[7], 10, 1126891415);
          c = ii(c, d, a, b, k[14], 15, -1416354905);
          b = ii(b, c, d, a, k[5], 21, -57434055);
          a = ii(a, b, c, d, k[12], 6, 1700485571);
          d = ii(d, a, b, c, k[3], 10, -1894986606);
          c = ii(c, d, a, b, k[10], 15, -1051523);
          b = ii(b, c, d, a, k[1], 21, -2054922799);
          a = ii(a, b, c, d, k[8], 6, 1873313359);
          d = ii(d, a, b, c, k[15], 10, -30611744);
          c = ii(c, d, a, b, k[6], 15, -1560198380);
          b = ii(b, c, d, a, k[13], 21, 1309151649);
          a = ii(a, b, c, d, k[4], 6, -145523070);
          d = ii(d, a, b, c, k[11], 10, -1120210379);
          c = ii(c, d, a, b, k[2], 15, 718787259);
          b = ii(b, c, d, a, k[9], 21, -343485551);
  
          x[0] = add32(a, x[0]);
          x[1] = add32(b, x[1]);
          x[2] = add32(c, x[2]);
          x[3] = add32(d, x[3]);
      },
  
      /* there needs to be support for Unicode here,
         * unless we pretend that we can redefine the MD-5
         * algorithm for multi-byte characters (perhaps
         * by adding every four 16-bit characters and
         * shortening the sum to 32 bits). Otherwise
         * I suggest performing MD-5 as if every character
         * was two bytes--e.g., 0040 0025 = @%--but then
         * how will an ordinary MD-5 sum be matched?
         * There is no way to standardize text to something
         * like UTF-8 before transformation; speed cost is
         * utterly prohibitive. The JavaScript standard
         * itself needs to look at this: it should start
         * providing access to strings as preformed UTF-8
         * 8-bit unsigned value arrays.
         */
      md5blk = function (s) {
          var md5blks = [],
              i; /* Andy King said do it this way. */
  
          for (i = 0; i < 64; i += 4) {
              md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
          }
          return md5blks;
      },
  
      md5blk_array = function (a) {
          var md5blks = [],
              i; /* Andy King said do it this way. */
  
          for (i = 0; i < 64; i += 4) {
              md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
          }
          return md5blks;
      },
  
      md51 = function (s) {
          var n = s.length,
              state = [1732584193, -271733879, -1732584194, 271733878],
              i,
              length,
              tail,
              tmp,
              lo,
              hi;
  
          for (i = 64; i <= n; i += 64) {
              md5cycle(state, md5blk(s.substring(i - 64, i)));
          }
          s = s.substring(i - 64);
          length = s.length;
          tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
          for (i = 0; i < length; i += 1) {
              tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
          }
          tail[i >> 2] |= 0x80 << ((i % 4) << 3);
          if (i > 55) {
              md5cycle(state, tail);
              for (i = 0; i < 16; i += 1) {
                  tail[i] = 0;
              }
          }
  
          // Beware that the final length might not fit in 32 bits so we take care of that
          tmp = n * 8;
          tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
          lo = parseInt(tmp[2], 16);
          hi = parseInt(tmp[1], 16) || 0;
  
          tail[14] = lo;
          tail[15] = hi;
  
          md5cycle(state, tail);
          return state;
      },
  
      md51_array = function (a) {
          var n = a.length,
              state = [1732584193, -271733879, -1732584194, 271733878],
              i,
              length,
              tail,
              tmp,
              lo,
              hi;
  
          for (i = 64; i <= n; i += 64) {
              md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
          }
  
          // Not sure if it is a bug, however IE10 will always produce a sub array of length 1
          // containing the last element of the parent array if the sub array specified starts
          // beyond the length of the parent array - weird.
          // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
          a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);
  
          length = a.length;
          tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
          for (i = 0; i < length; i += 1) {
              tail[i >> 2] |= a[i] << ((i % 4) << 3);
          }
  
          tail[i >> 2] |= 0x80 << ((i % 4) << 3);
          if (i > 55) {
              md5cycle(state, tail);
              for (i = 0; i < 16; i += 1) {
                  tail[i] = 0;
              }
          }
  
          // Beware that the final length might not fit in 32 bits so we take care of that
          tmp = n * 8;
          tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
          lo = parseInt(tmp[2], 16);
          hi = parseInt(tmp[1], 16) || 0;
  
          tail[14] = lo;
          tail[15] = hi;
  
          md5cycle(state, tail);
  
          return state;
      },
  
      hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'],
  
      rhex = function (n) {
          var s = '',
              j;
          for (j = 0; j < 4; j += 1) {
              s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
          }
          return s;
      },
  
      hex = function (x) {
          var i;
          for (i = 0; i < x.length; i += 1) {
              x[i] = rhex(x[i]);
          }
          return x.join('');
      },
  
      md5 = function (s) {
          return hex(md51(s));
      },
  
  
  
      ////////////////////////////////////////////////////////////////////////////
  
      /**
       * SparkMD5 OOP implementation.
       *
       * Use this class to perform an incremental md5, otherwise use the
       * static methods instead.
       */
      SparkMD5 = function () {
          // call reset to init the instance
          this.reset();
      };
  
  
      // In some cases the fast add32 function cannot be used..
      if (md5('hello') !== '5d41402abc4b2a76b9719d911017c592') {
          add32 = function (x, y) {
              var lsw = (x & 0xFFFF) + (y & 0xFFFF),
                  msw = (x >> 16) + (y >> 16) + (lsw >> 16);
              return (msw << 16) | (lsw & 0xFFFF);
          };
      }
  
  
      /**
       * Appends a string.
       * A conversion will be applied if an utf8 string is detected.
       *
       * @param {String} str The string to be appended
       *
       * @return {SparkMD5} The instance itself
       */
      SparkMD5.prototype.append = function (str) {
          // converts the string to utf8 bytes if necessary
          if (/[\u0080-\uFFFF]/.test(str)) {
              str = unescape(encodeURIComponent(str));
          }
  
          // then append as binary
          this.appendBinary(str);
  
          return this;
      };
  
      /**
       * Appends a binary string.
       *
       * @param {String} contents The binary string to be appended
       *
       * @return {SparkMD5} The instance itself
       */
      SparkMD5.prototype.appendBinary = function (contents) {
          this._buff += contents;
          this._length += contents.length;
  
          var length = this._buff.length,
              i;
  
          for (i = 64; i <= length; i += 64) {
              md5cycle(this._state, md5blk(this._buff.substring(i - 64, i)));
          }
  
          this._buff = this._buff.substr(i - 64);
  
          return this;
      };
  
      /**
       * Finishes the incremental computation, reseting the internal state and
       * returning the result.
       * Use the raw parameter to obtain the raw result instead of the hex one.
       *
       * @param {Boolean} raw True to get the raw result, false to get the hex result
       *
       * @return {String|Array} The result
       */
      SparkMD5.prototype.end = function (raw) {
          var buff = this._buff,
              length = buff.length,
              i,
              tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              ret;
  
          for (i = 0; i < length; i += 1) {
              tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
          }
  
          this._finish(tail, length);
          ret = !!raw ? this._state : hex(this._state);
  
          this.reset();
  
          return ret;
      };
  
      /**
       * Finish the final calculation based on the tail.
       *
       * @param {Array}  tail   The tail (will be modified)
       * @param {Number} length The length of the remaining buffer
       */
      SparkMD5.prototype._finish = function (tail, length) {
          var i = length,
              tmp,
              lo,
              hi;
  
          tail[i >> 2] |= 0x80 << ((i % 4) << 3);
          if (i > 55) {
              md5cycle(this._state, tail);
              for (i = 0; i < 16; i += 1) {
                  tail[i] = 0;
              }
          }
  
          // Do the final computation based on the tail and length
          // Beware that the final length may not fit in 32 bits so we take care of that
          tmp = this._length * 8;
          tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
          lo = parseInt(tmp[2], 16);
          hi = parseInt(tmp[1], 16) || 0;
  
          tail[14] = lo;
          tail[15] = hi;
          md5cycle(this._state, tail);
      };
  
      /**
       * Resets the internal state of the computation.
       *
       * @return {SparkMD5} The instance itself
       */
      SparkMD5.prototype.reset = function () {
          this._buff = "";
          this._length = 0;
          this._state = [1732584193, -271733879, -1732584194, 271733878];
  
          return this;
      };
  
      /**
       * Releases memory used by the incremental buffer and other aditional
       * resources. If you plan to use the instance again, use reset instead.
       */
      SparkMD5.prototype.destroy = function () {
          delete this._state;
          delete this._buff;
          delete this._length;
      };
  
  
      /**
       * Performs the md5 hash on a string.
       * A conversion will be applied if utf8 string is detected.
       *
       * @param {String}  str The string
       * @param {Boolean} raw True to get the raw result, false to get the hex result
       *
       * @return {String|Array} The result
       */
      SparkMD5.hash = function (str, raw) {
          // converts the string to utf8 bytes if necessary
          if (/[\u0080-\uFFFF]/.test(str)) {
              str = unescape(encodeURIComponent(str));
          }
  
          var hash = md51(str);
  
          return !!raw ? hash : hex(hash);
      };
  
      /**
       * Performs the md5 hash on a binary string.
       *
       * @param {String}  content The binary string
       * @param {Boolean} raw     True to get the raw result, false to get the hex result
       *
       * @return {String|Array} The result
       */
      SparkMD5.hashBinary = function (content, raw) {
          var hash = md51(content);
  
          return !!raw ? hash : hex(hash);
      };
  
      /**
       * SparkMD5 OOP implementation for array buffers.
       *
       * Use this class to perform an incremental md5 ONLY for array buffers.
       */
      SparkMD5.ArrayBuffer = function () {
          // call reset to init the instance
          this.reset();
      };
  
      ////////////////////////////////////////////////////////////////////////////
  
      /**
       * Appends an array buffer.
       *
       * @param {ArrayBuffer} arr The array to be appended
       *
       * @return {SparkMD5.ArrayBuffer} The instance itself
       */
      SparkMD5.ArrayBuffer.prototype.append = function (arr) {
          // TODO: we could avoid the concatenation here but the algorithm would be more complex
          //       if you find yourself needing extra performance, please make a PR.
          var buff = this._concatArrayBuffer(this._buff, arr),
              length = buff.length,
              i;
  
          this._length += arr.byteLength;
  
          for (i = 64; i <= length; i += 64) {
              md5cycle(this._state, md5blk_array(buff.subarray(i - 64, i)));
          }
  
          // Avoids IE10 weirdness (documented above)
          this._buff = (i - 64) < length ? buff.subarray(i - 64) : new Uint8Array(0);
  
          return this;
      };
  
      /**
       * Finishes the incremental computation, reseting the internal state and
       * returning the result.
       * Use the raw parameter to obtain the raw result instead of the hex one.
       *
       * @param {Boolean} raw True to get the raw result, false to get the hex result
       *
       * @return {String|Array} The result
       */
      SparkMD5.ArrayBuffer.prototype.end = function (raw) {
          var buff = this._buff,
              length = buff.length,
              tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
              i,
              ret;
  
          for (i = 0; i < length; i += 1) {
              tail[i >> 2] |= buff[i] << ((i % 4) << 3);
          }
  
          this._finish(tail, length);
          ret = !!raw ? this._state : hex(this._state);
  
          this.reset();
  
          return ret;
      };
  
      SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
  
      /**
       * Resets the internal state of the computation.
       *
       * @return {SparkMD5.ArrayBuffer} The instance itself
       */
      SparkMD5.ArrayBuffer.prototype.reset = function () {
          this._buff = new Uint8Array(0);
          this._length = 0;
          this._state = [1732584193, -271733879, -1732584194, 271733878];
  
          return this;
      };
  
      /**
       * Releases memory used by the incremental buffer and other aditional
       * resources. If you plan to use the instance again, use reset instead.
       */
      SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
  
      /**
       * Concats two array buffers, returning a new one.
       *
       * @param  {ArrayBuffer} first  The first array buffer
       * @param  {ArrayBuffer} second The second array buffer
       *
       * @return {ArrayBuffer} The new array buffer
       */
      SparkMD5.ArrayBuffer.prototype._concatArrayBuffer = function (first, second) {
          var firstLength = first.length,
              result = new Uint8Array(firstLength + second.byteLength);
  
          result.set(first);
          result.set(new Uint8Array(second), firstLength);
  
          return result;
      };
  
      /**
       * Performs the md5 hash on an array buffer.
       *
       * @param {ArrayBuffer} arr The array buffer
       * @param {Boolean}     raw True to get the raw result, false to get the hex result
       *
       * @return {String|Array} The result
       */
      SparkMD5.ArrayBuffer.hash = function (arr, raw) {
          var hash = md51_array(new Uint8Array(arr));
  
          return !!raw ? hash : hex(hash);
      };
  
      return SparkMD5;
  }));
  
  },{}],35:[function(_dereq_,module,exports){
  'use strict';
  
  var utils = _dereq_(17);
  
  var httpIndexes = _dereq_(6);
  var localIndexes = _dereq_(14);
  
  var plugin = {};
  plugin.createIndex = utils.toPromise(function (requestDef, callback) {
  
    if (typeof requestDef !== 'object') {
      return callback(new Error('you must provide an index to create'));
    }
  
    var adapter = this.type() === 'http' ? httpIndexes : localIndexes;
  
    adapter.createIndex(this, requestDef, callback);
  });
  
  plugin.find = utils.toPromise(function (requestDef, callback) {
  
    if (typeof callback === 'undefined') {
      callback = requestDef;
      requestDef = undefined;
    }
  
    if (typeof requestDef !== 'object') {
      return callback(new Error('you must provide search parameters to find()'));
    }
  
    var adapter = this.type() === 'http' ? httpIndexes : localIndexes;
  
    adapter.find(this, requestDef, callback);
  });
  
  plugin.getIndexes = utils.toPromise(function (callback) {
  
    var adapter = this.type() === 'http' ? httpIndexes : localIndexes;
  
    adapter.getIndexes(this, callback);
  });
  
  plugin.deleteIndex = utils.toPromise(function (indexDef, callback) {
  
    if (typeof indexDef !== 'object') {
      return callback(new Error('you must provide an index to delete'));
    }
  
    var adapter = this.type() === 'http' ? httpIndexes : localIndexes;
  
    adapter.deleteIndex(this, indexDef, callback);
  });
  
  module.exports = plugin;
  
  /* istanbul ignore next */
  if (typeof window !== 'undefined' && window.PouchDB) {
    window.PouchDB.plugin(plugin);
  }
  
  },{"14":14,"17":17,"6":6}]},{},[35])(35)
  });