UNPKG

148 kBJavaScriptView Raw
1// PouchDB indexeddb plugin 7.3.0
2(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(_dereq_,module,exports){
3'use strict';
4
5module.exports = argsArray;
6
7function argsArray(fun) {
8 return function () {
9 var len = arguments.length;
10 if (len) {
11 var args = [];
12 var i = -1;
13 while (++i < len) {
14 args[i] = arguments[i];
15 }
16 return fun.call(this, args);
17 } else {
18 return fun.call(this, []);
19 }
20 };
21}
22},{}],2:[function(_dereq_,module,exports){
23
24},{}],3:[function(_dereq_,module,exports){
25// Copyright Joyent, Inc. and other Node contributors.
26//
27// Permission is hereby granted, free of charge, to any person obtaining a
28// copy of this software and associated documentation files (the
29// "Software"), to deal in the Software without restriction, including
30// without limitation the rights to use, copy, modify, merge, publish,
31// distribute, sublicense, and/or sell copies of the Software, and to permit
32// persons to whom the Software is furnished to do so, subject to the
33// following conditions:
34//
35// The above copyright notice and this permission notice shall be included
36// in all copies or substantial portions of the Software.
37//
38// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
39// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
41// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
42// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
43// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
44// USE OR OTHER DEALINGS IN THE SOFTWARE.
45
46var objectCreate = Object.create || objectCreatePolyfill
47var objectKeys = Object.keys || objectKeysPolyfill
48var bind = Function.prototype.bind || functionBindPolyfill
49
50function EventEmitter() {
51 if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) {
52 this._events = objectCreate(null);
53 this._eventsCount = 0;
54 }
55
56 this._maxListeners = this._maxListeners || undefined;
57}
58module.exports = EventEmitter;
59
60// Backwards-compat with node 0.10.x
61EventEmitter.EventEmitter = EventEmitter;
62
63EventEmitter.prototype._events = undefined;
64EventEmitter.prototype._maxListeners = undefined;
65
66// By default EventEmitters will print a warning if more than 10 listeners are
67// added to it. This is a useful default which helps finding memory leaks.
68var defaultMaxListeners = 10;
69
70var hasDefineProperty;
71try {
72 var o = {};
73 if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 });
74 hasDefineProperty = o.x === 0;
75} catch (err) { hasDefineProperty = false }
76if (hasDefineProperty) {
77 Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
78 enumerable: true,
79 get: function() {
80 return defaultMaxListeners;
81 },
82 set: function(arg) {
83 // check whether the input is a positive number (whose value is zero or
84 // greater and not a NaN).
85 if (typeof arg !== 'number' || arg < 0 || arg !== arg)
86 throw new TypeError('"defaultMaxListeners" must be a positive number');
87 defaultMaxListeners = arg;
88 }
89 });
90} else {
91 EventEmitter.defaultMaxListeners = defaultMaxListeners;
92}
93
94// Obviously not all Emitters should be limited to 10. This function allows
95// that to be increased. Set to zero for unlimited.
96EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
97 if (typeof n !== 'number' || n < 0 || isNaN(n))
98 throw new TypeError('"n" argument must be a positive number');
99 this._maxListeners = n;
100 return this;
101};
102
103function $getMaxListeners(that) {
104 if (that._maxListeners === undefined)
105 return EventEmitter.defaultMaxListeners;
106 return that._maxListeners;
107}
108
109EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
110 return $getMaxListeners(this);
111};
112
113// These standalone emit* functions are used to optimize calling of event
114// handlers for fast cases because emit() itself often has a variable number of
115// arguments and can be deoptimized because of that. These functions always have
116// the same number of arguments and thus do not get deoptimized, so the code
117// inside them can execute faster.
118function emitNone(handler, isFn, self) {
119 if (isFn)
120 handler.call(self);
121 else {
122 var len = handler.length;
123 var listeners = arrayClone(handler, len);
124 for (var i = 0; i < len; ++i)
125 listeners[i].call(self);
126 }
127}
128function emitOne(handler, isFn, self, arg1) {
129 if (isFn)
130 handler.call(self, arg1);
131 else {
132 var len = handler.length;
133 var listeners = arrayClone(handler, len);
134 for (var i = 0; i < len; ++i)
135 listeners[i].call(self, arg1);
136 }
137}
138function emitTwo(handler, isFn, self, arg1, arg2) {
139 if (isFn)
140 handler.call(self, arg1, arg2);
141 else {
142 var len = handler.length;
143 var listeners = arrayClone(handler, len);
144 for (var i = 0; i < len; ++i)
145 listeners[i].call(self, arg1, arg2);
146 }
147}
148function emitThree(handler, isFn, self, arg1, arg2, arg3) {
149 if (isFn)
150 handler.call(self, arg1, arg2, arg3);
151 else {
152 var len = handler.length;
153 var listeners = arrayClone(handler, len);
154 for (var i = 0; i < len; ++i)
155 listeners[i].call(self, arg1, arg2, arg3);
156 }
157}
158
159function emitMany(handler, isFn, self, args) {
160 if (isFn)
161 handler.apply(self, args);
162 else {
163 var len = handler.length;
164 var listeners = arrayClone(handler, len);
165 for (var i = 0; i < len; ++i)
166 listeners[i].apply(self, args);
167 }
168}
169
170EventEmitter.prototype.emit = function emit(type) {
171 var er, handler, len, args, i, events;
172 var doError = (type === 'error');
173
174 events = this._events;
175 if (events)
176 doError = (doError && events.error == null);
177 else if (!doError)
178 return false;
179
180 // If there is no 'error' event listener then throw.
181 if (doError) {
182 if (arguments.length > 1)
183 er = arguments[1];
184 if (er instanceof Error) {
185 throw er; // Unhandled 'error' event
186 } else {
187 // At least give some kind of context to the user
188 var err = new Error('Unhandled "error" event. (' + er + ')');
189 err.context = er;
190 throw err;
191 }
192 return false;
193 }
194
195 handler = events[type];
196
197 if (!handler)
198 return false;
199
200 var isFn = typeof handler === 'function';
201 len = arguments.length;
202 switch (len) {
203 // fast cases
204 case 1:
205 emitNone(handler, isFn, this);
206 break;
207 case 2:
208 emitOne(handler, isFn, this, arguments[1]);
209 break;
210 case 3:
211 emitTwo(handler, isFn, this, arguments[1], arguments[2]);
212 break;
213 case 4:
214 emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
215 break;
216 // slower
217 default:
218 args = new Array(len - 1);
219 for (i = 1; i < len; i++)
220 args[i - 1] = arguments[i];
221 emitMany(handler, isFn, this, args);
222 }
223
224 return true;
225};
226
227function _addListener(target, type, listener, prepend) {
228 var m;
229 var events;
230 var existing;
231
232 if (typeof listener !== 'function')
233 throw new TypeError('"listener" argument must be a function');
234
235 events = target._events;
236 if (!events) {
237 events = target._events = objectCreate(null);
238 target._eventsCount = 0;
239 } else {
240 // To avoid recursion in the case that type === "newListener"! Before
241 // adding it to the listeners, first emit "newListener".
242 if (events.newListener) {
243 target.emit('newListener', type,
244 listener.listener ? listener.listener : listener);
245
246 // Re-assign `events` because a newListener handler could have caused the
247 // this._events to be assigned to a new object
248 events = target._events;
249 }
250 existing = events[type];
251 }
252
253 if (!existing) {
254 // Optimize the case of one listener. Don't need the extra array object.
255 existing = events[type] = listener;
256 ++target._eventsCount;
257 } else {
258 if (typeof existing === 'function') {
259 // Adding the second element, need to change to array.
260 existing = events[type] =
261 prepend ? [listener, existing] : [existing, listener];
262 } else {
263 // If we've already got an array, just append.
264 if (prepend) {
265 existing.unshift(listener);
266 } else {
267 existing.push(listener);
268 }
269 }
270
271 // Check for listener leak
272 if (!existing.warned) {
273 m = $getMaxListeners(target);
274 if (m && m > 0 && existing.length > m) {
275 existing.warned = true;
276 var w = new Error('Possible EventEmitter memory leak detected. ' +
277 existing.length + ' "' + String(type) + '" listeners ' +
278 'added. Use emitter.setMaxListeners() to ' +
279 'increase limit.');
280 w.name = 'MaxListenersExceededWarning';
281 w.emitter = target;
282 w.type = type;
283 w.count = existing.length;
284 if (typeof console === 'object' && console.warn) {
285 console.warn('%s: %s', w.name, w.message);
286 }
287 }
288 }
289 }
290
291 return target;
292}
293
294EventEmitter.prototype.addListener = function addListener(type, listener) {
295 return _addListener(this, type, listener, false);
296};
297
298EventEmitter.prototype.on = EventEmitter.prototype.addListener;
299
300EventEmitter.prototype.prependListener =
301 function prependListener(type, listener) {
302 return _addListener(this, type, listener, true);
303 };
304
305function onceWrapper() {
306 if (!this.fired) {
307 this.target.removeListener(this.type, this.wrapFn);
308 this.fired = true;
309 switch (arguments.length) {
310 case 0:
311 return this.listener.call(this.target);
312 case 1:
313 return this.listener.call(this.target, arguments[0]);
314 case 2:
315 return this.listener.call(this.target, arguments[0], arguments[1]);
316 case 3:
317 return this.listener.call(this.target, arguments[0], arguments[1],
318 arguments[2]);
319 default:
320 var args = new Array(arguments.length);
321 for (var i = 0; i < args.length; ++i)
322 args[i] = arguments[i];
323 this.listener.apply(this.target, args);
324 }
325 }
326}
327
328function _onceWrap(target, type, listener) {
329 var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
330 var wrapped = bind.call(onceWrapper, state);
331 wrapped.listener = listener;
332 state.wrapFn = wrapped;
333 return wrapped;
334}
335
336EventEmitter.prototype.once = function once(type, listener) {
337 if (typeof listener !== 'function')
338 throw new TypeError('"listener" argument must be a function');
339 this.on(type, _onceWrap(this, type, listener));
340 return this;
341};
342
343EventEmitter.prototype.prependOnceListener =
344 function prependOnceListener(type, listener) {
345 if (typeof listener !== 'function')
346 throw new TypeError('"listener" argument must be a function');
347 this.prependListener(type, _onceWrap(this, type, listener));
348 return this;
349 };
350
351// Emits a 'removeListener' event if and only if the listener was removed.
352EventEmitter.prototype.removeListener =
353 function removeListener(type, listener) {
354 var list, events, position, i, originalListener;
355
356 if (typeof listener !== 'function')
357 throw new TypeError('"listener" argument must be a function');
358
359 events = this._events;
360 if (!events)
361 return this;
362
363 list = events[type];
364 if (!list)
365 return this;
366
367 if (list === listener || list.listener === listener) {
368 if (--this._eventsCount === 0)
369 this._events = objectCreate(null);
370 else {
371 delete events[type];
372 if (events.removeListener)
373 this.emit('removeListener', type, list.listener || listener);
374 }
375 } else if (typeof list !== 'function') {
376 position = -1;
377
378 for (i = list.length - 1; i >= 0; i--) {
379 if (list[i] === listener || list[i].listener === listener) {
380 originalListener = list[i].listener;
381 position = i;
382 break;
383 }
384 }
385
386 if (position < 0)
387 return this;
388
389 if (position === 0)
390 list.shift();
391 else
392 spliceOne(list, position);
393
394 if (list.length === 1)
395 events[type] = list[0];
396
397 if (events.removeListener)
398 this.emit('removeListener', type, originalListener || listener);
399 }
400
401 return this;
402 };
403
404EventEmitter.prototype.removeAllListeners =
405 function removeAllListeners(type) {
406 var listeners, events, i;
407
408 events = this._events;
409 if (!events)
410 return this;
411
412 // not listening for removeListener, no need to emit
413 if (!events.removeListener) {
414 if (arguments.length === 0) {
415 this._events = objectCreate(null);
416 this._eventsCount = 0;
417 } else if (events[type]) {
418 if (--this._eventsCount === 0)
419 this._events = objectCreate(null);
420 else
421 delete events[type];
422 }
423 return this;
424 }
425
426 // emit removeListener for all listeners on all events
427 if (arguments.length === 0) {
428 var keys = objectKeys(events);
429 var key;
430 for (i = 0; i < keys.length; ++i) {
431 key = keys[i];
432 if (key === 'removeListener') continue;
433 this.removeAllListeners(key);
434 }
435 this.removeAllListeners('removeListener');
436 this._events = objectCreate(null);
437 this._eventsCount = 0;
438 return this;
439 }
440
441 listeners = events[type];
442
443 if (typeof listeners === 'function') {
444 this.removeListener(type, listeners);
445 } else if (listeners) {
446 // LIFO order
447 for (i = listeners.length - 1; i >= 0; i--) {
448 this.removeListener(type, listeners[i]);
449 }
450 }
451
452 return this;
453 };
454
455function _listeners(target, type, unwrap) {
456 var events = target._events;
457
458 if (!events)
459 return [];
460
461 var evlistener = events[type];
462 if (!evlistener)
463 return [];
464
465 if (typeof evlistener === 'function')
466 return unwrap ? [evlistener.listener || evlistener] : [evlistener];
467
468 return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
469}
470
471EventEmitter.prototype.listeners = function listeners(type) {
472 return _listeners(this, type, true);
473};
474
475EventEmitter.prototype.rawListeners = function rawListeners(type) {
476 return _listeners(this, type, false);
477};
478
479EventEmitter.listenerCount = function(emitter, type) {
480 if (typeof emitter.listenerCount === 'function') {
481 return emitter.listenerCount(type);
482 } else {
483 return listenerCount.call(emitter, type);
484 }
485};
486
487EventEmitter.prototype.listenerCount = listenerCount;
488function listenerCount(type) {
489 var events = this._events;
490
491 if (events) {
492 var evlistener = events[type];
493
494 if (typeof evlistener === 'function') {
495 return 1;
496 } else if (evlistener) {
497 return evlistener.length;
498 }
499 }
500
501 return 0;
502}
503
504EventEmitter.prototype.eventNames = function eventNames() {
505 return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
506};
507
508// About 1.5x faster than the two-arg version of Array#splice().
509function spliceOne(list, index) {
510 for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
511 list[i] = list[k];
512 list.pop();
513}
514
515function arrayClone(arr, n) {
516 var copy = new Array(n);
517 for (var i = 0; i < n; ++i)
518 copy[i] = arr[i];
519 return copy;
520}
521
522function unwrapListeners(arr) {
523 var ret = new Array(arr.length);
524 for (var i = 0; i < ret.length; ++i) {
525 ret[i] = arr[i].listener || arr[i];
526 }
527 return ret;
528}
529
530function objectCreatePolyfill(proto) {
531 var F = function() {};
532 F.prototype = proto;
533 return new F;
534}
535function objectKeysPolyfill(obj) {
536 var keys = [];
537 for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) {
538 keys.push(k);
539 }
540 return k;
541}
542function functionBindPolyfill(context) {
543 var fn = this;
544 return function () {
545 return fn.apply(context, arguments);
546 };
547}
548
549},{}],4:[function(_dereq_,module,exports){
550'use strict';
551var types = [
552 _dereq_(2),
553 _dereq_(7),
554 _dereq_(6),
555 _dereq_(5),
556 _dereq_(8),
557 _dereq_(9)
558];
559var draining;
560var currentQueue;
561var queueIndex = -1;
562var queue = [];
563var scheduled = false;
564function cleanUpNextTick() {
565 if (!draining || !currentQueue) {
566 return;
567 }
568 draining = false;
569 if (currentQueue.length) {
570 queue = currentQueue.concat(queue);
571 } else {
572 queueIndex = -1;
573 }
574 if (queue.length) {
575 nextTick();
576 }
577}
578
579//named nextTick for less confusing stack traces
580function nextTick() {
581 if (draining) {
582 return;
583 }
584 scheduled = false;
585 draining = true;
586 var len = queue.length;
587 var timeout = setTimeout(cleanUpNextTick);
588 while (len) {
589 currentQueue = queue;
590 queue = [];
591 while (currentQueue && ++queueIndex < len) {
592 currentQueue[queueIndex].run();
593 }
594 queueIndex = -1;
595 len = queue.length;
596 }
597 currentQueue = null;
598 queueIndex = -1;
599 draining = false;
600 clearTimeout(timeout);
601}
602var scheduleDrain;
603var i = -1;
604var len = types.length;
605while (++i < len) {
606 if (types[i] && types[i].test && types[i].test()) {
607 scheduleDrain = types[i].install(nextTick);
608 break;
609 }
610}
611// v8 likes predictible objects
612function Item(fun, array) {
613 this.fun = fun;
614 this.array = array;
615}
616Item.prototype.run = function () {
617 var fun = this.fun;
618 var array = this.array;
619 switch (array.length) {
620 case 0:
621 return fun();
622 case 1:
623 return fun(array[0]);
624 case 2:
625 return fun(array[0], array[1]);
626 case 3:
627 return fun(array[0], array[1], array[2]);
628 default:
629 return fun.apply(null, array);
630 }
631
632};
633module.exports = immediate;
634function immediate(task) {
635 var args = new Array(arguments.length - 1);
636 if (arguments.length > 1) {
637 for (var i = 1; i < arguments.length; i++) {
638 args[i - 1] = arguments[i];
639 }
640 }
641 queue.push(new Item(task, args));
642 if (!scheduled && !draining) {
643 scheduled = true;
644 scheduleDrain();
645 }
646}
647
648},{"2":2,"5":5,"6":6,"7":7,"8":8,"9":9}],5:[function(_dereq_,module,exports){
649(function (global){(function (){
650'use strict';
651
652exports.test = function () {
653 if (global.setImmediate) {
654 // we can only get here in IE10
655 // which doesn't handel postMessage well
656 return false;
657 }
658 return typeof global.MessageChannel !== 'undefined';
659};
660
661exports.install = function (func) {
662 var channel = new global.MessageChannel();
663 channel.port1.onmessage = func;
664 return function () {
665 channel.port2.postMessage(0);
666 };
667};
668}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
669},{}],6:[function(_dereq_,module,exports){
670(function (global){(function (){
671'use strict';
672//based off rsvp https://github.com/tildeio/rsvp.js
673//license https://github.com/tildeio/rsvp.js/blob/master/LICENSE
674//https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/asap.js
675
676var Mutation = global.MutationObserver || global.WebKitMutationObserver;
677
678exports.test = function () {
679 return Mutation;
680};
681
682exports.install = function (handle) {
683 var called = 0;
684 var observer = new Mutation(handle);
685 var element = global.document.createTextNode('');
686 observer.observe(element, {
687 characterData: true
688 });
689 return function () {
690 element.data = (called = ++called % 2);
691 };
692};
693}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
694},{}],7:[function(_dereq_,module,exports){
695(function (global){(function (){
696'use strict';
697exports.test = function () {
698 return typeof global.queueMicrotask === 'function';
699};
700
701exports.install = function (func) {
702 return function () {
703 global.queueMicrotask(func);
704 };
705};
706
707}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
708},{}],8:[function(_dereq_,module,exports){
709(function (global){(function (){
710'use strict';
711
712exports.test = function () {
713 return 'document' in global && 'onreadystatechange' in global.document.createElement('script');
714};
715
716exports.install = function (handle) {
717 return function () {
718
719 // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
720 // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
721 var scriptEl = global.document.createElement('script');
722 scriptEl.onreadystatechange = function () {
723 handle();
724
725 scriptEl.onreadystatechange = null;
726 scriptEl.parentNode.removeChild(scriptEl);
727 scriptEl = null;
728 };
729 global.document.documentElement.appendChild(scriptEl);
730
731 return handle;
732 };
733};
734}).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
735},{}],9:[function(_dereq_,module,exports){
736'use strict';
737exports.test = function () {
738 return true;
739};
740
741exports.install = function (t) {
742 return function () {
743 setTimeout(t, 0);
744 };
745};
746},{}],10:[function(_dereq_,module,exports){
747if (typeof Object.create === 'function') {
748 // implementation from standard node.js 'util' module
749 module.exports = function inherits(ctor, superCtor) {
750 if (superCtor) {
751 ctor.super_ = superCtor
752 ctor.prototype = Object.create(superCtor.prototype, {
753 constructor: {
754 value: ctor,
755 enumerable: false,
756 writable: true,
757 configurable: true
758 }
759 })
760 }
761 };
762} else {
763 // old school shim for old browsers
764 module.exports = function inherits(ctor, superCtor) {
765 if (superCtor) {
766 ctor.super_ = superCtor
767 var TempCtor = function () {}
768 TempCtor.prototype = superCtor.prototype
769 ctor.prototype = new TempCtor()
770 ctor.prototype.constructor = ctor
771 }
772 }
773}
774
775},{}],11:[function(_dereq_,module,exports){
776(function (factory) {
777 if (typeof exports === 'object') {
778 // Node/CommonJS
779 module.exports = factory();
780 } else if (typeof define === 'function' && define.amd) {
781 // AMD
782 define(factory);
783 } else {
784 // Browser globals (with support for web workers)
785 var glob;
786
787 try {
788 glob = window;
789 } catch (e) {
790 glob = self;
791 }
792
793 glob.SparkMD5 = factory();
794 }
795}(function (undefined) {
796
797 'use strict';
798
799 /*
800 * Fastest md5 implementation around (JKM md5).
801 * Credits: Joseph Myers
802 *
803 * @see http://www.myersdaily.org/joseph/javascript/md5-text.html
804 * @see http://jsperf.com/md5-shootout/7
805 */
806
807 /* this function is much faster,
808 so if possible we use it. Some IEs
809 are the only ones I know of that
810 need the idiotic second function,
811 generated by an if clause. */
812 var add32 = function (a, b) {
813 return (a + b) & 0xFFFFFFFF;
814 },
815 hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
816
817
818 function cmn(q, a, b, x, s, t) {
819 a = add32(add32(a, q), add32(x, t));
820 return add32((a << s) | (a >>> (32 - s)), b);
821 }
822
823 function md5cycle(x, k) {
824 var a = x[0],
825 b = x[1],
826 c = x[2],
827 d = x[3];
828
829 a += (b & c | ~b & d) + k[0] - 680876936 | 0;
830 a = (a << 7 | a >>> 25) + b | 0;
831 d += (a & b | ~a & c) + k[1] - 389564586 | 0;
832 d = (d << 12 | d >>> 20) + a | 0;
833 c += (d & a | ~d & b) + k[2] + 606105819 | 0;
834 c = (c << 17 | c >>> 15) + d | 0;
835 b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
836 b = (b << 22 | b >>> 10) + c | 0;
837 a += (b & c | ~b & d) + k[4] - 176418897 | 0;
838 a = (a << 7 | a >>> 25) + b | 0;
839 d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
840 d = (d << 12 | d >>> 20) + a | 0;
841 c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
842 c = (c << 17 | c >>> 15) + d | 0;
843 b += (c & d | ~c & a) + k[7] - 45705983 | 0;
844 b = (b << 22 | b >>> 10) + c | 0;
845 a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
846 a = (a << 7 | a >>> 25) + b | 0;
847 d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
848 d = (d << 12 | d >>> 20) + a | 0;
849 c += (d & a | ~d & b) + k[10] - 42063 | 0;
850 c = (c << 17 | c >>> 15) + d | 0;
851 b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
852 b = (b << 22 | b >>> 10) + c | 0;
853 a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
854 a = (a << 7 | a >>> 25) + b | 0;
855 d += (a & b | ~a & c) + k[13] - 40341101 | 0;
856 d = (d << 12 | d >>> 20) + a | 0;
857 c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
858 c = (c << 17 | c >>> 15) + d | 0;
859 b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
860 b = (b << 22 | b >>> 10) + c | 0;
861
862 a += (b & d | c & ~d) + k[1] - 165796510 | 0;
863 a = (a << 5 | a >>> 27) + b | 0;
864 d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
865 d = (d << 9 | d >>> 23) + a | 0;
866 c += (d & b | a & ~b) + k[11] + 643717713 | 0;
867 c = (c << 14 | c >>> 18) + d | 0;
868 b += (c & a | d & ~a) + k[0] - 373897302 | 0;
869 b = (b << 20 | b >>> 12) + c | 0;
870 a += (b & d | c & ~d) + k[5] - 701558691 | 0;
871 a = (a << 5 | a >>> 27) + b | 0;
872 d += (a & c | b & ~c) + k[10] + 38016083 | 0;
873 d = (d << 9 | d >>> 23) + a | 0;
874 c += (d & b | a & ~b) + k[15] - 660478335 | 0;
875 c = (c << 14 | c >>> 18) + d | 0;
876 b += (c & a | d & ~a) + k[4] - 405537848 | 0;
877 b = (b << 20 | b >>> 12) + c | 0;
878 a += (b & d | c & ~d) + k[9] + 568446438 | 0;
879 a = (a << 5 | a >>> 27) + b | 0;
880 d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
881 d = (d << 9 | d >>> 23) + a | 0;
882 c += (d & b | a & ~b) + k[3] - 187363961 | 0;
883 c = (c << 14 | c >>> 18) + d | 0;
884 b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
885 b = (b << 20 | b >>> 12) + c | 0;
886 a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
887 a = (a << 5 | a >>> 27) + b | 0;
888 d += (a & c | b & ~c) + k[2] - 51403784 | 0;
889 d = (d << 9 | d >>> 23) + a | 0;
890 c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
891 c = (c << 14 | c >>> 18) + d | 0;
892 b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
893 b = (b << 20 | b >>> 12) + c | 0;
894
895 a += (b ^ c ^ d) + k[5] - 378558 | 0;
896 a = (a << 4 | a >>> 28) + b | 0;
897 d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
898 d = (d << 11 | d >>> 21) + a | 0;
899 c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
900 c = (c << 16 | c >>> 16) + d | 0;
901 b += (c ^ d ^ a) + k[14] - 35309556 | 0;
902 b = (b << 23 | b >>> 9) + c | 0;
903 a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
904 a = (a << 4 | a >>> 28) + b | 0;
905 d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
906 d = (d << 11 | d >>> 21) + a | 0;
907 c += (d ^ a ^ b) + k[7] - 155497632 | 0;
908 c = (c << 16 | c >>> 16) + d | 0;
909 b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
910 b = (b << 23 | b >>> 9) + c | 0;
911 a += (b ^ c ^ d) + k[13] + 681279174 | 0;
912 a = (a << 4 | a >>> 28) + b | 0;
913 d += (a ^ b ^ c) + k[0] - 358537222 | 0;
914 d = (d << 11 | d >>> 21) + a | 0;
915 c += (d ^ a ^ b) + k[3] - 722521979 | 0;
916 c = (c << 16 | c >>> 16) + d | 0;
917 b += (c ^ d ^ a) + k[6] + 76029189 | 0;
918 b = (b << 23 | b >>> 9) + c | 0;
919 a += (b ^ c ^ d) + k[9] - 640364487 | 0;
920 a = (a << 4 | a >>> 28) + b | 0;
921 d += (a ^ b ^ c) + k[12] - 421815835 | 0;
922 d = (d << 11 | d >>> 21) + a | 0;
923 c += (d ^ a ^ b) + k[15] + 530742520 | 0;
924 c = (c << 16 | c >>> 16) + d | 0;
925 b += (c ^ d ^ a) + k[2] - 995338651 | 0;
926 b = (b << 23 | b >>> 9) + c | 0;
927
928 a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
929 a = (a << 6 | a >>> 26) + b | 0;
930 d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
931 d = (d << 10 | d >>> 22) + a | 0;
932 c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
933 c = (c << 15 | c >>> 17) + d | 0;
934 b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
935 b = (b << 21 |b >>> 11) + c | 0;
936 a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
937 a = (a << 6 | a >>> 26) + b | 0;
938 d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
939 d = (d << 10 | d >>> 22) + a | 0;
940 c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
941 c = (c << 15 | c >>> 17) + d | 0;
942 b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
943 b = (b << 21 |b >>> 11) + c | 0;
944 a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
945 a = (a << 6 | a >>> 26) + b | 0;
946 d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
947 d = (d << 10 | d >>> 22) + a | 0;
948 c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
949 c = (c << 15 | c >>> 17) + d | 0;
950 b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
951 b = (b << 21 |b >>> 11) + c | 0;
952 a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
953 a = (a << 6 | a >>> 26) + b | 0;
954 d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
955 d = (d << 10 | d >>> 22) + a | 0;
956 c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
957 c = (c << 15 | c >>> 17) + d | 0;
958 b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
959 b = (b << 21 | b >>> 11) + c | 0;
960
961 x[0] = a + x[0] | 0;
962 x[1] = b + x[1] | 0;
963 x[2] = c + x[2] | 0;
964 x[3] = d + x[3] | 0;
965 }
966
967 function md5blk(s) {
968 var md5blks = [],
969 i; /* Andy King said do it this way. */
970
971 for (i = 0; i < 64; i += 4) {
972 md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
973 }
974 return md5blks;
975 }
976
977 function md5blk_array(a) {
978 var md5blks = [],
979 i; /* Andy King said do it this way. */
980
981 for (i = 0; i < 64; i += 4) {
982 md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
983 }
984 return md5blks;
985 }
986
987 function md51(s) {
988 var n = s.length,
989 state = [1732584193, -271733879, -1732584194, 271733878],
990 i,
991 length,
992 tail,
993 tmp,
994 lo,
995 hi;
996
997 for (i = 64; i <= n; i += 64) {
998 md5cycle(state, md5blk(s.substring(i - 64, i)));
999 }
1000 s = s.substring(i - 64);
1001 length = s.length;
1002 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1003 for (i = 0; i < length; i += 1) {
1004 tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
1005 }
1006 tail[i >> 2] |= 0x80 << ((i % 4) << 3);
1007 if (i > 55) {
1008 md5cycle(state, tail);
1009 for (i = 0; i < 16; i += 1) {
1010 tail[i] = 0;
1011 }
1012 }
1013
1014 // Beware that the final length might not fit in 32 bits so we take care of that
1015 tmp = n * 8;
1016 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1017 lo = parseInt(tmp[2], 16);
1018 hi = parseInt(tmp[1], 16) || 0;
1019
1020 tail[14] = lo;
1021 tail[15] = hi;
1022
1023 md5cycle(state, tail);
1024 return state;
1025 }
1026
1027 function md51_array(a) {
1028 var n = a.length,
1029 state = [1732584193, -271733879, -1732584194, 271733878],
1030 i,
1031 length,
1032 tail,
1033 tmp,
1034 lo,
1035 hi;
1036
1037 for (i = 64; i <= n; i += 64) {
1038 md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
1039 }
1040
1041 // Not sure if it is a bug, however IE10 will always produce a sub array of length 1
1042 // containing the last element of the parent array if the sub array specified starts
1043 // beyond the length of the parent array - weird.
1044 // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
1045 a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);
1046
1047 length = a.length;
1048 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1049 for (i = 0; i < length; i += 1) {
1050 tail[i >> 2] |= a[i] << ((i % 4) << 3);
1051 }
1052
1053 tail[i >> 2] |= 0x80 << ((i % 4) << 3);
1054 if (i > 55) {
1055 md5cycle(state, tail);
1056 for (i = 0; i < 16; i += 1) {
1057 tail[i] = 0;
1058 }
1059 }
1060
1061 // Beware that the final length might not fit in 32 bits so we take care of that
1062 tmp = n * 8;
1063 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1064 lo = parseInt(tmp[2], 16);
1065 hi = parseInt(tmp[1], 16) || 0;
1066
1067 tail[14] = lo;
1068 tail[15] = hi;
1069
1070 md5cycle(state, tail);
1071
1072 return state;
1073 }
1074
1075 function rhex(n) {
1076 var s = '',
1077 j;
1078 for (j = 0; j < 4; j += 1) {
1079 s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
1080 }
1081 return s;
1082 }
1083
1084 function hex(x) {
1085 var i;
1086 for (i = 0; i < x.length; i += 1) {
1087 x[i] = rhex(x[i]);
1088 }
1089 return x.join('');
1090 }
1091
1092 // In some cases the fast add32 function cannot be used..
1093 if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') {
1094 add32 = function (x, y) {
1095 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
1096 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
1097 return (msw << 16) | (lsw & 0xFFFF);
1098 };
1099 }
1100
1101 // ---------------------------------------------------
1102
1103 /**
1104 * ArrayBuffer slice polyfill.
1105 *
1106 * @see https://github.com/ttaubert/node-arraybuffer-slice
1107 */
1108
1109 if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
1110 (function () {
1111 function clamp(val, length) {
1112 val = (val | 0) || 0;
1113
1114 if (val < 0) {
1115 return Math.max(val + length, 0);
1116 }
1117
1118 return Math.min(val, length);
1119 }
1120
1121 ArrayBuffer.prototype.slice = function (from, to) {
1122 var length = this.byteLength,
1123 begin = clamp(from, length),
1124 end = length,
1125 num,
1126 target,
1127 targetArray,
1128 sourceArray;
1129
1130 if (to !== undefined) {
1131 end = clamp(to, length);
1132 }
1133
1134 if (begin > end) {
1135 return new ArrayBuffer(0);
1136 }
1137
1138 num = end - begin;
1139 target = new ArrayBuffer(num);
1140 targetArray = new Uint8Array(target);
1141
1142 sourceArray = new Uint8Array(this, begin, num);
1143 targetArray.set(sourceArray);
1144
1145 return target;
1146 };
1147 })();
1148 }
1149
1150 // ---------------------------------------------------
1151
1152 /**
1153 * Helpers.
1154 */
1155
1156 function toUtf8(str) {
1157 if (/[\u0080-\uFFFF]/.test(str)) {
1158 str = unescape(encodeURIComponent(str));
1159 }
1160
1161 return str;
1162 }
1163
1164 function utf8Str2ArrayBuffer(str, returnUInt8Array) {
1165 var length = str.length,
1166 buff = new ArrayBuffer(length),
1167 arr = new Uint8Array(buff),
1168 i;
1169
1170 for (i = 0; i < length; i += 1) {
1171 arr[i] = str.charCodeAt(i);
1172 }
1173
1174 return returnUInt8Array ? arr : buff;
1175 }
1176
1177 function arrayBuffer2Utf8Str(buff) {
1178 return String.fromCharCode.apply(null, new Uint8Array(buff));
1179 }
1180
1181 function concatenateArrayBuffers(first, second, returnUInt8Array) {
1182 var result = new Uint8Array(first.byteLength + second.byteLength);
1183
1184 result.set(new Uint8Array(first));
1185 result.set(new Uint8Array(second), first.byteLength);
1186
1187 return returnUInt8Array ? result : result.buffer;
1188 }
1189
1190 function hexToBinaryString(hex) {
1191 var bytes = [],
1192 length = hex.length,
1193 x;
1194
1195 for (x = 0; x < length - 1; x += 2) {
1196 bytes.push(parseInt(hex.substr(x, 2), 16));
1197 }
1198
1199 return String.fromCharCode.apply(String, bytes);
1200 }
1201
1202 // ---------------------------------------------------
1203
1204 /**
1205 * SparkMD5 OOP implementation.
1206 *
1207 * Use this class to perform an incremental md5, otherwise use the
1208 * static methods instead.
1209 */
1210
1211 function SparkMD5() {
1212 // call reset to init the instance
1213 this.reset();
1214 }
1215
1216 /**
1217 * Appends a string.
1218 * A conversion will be applied if an utf8 string is detected.
1219 *
1220 * @param {String} str The string to be appended
1221 *
1222 * @return {SparkMD5} The instance itself
1223 */
1224 SparkMD5.prototype.append = function (str) {
1225 // Converts the string to utf8 bytes if necessary
1226 // Then append as binary
1227 this.appendBinary(toUtf8(str));
1228
1229 return this;
1230 };
1231
1232 /**
1233 * Appends a binary string.
1234 *
1235 * @param {String} contents The binary string to be appended
1236 *
1237 * @return {SparkMD5} The instance itself
1238 */
1239 SparkMD5.prototype.appendBinary = function (contents) {
1240 this._buff += contents;
1241 this._length += contents.length;
1242
1243 var length = this._buff.length,
1244 i;
1245
1246 for (i = 64; i <= length; i += 64) {
1247 md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
1248 }
1249
1250 this._buff = this._buff.substring(i - 64);
1251
1252 return this;
1253 };
1254
1255 /**
1256 * Finishes the incremental computation, reseting the internal state and
1257 * returning the result.
1258 *
1259 * @param {Boolean} raw True to get the raw string, false to get the hex string
1260 *
1261 * @return {String} The result
1262 */
1263 SparkMD5.prototype.end = function (raw) {
1264 var buff = this._buff,
1265 length = buff.length,
1266 i,
1267 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1268 ret;
1269
1270 for (i = 0; i < length; i += 1) {
1271 tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
1272 }
1273
1274 this._finish(tail, length);
1275 ret = hex(this._hash);
1276
1277 if (raw) {
1278 ret = hexToBinaryString(ret);
1279 }
1280
1281 this.reset();
1282
1283 return ret;
1284 };
1285
1286 /**
1287 * Resets the internal state of the computation.
1288 *
1289 * @return {SparkMD5} The instance itself
1290 */
1291 SparkMD5.prototype.reset = function () {
1292 this._buff = '';
1293 this._length = 0;
1294 this._hash = [1732584193, -271733879, -1732584194, 271733878];
1295
1296 return this;
1297 };
1298
1299 /**
1300 * Gets the internal state of the computation.
1301 *
1302 * @return {Object} The state
1303 */
1304 SparkMD5.prototype.getState = function () {
1305 return {
1306 buff: this._buff,
1307 length: this._length,
1308 hash: this._hash.slice()
1309 };
1310 };
1311
1312 /**
1313 * Gets the internal state of the computation.
1314 *
1315 * @param {Object} state The state
1316 *
1317 * @return {SparkMD5} The instance itself
1318 */
1319 SparkMD5.prototype.setState = function (state) {
1320 this._buff = state.buff;
1321 this._length = state.length;
1322 this._hash = state.hash;
1323
1324 return this;
1325 };
1326
1327 /**
1328 * Releases memory used by the incremental buffer and other additional
1329 * resources. If you plan to use the instance again, use reset instead.
1330 */
1331 SparkMD5.prototype.destroy = function () {
1332 delete this._hash;
1333 delete this._buff;
1334 delete this._length;
1335 };
1336
1337 /**
1338 * Finish the final calculation based on the tail.
1339 *
1340 * @param {Array} tail The tail (will be modified)
1341 * @param {Number} length The length of the remaining buffer
1342 */
1343 SparkMD5.prototype._finish = function (tail, length) {
1344 var i = length,
1345 tmp,
1346 lo,
1347 hi;
1348
1349 tail[i >> 2] |= 0x80 << ((i % 4) << 3);
1350 if (i > 55) {
1351 md5cycle(this._hash, tail);
1352 for (i = 0; i < 16; i += 1) {
1353 tail[i] = 0;
1354 }
1355 }
1356
1357 // Do the final computation based on the tail and length
1358 // Beware that the final length may not fit in 32 bits so we take care of that
1359 tmp = this._length * 8;
1360 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1361 lo = parseInt(tmp[2], 16);
1362 hi = parseInt(tmp[1], 16) || 0;
1363
1364 tail[14] = lo;
1365 tail[15] = hi;
1366 md5cycle(this._hash, tail);
1367 };
1368
1369 /**
1370 * Performs the md5 hash on a string.
1371 * A conversion will be applied if utf8 string is detected.
1372 *
1373 * @param {String} str The string
1374 * @param {Boolean} [raw] True to get the raw string, false to get the hex string
1375 *
1376 * @return {String} The result
1377 */
1378 SparkMD5.hash = function (str, raw) {
1379 // Converts the string to utf8 bytes if necessary
1380 // Then compute it using the binary function
1381 return SparkMD5.hashBinary(toUtf8(str), raw);
1382 };
1383
1384 /**
1385 * Performs the md5 hash on a binary string.
1386 *
1387 * @param {String} content The binary string
1388 * @param {Boolean} [raw] True to get the raw string, false to get the hex string
1389 *
1390 * @return {String} The result
1391 */
1392 SparkMD5.hashBinary = function (content, raw) {
1393 var hash = md51(content),
1394 ret = hex(hash);
1395
1396 return raw ? hexToBinaryString(ret) : ret;
1397 };
1398
1399 // ---------------------------------------------------
1400
1401 /**
1402 * SparkMD5 OOP implementation for array buffers.
1403 *
1404 * Use this class to perform an incremental md5 ONLY for array buffers.
1405 */
1406 SparkMD5.ArrayBuffer = function () {
1407 // call reset to init the instance
1408 this.reset();
1409 };
1410
1411 /**
1412 * Appends an array buffer.
1413 *
1414 * @param {ArrayBuffer} arr The array to be appended
1415 *
1416 * @return {SparkMD5.ArrayBuffer} The instance itself
1417 */
1418 SparkMD5.ArrayBuffer.prototype.append = function (arr) {
1419 var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),
1420 length = buff.length,
1421 i;
1422
1423 this._length += arr.byteLength;
1424
1425 for (i = 64; i <= length; i += 64) {
1426 md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
1427 }
1428
1429 this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
1430
1431 return this;
1432 };
1433
1434 /**
1435 * Finishes the incremental computation, reseting the internal state and
1436 * returning the result.
1437 *
1438 * @param {Boolean} raw True to get the raw string, false to get the hex string
1439 *
1440 * @return {String} The result
1441 */
1442 SparkMD5.ArrayBuffer.prototype.end = function (raw) {
1443 var buff = this._buff,
1444 length = buff.length,
1445 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1446 i,
1447 ret;
1448
1449 for (i = 0; i < length; i += 1) {
1450 tail[i >> 2] |= buff[i] << ((i % 4) << 3);
1451 }
1452
1453 this._finish(tail, length);
1454 ret = hex(this._hash);
1455
1456 if (raw) {
1457 ret = hexToBinaryString(ret);
1458 }
1459
1460 this.reset();
1461
1462 return ret;
1463 };
1464
1465 /**
1466 * Resets the internal state of the computation.
1467 *
1468 * @return {SparkMD5.ArrayBuffer} The instance itself
1469 */
1470 SparkMD5.ArrayBuffer.prototype.reset = function () {
1471 this._buff = new Uint8Array(0);
1472 this._length = 0;
1473 this._hash = [1732584193, -271733879, -1732584194, 271733878];
1474
1475 return this;
1476 };
1477
1478 /**
1479 * Gets the internal state of the computation.
1480 *
1481 * @return {Object} The state
1482 */
1483 SparkMD5.ArrayBuffer.prototype.getState = function () {
1484 var state = SparkMD5.prototype.getState.call(this);
1485
1486 // Convert buffer to a string
1487 state.buff = arrayBuffer2Utf8Str(state.buff);
1488
1489 return state;
1490 };
1491
1492 /**
1493 * Gets the internal state of the computation.
1494 *
1495 * @param {Object} state The state
1496 *
1497 * @return {SparkMD5.ArrayBuffer} The instance itself
1498 */
1499 SparkMD5.ArrayBuffer.prototype.setState = function (state) {
1500 // Convert string to buffer
1501 state.buff = utf8Str2ArrayBuffer(state.buff, true);
1502
1503 return SparkMD5.prototype.setState.call(this, state);
1504 };
1505
1506 SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
1507
1508 SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
1509
1510 /**
1511 * Performs the md5 hash on an array buffer.
1512 *
1513 * @param {ArrayBuffer} arr The array buffer
1514 * @param {Boolean} [raw] True to get the raw string, false to get the hex one
1515 *
1516 * @return {String} The result
1517 */
1518 SparkMD5.ArrayBuffer.hash = function (arr, raw) {
1519 var hash = md51_array(new Uint8Array(arr)),
1520 ret = hex(hash);
1521
1522 return raw ? hexToBinaryString(ret) : ret;
1523 };
1524
1525 return SparkMD5;
1526}));
1527
1528},{}],12:[function(_dereq_,module,exports){
1529"use strict";
1530
1531Object.defineProperty(exports, "__esModule", {
1532 value: true
1533});
1534Object.defineProperty(exports, "v1", {
1535 enumerable: true,
1536 get: function () {
1537 return _v.default;
1538 }
1539});
1540Object.defineProperty(exports, "v3", {
1541 enumerable: true,
1542 get: function () {
1543 return _v2.default;
1544 }
1545});
1546Object.defineProperty(exports, "v4", {
1547 enumerable: true,
1548 get: function () {
1549 return _v3.default;
1550 }
1551});
1552Object.defineProperty(exports, "v5", {
1553 enumerable: true,
1554 get: function () {
1555 return _v4.default;
1556 }
1557});
1558Object.defineProperty(exports, "NIL", {
1559 enumerable: true,
1560 get: function () {
1561 return _nil.default;
1562 }
1563});
1564Object.defineProperty(exports, "version", {
1565 enumerable: true,
1566 get: function () {
1567 return _version.default;
1568 }
1569});
1570Object.defineProperty(exports, "validate", {
1571 enumerable: true,
1572 get: function () {
1573 return _validate.default;
1574 }
1575});
1576Object.defineProperty(exports, "stringify", {
1577 enumerable: true,
1578 get: function () {
1579 return _stringify.default;
1580 }
1581});
1582Object.defineProperty(exports, "parse", {
1583 enumerable: true,
1584 get: function () {
1585 return _parse.default;
1586 }
1587});
1588
1589var _v = _interopRequireDefault(_dereq_(20));
1590
1591var _v2 = _interopRequireDefault(_dereq_(21));
1592
1593var _v3 = _interopRequireDefault(_dereq_(23));
1594
1595var _v4 = _interopRequireDefault(_dereq_(24));
1596
1597var _nil = _interopRequireDefault(_dereq_(14));
1598
1599var _version = _interopRequireDefault(_dereq_(26));
1600
1601var _validate = _interopRequireDefault(_dereq_(25));
1602
1603var _stringify = _interopRequireDefault(_dereq_(19));
1604
1605var _parse = _interopRequireDefault(_dereq_(15));
1606
1607function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1608},{"14":14,"15":15,"19":19,"20":20,"21":21,"23":23,"24":24,"25":25,"26":26}],13:[function(_dereq_,module,exports){
1609"use strict";
1610
1611Object.defineProperty(exports, "__esModule", {
1612 value: true
1613});
1614exports.default = void 0;
1615
1616/*
1617 * Browser-compatible JavaScript MD5
1618 *
1619 * Modification of JavaScript MD5
1620 * https://github.com/blueimp/JavaScript-MD5
1621 *
1622 * Copyright 2011, Sebastian Tschan
1623 * https://blueimp.net
1624 *
1625 * Licensed under the MIT license:
1626 * https://opensource.org/licenses/MIT
1627 *
1628 * Based on
1629 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
1630 * Digest Algorithm, as defined in RFC 1321.
1631 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
1632 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
1633 * Distributed under the BSD License
1634 * See http://pajhome.org.uk/crypt/md5 for more info.
1635 */
1636function md5(bytes) {
1637 if (typeof bytes === 'string') {
1638 const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
1639
1640 bytes = new Uint8Array(msg.length);
1641
1642 for (let i = 0; i < msg.length; ++i) {
1643 bytes[i] = msg.charCodeAt(i);
1644 }
1645 }
1646
1647 return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8));
1648}
1649/*
1650 * Convert an array of little-endian words to an array of bytes
1651 */
1652
1653
1654function md5ToHexEncodedArray(input) {
1655 const output = [];
1656 const length32 = input.length * 32;
1657 const hexTab = '0123456789abcdef';
1658
1659 for (let i = 0; i < length32; i += 8) {
1660 const x = input[i >> 5] >>> i % 32 & 0xff;
1661 const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16);
1662 output.push(hex);
1663 }
1664
1665 return output;
1666}
1667/**
1668 * Calculate output length with padding and bit length
1669 */
1670
1671
1672function getOutputLength(inputLength8) {
1673 return (inputLength8 + 64 >>> 9 << 4) + 14 + 1;
1674}
1675/*
1676 * Calculate the MD5 of an array of little-endian words, and a bit length.
1677 */
1678
1679
1680function wordsToMd5(x, len) {
1681 /* append padding */
1682 x[len >> 5] |= 0x80 << len % 32;
1683 x[getOutputLength(len) - 1] = len;
1684 let a = 1732584193;
1685 let b = -271733879;
1686 let c = -1732584194;
1687 let d = 271733878;
1688
1689 for (let i = 0; i < x.length; i += 16) {
1690 const olda = a;
1691 const oldb = b;
1692 const oldc = c;
1693 const oldd = d;
1694 a = md5ff(a, b, c, d, x[i], 7, -680876936);
1695 d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
1696 c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
1697 b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
1698 a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
1699 d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
1700 c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
1701 b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
1702 a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
1703 d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
1704 c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
1705 b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
1706 a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
1707 d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
1708 c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
1709 b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
1710 a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
1711 d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
1712 c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
1713 b = md5gg(b, c, d, a, x[i], 20, -373897302);
1714 a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
1715 d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
1716 c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
1717 b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
1718 a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
1719 d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
1720 c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
1721 b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
1722 a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
1723 d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
1724 c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
1725 b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
1726 a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
1727 d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
1728 c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
1729 b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
1730 a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
1731 d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
1732 c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
1733 b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
1734 a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
1735 d = md5hh(d, a, b, c, x[i], 11, -358537222);
1736 c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
1737 b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
1738 a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
1739 d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
1740 c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
1741 b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
1742 a = md5ii(a, b, c, d, x[i], 6, -198630844);
1743 d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
1744 c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
1745 b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
1746 a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
1747 d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
1748 c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
1749 b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
1750 a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
1751 d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
1752 c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
1753 b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
1754 a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
1755 d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
1756 c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
1757 b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
1758 a = safeAdd(a, olda);
1759 b = safeAdd(b, oldb);
1760 c = safeAdd(c, oldc);
1761 d = safeAdd(d, oldd);
1762 }
1763
1764 return [a, b, c, d];
1765}
1766/*
1767 * Convert an array bytes to an array of little-endian words
1768 * Characters >255 have their high-byte silently ignored.
1769 */
1770
1771
1772function bytesToWords(input) {
1773 if (input.length === 0) {
1774 return [];
1775 }
1776
1777 const length8 = input.length * 8;
1778 const output = new Uint32Array(getOutputLength(length8));
1779
1780 for (let i = 0; i < length8; i += 8) {
1781 output[i >> 5] |= (input[i / 8] & 0xff) << i % 32;
1782 }
1783
1784 return output;
1785}
1786/*
1787 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
1788 * to work around bugs in some JS interpreters.
1789 */
1790
1791
1792function safeAdd(x, y) {
1793 const lsw = (x & 0xffff) + (y & 0xffff);
1794 const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
1795 return msw << 16 | lsw & 0xffff;
1796}
1797/*
1798 * Bitwise rotate a 32-bit number to the left.
1799 */
1800
1801
1802function bitRotateLeft(num, cnt) {
1803 return num << cnt | num >>> 32 - cnt;
1804}
1805/*
1806 * These functions implement the four basic operations the algorithm uses.
1807 */
1808
1809
1810function md5cmn(q, a, b, x, s, t) {
1811 return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
1812}
1813
1814function md5ff(a, b, c, d, x, s, t) {
1815 return md5cmn(b & c | ~b & d, a, b, x, s, t);
1816}
1817
1818function md5gg(a, b, c, d, x, s, t) {
1819 return md5cmn(b & d | c & ~d, a, b, x, s, t);
1820}
1821
1822function md5hh(a, b, c, d, x, s, t) {
1823 return md5cmn(b ^ c ^ d, a, b, x, s, t);
1824}
1825
1826function md5ii(a, b, c, d, x, s, t) {
1827 return md5cmn(c ^ (b | ~d), a, b, x, s, t);
1828}
1829
1830var _default = md5;
1831exports.default = _default;
1832},{}],14:[function(_dereq_,module,exports){
1833"use strict";
1834
1835Object.defineProperty(exports, "__esModule", {
1836 value: true
1837});
1838exports.default = void 0;
1839var _default = '00000000-0000-0000-0000-000000000000';
1840exports.default = _default;
1841},{}],15:[function(_dereq_,module,exports){
1842"use strict";
1843
1844Object.defineProperty(exports, "__esModule", {
1845 value: true
1846});
1847exports.default = void 0;
1848
1849var _validate = _interopRequireDefault(_dereq_(25));
1850
1851function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1852
1853function parse(uuid) {
1854 if (!(0, _validate.default)(uuid)) {
1855 throw TypeError('Invalid UUID');
1856 }
1857
1858 let v;
1859 const arr = new Uint8Array(16); // Parse ########-....-....-....-............
1860
1861 arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24;
1862 arr[1] = v >>> 16 & 0xff;
1863 arr[2] = v >>> 8 & 0xff;
1864 arr[3] = v & 0xff; // Parse ........-####-....-....-............
1865
1866 arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8;
1867 arr[5] = v & 0xff; // Parse ........-....-####-....-............
1868
1869 arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8;
1870 arr[7] = v & 0xff; // Parse ........-....-....-####-............
1871
1872 arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8;
1873 arr[9] = v & 0xff; // Parse ........-....-....-....-############
1874 // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes)
1875
1876 arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff;
1877 arr[11] = v / 0x100000000 & 0xff;
1878 arr[12] = v >>> 24 & 0xff;
1879 arr[13] = v >>> 16 & 0xff;
1880 arr[14] = v >>> 8 & 0xff;
1881 arr[15] = v & 0xff;
1882 return arr;
1883}
1884
1885var _default = parse;
1886exports.default = _default;
1887},{"25":25}],16:[function(_dereq_,module,exports){
1888"use strict";
1889
1890Object.defineProperty(exports, "__esModule", {
1891 value: true
1892});
1893exports.default = void 0;
1894var _default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
1895exports.default = _default;
1896},{}],17:[function(_dereq_,module,exports){
1897"use strict";
1898
1899Object.defineProperty(exports, "__esModule", {
1900 value: true
1901});
1902exports.default = rng;
1903// Unique ID creation requires a high quality random # generator. In the browser we therefore
1904// require the crypto API and do not support built-in fallback to lower quality random number
1905// generators (like Math.random()).
1906let getRandomValues;
1907const rnds8 = new Uint8Array(16);
1908
1909function rng() {
1910 // lazy load so that environments that need to polyfill have a chance to do so
1911 if (!getRandomValues) {
1912 // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also,
1913 // find the complete implementation of crypto (msCrypto) on IE11.
1914 getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto);
1915
1916 if (!getRandomValues) {
1917 throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
1918 }
1919 }
1920
1921 return getRandomValues(rnds8);
1922}
1923},{}],18:[function(_dereq_,module,exports){
1924"use strict";
1925
1926Object.defineProperty(exports, "__esModule", {
1927 value: true
1928});
1929exports.default = void 0;
1930
1931// Adapted from Chris Veness' SHA1 code at
1932// http://www.movable-type.co.uk/scripts/sha1.html
1933function f(s, x, y, z) {
1934 switch (s) {
1935 case 0:
1936 return x & y ^ ~x & z;
1937
1938 case 1:
1939 return x ^ y ^ z;
1940
1941 case 2:
1942 return x & y ^ x & z ^ y & z;
1943
1944 case 3:
1945 return x ^ y ^ z;
1946 }
1947}
1948
1949function ROTL(x, n) {
1950 return x << n | x >>> 32 - n;
1951}
1952
1953function sha1(bytes) {
1954 const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
1955 const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
1956
1957 if (typeof bytes === 'string') {
1958 const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
1959
1960 bytes = [];
1961
1962 for (let i = 0; i < msg.length; ++i) {
1963 bytes.push(msg.charCodeAt(i));
1964 }
1965 } else if (!Array.isArray(bytes)) {
1966 // Convert Array-like to Array
1967 bytes = Array.prototype.slice.call(bytes);
1968 }
1969
1970 bytes.push(0x80);
1971 const l = bytes.length / 4 + 2;
1972 const N = Math.ceil(l / 16);
1973 const M = new Array(N);
1974
1975 for (let i = 0; i < N; ++i) {
1976 const arr = new Uint32Array(16);
1977
1978 for (let j = 0; j < 16; ++j) {
1979 arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3];
1980 }
1981
1982 M[i] = arr;
1983 }
1984
1985 M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32);
1986 M[N - 1][14] = Math.floor(M[N - 1][14]);
1987 M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff;
1988
1989 for (let i = 0; i < N; ++i) {
1990 const W = new Uint32Array(80);
1991
1992 for (let t = 0; t < 16; ++t) {
1993 W[t] = M[i][t];
1994 }
1995
1996 for (let t = 16; t < 80; ++t) {
1997 W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
1998 }
1999
2000 let a = H[0];
2001 let b = H[1];
2002 let c = H[2];
2003 let d = H[3];
2004 let e = H[4];
2005
2006 for (let t = 0; t < 80; ++t) {
2007 const s = Math.floor(t / 20);
2008 const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0;
2009 e = d;
2010 d = c;
2011 c = ROTL(b, 30) >>> 0;
2012 b = a;
2013 a = T;
2014 }
2015
2016 H[0] = H[0] + a >>> 0;
2017 H[1] = H[1] + b >>> 0;
2018 H[2] = H[2] + c >>> 0;
2019 H[3] = H[3] + d >>> 0;
2020 H[4] = H[4] + e >>> 0;
2021 }
2022
2023 return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff];
2024}
2025
2026var _default = sha1;
2027exports.default = _default;
2028},{}],19:[function(_dereq_,module,exports){
2029"use strict";
2030
2031Object.defineProperty(exports, "__esModule", {
2032 value: true
2033});
2034exports.default = void 0;
2035
2036var _validate = _interopRequireDefault(_dereq_(25));
2037
2038function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2039
2040/**
2041 * Convert array of 16 byte values to UUID string format of the form:
2042 * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
2043 */
2044const byteToHex = [];
2045
2046for (let i = 0; i < 256; ++i) {
2047 byteToHex.push((i + 0x100).toString(16).substr(1));
2048}
2049
2050function stringify(arr, offset = 0) {
2051 // Note: Be careful editing this code! It's been tuned for performance
2052 // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
2053 const uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one
2054 // of the following:
2055 // - One or more input array values don't map to a hex octet (leading to
2056 // "undefined" in the uuid)
2057 // - Invalid input values for the RFC `version` or `variant` fields
2058
2059 if (!(0, _validate.default)(uuid)) {
2060 throw TypeError('Stringified UUID is invalid');
2061 }
2062
2063 return uuid;
2064}
2065
2066var _default = stringify;
2067exports.default = _default;
2068},{"25":25}],20:[function(_dereq_,module,exports){
2069"use strict";
2070
2071Object.defineProperty(exports, "__esModule", {
2072 value: true
2073});
2074exports.default = void 0;
2075
2076var _rng = _interopRequireDefault(_dereq_(17));
2077
2078var _stringify = _interopRequireDefault(_dereq_(19));
2079
2080function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2081
2082// **`v1()` - Generate time-based UUID**
2083//
2084// Inspired by https://github.com/LiosK/UUID.js
2085// and http://docs.python.org/library/uuid.html
2086let _nodeId;
2087
2088let _clockseq; // Previous uuid creation time
2089
2090
2091let _lastMSecs = 0;
2092let _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details
2093
2094function v1(options, buf, offset) {
2095 let i = buf && offset || 0;
2096 const b = buf || new Array(16);
2097 options = options || {};
2098 let node = options.node || _nodeId;
2099 let clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not
2100 // specified. We do this lazily to minimize issues related to insufficient
2101 // system entropy. See #189
2102
2103 if (node == null || clockseq == null) {
2104 const seedBytes = options.random || (options.rng || _rng.default)();
2105
2106 if (node == null) {
2107 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
2108 node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]];
2109 }
2110
2111 if (clockseq == null) {
2112 // Per 4.2.2, randomize (14 bit) clockseq
2113 clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff;
2114 }
2115 } // UUID timestamps are 100 nano-second units since the Gregorian epoch,
2116 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
2117 // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
2118 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
2119
2120
2121 let msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock
2122 // cycle to simulate higher resolution clock
2123
2124 let nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs)
2125
2126 const dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression
2127
2128 if (dt < 0 && options.clockseq === undefined) {
2129 clockseq = clockseq + 1 & 0x3fff;
2130 } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
2131 // time interval
2132
2133
2134 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) {
2135 nsecs = 0;
2136 } // Per 4.2.1.2 Throw error if too many uuids are requested
2137
2138
2139 if (nsecs >= 10000) {
2140 throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");
2141 }
2142
2143 _lastMSecs = msecs;
2144 _lastNSecs = nsecs;
2145 _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
2146
2147 msecs += 12219292800000; // `time_low`
2148
2149 const tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
2150 b[i++] = tl >>> 24 & 0xff;
2151 b[i++] = tl >>> 16 & 0xff;
2152 b[i++] = tl >>> 8 & 0xff;
2153 b[i++] = tl & 0xff; // `time_mid`
2154
2155 const tmh = msecs / 0x100000000 * 10000 & 0xfffffff;
2156 b[i++] = tmh >>> 8 & 0xff;
2157 b[i++] = tmh & 0xff; // `time_high_and_version`
2158
2159 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
2160
2161 b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
2162
2163 b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low`
2164
2165 b[i++] = clockseq & 0xff; // `node`
2166
2167 for (let n = 0; n < 6; ++n) {
2168 b[i + n] = node[n];
2169 }
2170
2171 return buf || (0, _stringify.default)(b);
2172}
2173
2174var _default = v1;
2175exports.default = _default;
2176},{"17":17,"19":19}],21:[function(_dereq_,module,exports){
2177"use strict";
2178
2179Object.defineProperty(exports, "__esModule", {
2180 value: true
2181});
2182exports.default = void 0;
2183
2184var _v = _interopRequireDefault(_dereq_(22));
2185
2186var _md = _interopRequireDefault(_dereq_(13));
2187
2188function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2189
2190const v3 = (0, _v.default)('v3', 0x30, _md.default);
2191var _default = v3;
2192exports.default = _default;
2193},{"13":13,"22":22}],22:[function(_dereq_,module,exports){
2194"use strict";
2195
2196Object.defineProperty(exports, "__esModule", {
2197 value: true
2198});
2199exports.default = _default;
2200exports.URL = exports.DNS = void 0;
2201
2202var _stringify = _interopRequireDefault(_dereq_(19));
2203
2204var _parse = _interopRequireDefault(_dereq_(15));
2205
2206function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2207
2208function stringToBytes(str) {
2209 str = unescape(encodeURIComponent(str)); // UTF8 escape
2210
2211 const bytes = [];
2212
2213 for (let i = 0; i < str.length; ++i) {
2214 bytes.push(str.charCodeAt(i));
2215 }
2216
2217 return bytes;
2218}
2219
2220const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
2221exports.DNS = DNS;
2222const URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
2223exports.URL = URL;
2224
2225function _default(name, version, hashfunc) {
2226 function generateUUID(value, namespace, buf, offset) {
2227 if (typeof value === 'string') {
2228 value = stringToBytes(value);
2229 }
2230
2231 if (typeof namespace === 'string') {
2232 namespace = (0, _parse.default)(namespace);
2233 }
2234
2235 if (namespace.length !== 16) {
2236 throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)');
2237 } // Compute hash of namespace and value, Per 4.3
2238 // Future: Use spread syntax when supported on all platforms, e.g. `bytes =
2239 // hashfunc([...namespace, ... value])`
2240
2241
2242 let bytes = new Uint8Array(16 + value.length);
2243 bytes.set(namespace);
2244 bytes.set(value, namespace.length);
2245 bytes = hashfunc(bytes);
2246 bytes[6] = bytes[6] & 0x0f | version;
2247 bytes[8] = bytes[8] & 0x3f | 0x80;
2248
2249 if (buf) {
2250 offset = offset || 0;
2251
2252 for (let i = 0; i < 16; ++i) {
2253 buf[offset + i] = bytes[i];
2254 }
2255
2256 return buf;
2257 }
2258
2259 return (0, _stringify.default)(bytes);
2260 } // Function#name is not settable on some platforms (#270)
2261
2262
2263 try {
2264 generateUUID.name = name; // eslint-disable-next-line no-empty
2265 } catch (err) {} // For CommonJS default export support
2266
2267
2268 generateUUID.DNS = DNS;
2269 generateUUID.URL = URL;
2270 return generateUUID;
2271}
2272},{"15":15,"19":19}],23:[function(_dereq_,module,exports){
2273"use strict";
2274
2275Object.defineProperty(exports, "__esModule", {
2276 value: true
2277});
2278exports.default = void 0;
2279
2280var _rng = _interopRequireDefault(_dereq_(17));
2281
2282var _stringify = _interopRequireDefault(_dereq_(19));
2283
2284function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2285
2286function v4(options, buf, offset) {
2287 options = options || {};
2288
2289 const rnds = options.random || (options.rng || _rng.default)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
2290
2291
2292 rnds[6] = rnds[6] & 0x0f | 0x40;
2293 rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
2294
2295 if (buf) {
2296 offset = offset || 0;
2297
2298 for (let i = 0; i < 16; ++i) {
2299 buf[offset + i] = rnds[i];
2300 }
2301
2302 return buf;
2303 }
2304
2305 return (0, _stringify.default)(rnds);
2306}
2307
2308var _default = v4;
2309exports.default = _default;
2310},{"17":17,"19":19}],24:[function(_dereq_,module,exports){
2311"use strict";
2312
2313Object.defineProperty(exports, "__esModule", {
2314 value: true
2315});
2316exports.default = void 0;
2317
2318var _v = _interopRequireDefault(_dereq_(22));
2319
2320var _sha = _interopRequireDefault(_dereq_(18));
2321
2322function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2323
2324const v5 = (0, _v.default)('v5', 0x50, _sha.default);
2325var _default = v5;
2326exports.default = _default;
2327},{"18":18,"22":22}],25:[function(_dereq_,module,exports){
2328"use strict";
2329
2330Object.defineProperty(exports, "__esModule", {
2331 value: true
2332});
2333exports.default = void 0;
2334
2335var _regex = _interopRequireDefault(_dereq_(16));
2336
2337function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2338
2339function validate(uuid) {
2340 return typeof uuid === 'string' && _regex.default.test(uuid);
2341}
2342
2343var _default = validate;
2344exports.default = _default;
2345},{"16":16}],26:[function(_dereq_,module,exports){
2346"use strict";
2347
2348Object.defineProperty(exports, "__esModule", {
2349 value: true
2350});
2351exports.default = void 0;
2352
2353var _validate = _interopRequireDefault(_dereq_(25));
2354
2355function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2356
2357function version(uuid) {
2358 if (!(0, _validate.default)(uuid)) {
2359 throw TypeError('Invalid UUID');
2360 }
2361
2362 return parseInt(uuid.substr(14, 1), 16);
2363}
2364
2365var _default = version;
2366exports.default = _default;
2367},{"25":25}],27:[function(_dereq_,module,exports){
2368'use strict';
2369
2370function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
2371
2372_dereq_(1);
2373var immediate = _interopDefault(_dereq_(4));
2374var inherits = _interopDefault(_dereq_(10));
2375var EventEmitter = _interopDefault(_dereq_(3));
2376var uuid = _dereq_(12);
2377var Md5 = _interopDefault(_dereq_(11));
2378
2379// most of this is borrowed from lodash.isPlainObject:
2380// https://github.com/fis-components/lodash.isplainobject/
2381// blob/29c358140a74f252aeb08c9eb28bef86f2217d4a/index.js
2382
2383var funcToString = Function.prototype.toString;
2384var objectCtorString = funcToString.call(Object);
2385
2386function mangle(key) {
2387 return '$' + key;
2388}
2389function unmangle(key) {
2390 return key.substring(1);
2391}
2392function Map$1() {
2393 this._store = {};
2394}
2395Map$1.prototype.get = function (key) {
2396 var mangled = mangle(key);
2397 return this._store[mangled];
2398};
2399Map$1.prototype.set = function (key, value) {
2400 var mangled = mangle(key);
2401 this._store[mangled] = value;
2402 return true;
2403};
2404Map$1.prototype.has = function (key) {
2405 var mangled = mangle(key);
2406 return mangled in this._store;
2407};
2408Map$1.prototype.keys = function () {
2409 return Object.keys(this._store).map(k => unmangle(k));
2410};
2411Map$1.prototype["delete"] = function (key) {
2412 var mangled = mangle(key);
2413 var res = mangled in this._store;
2414 delete this._store[mangled];
2415 return res;
2416};
2417Map$1.prototype.forEach = function (cb) {
2418 var keys = Object.keys(this._store);
2419 for (var i = 0, len = keys.length; i < len; i++) {
2420 var key = keys[i];
2421 var value = this._store[key];
2422 key = unmangle(key);
2423 cb(value, key);
2424 }
2425};
2426Object.defineProperty(Map$1.prototype, 'size', {
2427 get: function () {
2428 return Object.keys(this._store).length;
2429 }
2430});
2431
2432function Set$1(array) {
2433 this._store = new Map$1();
2434
2435 // init with an array
2436 if (array && Array.isArray(array)) {
2437 for (var i = 0, len = array.length; i < len; i++) {
2438 this.add(array[i]);
2439 }
2440 }
2441}
2442Set$1.prototype.add = function (key) {
2443 return this._store.set(key, true);
2444};
2445Set$1.prototype.has = function (key) {
2446 return this._store.has(key);
2447};
2448Set$1.prototype.forEach = function (cb) {
2449 this._store.forEach(function (value, key) {
2450 cb(key);
2451 });
2452};
2453Object.defineProperty(Set$1.prototype, 'size', {
2454 get: function () {
2455 return this._store.size;
2456 }
2457});
2458
2459// Based on https://kangax.github.io/compat-table/es6/ we can sniff out
2460
2461// based on https://github.com/montagejs/collections
2462
2463// like underscore/lodash _.pick()
2464function pick(obj, arr) {
2465 var res = {};
2466 for (var i = 0, len = arr.length; i < len; i++) {
2467 var prop = arr[i];
2468 if (prop in obj) {
2469 res[prop] = obj[prop];
2470 }
2471 }
2472 return res;
2473}
2474
2475var hasLocal;
2476
2477try {
2478 localStorage.setItem('_pouch_check_localstorage', 1);
2479 hasLocal = !!localStorage.getItem('_pouch_check_localstorage');
2480} catch (e) {
2481 hasLocal = false;
2482}
2483
2484function hasLocalStorage() {
2485 return hasLocal;
2486}
2487
2488// Custom nextTick() shim for browsers. In node, this will just be process.nextTick(). We
2489
2490inherits(Changes, EventEmitter);
2491
2492/* istanbul ignore next */
2493function attachBrowserEvents(self) {
2494 if (hasLocalStorage()) {
2495 addEventListener("storage", function (e) {
2496 self.emit(e.key);
2497 });
2498 }
2499}
2500
2501function Changes() {
2502 EventEmitter.call(this);
2503 this._listeners = {};
2504
2505 attachBrowserEvents(this);
2506}
2507Changes.prototype.addListener = function (dbName, id, db, opts) {
2508 /* istanbul ignore if */
2509 if (this._listeners[id]) {
2510 return;
2511 }
2512 var self = this;
2513 var inprogress = false;
2514 function eventFunction() {
2515 /* istanbul ignore if */
2516 if (!self._listeners[id]) {
2517 return;
2518 }
2519 if (inprogress) {
2520 inprogress = 'waiting';
2521 return;
2522 }
2523 inprogress = true;
2524 var changesOpts = pick(opts, [
2525 'style', 'include_docs', 'attachments', 'conflicts', 'filter',
2526 'doc_ids', 'view', 'since', 'query_params', 'binary', 'return_docs'
2527 ]);
2528
2529 /* istanbul ignore next */
2530 function onError() {
2531 inprogress = false;
2532 }
2533
2534 db.changes(changesOpts).on('change', function (c) {
2535 if (c.seq > opts.since && !opts.cancelled) {
2536 opts.since = c.seq;
2537 opts.onChange(c);
2538 }
2539 }).on('complete', function () {
2540 if (inprogress === 'waiting') {
2541 immediate(eventFunction);
2542 }
2543 inprogress = false;
2544 }).on('error', onError);
2545 }
2546 this._listeners[id] = eventFunction;
2547 this.on(dbName, eventFunction);
2548};
2549
2550Changes.prototype.removeListener = function (dbName, id) {
2551 /* istanbul ignore if */
2552 if (!(id in this._listeners)) {
2553 return;
2554 }
2555 EventEmitter.prototype.removeListener.call(this, dbName,
2556 this._listeners[id]);
2557 delete this._listeners[id];
2558};
2559
2560
2561/* istanbul ignore next */
2562Changes.prototype.notifyLocalWindows = function (dbName) {
2563 //do a useless change on a storage thing
2564 //in order to get other windows's listeners to activate
2565 if (hasLocalStorage()) {
2566 localStorage[dbName] = (localStorage[dbName] === "a") ? "b" : "a";
2567 }
2568};
2569
2570Changes.prototype.notify = function (dbName) {
2571 this.emit(dbName);
2572 this.notifyLocalWindows(dbName);
2573};
2574
2575function guardedConsole(method) {
2576 /* istanbul ignore else */
2577 if (typeof console !== 'undefined' && typeof console[method] === 'function') {
2578 var args = Array.prototype.slice.call(arguments, 1);
2579 console[method].apply(console, args);
2580 }
2581}
2582
2583var assign;
2584{
2585 if (typeof Object.assign === 'function') {
2586 assign = Object.assign;
2587 } else {
2588 // lite Object.assign polyfill based on
2589 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
2590 assign = function (target) {
2591 var to = Object(target);
2592
2593 for (var index = 1; index < arguments.length; index++) {
2594 var nextSource = arguments[index];
2595
2596 if (nextSource != null) { // Skip over if undefined or null
2597 for (var nextKey in nextSource) {
2598 // Avoid bugs when hasOwnProperty is shadowed
2599 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
2600 to[nextKey] = nextSource[nextKey];
2601 }
2602 }
2603 }
2604 }
2605 return to;
2606 };
2607 }
2608}
2609
2610var $inject_Object_assign = assign;
2611
2612inherits(PouchError, Error);
2613
2614function PouchError(status, error, reason) {
2615 Error.call(this, reason);
2616 this.status = status;
2617 this.name = error;
2618 this.message = reason;
2619 this.error = true;
2620}
2621
2622PouchError.prototype.toString = function () {
2623 return JSON.stringify({
2624 status: this.status,
2625 name: this.name,
2626 message: this.message,
2627 reason: this.reason
2628 });
2629};
2630
2631var UNAUTHORIZED = new PouchError(401, 'unauthorized', "Name or password is incorrect.");
2632var MISSING_BULK_DOCS = new PouchError(400, 'bad_request', "Missing JSON list of 'docs'");
2633var MISSING_DOC = new PouchError(404, 'not_found', 'missing');
2634var REV_CONFLICT = new PouchError(409, 'conflict', 'Document update conflict');
2635var INVALID_ID = new PouchError(400, 'bad_request', '_id field must contain a string');
2636var MISSING_ID = new PouchError(412, 'missing_id', '_id is required for puts');
2637var RESERVED_ID = new PouchError(400, 'bad_request', 'Only reserved document ids may start with underscore.');
2638var NOT_OPEN = new PouchError(412, 'precondition_failed', 'Database not open');
2639var UNKNOWN_ERROR = new PouchError(500, 'unknown_error', 'Database encountered an unknown error');
2640var BAD_ARG = new PouchError(500, 'badarg', 'Some query argument is invalid');
2641var INVALID_REQUEST = new PouchError(400, 'invalid_request', 'Request was invalid');
2642var QUERY_PARSE_ERROR = new PouchError(400, 'query_parse_error', 'Some query parameter is invalid');
2643var DOC_VALIDATION = new PouchError(500, 'doc_validation', 'Bad special document member');
2644var BAD_REQUEST = new PouchError(400, 'bad_request', 'Something wrong with the request');
2645var NOT_AN_OBJECT = new PouchError(400, 'bad_request', 'Document must be a JSON object');
2646var DB_MISSING = new PouchError(404, 'not_found', 'Database not found');
2647var IDB_ERROR = new PouchError(500, 'indexed_db_went_bad', 'unknown');
2648var WSQ_ERROR = new PouchError(500, 'web_sql_went_bad', 'unknown');
2649var LDB_ERROR = new PouchError(500, 'levelDB_went_went_bad', 'unknown');
2650var FORBIDDEN = new PouchError(403, 'forbidden', 'Forbidden by design doc validate_doc_update function');
2651var INVALID_REV = new PouchError(400, 'bad_request', 'Invalid rev format');
2652var FILE_EXISTS = new PouchError(412, 'file_exists', 'The database could not be created, the file already exists.');
2653var MISSING_STUB = new PouchError(412, 'missing_stub', 'A pre-existing attachment stub wasn\'t found');
2654var INVALID_URL = new PouchError(413, 'invalid_url', 'Provided URL is invalid');
2655
2656function createError(error, reason) {
2657 function CustomPouchError(reason) {
2658 // inherit error properties from our parent error manually
2659 // so as to allow proper JSON parsing.
2660 /* jshint ignore:start */
2661 var names = Object.getOwnPropertyNames(error);
2662 for (var i = 0, len = names.length; i < len; i++) {
2663 if (typeof error[names[i]] !== 'function') {
2664 this[names[i]] = error[names[i]];
2665 }
2666 }
2667
2668 if (this.stack === undefined) {
2669 this.stack = (new Error()).stack;
2670 }
2671
2672 /* jshint ignore:end */
2673 if (reason !== undefined) {
2674 this.reason = reason;
2675 }
2676 }
2677 CustomPouchError.prototype = PouchError.prototype;
2678 return new CustomPouchError(reason);
2679}
2680
2681function tryFilter(filter, doc, req) {
2682 try {
2683 return !filter(doc, req);
2684 } catch (err) {
2685 var msg = 'Filter function threw: ' + err.toString();
2686 return createError(BAD_REQUEST, msg);
2687 }
2688}
2689
2690function filterChange(opts) {
2691 var req = {};
2692 var hasFilter = opts.filter && typeof opts.filter === 'function';
2693 req.query = opts.query_params;
2694
2695 return function filter(change) {
2696 if (!change.doc) {
2697 // CSG sends events on the changes feed that don't have documents,
2698 // this hack makes a whole lot of existing code robust.
2699 change.doc = {};
2700 }
2701
2702 var filterReturn = hasFilter && tryFilter(opts.filter, change.doc, req);
2703
2704 if (typeof filterReturn === 'object') {
2705 return filterReturn;
2706 }
2707
2708 if (filterReturn) {
2709 return false;
2710 }
2711
2712 if (!opts.include_docs) {
2713 delete change.doc;
2714 } else if (!opts.attachments) {
2715 for (var att in change.doc._attachments) {
2716 /* istanbul ignore else */
2717 if (Object.prototype.hasOwnProperty.call(change.doc._attachments, att)) {
2718 change.doc._attachments[att].stub = true;
2719 }
2720 }
2721 }
2722 return true;
2723 };
2724}
2725
2726// shim for Function.prototype.name,
2727
2728// Determine id an ID is valid
2729// - invalid IDs begin with an underescore that does not begin '_design' or
2730// '_local'
2731// - any other string value is a valid id
2732// Returns the specific error object for each case
2733function invalidIdError(id) {
2734 var err;
2735 if (!id) {
2736 err = createError(MISSING_ID);
2737 } else if (typeof id !== 'string') {
2738 err = createError(INVALID_ID);
2739 } else if (/^_/.test(id) && !(/^_(design|local)/).test(id)) {
2740 err = createError(RESERVED_ID);
2741 }
2742 if (err) {
2743 throw err;
2744 }
2745}
2746
2747// Checks if a PouchDB object is "remote" or not. This is
2748
2749// originally parseUri 1.2.2, now patched by us
2750
2751// Based on https://github.com/alexdavid/scope-eval v0.0.3
2752
2753var thisBtoa = function (str) {
2754 return btoa(str);
2755};
2756
2757// Abstracts constructing a Blob object, so it also works in older
2758// browsers that don't support the native Blob constructor (e.g.
2759// old QtWebKit versions, Android < 4.4).
2760function createBlob(parts, properties) {
2761 /* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */
2762 parts = parts || [];
2763 properties = properties || {};
2764 try {
2765 return new Blob(parts, properties);
2766 } catch (e) {
2767 if (e.name !== "TypeError") {
2768 throw e;
2769 }
2770 var Builder = typeof BlobBuilder !== 'undefined' ? BlobBuilder :
2771 typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder :
2772 typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder :
2773 WebKitBlobBuilder;
2774 var builder = new Builder();
2775 for (var i = 0; i < parts.length; i += 1) {
2776 builder.append(parts[i]);
2777 }
2778 return builder.getBlob(properties.type);
2779 }
2780}
2781
2782// From http://stackoverflow.com/questions/14967647/ (continues on next line)
2783// encode-decode-image-with-base64-breaks-image (2013-04-21)
2784function binaryStringToArrayBuffer(bin) {
2785 var length = bin.length;
2786 var buf = new ArrayBuffer(length);
2787 var arr = new Uint8Array(buf);
2788 for (var i = 0; i < length; i++) {
2789 arr[i] = bin.charCodeAt(i);
2790 }
2791 return buf;
2792}
2793
2794function binStringToBluffer(binString, type) {
2795 return createBlob([binaryStringToArrayBuffer(binString)], {type: type});
2796}
2797
2798//Can't find original post, but this is close
2799//http://stackoverflow.com/questions/6965107/ (continues on next line)
2800//converting-between-strings-and-arraybuffers
2801function arrayBufferToBinaryString(buffer) {
2802 var binary = '';
2803 var bytes = new Uint8Array(buffer);
2804 var length = bytes.byteLength;
2805 for (var i = 0; i < length; i++) {
2806 binary += String.fromCharCode(bytes[i]);
2807 }
2808 return binary;
2809}
2810
2811// shim for browsers that don't support it
2812function readAsBinaryString(blob, callback) {
2813 var reader = new FileReader();
2814 var hasBinaryString = typeof reader.readAsBinaryString === 'function';
2815 reader.onloadend = function (e) {
2816 var result = e.target.result || '';
2817 if (hasBinaryString) {
2818 return callback(result);
2819 }
2820 callback(arrayBufferToBinaryString(result));
2821 };
2822 if (hasBinaryString) {
2823 reader.readAsBinaryString(blob);
2824 } else {
2825 reader.readAsArrayBuffer(blob);
2826 }
2827}
2828
2829// simplified API. universal browser support is assumed
2830function readAsArrayBuffer(blob, callback) {
2831 var reader = new FileReader();
2832 reader.onloadend = function (e) {
2833 var result = e.target.result || new ArrayBuffer(0);
2834 callback(result);
2835 };
2836 reader.readAsArrayBuffer(blob);
2837}
2838
2839// this is not used in the browser
2840
2841var setImmediateShim = self.setImmediate || self.setTimeout;
2842var MD5_CHUNK_SIZE = 32768;
2843
2844function rawToBase64(raw) {
2845 return thisBtoa(raw);
2846}
2847
2848function sliceBlob(blob, start, end) {
2849 if (blob.webkitSlice) {
2850 return blob.webkitSlice(start, end);
2851 }
2852 return blob.slice(start, end);
2853}
2854
2855function appendBlob(buffer, blob, start, end, callback) {
2856 if (start > 0 || end < blob.size) {
2857 // only slice blob if we really need to
2858 blob = sliceBlob(blob, start, end);
2859 }
2860 readAsArrayBuffer(blob, function (arrayBuffer) {
2861 buffer.append(arrayBuffer);
2862 callback();
2863 });
2864}
2865
2866function appendString(buffer, string, start, end, callback) {
2867 if (start > 0 || end < string.length) {
2868 // only create a substring if we really need to
2869 string = string.substring(start, end);
2870 }
2871 buffer.appendBinary(string);
2872 callback();
2873}
2874
2875function binaryMd5(data, callback) {
2876 var inputIsString = typeof data === 'string';
2877 var len = inputIsString ? data.length : data.size;
2878 var chunkSize = Math.min(MD5_CHUNK_SIZE, len);
2879 var chunks = Math.ceil(len / chunkSize);
2880 var currentChunk = 0;
2881 var buffer = inputIsString ? new Md5() : new Md5.ArrayBuffer();
2882
2883 var append = inputIsString ? appendString : appendBlob;
2884
2885 function next() {
2886 setImmediateShim(loadNextChunk);
2887 }
2888
2889 function done() {
2890 var raw = buffer.end(true);
2891 var base64 = rawToBase64(raw);
2892 callback(base64);
2893 buffer.destroy();
2894 }
2895
2896 function loadNextChunk() {
2897 var start = currentChunk * chunkSize;
2898 var end = start + chunkSize;
2899 currentChunk++;
2900 if (currentChunk < chunks) {
2901 append(buffer, data, start, end, next);
2902 } else {
2903 append(buffer, data, start, end, done);
2904 }
2905 }
2906 loadNextChunk();
2907}
2908
2909function stringMd5(string) {
2910 return Md5.hash(string);
2911}
2912
2913/**
2914 * Creates a new revision string that does NOT include the revision height
2915 * For example '56649f1b0506c6ca9fda0746eb0cacdf'
2916 */
2917function rev$$1(doc, deterministic_revs) {
2918 if (!deterministic_revs) {
2919 return uuid.v4().replace(/-/g, '').toLowerCase();
2920 }
2921
2922 var mutateableDoc = $inject_Object_assign({}, doc);
2923 delete mutateableDoc._rev_tree;
2924 return stringMd5(JSON.stringify(mutateableDoc));
2925}
2926
2927var uuid$1 = uuid.v4; // mimic old import, only v4 is ever used elsewhere
2928
2929var IDB_NULL = Number.MIN_SAFE_INTEGER;
2930var IDB_FALSE = Number.MIN_SAFE_INTEGER + 1;
2931var IDB_TRUE = Number.MIN_SAFE_INTEGER + 2;
2932
2933// These are the same as bellow but without the global flag
2934// we want to use RegExp.test because it's really fast, but the global flag
2935// makes the regex const stateful (seriously) as it walked through all instances
2936var TEST_KEY_INVALID = /^[^a-zA-Z_$]|[^a-zA-Z0-9_$]+/;
2937var TEST_PATH_INVALID = /\\.|(^|\.)[^a-zA-Z_$]|[^a-zA-Z0-9_$.]+/;
2938function needsSanitise(name, isPath) {
2939 if (isPath) {
2940 return TEST_PATH_INVALID.test(name);
2941 } else {
2942 return TEST_KEY_INVALID.test(name);
2943 }
2944}
2945
2946//
2947// IndexedDB only allows valid JS names in its index paths, whereas JSON allows
2948// for any string at all. This converts invalid JS names to valid ones, to allow
2949// for them to be indexed.
2950//
2951// For example, "foo-bar" is a valid JSON key, but cannot be a valid JS name
2952// (because that would be read as foo minus bar).
2953//
2954// Very high level rules for valid JS names are:
2955// - First character cannot start with a number
2956// - Otherwise all characters must be be a-z, A-Z, 0-9, $ or _.
2957// - We allow . unless the name represents a single field, as that represents
2958// a deep index path.
2959//
2960// This is more aggressive than it needs to be, but also simpler.
2961//
2962var KEY_INVALID = new RegExp(TEST_KEY_INVALID.source, 'g');
2963var PATH_INVALID = new RegExp(TEST_PATH_INVALID.source, 'g');
2964var SLASH = '\\'.charCodeAt(0);
2965const IS_DOT = '.'.charCodeAt(0);
2966
2967function sanitise(name, isPath) {
2968 var correctCharacters = function (match) {
2969 var good = '';
2970 for (var i = 0; i < match.length; i++) {
2971 var code = match.charCodeAt(i);
2972 // If you're sanitising a path, a slash character is there to be interpreted
2973 // by whatever parses the path later as "escape the next thing".
2974 //
2975 // e.g., if you want to index THIS string:
2976 // {"foo": {"bar.baz": "THIS"}}
2977 // Your index path would be "foo.bar\.baz".
2978
2979 if (code === IS_DOT && isPath && i === 0) {
2980 good += '.';
2981 } else if (code === SLASH && isPath) {
2982 continue;
2983 } else {
2984 good += '_c' + code + '_';
2985 }
2986 }
2987 return good;
2988 };
2989
2990 if (isPath) {
2991 return name.replace(PATH_INVALID, correctCharacters);
2992 } else {
2993 return name.replace(KEY_INVALID, correctCharacters);
2994 }
2995}
2996
2997function needsRewrite(data) {
2998 for (var key of Object.keys(data)) {
2999 if (needsSanitise(key)) {
3000 return true;
3001 } else if (data[key] === null || typeof data[key] === 'boolean') {
3002 return true;
3003 } else if (typeof data[key] === 'object') {
3004 return needsRewrite(data[key]);
3005 }
3006 }
3007}
3008
3009function rewrite(data) {
3010 if (!needsRewrite(data)) {
3011 return false;
3012 }
3013
3014 var isArray = Array.isArray(data);
3015 var clone = isArray
3016 ? []
3017 : {};
3018
3019 Object.keys(data).forEach(function (key) {
3020 var safeKey = isArray ? key : sanitise(key);
3021
3022 if (data[key] === null) {
3023 clone[safeKey] = IDB_NULL;
3024 } else if (typeof data[key] === 'boolean') {
3025 clone[safeKey] = data[key] ? IDB_TRUE : IDB_FALSE;
3026 } else if (typeof data[key] === 'object') {
3027 clone[safeKey] = rewrite(data[key]);
3028 } else {
3029 clone[safeKey] = data[key];
3030 }
3031 });
3032
3033 return clone;
3034}
3035
3036var DOC_STORE = 'docs';
3037var META_STORE = 'meta';
3038
3039function idbError(callback) {
3040 return function (evt) {
3041 var message = 'unknown_error';
3042 if (evt.target && evt.target.error) {
3043 message = evt.target.error.name || evt.target.error.message;
3044 }
3045 callback(createError(IDB_ERROR, message, evt.type));
3046 };
3047}
3048
3049function processAttachment(name, src, doc, isBinary) {
3050
3051 delete doc._attachments[name].stub;
3052
3053 if (isBinary) {
3054 doc._attachments[name].data =
3055 src.attachments[doc._attachments[name].digest].data;
3056 return Promise.resolve();
3057 }
3058
3059 return new Promise(function (resolve) {
3060 var data = src.attachments[doc._attachments[name].digest].data;
3061 readAsBinaryString(data, function (binString) {
3062 doc._attachments[name].data = thisBtoa(binString);
3063 delete doc._attachments[name].length;
3064 resolve();
3065 });
3066 });
3067}
3068
3069function rawIndexFields(ddoc, viewName) {
3070 // fields are an array of either the string name of the field, or a key value
3071 var fields = ddoc.views[viewName].options &&
3072 ddoc.views[viewName].options.def &&
3073 ddoc.views[viewName].options.def.fields || [];
3074
3075 // Either ['foo'] or [{'foo': 'desc'}]
3076 return fields.map(function (field) {
3077 if (typeof field === 'string') {
3078 return field;
3079 } else {
3080 return Object.keys(field)[0];
3081 }
3082 });
3083}
3084
3085function naturalIndexName(fields) {
3086 return '_find_idx/' + fields.join('/');
3087}
3088
3089/**
3090 * Convert the fields the user gave us in the view and convert them to work for
3091 * indexeddb.
3092 *
3093 * fields is an array of field strings. A field string could be one field:
3094 * 'foo'
3095 * Or it could be a json path:
3096 * 'foo.bar'
3097 */
3098function correctIndexFields(fields) {
3099 // Every index has to have deleted at the front, because when we do a query
3100 // we need to filter out deleted documents.
3101 return ['deleted'].concat(
3102 fields.map(function (field) {
3103 if (field in ['_id', '_rev', '_deleted', '_attachments']) {
3104 // These properties are stored at the top level without the underscore
3105 return field.substr(1);
3106 } else {
3107 // The custom document fields are inside the `data` property
3108 return 'data.' + sanitise(field, true);
3109 }
3110 })
3111 );
3112}
3113
3114//
3115// Core PouchDB schema version. Increment this if we, as a library, want to make
3116// schema changes in indexeddb. See upgradePouchDbSchema()
3117//
3118var POUCHDB_IDB_VERSION = 1;
3119
3120//
3121// Functions that manage a combinate indexeddb version, by combining the current
3122// time in millis that represents user migrations with a large multiplier that
3123// represents PouchDB system migrations.
3124//
3125// This lets us use the idb version number to both represent
3126// PouchDB-library-level migrations as well as "user migrations" required for
3127// when design documents trigger the addition or removal of native indexes.
3128//
3129// Given that Number.MAX_SAFE_INTEGER = 9007199254740991
3130//
3131// We can easily use the largest 2-3 digits and either allow:
3132// - 900 system migrations up to 2198/02/18
3133// - or 89 system migrations up to 5050/02/14
3134//
3135// This impl does the former. If this code still exists after 2198 someone send my
3136// decendents a Spacebook message congratulating them on their impressive genes.
3137//
3138// 9007199254740991 <- MAX_SAFE_INTEGER
3139// 10000000000000 <- 10^13
3140// 7199254740991 <- 2198-02-18T16:59:00.991Z
3141//
3142var versionMultiplier = Math.pow(10, 13);
3143function createIdbVersion() {
3144 return (versionMultiplier * POUCHDB_IDB_VERSION) + new Date().getTime();
3145}
3146function getPouchDbVersion(version) {
3147 return Math.floor(version / versionMultiplier);
3148}
3149
3150function maintainNativeIndexes(openReq, reject) {
3151 var docStore = openReq.transaction.objectStore(DOC_STORE);
3152 var ddocsReq = docStore.getAll(IDBKeyRange.bound('_design/', '_design/\uffff'));
3153
3154 ddocsReq.onsuccess = function (e) {
3155 var results = e.target.result;
3156 var existingIndexNames = Array.from(docStore.indexNames);
3157
3158 // NB: the only thing we're supporting here is the declared indexing
3159 // fields nothing more.
3160 var expectedIndexes = results.filter(function (row) {
3161 return row.deleted === 0 && row.revs[row.rev].data.views;
3162 }).map(function (row) {
3163 return row.revs[row.rev].data;
3164 }).reduce(function (indexes, ddoc) {
3165 return Object.keys(ddoc.views).reduce(function (acc, viewName) {
3166 var fields = rawIndexFields(ddoc, viewName);
3167
3168 if (fields && fields.length > 0) {
3169 acc[naturalIndexName(fields)] = correctIndexFields(fields);
3170 }
3171
3172 return acc;
3173 }, indexes);
3174 }, {});
3175
3176 var expectedIndexNames = Object.keys(expectedIndexes);
3177
3178 // Delete any indexes that aren't system indexes or expected
3179 var systemIndexNames = ['seq'];
3180 existingIndexNames.forEach(function (index) {
3181 if (systemIndexNames.indexOf(index) === -1 && expectedIndexNames.indexOf(index) === -1) {
3182 docStore.deleteIndex(index);
3183 }
3184 });
3185
3186 // Work out which indexes are missing and create them
3187 var newIndexNames = expectedIndexNames.filter(function (ei) {
3188 return existingIndexNames.indexOf(ei) === -1;
3189 });
3190
3191 try {
3192 newIndexNames.forEach(function (indexName) {
3193 docStore.createIndex(indexName, expectedIndexes[indexName]);
3194 });
3195 } catch (err) {
3196 reject(err);
3197 }
3198 };
3199}
3200
3201function upgradePouchDbSchema(db, pouchdbVersion) {
3202 if (pouchdbVersion < 1) {
3203 var docStore = db.createObjectStore(DOC_STORE, {keyPath : 'id'});
3204 docStore.createIndex('seq', 'seq', {unique: true});
3205
3206 db.createObjectStore(META_STORE, {keyPath: 'id'});
3207 }
3208
3209 // Declare more PouchDB schema changes here
3210 // if (pouchdbVersion < 2) { .. }
3211}
3212
3213function openDatabase(openDatabases, api, opts, resolve, reject) {
3214 var openReq = opts.versionchanged ?
3215 indexedDB.open(opts.name) :
3216 indexedDB.open(opts.name, createIdbVersion());
3217
3218 openReq.onupgradeneeded = function (e) {
3219 if (e.oldVersion > 0 && e.oldVersion < versionMultiplier) {
3220 // This DB was created with the "idb" adapter, **not** this one.
3221 // For now we're going to just error out here: users must manually
3222 // migrate between the two. In the future, dependent on performance tests,
3223 // we might silently migrate
3224 throw new Error('Incorrect adapter: you should specify the "idb" adapter to open this DB');
3225 } else if (e.oldVersion === 0 && e.newVersion < versionMultiplier) {
3226 // Firefox still creates the database with version=1 even if we throw,
3227 // so we need to be sure to destroy the empty database before throwing
3228 indexedDB.deleteDatabase(opts.name);
3229 throw new Error('Database was deleted while open');
3230 }
3231
3232 var db = e.target.result;
3233
3234 var pouchdbVersion = getPouchDbVersion(e.oldVersion);
3235 upgradePouchDbSchema(db, pouchdbVersion);
3236 maintainNativeIndexes(openReq, reject);
3237 };
3238
3239 openReq.onblocked = function (e) {
3240 // AFAICT this only occurs if, after sending `onversionchange` events to
3241 // all other open DBs (ie in different tabs), there are still open
3242 // connections to the DB. In this code we should never see this because we
3243 // close our DBs on these events, and all DB interactions are wrapped in
3244 // safely re-opening the DB.
3245 console.error('onblocked, this should never happen', e);
3246 };
3247
3248 openReq.onsuccess = function (e) {
3249 var idb = e.target.result;
3250
3251 idb.onabort = function (e) {
3252 console.error('Database has a global failure', e.target.error);
3253 delete openDatabases[opts.name];
3254 idb.close();
3255 };
3256
3257 idb.onversionchange = function () {
3258 console.log('Database was made stale, closing handle');
3259 openDatabases[opts.name].versionchanged = true;
3260 idb.close();
3261 };
3262
3263 idb.onclose = function () {
3264 console.log('Database was made stale, closing handle');
3265 if (opts.name in openDatabases) {
3266 openDatabases[opts.name].versionchanged = true;
3267 }
3268 };
3269
3270 var metadata = {id: META_STORE};
3271 var txn = idb.transaction([META_STORE], 'readwrite');
3272
3273 txn.oncomplete = function () {
3274 resolve({idb: idb, metadata: metadata});
3275 };
3276
3277 var metaStore = txn.objectStore(META_STORE);
3278 metaStore.get(META_STORE).onsuccess = function (e) {
3279 metadata = e.target.result || metadata;
3280 var changed = false;
3281
3282 if (!('doc_count' in metadata)) {
3283 changed = true;
3284 metadata.doc_count = 0;
3285 }
3286
3287 if (!('seq' in metadata)) {
3288 changed = true;
3289 metadata.seq = 0;
3290 }
3291
3292 if (!('db_uuid' in metadata)) {
3293 changed = true;
3294 metadata.db_uuid = uuid$1();
3295 }
3296
3297 if (changed) {
3298 metaStore.put(metadata);
3299 }
3300 };
3301 };
3302
3303 openReq.onerror = function (e) {
3304 reject(e.target.error);
3305 };
3306}
3307
3308function setup (openDatabases, api, opts) {
3309 if (!openDatabases[opts.name] || openDatabases[opts.name].versionchanged) {
3310 opts.versionchanged = openDatabases[opts.name] &&
3311 openDatabases[opts.name].versionchanged;
3312
3313 openDatabases[opts.name] = new Promise(function (resolve, reject) {
3314 openDatabase(openDatabases, api, opts, resolve, reject);
3315 });
3316 }
3317
3318 return openDatabases[opts.name];
3319}
3320
3321function info (metadata, callback) {
3322 callback(null, {
3323 doc_count: metadata.doc_count,
3324 update_seq: metadata.seq
3325 });
3326}
3327
3328// We fetch all leafs of the revision tree, and sort them based on tree length
3329// and whether they were deleted, undeleted documents with the longest revision
3330// tree (most edits) win
3331// The final sort algorithm is slightly documented in a sidebar here:
3332// http://guide.couchdb.org/draft/conflicts.html
3333function winningRev(metadata) {
3334 var winningId;
3335 var winningPos;
3336 var winningDeleted;
3337 var toVisit = metadata.rev_tree.slice();
3338 var node;
3339 while ((node = toVisit.pop())) {
3340 var tree = node.ids;
3341 var branches = tree[2];
3342 var pos = node.pos;
3343 if (branches.length) { // non-leaf
3344 for (var i = 0, len = branches.length; i < len; i++) {
3345 toVisit.push({pos: pos + 1, ids: branches[i]});
3346 }
3347 continue;
3348 }
3349 var deleted = !!tree[1].deleted;
3350 var id = tree[0];
3351 // sort by deleted, then pos, then id
3352 if (!winningId || (winningDeleted !== deleted ? winningDeleted :
3353 winningPos !== pos ? winningPos < pos : winningId < id)) {
3354 winningId = id;
3355 winningPos = pos;
3356 winningDeleted = deleted;
3357 }
3358 }
3359
3360 return winningPos + '-' + winningId;
3361}
3362
3363// Pretty much all below can be combined into a higher order function to
3364// traverse revisions
3365// The return value from the callback will be passed as context to all
3366// children of that node
3367function traverseRevTree(revs, callback) {
3368 var toVisit = revs.slice();
3369
3370 var node;
3371 while ((node = toVisit.pop())) {
3372 var pos = node.pos;
3373 var tree = node.ids;
3374 var branches = tree[2];
3375 var newCtx =
3376 callback(branches.length === 0, pos, tree[0], node.ctx, tree[1]);
3377 for (var i = 0, len = branches.length; i < len; i++) {
3378 toVisit.push({pos: pos + 1, ids: branches[i], ctx: newCtx});
3379 }
3380 }
3381}
3382
3383function sortByPos(a, b) {
3384 return a.pos - b.pos;
3385}
3386
3387function collectLeaves(revs) {
3388 var leaves = [];
3389 traverseRevTree(revs, function (isLeaf, pos, id, acc, opts) {
3390 if (isLeaf) {
3391 leaves.push({rev: pos + "-" + id, pos: pos, opts: opts});
3392 }
3393 });
3394 leaves.sort(sortByPos).reverse();
3395 for (var i = 0, len = leaves.length; i < len; i++) {
3396 delete leaves[i].pos;
3397 }
3398 return leaves;
3399}
3400
3401// returns revs of all conflicts that is leaves such that
3402// 1. are not deleted and
3403// 2. are different than winning revision
3404function collectConflicts(metadata) {
3405 var win = winningRev(metadata);
3406 var leaves = collectLeaves(metadata.rev_tree);
3407 var conflicts = [];
3408 for (var i = 0, len = leaves.length; i < len; i++) {
3409 var leaf = leaves[i];
3410 if (leaf.rev !== win && !leaf.opts.deleted) {
3411 conflicts.push(leaf.rev);
3412 }
3413 }
3414 return conflicts;
3415}
3416
3417// compact a tree by marking its non-leafs as missing,
3418// and return a list of revs to delete
3419function compactTree(metadata) {
3420 var revs = [];
3421 traverseRevTree(metadata.rev_tree, function (isLeaf, pos,
3422 revHash, ctx, opts) {
3423 if (opts.status === 'available' && !isLeaf) {
3424 revs.push(pos + '-' + revHash);
3425 opts.status = 'missing';
3426 }
3427 });
3428 return revs;
3429}
3430
3431// build up a list of all the paths to the leafs in this revision tree
3432function rootToLeaf(revs) {
3433 var paths = [];
3434 var toVisit = revs.slice();
3435 var node;
3436 while ((node = toVisit.pop())) {
3437 var pos = node.pos;
3438 var tree = node.ids;
3439 var id = tree[0];
3440 var opts = tree[1];
3441 var branches = tree[2];
3442 var isLeaf = branches.length === 0;
3443
3444 var history = node.history ? node.history.slice() : [];
3445 history.push({id: id, opts: opts});
3446 if (isLeaf) {
3447 paths.push({pos: (pos + 1 - history.length), ids: history});
3448 }
3449 for (var i = 0, len = branches.length; i < len; i++) {
3450 toVisit.push({pos: pos + 1, ids: branches[i], history: history});
3451 }
3452 }
3453 return paths.reverse();
3454}
3455
3456// for a better overview of what this is doing, read:
3457
3458function sortByPos$1(a, b) {
3459 return a.pos - b.pos;
3460}
3461
3462// classic binary search
3463function binarySearch(arr, item, comparator) {
3464 var low = 0;
3465 var high = arr.length;
3466 var mid;
3467 while (low < high) {
3468 mid = (low + high) >>> 1;
3469 if (comparator(arr[mid], item) < 0) {
3470 low = mid + 1;
3471 } else {
3472 high = mid;
3473 }
3474 }
3475 return low;
3476}
3477
3478// assuming the arr is sorted, insert the item in the proper place
3479function insertSorted(arr, item, comparator) {
3480 var idx = binarySearch(arr, item, comparator);
3481 arr.splice(idx, 0, item);
3482}
3483
3484// Turn a path as a flat array into a tree with a single branch.
3485// If any should be stemmed from the beginning of the array, that's passed
3486// in as the second argument
3487function pathToTree(path, numStemmed) {
3488 var root;
3489 var leaf;
3490 for (var i = numStemmed, len = path.length; i < len; i++) {
3491 var node = path[i];
3492 var currentLeaf = [node.id, node.opts, []];
3493 if (leaf) {
3494 leaf[2].push(currentLeaf);
3495 leaf = currentLeaf;
3496 } else {
3497 root = leaf = currentLeaf;
3498 }
3499 }
3500 return root;
3501}
3502
3503// compare the IDs of two trees
3504function compareTree(a, b) {
3505 return a[0] < b[0] ? -1 : 1;
3506}
3507
3508// Merge two trees together
3509// The roots of tree1 and tree2 must be the same revision
3510function mergeTree(in_tree1, in_tree2) {
3511 var queue = [{tree1: in_tree1, tree2: in_tree2}];
3512 var conflicts = false;
3513 while (queue.length > 0) {
3514 var item = queue.pop();
3515 var tree1 = item.tree1;
3516 var tree2 = item.tree2;
3517
3518 if (tree1[1].status || tree2[1].status) {
3519 tree1[1].status =
3520 (tree1[1].status === 'available' ||
3521 tree2[1].status === 'available') ? 'available' : 'missing';
3522 }
3523
3524 for (var i = 0; i < tree2[2].length; i++) {
3525 if (!tree1[2][0]) {
3526 conflicts = 'new_leaf';
3527 tree1[2][0] = tree2[2][i];
3528 continue;
3529 }
3530
3531 var merged = false;
3532 for (var j = 0; j < tree1[2].length; j++) {
3533 if (tree1[2][j][0] === tree2[2][i][0]) {
3534 queue.push({tree1: tree1[2][j], tree2: tree2[2][i]});
3535 merged = true;
3536 }
3537 }
3538 if (!merged) {
3539 conflicts = 'new_branch';
3540 insertSorted(tree1[2], tree2[2][i], compareTree);
3541 }
3542 }
3543 }
3544 return {conflicts: conflicts, tree: in_tree1};
3545}
3546
3547function doMerge(tree, path, dontExpand) {
3548 var restree = [];
3549 var conflicts = false;
3550 var merged = false;
3551 var res;
3552
3553 if (!tree.length) {
3554 return {tree: [path], conflicts: 'new_leaf'};
3555 }
3556
3557 for (var i = 0, len = tree.length; i < len; i++) {
3558 var branch = tree[i];
3559 if (branch.pos === path.pos && branch.ids[0] === path.ids[0]) {
3560 // Paths start at the same position and have the same root, so they need
3561 // merged
3562 res = mergeTree(branch.ids, path.ids);
3563 restree.push({pos: branch.pos, ids: res.tree});
3564 conflicts = conflicts || res.conflicts;
3565 merged = true;
3566 } else if (dontExpand !== true) {
3567 // The paths start at a different position, take the earliest path and
3568 // traverse up until it as at the same point from root as the path we
3569 // want to merge. If the keys match we return the longer path with the
3570 // other merged After stemming we dont want to expand the trees
3571
3572 var t1 = branch.pos < path.pos ? branch : path;
3573 var t2 = branch.pos < path.pos ? path : branch;
3574 var diff = t2.pos - t1.pos;
3575
3576 var candidateParents = [];
3577
3578 var trees = [];
3579 trees.push({ids: t1.ids, diff: diff, parent: null, parentIdx: null});
3580 while (trees.length > 0) {
3581 var item = trees.pop();
3582 if (item.diff === 0) {
3583 if (item.ids[0] === t2.ids[0]) {
3584 candidateParents.push(item);
3585 }
3586 continue;
3587 }
3588 var elements = item.ids[2];
3589 for (var j = 0, elementsLen = elements.length; j < elementsLen; j++) {
3590 trees.push({
3591 ids: elements[j],
3592 diff: item.diff - 1,
3593 parent: item.ids,
3594 parentIdx: j
3595 });
3596 }
3597 }
3598
3599 var el = candidateParents[0];
3600
3601 if (!el) {
3602 restree.push(branch);
3603 } else {
3604 res = mergeTree(el.ids, t2.ids);
3605 el.parent[2][el.parentIdx] = res.tree;
3606 restree.push({pos: t1.pos, ids: t1.ids});
3607 conflicts = conflicts || res.conflicts;
3608 merged = true;
3609 }
3610 } else {
3611 restree.push(branch);
3612 }
3613 }
3614
3615 // We didnt find
3616 if (!merged) {
3617 restree.push(path);
3618 }
3619
3620 restree.sort(sortByPos$1);
3621
3622 return {
3623 tree: restree,
3624 conflicts: conflicts || 'internal_node'
3625 };
3626}
3627
3628// To ensure we dont grow the revision tree infinitely, we stem old revisions
3629function stem(tree, depth) {
3630 // First we break out the tree into a complete list of root to leaf paths
3631 var paths = rootToLeaf(tree);
3632 var stemmedRevs;
3633
3634 var result;
3635 for (var i = 0, len = paths.length; i < len; i++) {
3636 // Then for each path, we cut off the start of the path based on the
3637 // `depth` to stem to, and generate a new set of flat trees
3638 var path = paths[i];
3639 var stemmed = path.ids;
3640 var node;
3641 if (stemmed.length > depth) {
3642 // only do the stemming work if we actually need to stem
3643 if (!stemmedRevs) {
3644 stemmedRevs = {}; // avoid allocating this object unnecessarily
3645 }
3646 var numStemmed = stemmed.length - depth;
3647 node = {
3648 pos: path.pos + numStemmed,
3649 ids: pathToTree(stemmed, numStemmed)
3650 };
3651
3652 for (var s = 0; s < numStemmed; s++) {
3653 var rev = (path.pos + s) + '-' + stemmed[s].id;
3654 stemmedRevs[rev] = true;
3655 }
3656 } else { // no need to actually stem
3657 node = {
3658 pos: path.pos,
3659 ids: pathToTree(stemmed, 0)
3660 };
3661 }
3662
3663 // Then we remerge all those flat trees together, ensuring that we dont
3664 // connect trees that would go beyond the depth limit
3665 if (result) {
3666 result = doMerge(result, node, true).tree;
3667 } else {
3668 result = [node];
3669 }
3670 }
3671
3672 // this is memory-heavy per Chrome profiler, avoid unless we actually stemmed
3673 if (stemmedRevs) {
3674 traverseRevTree(result, function (isLeaf, pos, revHash) {
3675 // some revisions may have been removed in a branch but not in another
3676 delete stemmedRevs[pos + '-' + revHash];
3677 });
3678 }
3679
3680 return {
3681 tree: result,
3682 revs: stemmedRevs ? Object.keys(stemmedRevs) : []
3683 };
3684}
3685
3686function merge(tree, path, depth) {
3687 var newTree = doMerge(tree, path);
3688 var stemmed = stem(newTree.tree, depth);
3689 return {
3690 tree: stemmed.tree,
3691 stemmedRevs: stemmed.revs,
3692 conflicts: newTree.conflicts
3693 };
3694}
3695
3696// return true if a rev exists in the rev tree, false otherwise
3697
3698// returns the current leaf node for a given revision
3699function latest(rev, metadata) {
3700 var toVisit = metadata.rev_tree.slice();
3701 var node;
3702 while ((node = toVisit.pop())) {
3703 var pos = node.pos;
3704 var tree = node.ids;
3705 var id = tree[0];
3706 var opts = tree[1];
3707 var branches = tree[2];
3708 var isLeaf = branches.length === 0;
3709
3710 var history = node.history ? node.history.slice() : [];
3711 history.push({id: id, pos: pos, opts: opts});
3712
3713 if (isLeaf) {
3714 for (var i = 0, len = history.length; i < len; i++) {
3715 var historyNode = history[i];
3716 var historyRev = historyNode.pos + '-' + historyNode.id;
3717
3718 if (historyRev === rev) {
3719 // return the rev of this leaf
3720 return pos + '-' + id;
3721 }
3722 }
3723 }
3724
3725 for (var j = 0, l = branches.length; j < l; j++) {
3726 toVisit.push({pos: pos + 1, ids: branches[j], history: history});
3727 }
3728 }
3729
3730 /* istanbul ignore next */
3731 throw new Error('Unable to resolve latest revision for id ' + metadata.id + ', rev ' + rev);
3732}
3733
3734function get (txn, id, opts, callback) {
3735 if (txn.error) {
3736 return callback(txn.error);
3737 }
3738
3739 txn.txn.objectStore(DOC_STORE).get(id).onsuccess = function (e) {
3740 var doc = e.target.result;
3741 var rev;
3742 if (!opts.rev) {
3743 rev = (doc && doc.rev);
3744 } else {
3745 rev = opts.latest ? latest(opts.rev, doc) : opts.rev;
3746 }
3747
3748 if (!doc || (doc.deleted && !opts.rev) || !(rev in doc.revs)) {
3749 callback(createError(MISSING_DOC, 'missing'));
3750 return;
3751 }
3752
3753 var result = doc.revs[rev].data;
3754 result._id = doc.id;
3755 result._rev = rev;
3756
3757 // WARNING: expecting possible old format
3758 // TODO: why are we passing the transaction in the context?
3759 // It's not clear we ever thread these txns usefully
3760 callback(null, {
3761 doc: result,
3762 metadata: doc,
3763 ctx: txn
3764 });
3765 };
3766}
3767
3768function parseAttachment(attachment, opts, cb) {
3769 if (opts.binary) {
3770 return cb(null, attachment);
3771 } else {
3772 readAsBinaryString(attachment, function (binString) {
3773 cb(null, thisBtoa(binString));
3774 });
3775 }
3776}
3777
3778function getAttachment(txn, docId, attachId, _, opts, cb) {
3779 if (txn.error) {
3780 return cb(txn.error);
3781 }
3782
3783 var attachment;
3784
3785 txn.txn.objectStore(DOC_STORE).get(docId).onsuccess = function (e) {
3786 var doc = e.target.result;
3787 var rev = doc.revs[opts.rev || doc.rev].data;
3788 var digest = rev._attachments[attachId].digest;
3789 attachment = doc.attachments[digest].data;
3790 };
3791
3792 txn.txn.oncomplete = function () {
3793 parseAttachment(attachment, opts, cb);
3794 };
3795
3796 txn.txn.onabort = cb;
3797}
3798
3799function toObject(array) {
3800 return array.reduce(function (obj, item) {
3801 obj[item] = true;
3802 return obj;
3803 }, {});
3804}
3805// List of top level reserved words for doc
3806var reservedWords = toObject([
3807 '_id',
3808 '_rev',
3809 '_access',
3810 '_attachments',
3811 '_deleted',
3812 '_revisions',
3813 '_revs_info',
3814 '_conflicts',
3815 '_deleted_conflicts',
3816 '_local_seq',
3817 '_rev_tree',
3818 // replication documents
3819 '_replication_id',
3820 '_replication_state',
3821 '_replication_state_time',
3822 '_replication_state_reason',
3823 '_replication_stats',
3824 // Specific to Couchbase Sync Gateway
3825 '_removed'
3826]);
3827
3828// List of reserved words that should end up in the document
3829var dataWords = toObject([
3830 '_access',
3831 '_attachments',
3832 // replication documents
3833 '_replication_id',
3834 '_replication_state',
3835 '_replication_state_time',
3836 '_replication_state_reason',
3837 '_replication_stats'
3838]);
3839
3840function parseRevisionInfo(rev) {
3841 if (!/^\d+-/.test(rev)) {
3842 return createError(INVALID_REV);
3843 }
3844 var idx = rev.indexOf('-');
3845 var left = rev.substring(0, idx);
3846 var right = rev.substring(idx + 1);
3847 return {
3848 prefix: parseInt(left, 10),
3849 id: right
3850 };
3851}
3852
3853function makeRevTreeFromRevisions(revisions, opts) {
3854 var pos = revisions.start - revisions.ids.length + 1;
3855
3856 var revisionIds = revisions.ids;
3857 var ids = [revisionIds[0], opts, []];
3858
3859 for (var i = 1, len = revisionIds.length; i < len; i++) {
3860 ids = [revisionIds[i], {status: 'missing'}, [ids]];
3861 }
3862
3863 return [{
3864 pos: pos,
3865 ids: ids
3866 }];
3867}
3868
3869// Preprocess documents, parse their revisions, assign an id and a
3870// revision for new writes that are missing them, etc
3871function parseDoc(doc, newEdits, dbOpts) {
3872 if (!dbOpts) {
3873 dbOpts = {
3874 deterministic_revs: true
3875 };
3876 }
3877
3878 var nRevNum;
3879 var newRevId;
3880 var revInfo;
3881 var opts = {status: 'available'};
3882 if (doc._deleted) {
3883 opts.deleted = true;
3884 }
3885
3886 if (newEdits) {
3887 if (!doc._id) {
3888 doc._id = uuid$1();
3889 }
3890 newRevId = rev$$1(doc, dbOpts.deterministic_revs);
3891 if (doc._rev) {
3892 revInfo = parseRevisionInfo(doc._rev);
3893 if (revInfo.error) {
3894 return revInfo;
3895 }
3896 doc._rev_tree = [{
3897 pos: revInfo.prefix,
3898 ids: [revInfo.id, {status: 'missing'}, [[newRevId, opts, []]]]
3899 }];
3900 nRevNum = revInfo.prefix + 1;
3901 } else {
3902 doc._rev_tree = [{
3903 pos: 1,
3904 ids : [newRevId, opts, []]
3905 }];
3906 nRevNum = 1;
3907 }
3908 } else {
3909 if (doc._revisions) {
3910 doc._rev_tree = makeRevTreeFromRevisions(doc._revisions, opts);
3911 nRevNum = doc._revisions.start;
3912 newRevId = doc._revisions.ids[0];
3913 }
3914 if (!doc._rev_tree) {
3915 revInfo = parseRevisionInfo(doc._rev);
3916 if (revInfo.error) {
3917 return revInfo;
3918 }
3919 nRevNum = revInfo.prefix;
3920 newRevId = revInfo.id;
3921 doc._rev_tree = [{
3922 pos: nRevNum,
3923 ids: [newRevId, opts, []]
3924 }];
3925 }
3926 }
3927
3928 invalidIdError(doc._id);
3929
3930 doc._rev = nRevNum + '-' + newRevId;
3931
3932 var result = {metadata : {}, data : {}};
3933 for (var key in doc) {
3934 /* istanbul ignore else */
3935 if (Object.prototype.hasOwnProperty.call(doc, key)) {
3936 var specialKey = key[0] === '_';
3937 if (specialKey && !reservedWords[key]) {
3938 var error = createError(DOC_VALIDATION, key);
3939 error.message = DOC_VALIDATION.message + ': ' + key;
3940 throw error;
3941 } else if (specialKey && !dataWords[key]) {
3942 result.metadata[key.slice(1)] = doc[key];
3943 } else {
3944 result.data[key] = doc[key];
3945 }
3946 }
3947 }
3948 return result;
3949}
3950
3951function bulkDocs (api, req, opts, metadata, dbOpts, idbChanges, callback) {
3952
3953 var txn;
3954
3955 // TODO: I would prefer to get rid of these globals
3956 var error;
3957 var results = [];
3958 var docs = [];
3959 var lastWriteIndex;
3960
3961 var revsLimit = dbOpts.revs_limit || 1000;
3962 var rewriteEnabled = dbOpts.name.indexOf("-mrview-") === -1;
3963 const autoCompaction = dbOpts.auto_compaction;
3964
3965 // We only need to track 1 revision for local documents
3966 function docsRevsLimit(doc) {
3967 return /^_local/.test(doc.id) ? 1 : revsLimit;
3968 }
3969
3970 function rootIsMissing(doc) {
3971 return doc.rev_tree[0].ids[1].status === 'missing';
3972 }
3973
3974 function parseBase64(data) {
3975 try {
3976 return atob(data);
3977 } catch (e) {
3978 return {
3979 error: createError(BAD_ARG, 'Attachment is not a valid base64 string')
3980 };
3981 }
3982 }
3983
3984 // Reads the original doc from the store if available
3985 // As in allDocs with keys option using multiple get calls is the fastest way
3986 function fetchExistingDocs(txn, docs) {
3987 var fetched = 0;
3988 var oldDocs = {};
3989
3990 function readDone(e) {
3991 if (e.target.result) {
3992 oldDocs[e.target.result.id] = e.target.result;
3993 }
3994 if (++fetched === docs.length) {
3995 processDocs$$1(txn, docs, oldDocs);
3996 }
3997 }
3998
3999 docs.forEach(function (doc) {
4000 txn.objectStore(DOC_STORE).get(doc.id).onsuccess = readDone;
4001 });
4002 }
4003
4004 function revHasAttachment(doc, rev, digest) {
4005 return doc.revs[rev] &&
4006 doc.revs[rev].data._attachments &&
4007 Object.values(doc.revs[rev].data._attachments).find(function (att) {
4008 return att.digest === digest;
4009 });
4010 }
4011
4012 function processDocs$$1(txn, docs, oldDocs) {
4013
4014 docs.forEach(function (doc, i) {
4015 var newDoc;
4016
4017 // The first document write cannot be a deletion
4018 if ('was_delete' in opts && !(Object.prototype.hasOwnProperty.call(oldDocs, doc.id))) {
4019 newDoc = createError(MISSING_DOC, 'deleted');
4020
4021 // The first write of a document cannot specify a revision
4022 } else if (opts.new_edits &&
4023 !Object.prototype.hasOwnProperty.call(oldDocs, doc.id) &&
4024 rootIsMissing(doc)) {
4025 newDoc = createError(REV_CONFLICT);
4026
4027 // Update the existing document
4028 } else if (Object.prototype.hasOwnProperty.call(oldDocs, doc.id)) {
4029 newDoc = update(txn, doc, oldDocs[doc.id]);
4030 // The update can be rejected if it is an update to an existing
4031 // revision, if so skip it
4032 if (newDoc == false) {
4033 return;
4034 }
4035
4036 // New document
4037 } else {
4038 // Ensure new documents are also stemmed
4039 var merged = merge([], doc.rev_tree[0], docsRevsLimit(doc));
4040 doc.rev_tree = merged.tree;
4041 doc.stemmedRevs = merged.stemmedRevs;
4042 newDoc = doc;
4043 newDoc.isNewDoc = true;
4044 newDoc.wasDeleted = doc.revs[doc.rev].deleted ? 1 : 0;
4045 }
4046
4047 if (newDoc.error) {
4048 results[i] = newDoc;
4049 } else {
4050 oldDocs[newDoc.id] = newDoc;
4051 lastWriteIndex = i;
4052 write(txn, newDoc, i);
4053 }
4054 });
4055 }
4056
4057 // Converts from the format returned by parseDoc into the new format
4058 // we use to store
4059 function convertDocFormat(doc) {
4060
4061 var newDoc = {
4062 id: doc.metadata.id,
4063 rev: doc.metadata.rev,
4064 rev_tree: doc.metadata.rev_tree,
4065 revs: doc.metadata.revs || {}
4066 };
4067
4068 newDoc.revs[newDoc.rev] = {
4069 data: doc.data,
4070 deleted: doc.metadata.deleted
4071 };
4072
4073 return newDoc;
4074 }
4075
4076 function update(txn, doc, oldDoc) {
4077
4078 // Ignore updates to existing revisions
4079 if ((doc.rev in oldDoc.revs) && !opts.new_edits) {
4080 return false;
4081 }
4082
4083 var isRoot = /^1-/.test(doc.rev);
4084
4085 // Reattach first writes after a deletion to last deleted tree
4086 if (oldDoc.deleted && !doc.deleted && opts.new_edits && isRoot) {
4087 var tmp = doc.revs[doc.rev].data;
4088 tmp._rev = oldDoc.rev;
4089 tmp._id = oldDoc.id;
4090 doc = convertDocFormat(parseDoc(tmp, opts.new_edits, dbOpts));
4091 }
4092
4093 var merged = merge(oldDoc.rev_tree, doc.rev_tree[0], docsRevsLimit(doc));
4094 doc.stemmedRevs = merged.stemmedRevs;
4095 doc.rev_tree = merged.tree;
4096
4097 // Merge the old and new rev data
4098 var revs = oldDoc.revs;
4099 revs[doc.rev] = doc.revs[doc.rev];
4100 doc.revs = revs;
4101
4102 doc.attachments = oldDoc.attachments;
4103
4104 var inConflict = opts.new_edits && (((oldDoc.deleted && doc.deleted) ||
4105 (!oldDoc.deleted && merged.conflicts !== 'new_leaf') ||
4106 (oldDoc.deleted && !doc.deleted && merged.conflicts === 'new_branch') ||
4107 (oldDoc.rev === doc.rev)));
4108
4109 if (inConflict) {
4110 return createError(REV_CONFLICT);
4111 }
4112
4113 doc.wasDeleted = oldDoc.deleted;
4114
4115 return doc;
4116 }
4117
4118 function write(txn, doc, i) {
4119
4120 // We copy the data from the winning revision into the root
4121 // of the document so that it can be indexed
4122 var winningRev$$1 = winningRev(doc);
4123 // rev of new doc for attachments and to return it
4124 var writtenRev = doc.rev;
4125 var isLocal = /^_local/.test(doc.id);
4126
4127 var theDoc = doc.revs[winningRev$$1].data;
4128
4129 const isNewDoc = doc.isNewDoc;
4130
4131 if (rewriteEnabled) {
4132 // doc.data is what we index, so we need to clone and rewrite it, and clean
4133 // it up for indexability
4134 var result = rewrite(theDoc);
4135 if (result) {
4136 doc.data = result;
4137 delete doc.data._attachments;
4138 } else {
4139 doc.data = theDoc;
4140 }
4141 } else {
4142 doc.data = theDoc;
4143 }
4144
4145 doc.rev = winningRev$$1;
4146 // .deleted needs to be an int for indexing
4147 doc.deleted = doc.revs[winningRev$$1].deleted ? 1 : 0;
4148
4149 // Bump the seq for every new (non local) revision written
4150 // TODO: index expects a unique seq, not sure if ignoring local will
4151 // work
4152 if (!isLocal) {
4153 doc.seq = ++metadata.seq;
4154
4155 var delta = 0;
4156 // If its a new document, we wont decrement if deleted
4157 if (doc.isNewDoc) {
4158 delta = doc.deleted ? 0 : 1;
4159 } else if (doc.wasDeleted !== doc.deleted) {
4160 delta = doc.deleted ? -1 : 1;
4161 }
4162 metadata.doc_count += delta;
4163 }
4164 delete doc.isNewDoc;
4165 delete doc.wasDeleted;
4166
4167 // If there have been revisions stemmed when merging trees,
4168 // delete their data
4169 let revsToDelete = doc.stemmedRevs || [];
4170
4171 if (autoCompaction && !isNewDoc) {
4172 const result = compactTree(doc);
4173 if (result.length) {
4174 revsToDelete = revsToDelete.concat(result);
4175 }
4176 }
4177
4178 if (revsToDelete.length) {
4179 revsToDelete.forEach(function (rev) { delete doc.revs[rev]; });
4180 }
4181
4182 delete doc.stemmedRevs;
4183
4184 if (!('attachments' in doc)) {
4185 doc.attachments = {};
4186 }
4187
4188 if (theDoc._attachments) {
4189 for (var k in theDoc._attachments) {
4190 var attachment = theDoc._attachments[k];
4191 if (attachment.stub) {
4192 if (!(attachment.digest in doc.attachments)) {
4193 error = createError(MISSING_STUB);
4194 // TODO: Not sure how safe this manual abort is, seeing
4195 // console issues
4196 txn.abort();
4197 return;
4198 }
4199
4200 if (revHasAttachment(doc, writtenRev, attachment.digest)) {
4201 doc.attachments[attachment.digest].revs[writtenRev] = true;
4202 }
4203
4204 } else {
4205
4206 doc.attachments[attachment.digest] = attachment;
4207 doc.attachments[attachment.digest].revs = {};
4208 doc.attachments[attachment.digest].revs[writtenRev] = true;
4209
4210 theDoc._attachments[k] = {
4211 stub: true,
4212 digest: attachment.digest,
4213 content_type: attachment.content_type,
4214 length: attachment.length,
4215 revpos: parseInt(writtenRev, 10)
4216 };
4217 }
4218 }
4219 }
4220
4221 // Local documents have different revision handling
4222 if (isLocal && doc.deleted) {
4223 txn.objectStore(DOC_STORE)["delete"](doc.id).onsuccess = function () {
4224 results[i] = {
4225 ok: true,
4226 id: doc.id,
4227 rev: '0-0'
4228 };
4229 };
4230 updateSeq(i);
4231 return;
4232 }
4233
4234 txn.objectStore(DOC_STORE).put(doc).onsuccess = function () {
4235 results[i] = {
4236 ok: true,
4237 id: doc.id,
4238 rev: writtenRev
4239 };
4240 updateSeq(i);
4241 };
4242 }
4243
4244 function updateSeq(i) {
4245 if (i === lastWriteIndex) {
4246 txn.objectStore(META_STORE).put(metadata);
4247 }
4248 }
4249
4250 function preProcessAttachment(attachment) {
4251 if (attachment.stub) {
4252 return Promise.resolve(attachment);
4253 }
4254
4255 var binData;
4256 if (typeof attachment.data === 'string') {
4257 binData = parseBase64(attachment.data);
4258 if (binData.error) {
4259 return Promise.reject(binData.error);
4260 }
4261 attachment.data = binStringToBluffer(binData, attachment.content_type);
4262 } else {
4263 binData = attachment.data;
4264 }
4265
4266 return new Promise(function (resolve) {
4267 binaryMd5(binData, function (result) {
4268 attachment.digest = 'md5-' + result;
4269 attachment.length = binData.size || binData.length || 0;
4270 resolve(attachment);
4271 });
4272 });
4273 }
4274
4275 function preProcessAttachments() {
4276 var promises = docs.map(function (doc) {
4277 var data = doc.revs[doc.rev].data;
4278 if (!data._attachments) {
4279 return Promise.resolve(data);
4280 }
4281 var attachments = Object.keys(data._attachments).map(function (k) {
4282 data._attachments[k].name = k;
4283 return preProcessAttachment(data._attachments[k]);
4284 });
4285
4286 return Promise.all(attachments).then(function (newAttachments) {
4287 var processed = {};
4288 newAttachments.forEach(function (attachment) {
4289 processed[attachment.name] = attachment;
4290 delete attachment.name;
4291 });
4292 data._attachments = processed;
4293 return data;
4294 });
4295 });
4296 return Promise.all(promises);
4297 }
4298
4299 for (var i = 0, len = req.docs.length; i < len; i++) {
4300 var result;
4301 // TODO: We should get rid of throwing for invalid docs, also not sure
4302 // why this is needed in idb-next and not idb
4303 try {
4304 result = parseDoc(req.docs[i], opts.new_edits, dbOpts);
4305 } catch (err) {
4306 result = err;
4307 }
4308 if (result.error) {
4309 return callback(result);
4310 }
4311
4312 // Ideally parseDoc would return data in this format, but it is currently
4313 // shared so we need to convert
4314 docs.push(convertDocFormat(result));
4315 }
4316
4317 preProcessAttachments().then(function () {
4318 api._openTransactionSafely([DOC_STORE, META_STORE], 'readwrite', function (err, _txn) {
4319 if (err) {
4320 return callback(err);
4321 }
4322
4323 txn = _txn;
4324
4325 txn.onabort = function () {
4326 callback(error || createError(UNKNOWN_ERROR, 'transaction was aborted'));
4327 };
4328 txn.ontimeout = idbError(callback);
4329
4330 txn.oncomplete = function () {
4331 idbChanges.notify(dbOpts.name);
4332 callback(null, results);
4333 };
4334
4335 // We would like to use promises here, but idb sucks
4336 fetchExistingDocs(txn, docs);
4337 });
4338 })["catch"](function (err) {
4339 callback(err);
4340 });
4341}
4342
4343function allDocsKeys(keys, docStore, allDocsInner) {
4344 // It's not guaranted to be returned in right order
4345 var valuesBatch = new Array(keys.length);
4346 var count = 0;
4347 keys.forEach(function (key, index) {
4348 docStore.get(key).onsuccess = function (event) {
4349 if (event.target.result) {
4350 valuesBatch[index] = event.target.result;
4351 } else {
4352 valuesBatch[index] = {key: key, error: 'not_found'};
4353 }
4354 count++;
4355 if (count === keys.length) {
4356 valuesBatch.forEach(function (doc) {
4357 allDocsInner(doc);
4358 });
4359 }
4360 };
4361 });
4362}
4363
4364function createKeyRange(start, end, inclusiveEnd, key, descending) {
4365 try {
4366 if (start && end) {
4367 if (descending) {
4368 return IDBKeyRange.bound(end, start, !inclusiveEnd, false);
4369 } else {
4370 return IDBKeyRange.bound(start, end, false, !inclusiveEnd);
4371 }
4372 } else if (start) {
4373 if (descending) {
4374 return IDBKeyRange.upperBound(start);
4375 } else {
4376 return IDBKeyRange.lowerBound(start);
4377 }
4378 } else if (end) {
4379 if (descending) {
4380 return IDBKeyRange.lowerBound(end, !inclusiveEnd);
4381 } else {
4382 return IDBKeyRange.upperBound(end, !inclusiveEnd);
4383 }
4384 } else if (key) {
4385 return IDBKeyRange.only(key);
4386 }
4387 } catch (e) {
4388 return {error: e};
4389 }
4390 return null;
4391}
4392
4393function handleKeyRangeError(opts, metadata, err, callback) {
4394 if (err.name === "DataError" && err.code === 0) {
4395 // data error, start is less than end
4396 var returnVal = {
4397 total_rows: metadata.doc_count,
4398 offset: opts.skip,
4399 rows: []
4400 };
4401 /* istanbul ignore if */
4402 if (opts.update_seq) {
4403 returnVal.update_seq = metadata.seq;
4404 }
4405 return callback(null, returnVal);
4406 }
4407 callback(createError(IDB_ERROR, err.name, err.message));
4408}
4409
4410function allDocs (txn, metadata, opts, callback) {
4411 if (txn.error) {
4412 return callback(txn.error);
4413 }
4414
4415 // TODO: Weird hack, I dont like it
4416 if (opts.limit === 0) {
4417 var returnVal = {
4418 total_rows: metadata.doc_count,
4419 offset: opts.skip,
4420 rows: []
4421 };
4422
4423 /* istanbul ignore if */
4424 if (opts.update_seq) {
4425 returnVal.update_seq = metadata.seq;
4426 }
4427 return callback(null, returnVal);
4428 }
4429
4430 var results = [];
4431 var processing = [];
4432
4433 var start = 'startkey' in opts ? opts.startkey : false;
4434 var end = 'endkey' in opts ? opts.endkey : false;
4435 var key = 'key' in opts ? opts.key : false;
4436 var keys = 'keys' in opts ? opts.keys : false;
4437 var skip = opts.skip || 0;
4438 var limit = typeof opts.limit === 'number' ? opts.limit : -1;
4439 var inclusiveEnd = opts.inclusive_end !== false;
4440 var descending = 'descending' in opts && opts.descending ? 'prev' : null;
4441
4442 var keyRange;
4443 if (!keys) {
4444 keyRange = createKeyRange(start, end, inclusiveEnd, key, descending);
4445 if (keyRange && keyRange.error) {
4446 return handleKeyRangeError(opts, metadata, keyRange.error, callback);
4447 }
4448 }
4449
4450 var docStore = txn.txn.objectStore(DOC_STORE);
4451
4452 txn.txn.oncomplete = onTxnComplete;
4453
4454 if (keys) {
4455 return allDocsKeys(opts.keys, docStore, allDocsInner);
4456 }
4457
4458 function include_doc(row, doc) {
4459 var docData = doc.revs[doc.rev].data;
4460
4461 row.doc = docData;
4462 row.doc._id = doc.id;
4463 row.doc._rev = doc.rev;
4464 if (opts.conflicts) {
4465 var conflicts = collectConflicts(doc);
4466 if (conflicts.length) {
4467 row.doc._conflicts = conflicts;
4468 }
4469 }
4470 if (opts.attachments && docData._attachments) {
4471 for (var name in docData._attachments) {
4472 processing.push(processAttachment(name, doc, row.doc, opts.binary));
4473 }
4474 }
4475 }
4476
4477 function allDocsInner(doc) {
4478 if (doc.error && keys) {
4479 // key was not found with "keys" requests
4480 results.push(doc);
4481 return true;
4482 }
4483
4484 var row = {
4485 id: doc.id,
4486 key: doc.id,
4487 value: {
4488 rev: doc.rev
4489 }
4490 };
4491
4492 var deleted = doc.deleted;
4493 if (deleted) {
4494 if (keys) {
4495 results.push(row);
4496 row.value.deleted = true;
4497 row.doc = null;
4498 }
4499 } else if (skip-- <= 0) {
4500 results.push(row);
4501 if (opts.include_docs) {
4502 include_doc(row, doc);
4503 }
4504 if (--limit === 0) {
4505 return false;
4506 }
4507 }
4508 return true;
4509 }
4510
4511 function onTxnComplete() {
4512 Promise.all(processing).then(function () {
4513 var returnVal = {
4514 total_rows: metadata.doc_count,
4515 offset: 0,
4516 rows: results
4517 };
4518
4519 /* istanbul ignore if */
4520 if (opts.update_seq) {
4521 returnVal.update_seq = metadata.seq;
4522 }
4523 callback(null, returnVal);
4524 });
4525 }
4526
4527 var cursor = descending ?
4528 docStore.openCursor(keyRange, descending) :
4529 docStore.openCursor(keyRange);
4530
4531 cursor.onsuccess = function (e) {
4532
4533 var doc = e.target.result && e.target.result.value;
4534
4535 // Happens if opts does not have limit,
4536 // because cursor will end normally then,
4537 // when all docs are retrieved.
4538 // Would not be needed, if getAll() optimization was used like in #6059
4539 if (!doc) { return; }
4540
4541 // Skip local docs
4542 if (/^_local/.test(doc.id)) {
4543 return e.target.result["continue"]();
4544 }
4545
4546 var continueCursor = allDocsInner(doc);
4547 if (continueCursor) {
4548 e.target.result["continue"]();
4549 }
4550 };
4551
4552}
4553
4554function changes (txn, idbChanges, api, dbOpts, opts) {
4555 if (txn.error) {
4556 return opts.complete(txn.error);
4557 }
4558
4559 if (opts.continuous) {
4560 var id = dbOpts.name + ':' + uuid$1();
4561 idbChanges.addListener(dbOpts.name, id, api, opts);
4562 idbChanges.notify(dbOpts.name);
4563 return {
4564 cancel: function () {
4565 idbChanges.removeListener(dbOpts.name, id);
4566 }
4567 };
4568 }
4569
4570 var limit = 'limit' in opts ? opts.limit : -1;
4571 if (limit === 0) {
4572 limit = 1;
4573 }
4574
4575 var store = txn.txn.objectStore(DOC_STORE).index('seq');
4576
4577 var filter = filterChange(opts);
4578 var received = 0;
4579
4580 var lastSeq = opts.since || 0;
4581 var results = [];
4582
4583 var processing = [];
4584
4585 function onReqSuccess(e) {
4586 if (!e.target.result) { return; }
4587 var cursor = e.target.result;
4588 var doc = cursor.value;
4589 // Overwrite doc.data, which may have been rewritten (see rewrite.js) with
4590 // the clean version for that rev
4591 doc.data = doc.revs[doc.rev].data;
4592 doc.data._id = doc.id;
4593 doc.data._rev = doc.rev;
4594 if (doc.deleted) {
4595 doc.data._deleted = true;
4596 }
4597
4598 if (opts.doc_ids && opts.doc_ids.indexOf(doc.id) === -1) {
4599 return cursor["continue"]();
4600 }
4601
4602 // WARNING: expecting possible old format
4603 var change = opts.processChange(doc.data, doc, opts);
4604 change.seq = doc.seq;
4605 lastSeq = doc.seq;
4606 var filtered = filter(change);
4607
4608 // If its an error
4609 if (typeof filtered === 'object') {
4610 return opts.complete(filtered);
4611 }
4612
4613 if (filtered) {
4614 received++;
4615 if (opts.return_docs) {
4616 results.push(change);
4617 }
4618
4619 if (opts.include_docs && opts.attachments && doc.data._attachments) {
4620 var promises = [];
4621 for (var name in doc.data._attachments) {
4622 var p = processAttachment(name, doc, change.doc, opts.binary);
4623 // We add the processing promise to 2 arrays, one tracks all
4624 // the promises needed before we fire onChange, the other
4625 // ensure we process all attachments before onComplete
4626 promises.push(p);
4627 processing.push(p);
4628 }
4629
4630 Promise.all(promises).then(function () {
4631 opts.onChange(change);
4632 });
4633 } else {
4634 opts.onChange(change);
4635 }
4636 }
4637 if (received !== limit) {
4638 cursor["continue"]();
4639 }
4640 }
4641
4642 function onTxnComplete() {
4643 Promise.all(processing).then(function () {
4644 opts.complete(null, {
4645 results: results,
4646 last_seq: lastSeq
4647 });
4648 });
4649 }
4650
4651 var req;
4652 if (opts.descending) {
4653 req = store.openCursor(null, 'prev');
4654 } else {
4655 req = store.openCursor(IDBKeyRange.lowerBound(opts.since, true));
4656 }
4657
4658 txn.txn.oncomplete = onTxnComplete;
4659 req.onsuccess = onReqSuccess;
4660}
4661
4662function getRevisionTree (txn, id, callback) {
4663 if (txn.error) {
4664 return callback(txn.error);
4665 }
4666
4667 var req = txn.txn.objectStore(DOC_STORE).get(id);
4668 req.onsuccess = function (e) {
4669 if (!e.target.result) {
4670 callback(createError(MISSING_DOC));
4671 } else {
4672 callback(null, e.target.result.rev_tree);
4673 }
4674 };
4675}
4676
4677function doCompaction (txn, id, revs, callback) {
4678 if (txn.error) {
4679 return callback(txn.error);
4680 }
4681
4682 var docStore = txn.txn.objectStore(DOC_STORE);
4683
4684 docStore.get(id).onsuccess = function (e) {
4685 var doc = e.target.result;
4686
4687 traverseRevTree(doc.rev_tree, function (isLeaf, pos, revHash, ctx, opts) {
4688 var rev = pos + '-' + revHash;
4689 if (revs.indexOf(rev) !== -1) {
4690 opts.status = 'missing';
4691 }
4692 });
4693
4694 var attachments = [];
4695
4696 revs.forEach(function (rev) {
4697 if (rev in doc.revs) {
4698 // Make a list of attachments that are used by the revisions being
4699 // deleted
4700 if (doc.revs[rev].data._attachments) {
4701 for (var k in doc.revs[rev].data._attachments) {
4702 attachments.push(doc.revs[rev].data._attachments[k].digest);
4703 }
4704 }
4705 delete doc.revs[rev];
4706 }
4707 });
4708
4709 // Attachments have a list of revisions that are using them, when
4710 // that list becomes empty we can delete the attachment.
4711 attachments.forEach(function (digest) {
4712 revs.forEach(function (rev) {
4713 delete doc.attachments[digest].revs[rev];
4714 });
4715 if (!Object.keys(doc.attachments[digest].revs).length) {
4716 delete doc.attachments[digest];
4717 }
4718 });
4719
4720 docStore.put(doc);
4721 };
4722
4723 txn.txn.oncomplete = function () {
4724 callback();
4725 };
4726}
4727
4728function destroy (dbOpts, openDatabases, idbChanges, callback) {
4729
4730 idbChanges.removeAllListeners(dbOpts.name);
4731
4732 function doDestroy() {
4733 var req = indexedDB.deleteDatabase(dbOpts.name);
4734 req.onsuccess = function () {
4735 delete openDatabases[dbOpts.name];
4736 callback(null, {ok: true});
4737 };
4738 }
4739
4740 // If the database is open we need to close it
4741 if (dbOpts.name in openDatabases) {
4742 openDatabases[dbOpts.name].then(function (res) {
4743 res.idb.close();
4744 doDestroy();
4745 });
4746 } else {
4747 doDestroy();
4748 }
4749
4750}
4751
4752// Adapted from
4753// https://github.com/pouchdb/pouchdb/blob/master/packages/node_modules/pouchdb-find/src/adapters/local/find/query-planner.js#L20-L24
4754// This could change / improve in the future?
4755var COUCH_COLLATE_LO = null;
4756var COUCH_COLLATE_HI = '\uffff'; // actually used as {"\uffff": {}}
4757
4758// Adapted from: https://www.w3.org/TR/IndexedDB/#compare-two-keys
4759// Importantly, *there is no upper bound possible* in idb. The ideal data
4760// structure an infintely deep array:
4761// var IDB_COLLATE_HI = []; IDB_COLLATE_HI.push(IDB_COLLATE_HI)
4762// But IDBKeyRange is not a fan of shenanigans, so I've just gone with 12 layers
4763// because it looks nice and surely that's enough!
4764var IDB_COLLATE_LO = Number.NEGATIVE_INFINITY;
4765var IDB_COLLATE_HI = [[[[[[[[[[[[]]]]]]]]]]]];
4766
4767//
4768// TODO: this should be made offical somewhere and used by AllDocs / get /
4769// changes etc as well.
4770//
4771function externaliseRecord(idbDoc) {
4772 var doc = idbDoc.revs[idbDoc.rev].data;
4773 doc._id = idbDoc.id;
4774 doc._rev = idbDoc.rev;
4775 if (idbDoc.deleted) {
4776 doc._deleted = true;
4777 }
4778
4779 return doc;
4780}
4781
4782/**
4783 * Generates a keyrange based on the opts passed to query
4784 *
4785 * The first key is always 0, as that's how we're filtering out deleted entries.
4786 */
4787function generateKeyRange(opts) {
4788 function defined(obj, k) {
4789 return obj[k] !== void 0;
4790 }
4791
4792 // Converts a valid CouchDB key into a valid IndexedDB one
4793 function convert(key, exact) {
4794 // The first item in every native index is doc.deleted, and we always want
4795 // to only search documents that are not deleted.
4796 // "foo" -> [0, "foo"]
4797 var filterDeleted = [0].concat(key);
4798
4799 return filterDeleted.map(function (k) {
4800 // null, true and false are not indexable by indexeddb. When we write
4801 // these values we convert them to these constants, and so when we
4802 // query for them we need to convert the query also.
4803 if (k === null && exact) {
4804 // for non-exact queries we treat null as a collate property
4805 // see `if (!exact)` block below
4806 return IDB_NULL;
4807 } else if (k === true) {
4808 return IDB_TRUE;
4809 } else if (k === false) {
4810 return IDB_FALSE;
4811 }
4812
4813 if (!exact) {
4814 // We get passed CouchDB's collate low and high values, so for non-exact
4815 // ranged queries we're going to convert them to our IDB equivalents
4816 if (k === COUCH_COLLATE_LO) {
4817 return IDB_COLLATE_LO;
4818 } else if (Object.prototype.hasOwnProperty.call(k, COUCH_COLLATE_HI)) {
4819 return IDB_COLLATE_HI;
4820 }
4821 }
4822
4823 return k;
4824 });
4825 }
4826
4827 // CouchDB and so PouchdB defaults to true. We need to make this explicit as
4828 // we invert these later for IndexedDB.
4829 if (!defined(opts, 'inclusive_end')) {
4830 opts.inclusive_end = true;
4831 }
4832 if (!defined(opts, 'inclusive_start')) {
4833 opts.inclusive_start = true;
4834 }
4835
4836 if (opts.descending) {
4837 // Flip before generating. We'll check descending again later when performing
4838 // an index request
4839 var realEndkey = opts.startkey,
4840 realInclusiveEnd = opts.inclusive_start;
4841
4842 opts.startkey = opts.endkey;
4843 opts.endkey = realEndkey;
4844 opts.inclusive_start = opts.inclusive_end;
4845 opts.inclusive_end = realInclusiveEnd;
4846 }
4847
4848 try {
4849 if (defined(opts, 'key')) {
4850 return IDBKeyRange.only(convert(opts.key, true));
4851 }
4852
4853 if (defined(opts, 'startkey') && !defined(opts, 'endkey')) {
4854 return IDBKeyRange.lowerBound(convert(opts.startkey), !opts.inclusive_start);
4855 }
4856
4857 if (!defined(opts, 'startkey') && defined(opts, 'endkey')) {
4858 return IDBKeyRange.upperBound(convert(opts.endkey), !opts.inclusive_end);
4859 }
4860
4861 if (defined(opts, 'startkey') && defined(opts, 'endkey')) {
4862 return IDBKeyRange.bound(
4863 convert(opts.startkey), convert(opts.endkey),
4864 !opts.inclusive_start, !opts.inclusive_end
4865 );
4866 }
4867
4868 return IDBKeyRange.only([0]);
4869 } catch (err) {
4870 console.error('Could not generate keyRange', err, opts);
4871 throw Error('Could not generate key range with ' + JSON.stringify(opts));
4872 }
4873}
4874
4875function getIndexHandle(pdb, fields, reject) {
4876 var indexName = naturalIndexName(fields);
4877
4878 return new Promise(function (resolve) {
4879 pdb._openTransactionSafely([DOC_STORE], 'readonly', function (err, txn) {
4880 if (err) {
4881 return idbError(reject)(err);
4882 }
4883
4884 txn.onabort = idbError(reject);
4885 txn.ontimeout = idbError(reject);
4886
4887 var existingIndexNames = Array.from(txn.objectStore(DOC_STORE).indexNames);
4888
4889 if (existingIndexNames.indexOf(indexName) === -1) {
4890 // The index is missing, force a db restart and try again
4891 pdb._freshen()
4892 .then(function () { return getIndexHandle(pdb, fields, reject); })
4893 .then(resolve);
4894 } else {
4895 resolve(txn.objectStore(DOC_STORE).index(indexName));
4896 }
4897 });
4898 });
4899}
4900
4901// In theory we should return something like the doc example below, but find
4902// only needs rows: [{doc: {...}}], so I think we can just not bother for now
4903// {
4904// "offset" : 0,
4905// "rows": [{
4906// "id": "doc3",
4907// "key": "Lisa Says",
4908// "value": null,
4909// "doc": {
4910// "_id": "doc3",
4911// "_rev": "1-z",
4912// "title": "Lisa Says"
4913// }
4914// }],
4915// "total_rows" : 4
4916// }
4917function query(idb, signature, opts) {
4918 // At this stage, in the current implementation, find has already gone through
4919 // and determined if the index already exists from PouchDB's perspective (eg
4920 // there is a design doc for it).
4921 //
4922 // If we find that the index doesn't exist this means we have to close and
4923 // re-open the DB to correct indexes before proceeding, at which point the
4924 // index should exist.
4925
4926 var pdb = this;
4927
4928 // Assumption, there will be only one /, between the design document name
4929 // and the view name.
4930 var parts = signature.split('/');
4931
4932 return new Promise(function (resolve, reject) {
4933 pdb.get('_design/' + parts[0]).then(function (ddoc) {
4934 var fields = rawIndexFields(ddoc, parts[1]);
4935 if (!fields) {
4936 throw new Error('ddoc ' + ddoc._id +' with view ' + parts[1] +
4937 ' does not have map.options.def.fields defined.');
4938 }
4939
4940 var skip = opts.skip;
4941 var limit = Number.isInteger(opts.limit) && opts.limit;
4942
4943 return getIndexHandle(pdb, fields, reject)
4944 .then(function (indexHandle) {
4945 var keyRange = generateKeyRange(opts);
4946 var req = indexHandle.openCursor(keyRange, opts.descending ? 'prev' : 'next');
4947
4948 var rows = [];
4949 req.onerror = idbError(reject);
4950 req.onsuccess = function (e) {
4951 var cursor = e.target.result;
4952
4953 if (!cursor || limit === 0) {
4954 return resolve({
4955 rows: rows
4956 });
4957 }
4958
4959 if (skip) {
4960 cursor.advance(skip);
4961 skip = false;
4962 return;
4963 }
4964
4965 if (limit) {
4966 limit = limit - 1;
4967 }
4968
4969 rows.push({doc: externaliseRecord(cursor.value)});
4970 cursor["continue"]();
4971 };
4972 });
4973 })[
4974 "catch"](reject);
4975 });
4976
4977}
4978
4979function viewCleanup() {
4980 // I'm not sure we have to do anything here.
4981 //
4982 // One option is to just close and re-open the DB, which performs the same
4983 // action. The only reason you'd want to call this is if you deleted a bunch
4984 // of indexes and wanted the space back immediately.
4985 //
4986 // Otherwise index cleanup happens when:
4987 // - A DB is opened
4988 // - A find query is performed against an index that doesn't exist but should
4989
4990 return Promise.resolve();
4991}
4992
4993var ADAPTER_NAME = 'indexeddb';
4994
4995// TODO: Constructor should be capitalised
4996var idbChanges = new Changes();
4997
4998// A shared list of database handles
4999var openDatabases = {};
5000
5001function IdbPouch(dbOpts, callback) {
5002
5003 if (dbOpts.view_adapter) {
5004 console.log('Please note that the indexeddb adapter manages _find indexes itself, therefore it is not using your specified view_adapter');
5005 }
5006
5007 var api = this;
5008 var metadata = {};
5009
5010 // Wrapper that gives you an active DB handle. You probably want $t.
5011 var $ = function (fun) {
5012 return function () {
5013 var args = Array.prototype.slice.call(arguments);
5014 setup(openDatabases, api, dbOpts).then(function (res) {
5015 metadata = res.metadata;
5016 args.unshift(res.idb);
5017 fun.apply(api, args);
5018 })["catch"](function (err) {
5019 var last = args.pop();
5020 if (typeof last === 'function') {
5021 last(err);
5022 } else {
5023 console.error(err);
5024 }
5025 });
5026 };
5027 };
5028 // the promise version of $
5029 var $p = function (fun) {
5030 return function () {
5031 var args = Array.prototype.slice.call(arguments);
5032
5033 return setup(openDatabases, api, dbOpts).then(function (res) {
5034 metadata = res.metadata;
5035 args.unshift(res.idb);
5036
5037 return fun.apply(api, args);
5038 });
5039 };
5040 };
5041 // Wrapper that gives you a safe transaction handle. It's important to use
5042 // this instead of opening your own transaction from a db handle got from $,
5043 // because in the time between getting the db handle and opening the
5044 // transaction it may have been invalidated by index changes.
5045 var $t = function (fun, stores, mode) {
5046 stores = stores || [DOC_STORE];
5047 mode = mode || 'readonly';
5048
5049 return function () {
5050 var args = Array.prototype.slice.call(arguments);
5051 var txn = {};
5052 setup(openDatabases, api, dbOpts).then(function (res) {
5053 metadata = res.metadata;
5054 txn.txn = res.idb.transaction(stores, mode);
5055 })["catch"](function (err) {
5056 console.error('Failed to establish transaction safely');
5057 console.error(err);
5058 txn.error = err;
5059 }).then(function () {
5060 args.unshift(txn);
5061 fun.apply(api, args);
5062 });
5063 };
5064 };
5065
5066 api._openTransactionSafely = function (stores, mode, callback) {
5067 $t(function (txn, callback) {
5068 callback(txn.error, txn.txn);
5069 }, stores, mode)(callback);
5070 };
5071
5072 api._remote = false;
5073 api.type = function () { return ADAPTER_NAME; };
5074
5075 api._id = $(function (_, cb) {
5076 cb(null, metadata.db_uuid);
5077 });
5078
5079 api._info = $(function (_, cb) {
5080 return info(metadata, cb);
5081 });
5082
5083 api._get = $t(get);
5084
5085 api._bulkDocs = $(function (_, req, opts, callback) {
5086 bulkDocs(api, req, opts, metadata, dbOpts, idbChanges, callback);
5087 });
5088
5089 api._allDocs = $t(function (txn, opts, cb) {
5090 allDocs(txn, metadata, opts, cb);
5091 });
5092
5093 api._getAttachment = $t(getAttachment);
5094
5095 api._changes = $t(function (txn, opts) {
5096 changes(txn, idbChanges, api, dbOpts, opts);
5097 });
5098
5099 api._getRevisionTree = $t(getRevisionTree);
5100 api._doCompaction = $t(doCompaction, [DOC_STORE], 'readwrite');
5101
5102 api._customFindAbstractMapper = {
5103 query: $p(query),
5104 viewCleanup: $p(viewCleanup)
5105 };
5106
5107 api._destroy = function (opts, callback) {
5108 return destroy(dbOpts, openDatabases, idbChanges, callback);
5109 };
5110
5111 api._close = $(function (db, cb) {
5112 delete openDatabases[dbOpts.name];
5113 db.close();
5114 cb();
5115 });
5116
5117 // Closing and re-opening the DB re-generates native indexes
5118 api._freshen = function () {
5119 return new Promise(function (resolve) {
5120 api._close(function () {
5121 $(resolve)();
5122 });
5123 });
5124 };
5125
5126 // TODO: this setTimeout seems nasty, if its needed lets
5127 // figure out / explain why
5128 setTimeout(function () {
5129 callback(null, api);
5130 });
5131}
5132
5133// TODO: this isnt really valid permanently, just being lazy to start
5134IdbPouch.valid = function () {
5135 return true;
5136};
5137
5138function IndexeddbPouchPlugin (PouchDB) {
5139 PouchDB.adapter(ADAPTER_NAME, IdbPouch, true);
5140}
5141
5142// this code only runs in the browser, as its own dist/ script
5143
5144if (typeof PouchDB === 'undefined') {
5145 guardedConsole('error', 'indexeddb adapter plugin error: ' +
5146 'Cannot find global "PouchDB" object! ' +
5147 'Did you remember to include pouchdb.js?');
5148} else {
5149 PouchDB.plugin(IndexeddbPouchPlugin);
5150}
5151
5152},{"1":1,"10":10,"11":11,"12":12,"3":3,"4":4}]},{},[27]);
5153
\No newline at end of file