Просмотр исходного кода

Optimized cache algorithm in AirMusic

TC pushbot 5 2 лет назад
Родитель
Сommit
4eb500092b
6 измененных файлов с 5371 добавлено и 190 удалено
  1. 5192 0
      web/Music/dexie.js
  2. 1 0
      web/Music/img/delete.svg
  3. BIN
      web/Music/img/nothumb.png
  4. BIN
      web/Music/img/nothumb.psd
  5. 168 182
      web/Music/index.html
  6. 10 8
      web/Music/main.css

+ 5192 - 0
web/Music/dexie.js

@@ -0,0 +1,5192 @@
+/*
+ * Dexie.js - a minimalistic wrapper for IndexedDB
+ * ===============================================
+ *
+ * By David Fahlander, [email protected]
+ *
+ * Version 3.2.3, Mon Jan 23 2023
+ *
+ * https://dexie.org
+ *
+ * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/
+ */
+ 
+(function (global, factory) {
+    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+    typeof define === 'function' && define.amd ? define(factory) :
+    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Dexie = factory());
+})(this, (function () { 'use strict';
+
+    /*! *****************************************************************************
+    Copyright (c) Microsoft Corporation.
+    Permission to use, copy, modify, and/or distribute this software for any
+    purpose with or without fee is hereby granted.
+    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+    PERFORMANCE OF THIS SOFTWARE.
+    ***************************************************************************** */
+    var __assign = function() {
+        __assign = Object.assign || function __assign(t) {
+            for (var s, i = 1, n = arguments.length; i < n; i++) {
+                s = arguments[i];
+                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
+            }
+            return t;
+        };
+        return __assign.apply(this, arguments);
+    };
+    function __spreadArray(to, from, pack) {
+        if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
+            if (ar || !(i in from)) {
+                if (!ar) ar = Array.prototype.slice.call(from, 0, i);
+                ar[i] = from[i];
+            }
+        }
+        return to.concat(ar || Array.prototype.slice.call(from));
+    }
+
+    var _global = typeof globalThis !== 'undefined' ? globalThis :
+        typeof self !== 'undefined' ? self :
+            typeof window !== 'undefined' ? window :
+                global;
+
+    var keys = Object.keys;
+    var isArray = Array.isArray;
+    if (typeof Promise !== 'undefined' && !_global.Promise) {
+        _global.Promise = Promise;
+    }
+    function extend(obj, extension) {
+        if (typeof extension !== 'object')
+            return obj;
+        keys(extension).forEach(function (key) {
+            obj[key] = extension[key];
+        });
+        return obj;
+    }
+    var getProto = Object.getPrototypeOf;
+    var _hasOwn = {}.hasOwnProperty;
+    function hasOwn(obj, prop) {
+        return _hasOwn.call(obj, prop);
+    }
+    function props(proto, extension) {
+        if (typeof extension === 'function')
+            extension = extension(getProto(proto));
+        (typeof Reflect === "undefined" ? keys : Reflect.ownKeys)(extension).forEach(function (key) {
+            setProp(proto, key, extension[key]);
+        });
+    }
+    var defineProperty = Object.defineProperty;
+    function setProp(obj, prop, functionOrGetSet, options) {
+        defineProperty(obj, prop, extend(functionOrGetSet && hasOwn(functionOrGetSet, "get") && typeof functionOrGetSet.get === 'function' ?
+            { get: functionOrGetSet.get, set: functionOrGetSet.set, configurable: true } :
+            { value: functionOrGetSet, configurable: true, writable: true }, options));
+    }
+    function derive(Child) {
+        return {
+            from: function (Parent) {
+                Child.prototype = Object.create(Parent.prototype);
+                setProp(Child.prototype, "constructor", Child);
+                return {
+                    extend: props.bind(null, Child.prototype)
+                };
+            }
+        };
+    }
+    var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+    function getPropertyDescriptor(obj, prop) {
+        var pd = getOwnPropertyDescriptor(obj, prop);
+        var proto;
+        return pd || (proto = getProto(obj)) && getPropertyDescriptor(proto, prop);
+    }
+    var _slice = [].slice;
+    function slice(args, start, end) {
+        return _slice.call(args, start, end);
+    }
+    function override(origFunc, overridedFactory) {
+        return overridedFactory(origFunc);
+    }
+    function assert(b) {
+        if (!b)
+            throw new Error("Assertion Failed");
+    }
+    function asap$1(fn) {
+        if (_global.setImmediate)
+            setImmediate(fn);
+        else
+            setTimeout(fn, 0);
+    }
+    function arrayToObject(array, extractor) {
+        return array.reduce(function (result, item, i) {
+            var nameAndValue = extractor(item, i);
+            if (nameAndValue)
+                result[nameAndValue[0]] = nameAndValue[1];
+            return result;
+        }, {});
+    }
+    function tryCatch(fn, onerror, args) {
+        try {
+            fn.apply(null, args);
+        }
+        catch (ex) {
+            onerror && onerror(ex);
+        }
+    }
+    function getByKeyPath(obj, keyPath) {
+        if (hasOwn(obj, keyPath))
+            return obj[keyPath];
+        if (!keyPath)
+            return obj;
+        if (typeof keyPath !== 'string') {
+            var rv = [];
+            for (var i = 0, l = keyPath.length; i < l; ++i) {
+                var val = getByKeyPath(obj, keyPath[i]);
+                rv.push(val);
+            }
+            return rv;
+        }
+        var period = keyPath.indexOf('.');
+        if (period !== -1) {
+            var innerObj = obj[keyPath.substr(0, period)];
+            return innerObj === undefined ? undefined : getByKeyPath(innerObj, keyPath.substr(period + 1));
+        }
+        return undefined;
+    }
+    function setByKeyPath(obj, keyPath, value) {
+        if (!obj || keyPath === undefined)
+            return;
+        if ('isFrozen' in Object && Object.isFrozen(obj))
+            return;
+        if (typeof keyPath !== 'string' && 'length' in keyPath) {
+            assert(typeof value !== 'string' && 'length' in value);
+            for (var i = 0, l = keyPath.length; i < l; ++i) {
+                setByKeyPath(obj, keyPath[i], value[i]);
+            }
+        }
+        else {
+            var period = keyPath.indexOf('.');
+            if (period !== -1) {
+                var currentKeyPath = keyPath.substr(0, period);
+                var remainingKeyPath = keyPath.substr(period + 1);
+                if (remainingKeyPath === "")
+                    if (value === undefined) {
+                        if (isArray(obj) && !isNaN(parseInt(currentKeyPath)))
+                            obj.splice(currentKeyPath, 1);
+                        else
+                            delete obj[currentKeyPath];
+                    }
+                    else
+                        obj[currentKeyPath] = value;
+                else {
+                    var innerObj = obj[currentKeyPath];
+                    if (!innerObj || !hasOwn(obj, currentKeyPath))
+                        innerObj = (obj[currentKeyPath] = {});
+                    setByKeyPath(innerObj, remainingKeyPath, value);
+                }
+            }
+            else {
+                if (value === undefined) {
+                    if (isArray(obj) && !isNaN(parseInt(keyPath)))
+                        obj.splice(keyPath, 1);
+                    else
+                        delete obj[keyPath];
+                }
+                else
+                    obj[keyPath] = value;
+            }
+        }
+    }
+    function delByKeyPath(obj, keyPath) {
+        if (typeof keyPath === 'string')
+            setByKeyPath(obj, keyPath, undefined);
+        else if ('length' in keyPath)
+            [].map.call(keyPath, function (kp) {
+                setByKeyPath(obj, kp, undefined);
+            });
+    }
+    function shallowClone(obj) {
+        var rv = {};
+        for (var m in obj) {
+            if (hasOwn(obj, m))
+                rv[m] = obj[m];
+        }
+        return rv;
+    }
+    var concat = [].concat;
+    function flatten(a) {
+        return concat.apply([], a);
+    }
+    var intrinsicTypeNames = "Boolean,String,Date,RegExp,Blob,File,FileList,FileSystemFileHandle,ArrayBuffer,DataView,Uint8ClampedArray,ImageBitmap,ImageData,Map,Set,CryptoKey"
+        .split(',').concat(flatten([8, 16, 32, 64].map(function (num) { return ["Int", "Uint", "Float"].map(function (t) { return t + num + "Array"; }); }))).filter(function (t) { return _global[t]; });
+    var intrinsicTypes = intrinsicTypeNames.map(function (t) { return _global[t]; });
+    arrayToObject(intrinsicTypeNames, function (x) { return [x, true]; });
+    var circularRefs = null;
+    function deepClone(any) {
+        circularRefs = typeof WeakMap !== 'undefined' && new WeakMap();
+        var rv = innerDeepClone(any);
+        circularRefs = null;
+        return rv;
+    }
+    function innerDeepClone(any) {
+        if (!any || typeof any !== 'object')
+            return any;
+        var rv = circularRefs && circularRefs.get(any);
+        if (rv)
+            return rv;
+        if (isArray(any)) {
+            rv = [];
+            circularRefs && circularRefs.set(any, rv);
+            for (var i = 0, l = any.length; i < l; ++i) {
+                rv.push(innerDeepClone(any[i]));
+            }
+        }
+        else if (intrinsicTypes.indexOf(any.constructor) >= 0) {
+            rv = any;
+        }
+        else {
+            var proto = getProto(any);
+            rv = proto === Object.prototype ? {} : Object.create(proto);
+            circularRefs && circularRefs.set(any, rv);
+            for (var prop in any) {
+                if (hasOwn(any, prop)) {
+                    rv[prop] = innerDeepClone(any[prop]);
+                }
+            }
+        }
+        return rv;
+    }
+    var toString = {}.toString;
+    function toStringTag(o) {
+        return toString.call(o).slice(8, -1);
+    }
+    var iteratorSymbol = typeof Symbol !== 'undefined' ?
+        Symbol.iterator :
+        '@@iterator';
+    var getIteratorOf = typeof iteratorSymbol === "symbol" ? function (x) {
+        var i;
+        return x != null && (i = x[iteratorSymbol]) && i.apply(x);
+    } : function () { return null; };
+    var NO_CHAR_ARRAY = {};
+    function getArrayOf(arrayLike) {
+        var i, a, x, it;
+        if (arguments.length === 1) {
+            if (isArray(arrayLike))
+                return arrayLike.slice();
+            if (this === NO_CHAR_ARRAY && typeof arrayLike === 'string')
+                return [arrayLike];
+            if ((it = getIteratorOf(arrayLike))) {
+                a = [];
+                while ((x = it.next()), !x.done)
+                    a.push(x.value);
+                return a;
+            }
+            if (arrayLike == null)
+                return [arrayLike];
+            i = arrayLike.length;
+            if (typeof i === 'number') {
+                a = new Array(i);
+                while (i--)
+                    a[i] = arrayLike[i];
+                return a;
+            }
+            return [arrayLike];
+        }
+        i = arguments.length;
+        a = new Array(i);
+        while (i--)
+            a[i] = arguments[i];
+        return a;
+    }
+    var isAsyncFunction = typeof Symbol !== 'undefined'
+        ? function (fn) { return fn[Symbol.toStringTag] === 'AsyncFunction'; }
+        : function () { return false; };
+
+    var debug = typeof location !== 'undefined' &&
+        /^(http|https):\/\/(localhost|127\.0\.0\.1)/.test(location.href);
+    function setDebug(value, filter) {
+        debug = value;
+        libraryFilter = filter;
+    }
+    var libraryFilter = function () { return true; };
+    var NEEDS_THROW_FOR_STACK = !new Error("").stack;
+    function getErrorWithStack() {
+        if (NEEDS_THROW_FOR_STACK)
+            try {
+                getErrorWithStack.arguments;
+                throw new Error();
+            }
+            catch (e) {
+                return e;
+            }
+        return new Error();
+    }
+    function prettyStack(exception, numIgnoredFrames) {
+        var stack = exception.stack;
+        if (!stack)
+            return "";
+        numIgnoredFrames = (numIgnoredFrames || 0);
+        if (stack.indexOf(exception.name) === 0)
+            numIgnoredFrames += (exception.name + exception.message).split('\n').length;
+        return stack.split('\n')
+            .slice(numIgnoredFrames)
+            .filter(libraryFilter)
+            .map(function (frame) { return "\n" + frame; })
+            .join('');
+    }
+
+    var dexieErrorNames = [
+        'Modify',
+        'Bulk',
+        'OpenFailed',
+        'VersionChange',
+        'Schema',
+        'Upgrade',
+        'InvalidTable',
+        'MissingAPI',
+        'NoSuchDatabase',
+        'InvalidArgument',
+        'SubTransaction',
+        'Unsupported',
+        'Internal',
+        'DatabaseClosed',
+        'PrematureCommit',
+        'ForeignAwait'
+    ];
+    var idbDomErrorNames = [
+        'Unknown',
+        'Constraint',
+        'Data',
+        'TransactionInactive',
+        'ReadOnly',
+        'Version',
+        'NotFound',
+        'InvalidState',
+        'InvalidAccess',
+        'Abort',
+        'Timeout',
+        'QuotaExceeded',
+        'Syntax',
+        'DataClone'
+    ];
+    var errorList = dexieErrorNames.concat(idbDomErrorNames);
+    var defaultTexts = {
+        VersionChanged: "Database version changed by other database connection",
+        DatabaseClosed: "Database has been closed",
+        Abort: "Transaction aborted",
+        TransactionInactive: "Transaction has already completed or failed",
+        MissingAPI: "IndexedDB API missing. Please visit https://tinyurl.com/y2uuvskb"
+    };
+    function DexieError(name, msg) {
+        this._e = getErrorWithStack();
+        this.name = name;
+        this.message = msg;
+    }
+    derive(DexieError).from(Error).extend({
+        stack: {
+            get: function () {
+                return this._stack ||
+                    (this._stack = this.name + ": " + this.message + prettyStack(this._e, 2));
+            }
+        },
+        toString: function () { return this.name + ": " + this.message; }
+    });
+    function getMultiErrorMessage(msg, failures) {
+        return msg + ". Errors: " + Object.keys(failures)
+            .map(function (key) { return failures[key].toString(); })
+            .filter(function (v, i, s) { return s.indexOf(v) === i; })
+            .join('\n');
+    }
+    function ModifyError(msg, failures, successCount, failedKeys) {
+        this._e = getErrorWithStack();
+        this.failures = failures;
+        this.failedKeys = failedKeys;
+        this.successCount = successCount;
+        this.message = getMultiErrorMessage(msg, failures);
+    }
+    derive(ModifyError).from(DexieError);
+    function BulkError(msg, failures) {
+        this._e = getErrorWithStack();
+        this.name = "BulkError";
+        this.failures = Object.keys(failures).map(function (pos) { return failures[pos]; });
+        this.failuresByPos = failures;
+        this.message = getMultiErrorMessage(msg, failures);
+    }
+    derive(BulkError).from(DexieError);
+    var errnames = errorList.reduce(function (obj, name) { return (obj[name] = name + "Error", obj); }, {});
+    var BaseException = DexieError;
+    var exceptions = errorList.reduce(function (obj, name) {
+        var fullName = name + "Error";
+        function DexieError(msgOrInner, inner) {
+            this._e = getErrorWithStack();
+            this.name = fullName;
+            if (!msgOrInner) {
+                this.message = defaultTexts[name] || fullName;
+                this.inner = null;
+            }
+            else if (typeof msgOrInner === 'string') {
+                this.message = "" + msgOrInner + (!inner ? '' : '\n ' + inner);
+                this.inner = inner || null;
+            }
+            else if (typeof msgOrInner === 'object') {
+                this.message = msgOrInner.name + " " + msgOrInner.message;
+                this.inner = msgOrInner;
+            }
+        }
+        derive(DexieError).from(BaseException);
+        obj[name] = DexieError;
+        return obj;
+    }, {});
+    exceptions.Syntax = SyntaxError;
+    exceptions.Type = TypeError;
+    exceptions.Range = RangeError;
+    var exceptionMap = idbDomErrorNames.reduce(function (obj, name) {
+        obj[name + "Error"] = exceptions[name];
+        return obj;
+    }, {});
+    function mapError(domError, message) {
+        if (!domError || domError instanceof DexieError || domError instanceof TypeError || domError instanceof SyntaxError || !domError.name || !exceptionMap[domError.name])
+            return domError;
+        var rv = new exceptionMap[domError.name](message || domError.message, domError);
+        if ("stack" in domError) {
+            setProp(rv, "stack", { get: function () {
+                    return this.inner.stack;
+                } });
+        }
+        return rv;
+    }
+    var fullNameExceptions = errorList.reduce(function (obj, name) {
+        if (["Syntax", "Type", "Range"].indexOf(name) === -1)
+            obj[name + "Error"] = exceptions[name];
+        return obj;
+    }, {});
+    fullNameExceptions.ModifyError = ModifyError;
+    fullNameExceptions.DexieError = DexieError;
+    fullNameExceptions.BulkError = BulkError;
+
+    function nop() { }
+    function mirror(val) { return val; }
+    function pureFunctionChain(f1, f2) {
+        if (f1 == null || f1 === mirror)
+            return f2;
+        return function (val) {
+            return f2(f1(val));
+        };
+    }
+    function callBoth(on1, on2) {
+        return function () {
+            on1.apply(this, arguments);
+            on2.apply(this, arguments);
+        };
+    }
+    function hookCreatingChain(f1, f2) {
+        if (f1 === nop)
+            return f2;
+        return function () {
+            var res = f1.apply(this, arguments);
+            if (res !== undefined)
+                arguments[0] = res;
+            var onsuccess = this.onsuccess,
+            onerror = this.onerror;
+            this.onsuccess = null;
+            this.onerror = null;
+            var res2 = f2.apply(this, arguments);
+            if (onsuccess)
+                this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
+            if (onerror)
+                this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
+            return res2 !== undefined ? res2 : res;
+        };
+    }
+    function hookDeletingChain(f1, f2) {
+        if (f1 === nop)
+            return f2;
+        return function () {
+            f1.apply(this, arguments);
+            var onsuccess = this.onsuccess,
+            onerror = this.onerror;
+            this.onsuccess = this.onerror = null;
+            f2.apply(this, arguments);
+            if (onsuccess)
+                this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
+            if (onerror)
+                this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
+        };
+    }
+    function hookUpdatingChain(f1, f2) {
+        if (f1 === nop)
+            return f2;
+        return function (modifications) {
+            var res = f1.apply(this, arguments);
+            extend(modifications, res);
+            var onsuccess = this.onsuccess,
+            onerror = this.onerror;
+            this.onsuccess = null;
+            this.onerror = null;
+            var res2 = f2.apply(this, arguments);
+            if (onsuccess)
+                this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
+            if (onerror)
+                this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
+            return res === undefined ?
+                (res2 === undefined ? undefined : res2) :
+                (extend(res, res2));
+        };
+    }
+    function reverseStoppableEventChain(f1, f2) {
+        if (f1 === nop)
+            return f2;
+        return function () {
+            if (f2.apply(this, arguments) === false)
+                return false;
+            return f1.apply(this, arguments);
+        };
+    }
+    function promisableChain(f1, f2) {
+        if (f1 === nop)
+            return f2;
+        return function () {
+            var res = f1.apply(this, arguments);
+            if (res && typeof res.then === 'function') {
+                var thiz = this, i = arguments.length, args = new Array(i);
+                while (i--)
+                    args[i] = arguments[i];
+                return res.then(function () {
+                    return f2.apply(thiz, args);
+                });
+            }
+            return f2.apply(this, arguments);
+        };
+    }
+
+    var INTERNAL = {};
+    var LONG_STACKS_CLIP_LIMIT = 100,
+    MAX_LONG_STACKS = 20, ZONE_ECHO_LIMIT = 100, _a$1 = typeof Promise === 'undefined' ?
+        [] :
+        (function () {
+            var globalP = Promise.resolve();
+            if (typeof crypto === 'undefined' || !crypto.subtle)
+                return [globalP, getProto(globalP), globalP];
+            var nativeP = crypto.subtle.digest("SHA-512", new Uint8Array([0]));
+            return [
+                nativeP,
+                getProto(nativeP),
+                globalP
+            ];
+        })(), resolvedNativePromise = _a$1[0], nativePromiseProto = _a$1[1], resolvedGlobalPromise = _a$1[2], nativePromiseThen = nativePromiseProto && nativePromiseProto.then;
+    var NativePromise = resolvedNativePromise && resolvedNativePromise.constructor;
+    var patchGlobalPromise = !!resolvedGlobalPromise;
+    var stack_being_generated = false;
+    var schedulePhysicalTick = resolvedGlobalPromise ?
+        function () { resolvedGlobalPromise.then(physicalTick); }
+        :
+            _global.setImmediate ?
+                setImmediate.bind(null, physicalTick) :
+                _global.MutationObserver ?
+                    function () {
+                        var hiddenDiv = document.createElement("div");
+                        (new MutationObserver(function () {
+                            physicalTick();
+                            hiddenDiv = null;
+                        })).observe(hiddenDiv, { attributes: true });
+                        hiddenDiv.setAttribute('i', '1');
+                    } :
+                    function () { setTimeout(physicalTick, 0); };
+    var asap = function (callback, args) {
+        microtickQueue.push([callback, args]);
+        if (needsNewPhysicalTick) {
+            schedulePhysicalTick();
+            needsNewPhysicalTick = false;
+        }
+    };
+    var isOutsideMicroTick = true,
+    needsNewPhysicalTick = true,
+    unhandledErrors = [],
+    rejectingErrors = [],
+    currentFulfiller = null, rejectionMapper = mirror;
+    var globalPSD = {
+        id: 'global',
+        global: true,
+        ref: 0,
+        unhandleds: [],
+        onunhandled: globalError,
+        pgp: false,
+        env: {},
+        finalize: function () {
+            this.unhandleds.forEach(function (uh) {
+                try {
+                    globalError(uh[0], uh[1]);
+                }
+                catch (e) { }
+            });
+        }
+    };
+    var PSD = globalPSD;
+    var microtickQueue = [];
+    var numScheduledCalls = 0;
+    var tickFinalizers = [];
+    function DexiePromise(fn) {
+        if (typeof this !== 'object')
+            throw new TypeError('Promises must be constructed via new');
+        this._listeners = [];
+        this.onuncatched = nop;
+        this._lib = false;
+        var psd = (this._PSD = PSD);
+        if (debug) {
+            this._stackHolder = getErrorWithStack();
+            this._prev = null;
+            this._numPrev = 0;
+        }
+        if (typeof fn !== 'function') {
+            if (fn !== INTERNAL)
+                throw new TypeError('Not a function');
+            this._state = arguments[1];
+            this._value = arguments[2];
+            if (this._state === false)
+                handleRejection(this, this._value);
+            return;
+        }
+        this._state = null;
+        this._value = null;
+        ++psd.ref;
+        executePromiseTask(this, fn);
+    }
+    var thenProp = {
+        get: function () {
+            var psd = PSD, microTaskId = totalEchoes;
+            function then(onFulfilled, onRejected) {
+                var _this = this;
+                var possibleAwait = !psd.global && (psd !== PSD || microTaskId !== totalEchoes);
+                var cleanup = possibleAwait && !decrementExpectedAwaits();
+                var rv = new DexiePromise(function (resolve, reject) {
+                    propagateToListener(_this, new Listener(nativeAwaitCompatibleWrap(onFulfilled, psd, possibleAwait, cleanup), nativeAwaitCompatibleWrap(onRejected, psd, possibleAwait, cleanup), resolve, reject, psd));
+                });
+                debug && linkToPreviousPromise(rv, this);
+                return rv;
+            }
+            then.prototype = INTERNAL;
+            return then;
+        },
+        set: function (value) {
+            setProp(this, 'then', value && value.prototype === INTERNAL ?
+                thenProp :
+                {
+                    get: function () {
+                        return value;
+                    },
+                    set: thenProp.set
+                });
+        }
+    };
+    props(DexiePromise.prototype, {
+        then: thenProp,
+        _then: function (onFulfilled, onRejected) {
+            propagateToListener(this, new Listener(null, null, onFulfilled, onRejected, PSD));
+        },
+        catch: function (onRejected) {
+            if (arguments.length === 1)
+                return this.then(null, onRejected);
+            var type = arguments[0], handler = arguments[1];
+            return typeof type === 'function' ? this.then(null, function (err) {
+                return err instanceof type ? handler(err) : PromiseReject(err);
+            })
+                : this.then(null, function (err) {
+                    return err && err.name === type ? handler(err) : PromiseReject(err);
+                });
+        },
+        finally: function (onFinally) {
+            return this.then(function (value) {
+                onFinally();
+                return value;
+            }, function (err) {
+                onFinally();
+                return PromiseReject(err);
+            });
+        },
+        stack: {
+            get: function () {
+                if (this._stack)
+                    return this._stack;
+                try {
+                    stack_being_generated = true;
+                    var stacks = getStack(this, [], MAX_LONG_STACKS);
+                    var stack = stacks.join("\nFrom previous: ");
+                    if (this._state !== null)
+                        this._stack = stack;
+                    return stack;
+                }
+                finally {
+                    stack_being_generated = false;
+                }
+            }
+        },
+        timeout: function (ms, msg) {
+            var _this = this;
+            return ms < Infinity ?
+                new DexiePromise(function (resolve, reject) {
+                    var handle = setTimeout(function () { return reject(new exceptions.Timeout(msg)); }, ms);
+                    _this.then(resolve, reject).finally(clearTimeout.bind(null, handle));
+                }) : this;
+        }
+    });
+    if (typeof Symbol !== 'undefined' && Symbol.toStringTag)
+        setProp(DexiePromise.prototype, Symbol.toStringTag, 'Dexie.Promise');
+    globalPSD.env = snapShot();
+    function Listener(onFulfilled, onRejected, resolve, reject, zone) {
+        this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
+        this.onRejected = typeof onRejected === 'function' ? onRejected : null;
+        this.resolve = resolve;
+        this.reject = reject;
+        this.psd = zone;
+    }
+    props(DexiePromise, {
+        all: function () {
+            var values = getArrayOf.apply(null, arguments)
+                .map(onPossibleParallellAsync);
+            return new DexiePromise(function (resolve, reject) {
+                if (values.length === 0)
+                    resolve([]);
+                var remaining = values.length;
+                values.forEach(function (a, i) { return DexiePromise.resolve(a).then(function (x) {
+                    values[i] = x;
+                    if (!--remaining)
+                        resolve(values);
+                }, reject); });
+            });
+        },
+        resolve: function (value) {
+            if (value instanceof DexiePromise)
+                return value;
+            if (value && typeof value.then === 'function')
+                return new DexiePromise(function (resolve, reject) {
+                    value.then(resolve, reject);
+                });
+            var rv = new DexiePromise(INTERNAL, true, value);
+            linkToPreviousPromise(rv, currentFulfiller);
+            return rv;
+        },
+        reject: PromiseReject,
+        race: function () {
+            var values = getArrayOf.apply(null, arguments).map(onPossibleParallellAsync);
+            return new DexiePromise(function (resolve, reject) {
+                values.map(function (value) { return DexiePromise.resolve(value).then(resolve, reject); });
+            });
+        },
+        PSD: {
+            get: function () { return PSD; },
+            set: function (value) { return PSD = value; }
+        },
+        totalEchoes: { get: function () { return totalEchoes; } },
+        newPSD: newScope,
+        usePSD: usePSD,
+        scheduler: {
+            get: function () { return asap; },
+            set: function (value) { asap = value; }
+        },
+        rejectionMapper: {
+            get: function () { return rejectionMapper; },
+            set: function (value) { rejectionMapper = value; }
+        },
+        follow: function (fn, zoneProps) {
+            return new DexiePromise(function (resolve, reject) {
+                return newScope(function (resolve, reject) {
+                    var psd = PSD;
+                    psd.unhandleds = [];
+                    psd.onunhandled = reject;
+                    psd.finalize = callBoth(function () {
+                        var _this = this;
+                        run_at_end_of_this_or_next_physical_tick(function () {
+                            _this.unhandleds.length === 0 ? resolve() : reject(_this.unhandleds[0]);
+                        });
+                    }, psd.finalize);
+                    fn();
+                }, zoneProps, resolve, reject);
+            });
+        }
+    });
+    if (NativePromise) {
+        if (NativePromise.allSettled)
+            setProp(DexiePromise, "allSettled", function () {
+                var possiblePromises = getArrayOf.apply(null, arguments).map(onPossibleParallellAsync);
+                return new DexiePromise(function (resolve) {
+                    if (possiblePromises.length === 0)
+                        resolve([]);
+                    var remaining = possiblePromises.length;
+                    var results = new Array(remaining);
+                    possiblePromises.forEach(function (p, i) { return DexiePromise.resolve(p).then(function (value) { return results[i] = { status: "fulfilled", value: value }; }, function (reason) { return results[i] = { status: "rejected", reason: reason }; })
+                        .then(function () { return --remaining || resolve(results); }); });
+                });
+            });
+        if (NativePromise.any && typeof AggregateError !== 'undefined')
+            setProp(DexiePromise, "any", function () {
+                var possiblePromises = getArrayOf.apply(null, arguments).map(onPossibleParallellAsync);
+                return new DexiePromise(function (resolve, reject) {
+                    if (possiblePromises.length === 0)
+                        reject(new AggregateError([]));
+                    var remaining = possiblePromises.length;
+                    var failures = new Array(remaining);
+                    possiblePromises.forEach(function (p, i) { return DexiePromise.resolve(p).then(function (value) { return resolve(value); }, function (failure) {
+                        failures[i] = failure;
+                        if (!--remaining)
+                            reject(new AggregateError(failures));
+                    }); });
+                });
+            });
+    }
+    function executePromiseTask(promise, fn) {
+        try {
+            fn(function (value) {
+                if (promise._state !== null)
+                    return;
+                if (value === promise)
+                    throw new TypeError('A promise cannot be resolved with itself.');
+                var shouldExecuteTick = promise._lib && beginMicroTickScope();
+                if (value && typeof value.then === 'function') {
+                    executePromiseTask(promise, function (resolve, reject) {
+                        value instanceof DexiePromise ?
+                            value._then(resolve, reject) :
+                            value.then(resolve, reject);
+                    });
+                }
+                else {
+                    promise._state = true;
+                    promise._value = value;
+                    propagateAllListeners(promise);
+                }
+                if (shouldExecuteTick)
+                    endMicroTickScope();
+            }, handleRejection.bind(null, promise));
+        }
+        catch (ex) {
+            handleRejection(promise, ex);
+        }
+    }
+    function handleRejection(promise, reason) {
+        rejectingErrors.push(reason);
+        if (promise._state !== null)
+            return;
+        var shouldExecuteTick = promise._lib && beginMicroTickScope();
+        reason = rejectionMapper(reason);
+        promise._state = false;
+        promise._value = reason;
+        debug && reason !== null && typeof reason === 'object' && !reason._promise && tryCatch(function () {
+            var origProp = getPropertyDescriptor(reason, "stack");
+            reason._promise = promise;
+            setProp(reason, "stack", {
+                get: function () {
+                    return stack_being_generated ?
+                        origProp && (origProp.get ?
+                            origProp.get.apply(reason) :
+                            origProp.value) :
+                        promise.stack;
+                }
+            });
+        });
+        addPossiblyUnhandledError(promise);
+        propagateAllListeners(promise);
+        if (shouldExecuteTick)
+            endMicroTickScope();
+    }
+    function propagateAllListeners(promise) {
+        var listeners = promise._listeners;
+        promise._listeners = [];
+        for (var i = 0, len = listeners.length; i < len; ++i) {
+            propagateToListener(promise, listeners[i]);
+        }
+        var psd = promise._PSD;
+        --psd.ref || psd.finalize();
+        if (numScheduledCalls === 0) {
+            ++numScheduledCalls;
+            asap(function () {
+                if (--numScheduledCalls === 0)
+                    finalizePhysicalTick();
+            }, []);
+        }
+    }
+    function propagateToListener(promise, listener) {
+        if (promise._state === null) {
+            promise._listeners.push(listener);
+            return;
+        }
+        var cb = promise._state ? listener.onFulfilled : listener.onRejected;
+        if (cb === null) {
+            return (promise._state ? listener.resolve : listener.reject)(promise._value);
+        }
+        ++listener.psd.ref;
+        ++numScheduledCalls;
+        asap(callListener, [cb, promise, listener]);
+    }
+    function callListener(cb, promise, listener) {
+        try {
+            currentFulfiller = promise;
+            var ret, value = promise._value;
+            if (promise._state) {
+                ret = cb(value);
+            }
+            else {
+                if (rejectingErrors.length)
+                    rejectingErrors = [];
+                ret = cb(value);
+                if (rejectingErrors.indexOf(value) === -1)
+                    markErrorAsHandled(promise);
+            }
+            listener.resolve(ret);
+        }
+        catch (e) {
+            listener.reject(e);
+        }
+        finally {
+            currentFulfiller = null;
+            if (--numScheduledCalls === 0)
+                finalizePhysicalTick();
+            --listener.psd.ref || listener.psd.finalize();
+        }
+    }
+    function getStack(promise, stacks, limit) {
+        if (stacks.length === limit)
+            return stacks;
+        var stack = "";
+        if (promise._state === false) {
+            var failure = promise._value, errorName, message;
+            if (failure != null) {
+                errorName = failure.name || "Error";
+                message = failure.message || failure;
+                stack = prettyStack(failure, 0);
+            }
+            else {
+                errorName = failure;
+                message = "";
+            }
+            stacks.push(errorName + (message ? ": " + message : "") + stack);
+        }
+        if (debug) {
+            stack = prettyStack(promise._stackHolder, 2);
+            if (stack && stacks.indexOf(stack) === -1)
+                stacks.push(stack);
+            if (promise._prev)
+                getStack(promise._prev, stacks, limit);
+        }
+        return stacks;
+    }
+    function linkToPreviousPromise(promise, prev) {
+        var numPrev = prev ? prev._numPrev + 1 : 0;
+        if (numPrev < LONG_STACKS_CLIP_LIMIT) {
+            promise._prev = prev;
+            promise._numPrev = numPrev;
+        }
+    }
+    function physicalTick() {
+        beginMicroTickScope() && endMicroTickScope();
+    }
+    function beginMicroTickScope() {
+        var wasRootExec = isOutsideMicroTick;
+        isOutsideMicroTick = false;
+        needsNewPhysicalTick = false;
+        return wasRootExec;
+    }
+    function endMicroTickScope() {
+        var callbacks, i, l;
+        do {
+            while (microtickQueue.length > 0) {
+                callbacks = microtickQueue;
+                microtickQueue = [];
+                l = callbacks.length;
+                for (i = 0; i < l; ++i) {
+                    var item = callbacks[i];
+                    item[0].apply(null, item[1]);
+                }
+            }
+        } while (microtickQueue.length > 0);
+        isOutsideMicroTick = true;
+        needsNewPhysicalTick = true;
+    }
+    function finalizePhysicalTick() {
+        var unhandledErrs = unhandledErrors;
+        unhandledErrors = [];
+        unhandledErrs.forEach(function (p) {
+            p._PSD.onunhandled.call(null, p._value, p);
+        });
+        var finalizers = tickFinalizers.slice(0);
+        var i = finalizers.length;
+        while (i)
+            finalizers[--i]();
+    }
+    function run_at_end_of_this_or_next_physical_tick(fn) {
+        function finalizer() {
+            fn();
+            tickFinalizers.splice(tickFinalizers.indexOf(finalizer), 1);
+        }
+        tickFinalizers.push(finalizer);
+        ++numScheduledCalls;
+        asap(function () {
+            if (--numScheduledCalls === 0)
+                finalizePhysicalTick();
+        }, []);
+    }
+    function addPossiblyUnhandledError(promise) {
+        if (!unhandledErrors.some(function (p) { return p._value === promise._value; }))
+            unhandledErrors.push(promise);
+    }
+    function markErrorAsHandled(promise) {
+        var i = unhandledErrors.length;
+        while (i)
+            if (unhandledErrors[--i]._value === promise._value) {
+                unhandledErrors.splice(i, 1);
+                return;
+            }
+    }
+    function PromiseReject(reason) {
+        return new DexiePromise(INTERNAL, false, reason);
+    }
+    function wrap(fn, errorCatcher) {
+        var psd = PSD;
+        return function () {
+            var wasRootExec = beginMicroTickScope(), outerScope = PSD;
+            try {
+                switchToZone(psd, true);
+                return fn.apply(this, arguments);
+            }
+            catch (e) {
+                errorCatcher && errorCatcher(e);
+            }
+            finally {
+                switchToZone(outerScope, false);
+                if (wasRootExec)
+                    endMicroTickScope();
+            }
+        };
+    }
+    var task = { awaits: 0, echoes: 0, id: 0 };
+    var taskCounter = 0;
+    var zoneStack = [];
+    var zoneEchoes = 0;
+    var totalEchoes = 0;
+    var zone_id_counter = 0;
+    function newScope(fn, props, a1, a2) {
+        var parent = PSD, psd = Object.create(parent);
+        psd.parent = parent;
+        psd.ref = 0;
+        psd.global = false;
+        psd.id = ++zone_id_counter;
+        var globalEnv = globalPSD.env;
+        psd.env = patchGlobalPromise ? {
+            Promise: DexiePromise,
+            PromiseProp: { value: DexiePromise, configurable: true, writable: true },
+            all: DexiePromise.all,
+            race: DexiePromise.race,
+            allSettled: DexiePromise.allSettled,
+            any: DexiePromise.any,
+            resolve: DexiePromise.resolve,
+            reject: DexiePromise.reject,
+            nthen: getPatchedPromiseThen(globalEnv.nthen, psd),
+            gthen: getPatchedPromiseThen(globalEnv.gthen, psd)
+        } : {};
+        if (props)
+            extend(psd, props);
+        ++parent.ref;
+        psd.finalize = function () {
+            --this.parent.ref || this.parent.finalize();
+        };
+        var rv = usePSD(psd, fn, a1, a2);
+        if (psd.ref === 0)
+            psd.finalize();
+        return rv;
+    }
+    function incrementExpectedAwaits() {
+        if (!task.id)
+            task.id = ++taskCounter;
+        ++task.awaits;
+        task.echoes += ZONE_ECHO_LIMIT;
+        return task.id;
+    }
+    function decrementExpectedAwaits() {
+        if (!task.awaits)
+            return false;
+        if (--task.awaits === 0)
+            task.id = 0;
+        task.echoes = task.awaits * ZONE_ECHO_LIMIT;
+        return true;
+    }
+    if (('' + nativePromiseThen).indexOf('[native code]') === -1) {
+        incrementExpectedAwaits = decrementExpectedAwaits = nop;
+    }
+    function onPossibleParallellAsync(possiblePromise) {
+        if (task.echoes && possiblePromise && possiblePromise.constructor === NativePromise) {
+            incrementExpectedAwaits();
+            return possiblePromise.then(function (x) {
+                decrementExpectedAwaits();
+                return x;
+            }, function (e) {
+                decrementExpectedAwaits();
+                return rejection(e);
+            });
+        }
+        return possiblePromise;
+    }
+    function zoneEnterEcho(targetZone) {
+        ++totalEchoes;
+        if (!task.echoes || --task.echoes === 0) {
+            task.echoes = task.id = 0;
+        }
+        zoneStack.push(PSD);
+        switchToZone(targetZone, true);
+    }
+    function zoneLeaveEcho() {
+        var zone = zoneStack[zoneStack.length - 1];
+        zoneStack.pop();
+        switchToZone(zone, false);
+    }
+    function switchToZone(targetZone, bEnteringZone) {
+        var currentZone = PSD;
+        if (bEnteringZone ? task.echoes && (!zoneEchoes++ || targetZone !== PSD) : zoneEchoes && (!--zoneEchoes || targetZone !== PSD)) {
+            enqueueNativeMicroTask(bEnteringZone ? zoneEnterEcho.bind(null, targetZone) : zoneLeaveEcho);
+        }
+        if (targetZone === PSD)
+            return;
+        PSD = targetZone;
+        if (currentZone === globalPSD)
+            globalPSD.env = snapShot();
+        if (patchGlobalPromise) {
+            var GlobalPromise_1 = globalPSD.env.Promise;
+            var targetEnv = targetZone.env;
+            nativePromiseProto.then = targetEnv.nthen;
+            GlobalPromise_1.prototype.then = targetEnv.gthen;
+            if (currentZone.global || targetZone.global) {
+                Object.defineProperty(_global, 'Promise', targetEnv.PromiseProp);
+                GlobalPromise_1.all = targetEnv.all;
+                GlobalPromise_1.race = targetEnv.race;
+                GlobalPromise_1.resolve = targetEnv.resolve;
+                GlobalPromise_1.reject = targetEnv.reject;
+                if (targetEnv.allSettled)
+                    GlobalPromise_1.allSettled = targetEnv.allSettled;
+                if (targetEnv.any)
+                    GlobalPromise_1.any = targetEnv.any;
+            }
+        }
+    }
+    function snapShot() {
+        var GlobalPromise = _global.Promise;
+        return patchGlobalPromise ? {
+            Promise: GlobalPromise,
+            PromiseProp: Object.getOwnPropertyDescriptor(_global, "Promise"),
+            all: GlobalPromise.all,
+            race: GlobalPromise.race,
+            allSettled: GlobalPromise.allSettled,
+            any: GlobalPromise.any,
+            resolve: GlobalPromise.resolve,
+            reject: GlobalPromise.reject,
+            nthen: nativePromiseProto.then,
+            gthen: GlobalPromise.prototype.then
+        } : {};
+    }
+    function usePSD(psd, fn, a1, a2, a3) {
+        var outerScope = PSD;
+        try {
+            switchToZone(psd, true);
+            return fn(a1, a2, a3);
+        }
+        finally {
+            switchToZone(outerScope, false);
+        }
+    }
+    function enqueueNativeMicroTask(job) {
+        nativePromiseThen.call(resolvedNativePromise, job);
+    }
+    function nativeAwaitCompatibleWrap(fn, zone, possibleAwait, cleanup) {
+        return typeof fn !== 'function' ? fn : function () {
+            var outerZone = PSD;
+            if (possibleAwait)
+                incrementExpectedAwaits();
+            switchToZone(zone, true);
+            try {
+                return fn.apply(this, arguments);
+            }
+            finally {
+                switchToZone(outerZone, false);
+                if (cleanup)
+                    enqueueNativeMicroTask(decrementExpectedAwaits);
+            }
+        };
+    }
+    function getPatchedPromiseThen(origThen, zone) {
+        return function (onResolved, onRejected) {
+            return origThen.call(this, nativeAwaitCompatibleWrap(onResolved, zone), nativeAwaitCompatibleWrap(onRejected, zone));
+        };
+    }
+    var UNHANDLEDREJECTION = "unhandledrejection";
+    function globalError(err, promise) {
+        var rv;
+        try {
+            rv = promise.onuncatched(err);
+        }
+        catch (e) { }
+        if (rv !== false)
+            try {
+                var event, eventData = { promise: promise, reason: err };
+                if (_global.document && document.createEvent) {
+                    event = document.createEvent('Event');
+                    event.initEvent(UNHANDLEDREJECTION, true, true);
+                    extend(event, eventData);
+                }
+                else if (_global.CustomEvent) {
+                    event = new CustomEvent(UNHANDLEDREJECTION, { detail: eventData });
+                    extend(event, eventData);
+                }
+                if (event && _global.dispatchEvent) {
+                    dispatchEvent(event);
+                    if (!_global.PromiseRejectionEvent && _global.onunhandledrejection)
+                        try {
+                            _global.onunhandledrejection(event);
+                        }
+                        catch (_) { }
+                }
+                if (debug && event && !event.defaultPrevented) {
+                    console.warn("Unhandled rejection: " + (err.stack || err));
+                }
+            }
+            catch (e) { }
+    }
+    var rejection = DexiePromise.reject;
+
+    function tempTransaction(db, mode, storeNames, fn) {
+        if (!db.idbdb || (!db._state.openComplete && (!PSD.letThrough && !db._vip))) {
+            if (db._state.openComplete) {
+                return rejection(new exceptions.DatabaseClosed(db._state.dbOpenError));
+            }
+            if (!db._state.isBeingOpened) {
+                if (!db._options.autoOpen)
+                    return rejection(new exceptions.DatabaseClosed());
+                db.open().catch(nop);
+            }
+            return db._state.dbReadyPromise.then(function () { return tempTransaction(db, mode, storeNames, fn); });
+        }
+        else {
+            var trans = db._createTransaction(mode, storeNames, db._dbSchema);
+            try {
+                trans.create();
+                db._state.PR1398_maxLoop = 3;
+            }
+            catch (ex) {
+                if (ex.name === errnames.InvalidState && db.isOpen() && --db._state.PR1398_maxLoop > 0) {
+                    console.warn('Dexie: Need to reopen db');
+                    db._close();
+                    return db.open().then(function () { return tempTransaction(db, mode, storeNames, fn); });
+                }
+                return rejection(ex);
+            }
+            return trans._promise(mode, function (resolve, reject) {
+                return newScope(function () {
+                    PSD.trans = trans;
+                    return fn(resolve, reject, trans);
+                });
+            }).then(function (result) {
+                return trans._completion.then(function () { return result; });
+            });
+        }
+    }
+
+    var DEXIE_VERSION = '3.2.3';
+    var maxString = String.fromCharCode(65535);
+    var minKey = -Infinity;
+    var INVALID_KEY_ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>.";
+    var STRING_EXPECTED = "String expected.";
+    var connections = [];
+    var isIEOrEdge = typeof navigator !== 'undefined' && /(MSIE|Trident|Edge)/.test(navigator.userAgent);
+    var hasIEDeleteObjectStoreBug = isIEOrEdge;
+    var hangsOnDeleteLargeKeyRange = isIEOrEdge;
+    var dexieStackFrameFilter = function (frame) { return !/(dexie\.js|dexie\.min\.js)/.test(frame); };
+    var DBNAMES_DB = '__dbnames';
+    var READONLY = 'readonly';
+    var READWRITE = 'readwrite';
+
+    function combine(filter1, filter2) {
+        return filter1 ?
+            filter2 ?
+                function () { return filter1.apply(this, arguments) && filter2.apply(this, arguments); } :
+                filter1 :
+            filter2;
+    }
+
+    var AnyRange = {
+        type: 3 ,
+        lower: -Infinity,
+        lowerOpen: false,
+        upper: [[]],
+        upperOpen: false
+    };
+
+    function workaroundForUndefinedPrimKey(keyPath) {
+        return typeof keyPath === "string" && !/\./.test(keyPath)
+            ? function (obj) {
+                if (obj[keyPath] === undefined && (keyPath in obj)) {
+                    obj = deepClone(obj);
+                    delete obj[keyPath];
+                }
+                return obj;
+            }
+            : function (obj) { return obj; };
+    }
+
+    var Table =  (function () {
+        function Table() {
+        }
+        Table.prototype._trans = function (mode, fn, writeLocked) {
+            var trans = this._tx || PSD.trans;
+            var tableName = this.name;
+            function checkTableInTransaction(resolve, reject, trans) {
+                if (!trans.schema[tableName])
+                    throw new exceptions.NotFound("Table " + tableName + " not part of transaction");
+                return fn(trans.idbtrans, trans);
+            }
+            var wasRootExec = beginMicroTickScope();
+            try {
+                return trans && trans.db === this.db ?
+                    trans === PSD.trans ?
+                        trans._promise(mode, checkTableInTransaction, writeLocked) :
+                        newScope(function () { return trans._promise(mode, checkTableInTransaction, writeLocked); }, { trans: trans, transless: PSD.transless || PSD }) :
+                    tempTransaction(this.db, mode, [this.name], checkTableInTransaction);
+            }
+            finally {
+                if (wasRootExec)
+                    endMicroTickScope();
+            }
+        };
+        Table.prototype.get = function (keyOrCrit, cb) {
+            var _this = this;
+            if (keyOrCrit && keyOrCrit.constructor === Object)
+                return this.where(keyOrCrit).first(cb);
+            return this._trans('readonly', function (trans) {
+                return _this.core.get({ trans: trans, key: keyOrCrit })
+                    .then(function (res) { return _this.hook.reading.fire(res); });
+            }).then(cb);
+        };
+        Table.prototype.where = function (indexOrCrit) {
+            if (typeof indexOrCrit === 'string')
+                return new this.db.WhereClause(this, indexOrCrit);
+            if (isArray(indexOrCrit))
+                return new this.db.WhereClause(this, "[" + indexOrCrit.join('+') + "]");
+            var keyPaths = keys(indexOrCrit);
+            if (keyPaths.length === 1)
+                return this
+                    .where(keyPaths[0])
+                    .equals(indexOrCrit[keyPaths[0]]);
+            var compoundIndex = this.schema.indexes.concat(this.schema.primKey).filter(function (ix) {
+                return ix.compound &&
+                    keyPaths.every(function (keyPath) { return ix.keyPath.indexOf(keyPath) >= 0; }) &&
+                    ix.keyPath.every(function (keyPath) { return keyPaths.indexOf(keyPath) >= 0; });
+            })[0];
+            if (compoundIndex && this.db._maxKey !== maxString)
+                return this
+                    .where(compoundIndex.name)
+                    .equals(compoundIndex.keyPath.map(function (kp) { return indexOrCrit[kp]; }));
+            if (!compoundIndex && debug)
+                console.warn("The query " + JSON.stringify(indexOrCrit) + " on " + this.name + " would benefit of a " +
+                    ("compound index [" + keyPaths.join('+') + "]"));
+            var idxByName = this.schema.idxByName;
+            var idb = this.db._deps.indexedDB;
+            function equals(a, b) {
+                try {
+                    return idb.cmp(a, b) === 0;
+                }
+                catch (e) {
+                    return false;
+                }
+            }
+            var _a = keyPaths.reduce(function (_a, keyPath) {
+                var prevIndex = _a[0], prevFilterFn = _a[1];
+                var index = idxByName[keyPath];
+                var value = indexOrCrit[keyPath];
+                return [
+                    prevIndex || index,
+                    prevIndex || !index ?
+                        combine(prevFilterFn, index && index.multi ?
+                            function (x) {
+                                var prop = getByKeyPath(x, keyPath);
+                                return isArray(prop) && prop.some(function (item) { return equals(value, item); });
+                            } : function (x) { return equals(value, getByKeyPath(x, keyPath)); })
+                        : prevFilterFn
+                ];
+            }, [null, null]), idx = _a[0], filterFunction = _a[1];
+            return idx ?
+                this.where(idx.name).equals(indexOrCrit[idx.keyPath])
+                    .filter(filterFunction) :
+                compoundIndex ?
+                    this.filter(filterFunction) :
+                    this.where(keyPaths).equals('');
+        };
+        Table.prototype.filter = function (filterFunction) {
+            return this.toCollection().and(filterFunction);
+        };
+        Table.prototype.count = function (thenShortcut) {
+            return this.toCollection().count(thenShortcut);
+        };
+        Table.prototype.offset = function (offset) {
+            return this.toCollection().offset(offset);
+        };
+        Table.prototype.limit = function (numRows) {
+            return this.toCollection().limit(numRows);
+        };
+        Table.prototype.each = function (callback) {
+            return this.toCollection().each(callback);
+        };
+        Table.prototype.toArray = function (thenShortcut) {
+            return this.toCollection().toArray(thenShortcut);
+        };
+        Table.prototype.toCollection = function () {
+            return new this.db.Collection(new this.db.WhereClause(this));
+        };
+        Table.prototype.orderBy = function (index) {
+            return new this.db.Collection(new this.db.WhereClause(this, isArray(index) ?
+                "[" + index.join('+') + "]" :
+                index));
+        };
+        Table.prototype.reverse = function () {
+            return this.toCollection().reverse();
+        };
+        Table.prototype.mapToClass = function (constructor) {
+            this.schema.mappedClass = constructor;
+            var readHook = function (obj) {
+                if (!obj)
+                    return obj;
+                var res = Object.create(constructor.prototype);
+                for (var m in obj)
+                    if (hasOwn(obj, m))
+                        try {
+                            res[m] = obj[m];
+                        }
+                        catch (_) { }
+                return res;
+            };
+            if (this.schema.readHook) {
+                this.hook.reading.unsubscribe(this.schema.readHook);
+            }
+            this.schema.readHook = readHook;
+            this.hook("reading", readHook);
+            return constructor;
+        };
+        Table.prototype.defineClass = function () {
+            function Class(content) {
+                extend(this, content);
+            }
+            return this.mapToClass(Class);
+        };
+        Table.prototype.add = function (obj, key) {
+            var _this = this;
+            var _a = this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
+            var objToAdd = obj;
+            if (keyPath && auto) {
+                objToAdd = workaroundForUndefinedPrimKey(keyPath)(obj);
+            }
+            return this._trans('readwrite', function (trans) {
+                return _this.core.mutate({ trans: trans, type: 'add', keys: key != null ? [key] : null, values: [objToAdd] });
+            }).then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : res.lastResult; })
+                .then(function (lastResult) {
+                if (keyPath) {
+                    try {
+                        setByKeyPath(obj, keyPath, lastResult);
+                    }
+                    catch (_) { }
+                }
+                return lastResult;
+            });
+        };
+        Table.prototype.update = function (keyOrObject, modifications) {
+            if (typeof keyOrObject === 'object' && !isArray(keyOrObject)) {
+                var key = getByKeyPath(keyOrObject, this.schema.primKey.keyPath);
+                if (key === undefined)
+                    return rejection(new exceptions.InvalidArgument("Given object does not contain its primary key"));
+                try {
+                    if (typeof modifications !== "function") {
+                        keys(modifications).forEach(function (keyPath) {
+                            setByKeyPath(keyOrObject, keyPath, modifications[keyPath]);
+                        });
+                    }
+                    else {
+                        modifications(keyOrObject, { value: keyOrObject, primKey: key });
+                    }
+                }
+                catch (_a) {
+                }
+                return this.where(":id").equals(key).modify(modifications);
+            }
+            else {
+                return this.where(":id").equals(keyOrObject).modify(modifications);
+            }
+        };
+        Table.prototype.put = function (obj, key) {
+            var _this = this;
+            var _a = this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
+            var objToAdd = obj;
+            if (keyPath && auto) {
+                objToAdd = workaroundForUndefinedPrimKey(keyPath)(obj);
+            }
+            return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'put', values: [objToAdd], keys: key != null ? [key] : null }); })
+                .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : res.lastResult; })
+                .then(function (lastResult) {
+                if (keyPath) {
+                    try {
+                        setByKeyPath(obj, keyPath, lastResult);
+                    }
+                    catch (_) { }
+                }
+                return lastResult;
+            });
+        };
+        Table.prototype.delete = function (key) {
+            var _this = this;
+            return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'delete', keys: [key] }); })
+                .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : undefined; });
+        };
+        Table.prototype.clear = function () {
+            var _this = this;
+            return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'deleteRange', range: AnyRange }); })
+                .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : undefined; });
+        };
+        Table.prototype.bulkGet = function (keys) {
+            var _this = this;
+            return this._trans('readonly', function (trans) {
+                return _this.core.getMany({
+                    keys: keys,
+                    trans: trans
+                }).then(function (result) { return result.map(function (res) { return _this.hook.reading.fire(res); }); });
+            });
+        };
+        Table.prototype.bulkAdd = function (objects, keysOrOptions, options) {
+            var _this = this;
+            var keys = Array.isArray(keysOrOptions) ? keysOrOptions : undefined;
+            options = options || (keys ? undefined : keysOrOptions);
+            var wantResults = options ? options.allKeys : undefined;
+            return this._trans('readwrite', function (trans) {
+                var _a = _this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
+                if (keyPath && keys)
+                    throw new exceptions.InvalidArgument("bulkAdd(): keys argument invalid on tables with inbound keys");
+                if (keys && keys.length !== objects.length)
+                    throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length");
+                var numObjects = objects.length;
+                var objectsToAdd = keyPath && auto ?
+                    objects.map(workaroundForUndefinedPrimKey(keyPath)) :
+                    objects;
+                return _this.core.mutate({ trans: trans, type: 'add', keys: keys, values: objectsToAdd, wantResults: wantResults })
+                    .then(function (_a) {
+                    var numFailures = _a.numFailures, results = _a.results, lastResult = _a.lastResult, failures = _a.failures;
+                    var result = wantResults ? results : lastResult;
+                    if (numFailures === 0)
+                        return result;
+                    throw new BulkError(_this.name + ".bulkAdd(): " + numFailures + " of " + numObjects + " operations failed", failures);
+                });
+            });
+        };
+        Table.prototype.bulkPut = function (objects, keysOrOptions, options) {
+            var _this = this;
+            var keys = Array.isArray(keysOrOptions) ? keysOrOptions : undefined;
+            options = options || (keys ? undefined : keysOrOptions);
+            var wantResults = options ? options.allKeys : undefined;
+            return this._trans('readwrite', function (trans) {
+                var _a = _this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
+                if (keyPath && keys)
+                    throw new exceptions.InvalidArgument("bulkPut(): keys argument invalid on tables with inbound keys");
+                if (keys && keys.length !== objects.length)
+                    throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length");
+                var numObjects = objects.length;
+                var objectsToPut = keyPath && auto ?
+                    objects.map(workaroundForUndefinedPrimKey(keyPath)) :
+                    objects;
+                return _this.core.mutate({ trans: trans, type: 'put', keys: keys, values: objectsToPut, wantResults: wantResults })
+                    .then(function (_a) {
+                    var numFailures = _a.numFailures, results = _a.results, lastResult = _a.lastResult, failures = _a.failures;
+                    var result = wantResults ? results : lastResult;
+                    if (numFailures === 0)
+                        return result;
+                    throw new BulkError(_this.name + ".bulkPut(): " + numFailures + " of " + numObjects + " operations failed", failures);
+                });
+            });
+        };
+        Table.prototype.bulkDelete = function (keys) {
+            var _this = this;
+            var numKeys = keys.length;
+            return this._trans('readwrite', function (trans) {
+                return _this.core.mutate({ trans: trans, type: 'delete', keys: keys });
+            }).then(function (_a) {
+                var numFailures = _a.numFailures, lastResult = _a.lastResult, failures = _a.failures;
+                if (numFailures === 0)
+                    return lastResult;
+                throw new BulkError(_this.name + ".bulkDelete(): " + numFailures + " of " + numKeys + " operations failed", failures);
+            });
+        };
+        return Table;
+    }());
+
+    function Events(ctx) {
+        var evs = {};
+        var rv = function (eventName, subscriber) {
+            if (subscriber) {
+                var i = arguments.length, args = new Array(i - 1);
+                while (--i)
+                    args[i - 1] = arguments[i];
+                evs[eventName].subscribe.apply(null, args);
+                return ctx;
+            }
+            else if (typeof (eventName) === 'string') {
+                return evs[eventName];
+            }
+        };
+        rv.addEventType = add;
+        for (var i = 1, l = arguments.length; i < l; ++i) {
+            add(arguments[i]);
+        }
+        return rv;
+        function add(eventName, chainFunction, defaultFunction) {
+            if (typeof eventName === 'object')
+                return addConfiguredEvents(eventName);
+            if (!chainFunction)
+                chainFunction = reverseStoppableEventChain;
+            if (!defaultFunction)
+                defaultFunction = nop;
+            var context = {
+                subscribers: [],
+                fire: defaultFunction,
+                subscribe: function (cb) {
+                    if (context.subscribers.indexOf(cb) === -1) {
+                        context.subscribers.push(cb);
+                        context.fire = chainFunction(context.fire, cb);
+                    }
+                },
+                unsubscribe: function (cb) {
+                    context.subscribers = context.subscribers.filter(function (fn) { return fn !== cb; });
+                    context.fire = context.subscribers.reduce(chainFunction, defaultFunction);
+                }
+            };
+            evs[eventName] = rv[eventName] = context;
+            return context;
+        }
+        function addConfiguredEvents(cfg) {
+            keys(cfg).forEach(function (eventName) {
+                var args = cfg[eventName];
+                if (isArray(args)) {
+                    add(eventName, cfg[eventName][0], cfg[eventName][1]);
+                }
+                else if (args === 'asap') {
+                    var context = add(eventName, mirror, function fire() {
+                        var i = arguments.length, args = new Array(i);
+                        while (i--)
+                            args[i] = arguments[i];
+                        context.subscribers.forEach(function (fn) {
+                            asap$1(function fireEvent() {
+                                fn.apply(null, args);
+                            });
+                        });
+                    });
+                }
+                else
+                    throw new exceptions.InvalidArgument("Invalid event config");
+            });
+        }
+    }
+
+    function makeClassConstructor(prototype, constructor) {
+        derive(constructor).from({ prototype: prototype });
+        return constructor;
+    }
+
+    function createTableConstructor(db) {
+        return makeClassConstructor(Table.prototype, function Table(name, tableSchema, trans) {
+            this.db = db;
+            this._tx = trans;
+            this.name = name;
+            this.schema = tableSchema;
+            this.hook = db._allTables[name] ? db._allTables[name].hook : Events(null, {
+                "creating": [hookCreatingChain, nop],
+                "reading": [pureFunctionChain, mirror],
+                "updating": [hookUpdatingChain, nop],
+                "deleting": [hookDeletingChain, nop]
+            });
+        });
+    }
+
+    function isPlainKeyRange(ctx, ignoreLimitFilter) {
+        return !(ctx.filter || ctx.algorithm || ctx.or) &&
+            (ignoreLimitFilter ? ctx.justLimit : !ctx.replayFilter);
+    }
+    function addFilter(ctx, fn) {
+        ctx.filter = combine(ctx.filter, fn);
+    }
+    function addReplayFilter(ctx, factory, isLimitFilter) {
+        var curr = ctx.replayFilter;
+        ctx.replayFilter = curr ? function () { return combine(curr(), factory()); } : factory;
+        ctx.justLimit = isLimitFilter && !curr;
+    }
+    function addMatchFilter(ctx, fn) {
+        ctx.isMatch = combine(ctx.isMatch, fn);
+    }
+    function getIndexOrStore(ctx, coreSchema) {
+        if (ctx.isPrimKey)
+            return coreSchema.primaryKey;
+        var index = coreSchema.getIndexByKeyPath(ctx.index);
+        if (!index)
+            throw new exceptions.Schema("KeyPath " + ctx.index + " on object store " + coreSchema.name + " is not indexed");
+        return index;
+    }
+    function openCursor(ctx, coreTable, trans) {
+        var index = getIndexOrStore(ctx, coreTable.schema);
+        return coreTable.openCursor({
+            trans: trans,
+            values: !ctx.keysOnly,
+            reverse: ctx.dir === 'prev',
+            unique: !!ctx.unique,
+            query: {
+                index: index,
+                range: ctx.range
+            }
+        });
+    }
+    function iter(ctx, fn, coreTrans, coreTable) {
+        var filter = ctx.replayFilter ? combine(ctx.filter, ctx.replayFilter()) : ctx.filter;
+        if (!ctx.or) {
+            return iterate(openCursor(ctx, coreTable, coreTrans), combine(ctx.algorithm, filter), fn, !ctx.keysOnly && ctx.valueMapper);
+        }
+        else {
+            var set_1 = {};
+            var union = function (item, cursor, advance) {
+                if (!filter || filter(cursor, advance, function (result) { return cursor.stop(result); }, function (err) { return cursor.fail(err); })) {
+                    var primaryKey = cursor.primaryKey;
+                    var key = '' + primaryKey;
+                    if (key === '[object ArrayBuffer]')
+                        key = '' + new Uint8Array(primaryKey);
+                    if (!hasOwn(set_1, key)) {
+                        set_1[key] = true;
+                        fn(item, cursor, advance);
+                    }
+                }
+            };
+            return Promise.all([
+                ctx.or._iterate(union, coreTrans),
+                iterate(openCursor(ctx, coreTable, coreTrans), ctx.algorithm, union, !ctx.keysOnly && ctx.valueMapper)
+            ]);
+        }
+    }
+    function iterate(cursorPromise, filter, fn, valueMapper) {
+        var mappedFn = valueMapper ? function (x, c, a) { return fn(valueMapper(x), c, a); } : fn;
+        var wrappedFn = wrap(mappedFn);
+        return cursorPromise.then(function (cursor) {
+            if (cursor) {
+                return cursor.start(function () {
+                    var c = function () { return cursor.continue(); };
+                    if (!filter || filter(cursor, function (advancer) { return c = advancer; }, function (val) { cursor.stop(val); c = nop; }, function (e) { cursor.fail(e); c = nop; }))
+                        wrappedFn(cursor.value, cursor, function (advancer) { return c = advancer; });
+                    c();
+                });
+            }
+        });
+    }
+
+    function cmp(a, b) {
+        try {
+            var ta = type(a);
+            var tb = type(b);
+            if (ta !== tb) {
+                if (ta === 'Array')
+                    return 1;
+                if (tb === 'Array')
+                    return -1;
+                if (ta === 'binary')
+                    return 1;
+                if (tb === 'binary')
+                    return -1;
+                if (ta === 'string')
+                    return 1;
+                if (tb === 'string')
+                    return -1;
+                if (ta === 'Date')
+                    return 1;
+                if (tb !== 'Date')
+                    return NaN;
+                return -1;
+            }
+            switch (ta) {
+                case 'number':
+                case 'Date':
+                case 'string':
+                    return a > b ? 1 : a < b ? -1 : 0;
+                case 'binary': {
+                    return compareUint8Arrays(getUint8Array(a), getUint8Array(b));
+                }
+                case 'Array':
+                    return compareArrays(a, b);
+            }
+        }
+        catch (_a) { }
+        return NaN;
+    }
+    function compareArrays(a, b) {
+        var al = a.length;
+        var bl = b.length;
+        var l = al < bl ? al : bl;
+        for (var i = 0; i < l; ++i) {
+            var res = cmp(a[i], b[i]);
+            if (res !== 0)
+                return res;
+        }
+        return al === bl ? 0 : al < bl ? -1 : 1;
+    }
+    function compareUint8Arrays(a, b) {
+        var al = a.length;
+        var bl = b.length;
+        var l = al < bl ? al : bl;
+        for (var i = 0; i < l; ++i) {
+            if (a[i] !== b[i])
+                return a[i] < b[i] ? -1 : 1;
+        }
+        return al === bl ? 0 : al < bl ? -1 : 1;
+    }
+    function type(x) {
+        var t = typeof x;
+        if (t !== 'object')
+            return t;
+        if (ArrayBuffer.isView(x))
+            return 'binary';
+        var tsTag = toStringTag(x);
+        return tsTag === 'ArrayBuffer' ? 'binary' : tsTag;
+    }
+    function getUint8Array(a) {
+        if (a instanceof Uint8Array)
+            return a;
+        if (ArrayBuffer.isView(a))
+            return new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
+        return new Uint8Array(a);
+    }
+
+    var Collection =  (function () {
+        function Collection() {
+        }
+        Collection.prototype._read = function (fn, cb) {
+            var ctx = this._ctx;
+            return ctx.error ?
+                ctx.table._trans(null, rejection.bind(null, ctx.error)) :
+                ctx.table._trans('readonly', fn).then(cb);
+        };
+        Collection.prototype._write = function (fn) {
+            var ctx = this._ctx;
+            return ctx.error ?
+                ctx.table._trans(null, rejection.bind(null, ctx.error)) :
+                ctx.table._trans('readwrite', fn, "locked");
+        };
+        Collection.prototype._addAlgorithm = function (fn) {
+            var ctx = this._ctx;
+            ctx.algorithm = combine(ctx.algorithm, fn);
+        };
+        Collection.prototype._iterate = function (fn, coreTrans) {
+            return iter(this._ctx, fn, coreTrans, this._ctx.table.core);
+        };
+        Collection.prototype.clone = function (props) {
+            var rv = Object.create(this.constructor.prototype), ctx = Object.create(this._ctx);
+            if (props)
+                extend(ctx, props);
+            rv._ctx = ctx;
+            return rv;
+        };
+        Collection.prototype.raw = function () {
+            this._ctx.valueMapper = null;
+            return this;
+        };
+        Collection.prototype.each = function (fn) {
+            var ctx = this._ctx;
+            return this._read(function (trans) { return iter(ctx, fn, trans, ctx.table.core); });
+        };
+        Collection.prototype.count = function (cb) {
+            var _this = this;
+            return this._read(function (trans) {
+                var ctx = _this._ctx;
+                var coreTable = ctx.table.core;
+                if (isPlainKeyRange(ctx, true)) {
+                    return coreTable.count({
+                        trans: trans,
+                        query: {
+                            index: getIndexOrStore(ctx, coreTable.schema),
+                            range: ctx.range
+                        }
+                    }).then(function (count) { return Math.min(count, ctx.limit); });
+                }
+                else {
+                    var count = 0;
+                    return iter(ctx, function () { ++count; return false; }, trans, coreTable)
+                        .then(function () { return count; });
+                }
+            }).then(cb);
+        };
+        Collection.prototype.sortBy = function (keyPath, cb) {
+            var parts = keyPath.split('.').reverse(), lastPart = parts[0], lastIndex = parts.length - 1;
+            function getval(obj, i) {
+                if (i)
+                    return getval(obj[parts[i]], i - 1);
+                return obj[lastPart];
+            }
+            var order = this._ctx.dir === "next" ? 1 : -1;
+            function sorter(a, b) {
+                var aVal = getval(a, lastIndex), bVal = getval(b, lastIndex);
+                return aVal < bVal ? -order : aVal > bVal ? order : 0;
+            }
+            return this.toArray(function (a) {
+                return a.sort(sorter);
+            }).then(cb);
+        };
+        Collection.prototype.toArray = function (cb) {
+            var _this = this;
+            return this._read(function (trans) {
+                var ctx = _this._ctx;
+                if (ctx.dir === 'next' && isPlainKeyRange(ctx, true) && ctx.limit > 0) {
+                    var valueMapper_1 = ctx.valueMapper;
+                    var index = getIndexOrStore(ctx, ctx.table.core.schema);
+                    return ctx.table.core.query({
+                        trans: trans,
+                        limit: ctx.limit,
+                        values: true,
+                        query: {
+                            index: index,
+                            range: ctx.range
+                        }
+                    }).then(function (_a) {
+                        var result = _a.result;
+                        return valueMapper_1 ? result.map(valueMapper_1) : result;
+                    });
+                }
+                else {
+                    var a_1 = [];
+                    return iter(ctx, function (item) { return a_1.push(item); }, trans, ctx.table.core).then(function () { return a_1; });
+                }
+            }, cb);
+        };
+        Collection.prototype.offset = function (offset) {
+            var ctx = this._ctx;
+            if (offset <= 0)
+                return this;
+            ctx.offset += offset;
+            if (isPlainKeyRange(ctx)) {
+                addReplayFilter(ctx, function () {
+                    var offsetLeft = offset;
+                    return function (cursor, advance) {
+                        if (offsetLeft === 0)
+                            return true;
+                        if (offsetLeft === 1) {
+                            --offsetLeft;
+                            return false;
+                        }
+                        advance(function () {
+                            cursor.advance(offsetLeft);
+                            offsetLeft = 0;
+                        });
+                        return false;
+                    };
+                });
+            }
+            else {
+                addReplayFilter(ctx, function () {
+                    var offsetLeft = offset;
+                    return function () { return (--offsetLeft < 0); };
+                });
+            }
+            return this;
+        };
+        Collection.prototype.limit = function (numRows) {
+            this._ctx.limit = Math.min(this._ctx.limit, numRows);
+            addReplayFilter(this._ctx, function () {
+                var rowsLeft = numRows;
+                return function (cursor, advance, resolve) {
+                    if (--rowsLeft <= 0)
+                        advance(resolve);
+                    return rowsLeft >= 0;
+                };
+            }, true);
+            return this;
+        };
+        Collection.prototype.until = function (filterFunction, bIncludeStopEntry) {
+            addFilter(this._ctx, function (cursor, advance, resolve) {
+                if (filterFunction(cursor.value)) {
+                    advance(resolve);
+                    return bIncludeStopEntry;
+                }
+                else {
+                    return true;
+                }
+            });
+            return this;
+        };
+        Collection.prototype.first = function (cb) {
+            return this.limit(1).toArray(function (a) { return a[0]; }).then(cb);
+        };
+        Collection.prototype.last = function (cb) {
+            return this.reverse().first(cb);
+        };
+        Collection.prototype.filter = function (filterFunction) {
+            addFilter(this._ctx, function (cursor) {
+                return filterFunction(cursor.value);
+            });
+            addMatchFilter(this._ctx, filterFunction);
+            return this;
+        };
+        Collection.prototype.and = function (filter) {
+            return this.filter(filter);
+        };
+        Collection.prototype.or = function (indexName) {
+            return new this.db.WhereClause(this._ctx.table, indexName, this);
+        };
+        Collection.prototype.reverse = function () {
+            this._ctx.dir = (this._ctx.dir === "prev" ? "next" : "prev");
+            if (this._ondirectionchange)
+                this._ondirectionchange(this._ctx.dir);
+            return this;
+        };
+        Collection.prototype.desc = function () {
+            return this.reverse();
+        };
+        Collection.prototype.eachKey = function (cb) {
+            var ctx = this._ctx;
+            ctx.keysOnly = !ctx.isMatch;
+            return this.each(function (val, cursor) { cb(cursor.key, cursor); });
+        };
+        Collection.prototype.eachUniqueKey = function (cb) {
+            this._ctx.unique = "unique";
+            return this.eachKey(cb);
+        };
+        Collection.prototype.eachPrimaryKey = function (cb) {
+            var ctx = this._ctx;
+            ctx.keysOnly = !ctx.isMatch;
+            return this.each(function (val, cursor) { cb(cursor.primaryKey, cursor); });
+        };
+        Collection.prototype.keys = function (cb) {
+            var ctx = this._ctx;
+            ctx.keysOnly = !ctx.isMatch;
+            var a = [];
+            return this.each(function (item, cursor) {
+                a.push(cursor.key);
+            }).then(function () {
+                return a;
+            }).then(cb);
+        };
+        Collection.prototype.primaryKeys = function (cb) {
+            var ctx = this._ctx;
+            if (ctx.dir === 'next' && isPlainKeyRange(ctx, true) && ctx.limit > 0) {
+                return this._read(function (trans) {
+                    var index = getIndexOrStore(ctx, ctx.table.core.schema);
+                    return ctx.table.core.query({
+                        trans: trans,
+                        values: false,
+                        limit: ctx.limit,
+                        query: {
+                            index: index,
+                            range: ctx.range
+                        }
+                    });
+                }).then(function (_a) {
+                    var result = _a.result;
+                    return result;
+                }).then(cb);
+            }
+            ctx.keysOnly = !ctx.isMatch;
+            var a = [];
+            return this.each(function (item, cursor) {
+                a.push(cursor.primaryKey);
+            }).then(function () {
+                return a;
+            }).then(cb);
+        };
+        Collection.prototype.uniqueKeys = function (cb) {
+            this._ctx.unique = "unique";
+            return this.keys(cb);
+        };
+        Collection.prototype.firstKey = function (cb) {
+            return this.limit(1).keys(function (a) { return a[0]; }).then(cb);
+        };
+        Collection.prototype.lastKey = function (cb) {
+            return this.reverse().firstKey(cb);
+        };
+        Collection.prototype.distinct = function () {
+            var ctx = this._ctx, idx = ctx.index && ctx.table.schema.idxByName[ctx.index];
+            if (!idx || !idx.multi)
+                return this;
+            var set = {};
+            addFilter(this._ctx, function (cursor) {
+                var strKey = cursor.primaryKey.toString();
+                var found = hasOwn(set, strKey);
+                set[strKey] = true;
+                return !found;
+            });
+            return this;
+        };
+        Collection.prototype.modify = function (changes) {
+            var _this = this;
+            var ctx = this._ctx;
+            return this._write(function (trans) {
+                var modifyer;
+                if (typeof changes === 'function') {
+                    modifyer = changes;
+                }
+                else {
+                    var keyPaths = keys(changes);
+                    var numKeys = keyPaths.length;
+                    modifyer = function (item) {
+                        var anythingModified = false;
+                        for (var i = 0; i < numKeys; ++i) {
+                            var keyPath = keyPaths[i], val = changes[keyPath];
+                            if (getByKeyPath(item, keyPath) !== val) {
+                                setByKeyPath(item, keyPath, val);
+                                anythingModified = true;
+                            }
+                        }
+                        return anythingModified;
+                    };
+                }
+                var coreTable = ctx.table.core;
+                var _a = coreTable.schema.primaryKey, outbound = _a.outbound, extractKey = _a.extractKey;
+                var limit = _this.db._options.modifyChunkSize || 200;
+                var totalFailures = [];
+                var successCount = 0;
+                var failedKeys = [];
+                var applyMutateResult = function (expectedCount, res) {
+                    var failures = res.failures, numFailures = res.numFailures;
+                    successCount += expectedCount - numFailures;
+                    for (var _i = 0, _a = keys(failures); _i < _a.length; _i++) {
+                        var pos = _a[_i];
+                        totalFailures.push(failures[pos]);
+                    }
+                };
+                return _this.clone().primaryKeys().then(function (keys) {
+                    var nextChunk = function (offset) {
+                        var count = Math.min(limit, keys.length - offset);
+                        return coreTable.getMany({
+                            trans: trans,
+                            keys: keys.slice(offset, offset + count),
+                            cache: "immutable"
+                        }).then(function (values) {
+                            var addValues = [];
+                            var putValues = [];
+                            var putKeys = outbound ? [] : null;
+                            var deleteKeys = [];
+                            for (var i = 0; i < count; ++i) {
+                                var origValue = values[i];
+                                var ctx_1 = {
+                                    value: deepClone(origValue),
+                                    primKey: keys[offset + i]
+                                };
+                                if (modifyer.call(ctx_1, ctx_1.value, ctx_1) !== false) {
+                                    if (ctx_1.value == null) {
+                                        deleteKeys.push(keys[offset + i]);
+                                    }
+                                    else if (!outbound && cmp(extractKey(origValue), extractKey(ctx_1.value)) !== 0) {
+                                        deleteKeys.push(keys[offset + i]);
+                                        addValues.push(ctx_1.value);
+                                    }
+                                    else {
+                                        putValues.push(ctx_1.value);
+                                        if (outbound)
+                                            putKeys.push(keys[offset + i]);
+                                    }
+                                }
+                            }
+                            var criteria = isPlainKeyRange(ctx) &&
+                                ctx.limit === Infinity &&
+                                (typeof changes !== 'function' || changes === deleteCallback) && {
+                                index: ctx.index,
+                                range: ctx.range
+                            };
+                            return Promise.resolve(addValues.length > 0 &&
+                                coreTable.mutate({ trans: trans, type: 'add', values: addValues })
+                                    .then(function (res) {
+                                    for (var pos in res.failures) {
+                                        deleteKeys.splice(parseInt(pos), 1);
+                                    }
+                                    applyMutateResult(addValues.length, res);
+                                })).then(function () { return (putValues.length > 0 || (criteria && typeof changes === 'object')) &&
+                                coreTable.mutate({
+                                    trans: trans,
+                                    type: 'put',
+                                    keys: putKeys,
+                                    values: putValues,
+                                    criteria: criteria,
+                                    changeSpec: typeof changes !== 'function'
+                                        && changes
+                                }).then(function (res) { return applyMutateResult(putValues.length, res); }); }).then(function () { return (deleteKeys.length > 0 || (criteria && changes === deleteCallback)) &&
+                                coreTable.mutate({
+                                    trans: trans,
+                                    type: 'delete',
+                                    keys: deleteKeys,
+                                    criteria: criteria
+                                }).then(function (res) { return applyMutateResult(deleteKeys.length, res); }); }).then(function () {
+                                return keys.length > offset + count && nextChunk(offset + limit);
+                            });
+                        });
+                    };
+                    return nextChunk(0).then(function () {
+                        if (totalFailures.length > 0)
+                            throw new ModifyError("Error modifying one or more objects", totalFailures, successCount, failedKeys);
+                        return keys.length;
+                    });
+                });
+            });
+        };
+        Collection.prototype.delete = function () {
+            var ctx = this._ctx, range = ctx.range;
+            if (isPlainKeyRange(ctx) &&
+                ((ctx.isPrimKey && !hangsOnDeleteLargeKeyRange) || range.type === 3 ))
+             {
+                return this._write(function (trans) {
+                    var primaryKey = ctx.table.core.schema.primaryKey;
+                    var coreRange = range;
+                    return ctx.table.core.count({ trans: trans, query: { index: primaryKey, range: coreRange } }).then(function (count) {
+                        return ctx.table.core.mutate({ trans: trans, type: 'deleteRange', range: coreRange })
+                            .then(function (_a) {
+                            var failures = _a.failures; _a.lastResult; _a.results; var numFailures = _a.numFailures;
+                            if (numFailures)
+                                throw new ModifyError("Could not delete some values", Object.keys(failures).map(function (pos) { return failures[pos]; }), count - numFailures);
+                            return count - numFailures;
+                        });
+                    });
+                });
+            }
+            return this.modify(deleteCallback);
+        };
+        return Collection;
+    }());
+    var deleteCallback = function (value, ctx) { return ctx.value = null; };
+
+    function createCollectionConstructor(db) {
+        return makeClassConstructor(Collection.prototype, function Collection(whereClause, keyRangeGenerator) {
+            this.db = db;
+            var keyRange = AnyRange, error = null;
+            if (keyRangeGenerator)
+                try {
+                    keyRange = keyRangeGenerator();
+                }
+                catch (ex) {
+                    error = ex;
+                }
+            var whereCtx = whereClause._ctx;
+            var table = whereCtx.table;
+            var readingHook = table.hook.reading.fire;
+            this._ctx = {
+                table: table,
+                index: whereCtx.index,
+                isPrimKey: (!whereCtx.index || (table.schema.primKey.keyPath && whereCtx.index === table.schema.primKey.name)),
+                range: keyRange,
+                keysOnly: false,
+                dir: "next",
+                unique: "",
+                algorithm: null,
+                filter: null,
+                replayFilter: null,
+                justLimit: true,
+                isMatch: null,
+                offset: 0,
+                limit: Infinity,
+                error: error,
+                or: whereCtx.or,
+                valueMapper: readingHook !== mirror ? readingHook : null
+            };
+        });
+    }
+
+    function simpleCompare(a, b) {
+        return a < b ? -1 : a === b ? 0 : 1;
+    }
+    function simpleCompareReverse(a, b) {
+        return a > b ? -1 : a === b ? 0 : 1;
+    }
+
+    function fail(collectionOrWhereClause, err, T) {
+        var collection = collectionOrWhereClause instanceof WhereClause ?
+            new collectionOrWhereClause.Collection(collectionOrWhereClause) :
+            collectionOrWhereClause;
+        collection._ctx.error = T ? new T(err) : new TypeError(err);
+        return collection;
+    }
+    function emptyCollection(whereClause) {
+        return new whereClause.Collection(whereClause, function () { return rangeEqual(""); }).limit(0);
+    }
+    function upperFactory(dir) {
+        return dir === "next" ?
+            function (s) { return s.toUpperCase(); } :
+            function (s) { return s.toLowerCase(); };
+    }
+    function lowerFactory(dir) {
+        return dir === "next" ?
+            function (s) { return s.toLowerCase(); } :
+            function (s) { return s.toUpperCase(); };
+    }
+    function nextCasing(key, lowerKey, upperNeedle, lowerNeedle, cmp, dir) {
+        var length = Math.min(key.length, lowerNeedle.length);
+        var llp = -1;
+        for (var i = 0; i < length; ++i) {
+            var lwrKeyChar = lowerKey[i];
+            if (lwrKeyChar !== lowerNeedle[i]) {
+                if (cmp(key[i], upperNeedle[i]) < 0)
+                    return key.substr(0, i) + upperNeedle[i] + upperNeedle.substr(i + 1);
+                if (cmp(key[i], lowerNeedle[i]) < 0)
+                    return key.substr(0, i) + lowerNeedle[i] + upperNeedle.substr(i + 1);
+                if (llp >= 0)
+                    return key.substr(0, llp) + lowerKey[llp] + upperNeedle.substr(llp + 1);
+                return null;
+            }
+            if (cmp(key[i], lwrKeyChar) < 0)
+                llp = i;
+        }
+        if (length < lowerNeedle.length && dir === "next")
+            return key + upperNeedle.substr(key.length);
+        if (length < key.length && dir === "prev")
+            return key.substr(0, upperNeedle.length);
+        return (llp < 0 ? null : key.substr(0, llp) + lowerNeedle[llp] + upperNeedle.substr(llp + 1));
+    }
+    function addIgnoreCaseAlgorithm(whereClause, match, needles, suffix) {
+        var upper, lower, compare, upperNeedles, lowerNeedles, direction, nextKeySuffix, needlesLen = needles.length;
+        if (!needles.every(function (s) { return typeof s === 'string'; })) {
+            return fail(whereClause, STRING_EXPECTED);
+        }
+        function initDirection(dir) {
+            upper = upperFactory(dir);
+            lower = lowerFactory(dir);
+            compare = (dir === "next" ? simpleCompare : simpleCompareReverse);
+            var needleBounds = needles.map(function (needle) {
+                return { lower: lower(needle), upper: upper(needle) };
+            }).sort(function (a, b) {
+                return compare(a.lower, b.lower);
+            });
+            upperNeedles = needleBounds.map(function (nb) { return nb.upper; });
+            lowerNeedles = needleBounds.map(function (nb) { return nb.lower; });
+            direction = dir;
+            nextKeySuffix = (dir === "next" ? "" : suffix);
+        }
+        initDirection("next");
+        var c = new whereClause.Collection(whereClause, function () { return createRange(upperNeedles[0], lowerNeedles[needlesLen - 1] + suffix); });
+        c._ondirectionchange = function (direction) {
+            initDirection(direction);
+        };
+        var firstPossibleNeedle = 0;
+        c._addAlgorithm(function (cursor, advance, resolve) {
+            var key = cursor.key;
+            if (typeof key !== 'string')
+                return false;
+            var lowerKey = lower(key);
+            if (match(lowerKey, lowerNeedles, firstPossibleNeedle)) {
+                return true;
+            }
+            else {
+                var lowestPossibleCasing = null;
+                for (var i = firstPossibleNeedle; i < needlesLen; ++i) {
+                    var casing = nextCasing(key, lowerKey, upperNeedles[i], lowerNeedles[i], compare, direction);
+                    if (casing === null && lowestPossibleCasing === null)
+                        firstPossibleNeedle = i + 1;
+                    else if (lowestPossibleCasing === null || compare(lowestPossibleCasing, casing) > 0) {
+                        lowestPossibleCasing = casing;
+                    }
+                }
+                if (lowestPossibleCasing !== null) {
+                    advance(function () { cursor.continue(lowestPossibleCasing + nextKeySuffix); });
+                }
+                else {
+                    advance(resolve);
+                }
+                return false;
+            }
+        });
+        return c;
+    }
+    function createRange(lower, upper, lowerOpen, upperOpen) {
+        return {
+            type: 2 ,
+            lower: lower,
+            upper: upper,
+            lowerOpen: lowerOpen,
+            upperOpen: upperOpen
+        };
+    }
+    function rangeEqual(value) {
+        return {
+            type: 1 ,
+            lower: value,
+            upper: value
+        };
+    }
+
+    var WhereClause =  (function () {
+        function WhereClause() {
+        }
+        Object.defineProperty(WhereClause.prototype, "Collection", {
+            get: function () {
+                return this._ctx.table.db.Collection;
+            },
+            enumerable: false,
+            configurable: true
+        });
+        WhereClause.prototype.between = function (lower, upper, includeLower, includeUpper) {
+            includeLower = includeLower !== false;
+            includeUpper = includeUpper === true;
+            try {
+                if ((this._cmp(lower, upper) > 0) ||
+                    (this._cmp(lower, upper) === 0 && (includeLower || includeUpper) && !(includeLower && includeUpper)))
+                    return emptyCollection(this);
+                return new this.Collection(this, function () { return createRange(lower, upper, !includeLower, !includeUpper); });
+            }
+            catch (e) {
+                return fail(this, INVALID_KEY_ARGUMENT);
+            }
+        };
+        WhereClause.prototype.equals = function (value) {
+            if (value == null)
+                return fail(this, INVALID_KEY_ARGUMENT);
+            return new this.Collection(this, function () { return rangeEqual(value); });
+        };
+        WhereClause.prototype.above = function (value) {
+            if (value == null)
+                return fail(this, INVALID_KEY_ARGUMENT);
+            return new this.Collection(this, function () { return createRange(value, undefined, true); });
+        };
+        WhereClause.prototype.aboveOrEqual = function (value) {
+            if (value == null)
+                return fail(this, INVALID_KEY_ARGUMENT);
+            return new this.Collection(this, function () { return createRange(value, undefined, false); });
+        };
+        WhereClause.prototype.below = function (value) {
+            if (value == null)
+                return fail(this, INVALID_KEY_ARGUMENT);
+            return new this.Collection(this, function () { return createRange(undefined, value, false, true); });
+        };
+        WhereClause.prototype.belowOrEqual = function (value) {
+            if (value == null)
+                return fail(this, INVALID_KEY_ARGUMENT);
+            return new this.Collection(this, function () { return createRange(undefined, value); });
+        };
+        WhereClause.prototype.startsWith = function (str) {
+            if (typeof str !== 'string')
+                return fail(this, STRING_EXPECTED);
+            return this.between(str, str + maxString, true, true);
+        };
+        WhereClause.prototype.startsWithIgnoreCase = function (str) {
+            if (str === "")
+                return this.startsWith(str);
+            return addIgnoreCaseAlgorithm(this, function (x, a) { return x.indexOf(a[0]) === 0; }, [str], maxString);
+        };
+        WhereClause.prototype.equalsIgnoreCase = function (str) {
+            return addIgnoreCaseAlgorithm(this, function (x, a) { return x === a[0]; }, [str], "");
+        };
+        WhereClause.prototype.anyOfIgnoreCase = function () {
+            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
+            if (set.length === 0)
+                return emptyCollection(this);
+            return addIgnoreCaseAlgorithm(this, function (x, a) { return a.indexOf(x) !== -1; }, set, "");
+        };
+        WhereClause.prototype.startsWithAnyOfIgnoreCase = function () {
+            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
+            if (set.length === 0)
+                return emptyCollection(this);
+            return addIgnoreCaseAlgorithm(this, function (x, a) { return a.some(function (n) { return x.indexOf(n) === 0; }); }, set, maxString);
+        };
+        WhereClause.prototype.anyOf = function () {
+            var _this = this;
+            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
+            var compare = this._cmp;
+            try {
+                set.sort(compare);
+            }
+            catch (e) {
+                return fail(this, INVALID_KEY_ARGUMENT);
+            }
+            if (set.length === 0)
+                return emptyCollection(this);
+            var c = new this.Collection(this, function () { return createRange(set[0], set[set.length - 1]); });
+            c._ondirectionchange = function (direction) {
+                compare = (direction === "next" ?
+                    _this._ascending :
+                    _this._descending);
+                set.sort(compare);
+            };
+            var i = 0;
+            c._addAlgorithm(function (cursor, advance, resolve) {
+                var key = cursor.key;
+                while (compare(key, set[i]) > 0) {
+                    ++i;
+                    if (i === set.length) {
+                        advance(resolve);
+                        return false;
+                    }
+                }
+                if (compare(key, set[i]) === 0) {
+                    return true;
+                }
+                else {
+                    advance(function () { cursor.continue(set[i]); });
+                    return false;
+                }
+            });
+            return c;
+        };
+        WhereClause.prototype.notEqual = function (value) {
+            return this.inAnyRange([[minKey, value], [value, this.db._maxKey]], { includeLowers: false, includeUppers: false });
+        };
+        WhereClause.prototype.noneOf = function () {
+            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
+            if (set.length === 0)
+                return new this.Collection(this);
+            try {
+                set.sort(this._ascending);
+            }
+            catch (e) {
+                return fail(this, INVALID_KEY_ARGUMENT);
+            }
+            var ranges = set.reduce(function (res, val) { return res ?
+                res.concat([[res[res.length - 1][1], val]]) :
+                [[minKey, val]]; }, null);
+            ranges.push([set[set.length - 1], this.db._maxKey]);
+            return this.inAnyRange(ranges, { includeLowers: false, includeUppers: false });
+        };
+        WhereClause.prototype.inAnyRange = function (ranges, options) {
+            var _this = this;
+            var cmp = this._cmp, ascending = this._ascending, descending = this._descending, min = this._min, max = this._max;
+            if (ranges.length === 0)
+                return emptyCollection(this);
+            if (!ranges.every(function (range) {
+                return range[0] !== undefined &&
+                    range[1] !== undefined &&
+                    ascending(range[0], range[1]) <= 0;
+            })) {
+                return fail(this, "First argument to inAnyRange() must be an Array of two-value Arrays [lower,upper] where upper must not be lower than lower", exceptions.InvalidArgument);
+            }
+            var includeLowers = !options || options.includeLowers !== false;
+            var includeUppers = options && options.includeUppers === true;
+            function addRange(ranges, newRange) {
+                var i = 0, l = ranges.length;
+                for (; i < l; ++i) {
+                    var range = ranges[i];
+                    if (cmp(newRange[0], range[1]) < 0 && cmp(newRange[1], range[0]) > 0) {
+                        range[0] = min(range[0], newRange[0]);
+                        range[1] = max(range[1], newRange[1]);
+                        break;
+                    }
+                }
+                if (i === l)
+                    ranges.push(newRange);
+                return ranges;
+            }
+            var sortDirection = ascending;
+            function rangeSorter(a, b) { return sortDirection(a[0], b[0]); }
+            var set;
+            try {
+                set = ranges.reduce(addRange, []);
+                set.sort(rangeSorter);
+            }
+            catch (ex) {
+                return fail(this, INVALID_KEY_ARGUMENT);
+            }
+            var rangePos = 0;
+            var keyIsBeyondCurrentEntry = includeUppers ?
+                function (key) { return ascending(key, set[rangePos][1]) > 0; } :
+                function (key) { return ascending(key, set[rangePos][1]) >= 0; };
+            var keyIsBeforeCurrentEntry = includeLowers ?
+                function (key) { return descending(key, set[rangePos][0]) > 0; } :
+                function (key) { return descending(key, set[rangePos][0]) >= 0; };
+            function keyWithinCurrentRange(key) {
+                return !keyIsBeyondCurrentEntry(key) && !keyIsBeforeCurrentEntry(key);
+            }
+            var checkKey = keyIsBeyondCurrentEntry;
+            var c = new this.Collection(this, function () { return createRange(set[0][0], set[set.length - 1][1], !includeLowers, !includeUppers); });
+            c._ondirectionchange = function (direction) {
+                if (direction === "next") {
+                    checkKey = keyIsBeyondCurrentEntry;
+                    sortDirection = ascending;
+                }
+                else {
+                    checkKey = keyIsBeforeCurrentEntry;
+                    sortDirection = descending;
+                }
+                set.sort(rangeSorter);
+            };
+            c._addAlgorithm(function (cursor, advance, resolve) {
+                var key = cursor.key;
+                while (checkKey(key)) {
+                    ++rangePos;
+                    if (rangePos === set.length) {
+                        advance(resolve);
+                        return false;
+                    }
+                }
+                if (keyWithinCurrentRange(key)) {
+                    return true;
+                }
+                else if (_this._cmp(key, set[rangePos][1]) === 0 || _this._cmp(key, set[rangePos][0]) === 0) {
+                    return false;
+                }
+                else {
+                    advance(function () {
+                        if (sortDirection === ascending)
+                            cursor.continue(set[rangePos][0]);
+                        else
+                            cursor.continue(set[rangePos][1]);
+                    });
+                    return false;
+                }
+            });
+            return c;
+        };
+        WhereClause.prototype.startsWithAnyOf = function () {
+            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
+            if (!set.every(function (s) { return typeof s === 'string'; })) {
+                return fail(this, "startsWithAnyOf() only works with strings");
+            }
+            if (set.length === 0)
+                return emptyCollection(this);
+            return this.inAnyRange(set.map(function (str) { return [str, str + maxString]; }));
+        };
+        return WhereClause;
+    }());
+
+    function createWhereClauseConstructor(db) {
+        return makeClassConstructor(WhereClause.prototype, function WhereClause(table, index, orCollection) {
+            this.db = db;
+            this._ctx = {
+                table: table,
+                index: index === ":id" ? null : index,
+                or: orCollection
+            };
+            var indexedDB = db._deps.indexedDB;
+            if (!indexedDB)
+                throw new exceptions.MissingAPI();
+            this._cmp = this._ascending = indexedDB.cmp.bind(indexedDB);
+            this._descending = function (a, b) { return indexedDB.cmp(b, a); };
+            this._max = function (a, b) { return indexedDB.cmp(a, b) > 0 ? a : b; };
+            this._min = function (a, b) { return indexedDB.cmp(a, b) < 0 ? a : b; };
+            this._IDBKeyRange = db._deps.IDBKeyRange;
+        });
+    }
+
+    function eventRejectHandler(reject) {
+        return wrap(function (event) {
+            preventDefault(event);
+            reject(event.target.error);
+            return false;
+        });
+    }
+    function preventDefault(event) {
+        if (event.stopPropagation)
+            event.stopPropagation();
+        if (event.preventDefault)
+            event.preventDefault();
+    }
+
+    var DEXIE_STORAGE_MUTATED_EVENT_NAME = 'storagemutated';
+    var STORAGE_MUTATED_DOM_EVENT_NAME = 'x-storagemutated-1';
+    var globalEvents = Events(null, DEXIE_STORAGE_MUTATED_EVENT_NAME);
+
+    var Transaction =  (function () {
+        function Transaction() {
+        }
+        Transaction.prototype._lock = function () {
+            assert(!PSD.global);
+            ++this._reculock;
+            if (this._reculock === 1 && !PSD.global)
+                PSD.lockOwnerFor = this;
+            return this;
+        };
+        Transaction.prototype._unlock = function () {
+            assert(!PSD.global);
+            if (--this._reculock === 0) {
+                if (!PSD.global)
+                    PSD.lockOwnerFor = null;
+                while (this._blockedFuncs.length > 0 && !this._locked()) {
+                    var fnAndPSD = this._blockedFuncs.shift();
+                    try {
+                        usePSD(fnAndPSD[1], fnAndPSD[0]);
+                    }
+                    catch (e) { }
+                }
+            }
+            return this;
+        };
+        Transaction.prototype._locked = function () {
+            return this._reculock && PSD.lockOwnerFor !== this;
+        };
+        Transaction.prototype.create = function (idbtrans) {
+            var _this = this;
+            if (!this.mode)
+                return this;
+            var idbdb = this.db.idbdb;
+            var dbOpenError = this.db._state.dbOpenError;
+            assert(!this.idbtrans);
+            if (!idbtrans && !idbdb) {
+                switch (dbOpenError && dbOpenError.name) {
+                    case "DatabaseClosedError":
+                        throw new exceptions.DatabaseClosed(dbOpenError);
+                    case "MissingAPIError":
+                        throw new exceptions.MissingAPI(dbOpenError.message, dbOpenError);
+                    default:
+                        throw new exceptions.OpenFailed(dbOpenError);
+                }
+            }
+            if (!this.active)
+                throw new exceptions.TransactionInactive();
+            assert(this._completion._state === null);
+            idbtrans = this.idbtrans = idbtrans ||
+                (this.db.core
+                    ? this.db.core.transaction(this.storeNames, this.mode, { durability: this.chromeTransactionDurability })
+                    : idbdb.transaction(this.storeNames, this.mode, { durability: this.chromeTransactionDurability }));
+            idbtrans.onerror = wrap(function (ev) {
+                preventDefault(ev);
+                _this._reject(idbtrans.error);
+            });
+            idbtrans.onabort = wrap(function (ev) {
+                preventDefault(ev);
+                _this.active && _this._reject(new exceptions.Abort(idbtrans.error));
+                _this.active = false;
+                _this.on("abort").fire(ev);
+            });
+            idbtrans.oncomplete = wrap(function () {
+                _this.active = false;
+                _this._resolve();
+                if ('mutatedParts' in idbtrans) {
+                    globalEvents.storagemutated.fire(idbtrans["mutatedParts"]);
+                }
+            });
+            return this;
+        };
+        Transaction.prototype._promise = function (mode, fn, bWriteLock) {
+            var _this = this;
+            if (mode === 'readwrite' && this.mode !== 'readwrite')
+                return rejection(new exceptions.ReadOnly("Transaction is readonly"));
+            if (!this.active)
+                return rejection(new exceptions.TransactionInactive());
+            if (this._locked()) {
+                return new DexiePromise(function (resolve, reject) {
+                    _this._blockedFuncs.push([function () {
+                            _this._promise(mode, fn, bWriteLock).then(resolve, reject);
+                        }, PSD]);
+                });
+            }
+            else if (bWriteLock) {
+                return newScope(function () {
+                    var p = new DexiePromise(function (resolve, reject) {
+                        _this._lock();
+                        var rv = fn(resolve, reject, _this);
+                        if (rv && rv.then)
+                            rv.then(resolve, reject);
+                    });
+                    p.finally(function () { return _this._unlock(); });
+                    p._lib = true;
+                    return p;
+                });
+            }
+            else {
+                var p = new DexiePromise(function (resolve, reject) {
+                    var rv = fn(resolve, reject, _this);
+                    if (rv && rv.then)
+                        rv.then(resolve, reject);
+                });
+                p._lib = true;
+                return p;
+            }
+        };
+        Transaction.prototype._root = function () {
+            return this.parent ? this.parent._root() : this;
+        };
+        Transaction.prototype.waitFor = function (promiseLike) {
+            var root = this._root();
+            var promise = DexiePromise.resolve(promiseLike);
+            if (root._waitingFor) {
+                root._waitingFor = root._waitingFor.then(function () { return promise; });
+            }
+            else {
+                root._waitingFor = promise;
+                root._waitingQueue = [];
+                var store = root.idbtrans.objectStore(root.storeNames[0]);
+                (function spin() {
+                    ++root._spinCount;
+                    while (root._waitingQueue.length)
+                        (root._waitingQueue.shift())();
+                    if (root._waitingFor)
+                        store.get(-Infinity).onsuccess = spin;
+                }());
+            }
+            var currentWaitPromise = root._waitingFor;
+            return new DexiePromise(function (resolve, reject) {
+                promise.then(function (res) { return root._waitingQueue.push(wrap(resolve.bind(null, res))); }, function (err) { return root._waitingQueue.push(wrap(reject.bind(null, err))); }).finally(function () {
+                    if (root._waitingFor === currentWaitPromise) {
+                        root._waitingFor = null;
+                    }
+                });
+            });
+        };
+        Transaction.prototype.abort = function () {
+            if (this.active) {
+                this.active = false;
+                if (this.idbtrans)
+                    this.idbtrans.abort();
+                this._reject(new exceptions.Abort());
+            }
+        };
+        Transaction.prototype.table = function (tableName) {
+            var memoizedTables = (this._memoizedTables || (this._memoizedTables = {}));
+            if (hasOwn(memoizedTables, tableName))
+                return memoizedTables[tableName];
+            var tableSchema = this.schema[tableName];
+            if (!tableSchema) {
+                throw new exceptions.NotFound("Table " + tableName + " not part of transaction");
+            }
+            var transactionBoundTable = new this.db.Table(tableName, tableSchema, this);
+            transactionBoundTable.core = this.db.core.table(tableName);
+            memoizedTables[tableName] = transactionBoundTable;
+            return transactionBoundTable;
+        };
+        return Transaction;
+    }());
+
+    function createTransactionConstructor(db) {
+        return makeClassConstructor(Transaction.prototype, function Transaction(mode, storeNames, dbschema, chromeTransactionDurability, parent) {
+            var _this = this;
+            this.db = db;
+            this.mode = mode;
+            this.storeNames = storeNames;
+            this.schema = dbschema;
+            this.chromeTransactionDurability = chromeTransactionDurability;
+            this.idbtrans = null;
+            this.on = Events(this, "complete", "error", "abort");
+            this.parent = parent || null;
+            this.active = true;
+            this._reculock = 0;
+            this._blockedFuncs = [];
+            this._resolve = null;
+            this._reject = null;
+            this._waitingFor = null;
+            this._waitingQueue = null;
+            this._spinCount = 0;
+            this._completion = new DexiePromise(function (resolve, reject) {
+                _this._resolve = resolve;
+                _this._reject = reject;
+            });
+            this._completion.then(function () {
+                _this.active = false;
+                _this.on.complete.fire();
+            }, function (e) {
+                var wasActive = _this.active;
+                _this.active = false;
+                _this.on.error.fire(e);
+                _this.parent ?
+                    _this.parent._reject(e) :
+                    wasActive && _this.idbtrans && _this.idbtrans.abort();
+                return rejection(e);
+            });
+        });
+    }
+
+    function createIndexSpec(name, keyPath, unique, multi, auto, compound, isPrimKey) {
+        return {
+            name: name,
+            keyPath: keyPath,
+            unique: unique,
+            multi: multi,
+            auto: auto,
+            compound: compound,
+            src: (unique && !isPrimKey ? '&' : '') + (multi ? '*' : '') + (auto ? "++" : "") + nameFromKeyPath(keyPath)
+        };
+    }
+    function nameFromKeyPath(keyPath) {
+        return typeof keyPath === 'string' ?
+            keyPath :
+            keyPath ? ('[' + [].join.call(keyPath, '+') + ']') : "";
+    }
+
+    function createTableSchema(name, primKey, indexes) {
+        return {
+            name: name,
+            primKey: primKey,
+            indexes: indexes,
+            mappedClass: null,
+            idxByName: arrayToObject(indexes, function (index) { return [index.name, index]; })
+        };
+    }
+
+    function safariMultiStoreFix(storeNames) {
+        return storeNames.length === 1 ? storeNames[0] : storeNames;
+    }
+    var getMaxKey = function (IdbKeyRange) {
+        try {
+            IdbKeyRange.only([[]]);
+            getMaxKey = function () { return [[]]; };
+            return [[]];
+        }
+        catch (e) {
+            getMaxKey = function () { return maxString; };
+            return maxString;
+        }
+    };
+
+    function getKeyExtractor(keyPath) {
+        if (keyPath == null) {
+            return function () { return undefined; };
+        }
+        else if (typeof keyPath === 'string') {
+            return getSinglePathKeyExtractor(keyPath);
+        }
+        else {
+            return function (obj) { return getByKeyPath(obj, keyPath); };
+        }
+    }
+    function getSinglePathKeyExtractor(keyPath) {
+        var split = keyPath.split('.');
+        if (split.length === 1) {
+            return function (obj) { return obj[keyPath]; };
+        }
+        else {
+            return function (obj) { return getByKeyPath(obj, keyPath); };
+        }
+    }
+
+    function arrayify(arrayLike) {
+        return [].slice.call(arrayLike);
+    }
+    var _id_counter = 0;
+    function getKeyPathAlias(keyPath) {
+        return keyPath == null ?
+            ":id" :
+            typeof keyPath === 'string' ?
+                keyPath :
+                "[" + keyPath.join('+') + "]";
+    }
+    function createDBCore(db, IdbKeyRange, tmpTrans) {
+        function extractSchema(db, trans) {
+            var tables = arrayify(db.objectStoreNames);
+            return {
+                schema: {
+                    name: db.name,
+                    tables: tables.map(function (table) { return trans.objectStore(table); }).map(function (store) {
+                        var keyPath = store.keyPath, autoIncrement = store.autoIncrement;
+                        var compound = isArray(keyPath);
+                        var outbound = keyPath == null;
+                        var indexByKeyPath = {};
+                        var result = {
+                            name: store.name,
+                            primaryKey: {
+                                name: null,
+                                isPrimaryKey: true,
+                                outbound: outbound,
+                                compound: compound,
+                                keyPath: keyPath,
+                                autoIncrement: autoIncrement,
+                                unique: true,
+                                extractKey: getKeyExtractor(keyPath)
+                            },
+                            indexes: arrayify(store.indexNames).map(function (indexName) { return store.index(indexName); })
+                                .map(function (index) {
+                                var name = index.name, unique = index.unique, multiEntry = index.multiEntry, keyPath = index.keyPath;
+                                var compound = isArray(keyPath);
+                                var result = {
+                                    name: name,
+                                    compound: compound,
+                                    keyPath: keyPath,
+                                    unique: unique,
+                                    multiEntry: multiEntry,
+                                    extractKey: getKeyExtractor(keyPath)
+                                };
+                                indexByKeyPath[getKeyPathAlias(keyPath)] = result;
+                                return result;
+                            }),
+                            getIndexByKeyPath: function (keyPath) { return indexByKeyPath[getKeyPathAlias(keyPath)]; }
+                        };
+                        indexByKeyPath[":id"] = result.primaryKey;
+                        if (keyPath != null) {
+                            indexByKeyPath[getKeyPathAlias(keyPath)] = result.primaryKey;
+                        }
+                        return result;
+                    })
+                },
+                hasGetAll: tables.length > 0 && ('getAll' in trans.objectStore(tables[0])) &&
+                    !(typeof navigator !== 'undefined' && /Safari/.test(navigator.userAgent) &&
+                        !/(Chrome\/|Edge\/)/.test(navigator.userAgent) &&
+                        [].concat(navigator.userAgent.match(/Safari\/(\d*)/))[1] < 604)
+            };
+        }
+        function makeIDBKeyRange(range) {
+            if (range.type === 3 )
+                return null;
+            if (range.type === 4 )
+                throw new Error("Cannot convert never type to IDBKeyRange");
+            var lower = range.lower, upper = range.upper, lowerOpen = range.lowerOpen, upperOpen = range.upperOpen;
+            var idbRange = lower === undefined ?
+                upper === undefined ?
+                    null :
+                    IdbKeyRange.upperBound(upper, !!upperOpen) :
+                upper === undefined ?
+                    IdbKeyRange.lowerBound(lower, !!lowerOpen) :
+                    IdbKeyRange.bound(lower, upper, !!lowerOpen, !!upperOpen);
+            return idbRange;
+        }
+        function createDbCoreTable(tableSchema) {
+            var tableName = tableSchema.name;
+            function mutate(_a) {
+                var trans = _a.trans, type = _a.type, keys = _a.keys, values = _a.values, range = _a.range;
+                return new Promise(function (resolve, reject) {
+                    resolve = wrap(resolve);
+                    var store = trans.objectStore(tableName);
+                    var outbound = store.keyPath == null;
+                    var isAddOrPut = type === "put" || type === "add";
+                    if (!isAddOrPut && type !== 'delete' && type !== 'deleteRange')
+                        throw new Error("Invalid operation type: " + type);
+                    var length = (keys || values || { length: 1 }).length;
+                    if (keys && values && keys.length !== values.length) {
+                        throw new Error("Given keys array must have same length as given values array.");
+                    }
+                    if (length === 0)
+                        return resolve({ numFailures: 0, failures: {}, results: [], lastResult: undefined });
+                    var req;
+                    var reqs = [];
+                    var failures = [];
+                    var numFailures = 0;
+                    var errorHandler = function (event) {
+                        ++numFailures;
+                        preventDefault(event);
+                    };
+                    if (type === 'deleteRange') {
+                        if (range.type === 4 )
+                            return resolve({ numFailures: numFailures, failures: failures, results: [], lastResult: undefined });
+                        if (range.type === 3 )
+                            reqs.push(req = store.clear());
+                        else
+                            reqs.push(req = store.delete(makeIDBKeyRange(range)));
+                    }
+                    else {
+                        var _a = isAddOrPut ?
+                            outbound ?
+                                [values, keys] :
+                                [values, null] :
+                            [keys, null], args1 = _a[0], args2 = _a[1];
+                        if (isAddOrPut) {
+                            for (var i = 0; i < length; ++i) {
+                                reqs.push(req = (args2 && args2[i] !== undefined ?
+                                    store[type](args1[i], args2[i]) :
+                                    store[type](args1[i])));
+                                req.onerror = errorHandler;
+                            }
+                        }
+                        else {
+                            for (var i = 0; i < length; ++i) {
+                                reqs.push(req = store[type](args1[i]));
+                                req.onerror = errorHandler;
+                            }
+                        }
+                    }
+                    var done = function (event) {
+                        var lastResult = event.target.result;
+                        reqs.forEach(function (req, i) { return req.error != null && (failures[i] = req.error); });
+                        resolve({
+                            numFailures: numFailures,
+                            failures: failures,
+                            results: type === "delete" ? keys : reqs.map(function (req) { return req.result; }),
+                            lastResult: lastResult
+                        });
+                    };
+                    req.onerror = function (event) {
+                        errorHandler(event);
+                        done(event);
+                    };
+                    req.onsuccess = done;
+                });
+            }
+            function openCursor(_a) {
+                var trans = _a.trans, values = _a.values, query = _a.query, reverse = _a.reverse, unique = _a.unique;
+                return new Promise(function (resolve, reject) {
+                    resolve = wrap(resolve);
+                    var index = query.index, range = query.range;
+                    var store = trans.objectStore(tableName);
+                    var source = index.isPrimaryKey ?
+                        store :
+                        store.index(index.name);
+                    var direction = reverse ?
+                        unique ?
+                            "prevunique" :
+                            "prev" :
+                        unique ?
+                            "nextunique" :
+                            "next";
+                    var req = values || !('openKeyCursor' in source) ?
+                        source.openCursor(makeIDBKeyRange(range), direction) :
+                        source.openKeyCursor(makeIDBKeyRange(range), direction);
+                    req.onerror = eventRejectHandler(reject);
+                    req.onsuccess = wrap(function (ev) {
+                        var cursor = req.result;
+                        if (!cursor) {
+                            resolve(null);
+                            return;
+                        }
+                        cursor.___id = ++_id_counter;
+                        cursor.done = false;
+                        var _cursorContinue = cursor.continue.bind(cursor);
+                        var _cursorContinuePrimaryKey = cursor.continuePrimaryKey;
+                        if (_cursorContinuePrimaryKey)
+                            _cursorContinuePrimaryKey = _cursorContinuePrimaryKey.bind(cursor);
+                        var _cursorAdvance = cursor.advance.bind(cursor);
+                        var doThrowCursorIsNotStarted = function () { throw new Error("Cursor not started"); };
+                        var doThrowCursorIsStopped = function () { throw new Error("Cursor not stopped"); };
+                        cursor.trans = trans;
+                        cursor.stop = cursor.continue = cursor.continuePrimaryKey = cursor.advance = doThrowCursorIsNotStarted;
+                        cursor.fail = wrap(reject);
+                        cursor.next = function () {
+                            var _this = this;
+                            var gotOne = 1;
+                            return this.start(function () { return gotOne-- ? _this.continue() : _this.stop(); }).then(function () { return _this; });
+                        };
+                        cursor.start = function (callback) {
+                            var iterationPromise = new Promise(function (resolveIteration, rejectIteration) {
+                                resolveIteration = wrap(resolveIteration);
+                                req.onerror = eventRejectHandler(rejectIteration);
+                                cursor.fail = rejectIteration;
+                                cursor.stop = function (value) {
+                                    cursor.stop = cursor.continue = cursor.continuePrimaryKey = cursor.advance = doThrowCursorIsStopped;
+                                    resolveIteration(value);
+                                };
+                            });
+                            var guardedCallback = function () {
+                                if (req.result) {
+                                    try {
+                                        callback();
+                                    }
+                                    catch (err) {
+                                        cursor.fail(err);
+                                    }
+                                }
+                                else {
+                                    cursor.done = true;
+                                    cursor.start = function () { throw new Error("Cursor behind last entry"); };
+                                    cursor.stop();
+                                }
+                            };
+                            req.onsuccess = wrap(function (ev) {
+                                req.onsuccess = guardedCallback;
+                                guardedCallback();
+                            });
+                            cursor.continue = _cursorContinue;
+                            cursor.continuePrimaryKey = _cursorContinuePrimaryKey;
+                            cursor.advance = _cursorAdvance;
+                            guardedCallback();
+                            return iterationPromise;
+                        };
+                        resolve(cursor);
+                    }, reject);
+                });
+            }
+            function query(hasGetAll) {
+                return function (request) {
+                    return new Promise(function (resolve, reject) {
+                        resolve = wrap(resolve);
+                        var trans = request.trans, values = request.values, limit = request.limit, query = request.query;
+                        var nonInfinitLimit = limit === Infinity ? undefined : limit;
+                        var index = query.index, range = query.range;
+                        var store = trans.objectStore(tableName);
+                        var source = index.isPrimaryKey ? store : store.index(index.name);
+                        var idbKeyRange = makeIDBKeyRange(range);
+                        if (limit === 0)
+                            return resolve({ result: [] });
+                        if (hasGetAll) {
+                            var req = values ?
+                                source.getAll(idbKeyRange, nonInfinitLimit) :
+                                source.getAllKeys(idbKeyRange, nonInfinitLimit);
+                            req.onsuccess = function (event) { return resolve({ result: event.target.result }); };
+                            req.onerror = eventRejectHandler(reject);
+                        }
+                        else {
+                            var count_1 = 0;
+                            var req_1 = values || !('openKeyCursor' in source) ?
+                                source.openCursor(idbKeyRange) :
+                                source.openKeyCursor(idbKeyRange);
+                            var result_1 = [];
+                            req_1.onsuccess = function (event) {
+                                var cursor = req_1.result;
+                                if (!cursor)
+                                    return resolve({ result: result_1 });
+                                result_1.push(values ? cursor.value : cursor.primaryKey);
+                                if (++count_1 === limit)
+                                    return resolve({ result: result_1 });
+                                cursor.continue();
+                            };
+                            req_1.onerror = eventRejectHandler(reject);
+                        }
+                    });
+                };
+            }
+            return {
+                name: tableName,
+                schema: tableSchema,
+                mutate: mutate,
+                getMany: function (_a) {
+                    var trans = _a.trans, keys = _a.keys;
+                    return new Promise(function (resolve, reject) {
+                        resolve = wrap(resolve);
+                        var store = trans.objectStore(tableName);
+                        var length = keys.length;
+                        var result = new Array(length);
+                        var keyCount = 0;
+                        var callbackCount = 0;
+                        var req;
+                        var successHandler = function (event) {
+                            var req = event.target;
+                            if ((result[req._pos] = req.result) != null)
+                                ;
+                            if (++callbackCount === keyCount)
+                                resolve(result);
+                        };
+                        var errorHandler = eventRejectHandler(reject);
+                        for (var i = 0; i < length; ++i) {
+                            var key = keys[i];
+                            if (key != null) {
+                                req = store.get(keys[i]);
+                                req._pos = i;
+                                req.onsuccess = successHandler;
+                                req.onerror = errorHandler;
+                                ++keyCount;
+                            }
+                        }
+                        if (keyCount === 0)
+                            resolve(result);
+                    });
+                },
+                get: function (_a) {
+                    var trans = _a.trans, key = _a.key;
+                    return new Promise(function (resolve, reject) {
+                        resolve = wrap(resolve);
+                        var store = trans.objectStore(tableName);
+                        var req = store.get(key);
+                        req.onsuccess = function (event) { return resolve(event.target.result); };
+                        req.onerror = eventRejectHandler(reject);
+                    });
+                },
+                query: query(hasGetAll),
+                openCursor: openCursor,
+                count: function (_a) {
+                    var query = _a.query, trans = _a.trans;
+                    var index = query.index, range = query.range;
+                    return new Promise(function (resolve, reject) {
+                        var store = trans.objectStore(tableName);
+                        var source = index.isPrimaryKey ? store : store.index(index.name);
+                        var idbKeyRange = makeIDBKeyRange(range);
+                        var req = idbKeyRange ? source.count(idbKeyRange) : source.count();
+                        req.onsuccess = wrap(function (ev) { return resolve(ev.target.result); });
+                        req.onerror = eventRejectHandler(reject);
+                    });
+                }
+            };
+        }
+        var _a = extractSchema(db, tmpTrans), schema = _a.schema, hasGetAll = _a.hasGetAll;
+        var tables = schema.tables.map(function (tableSchema) { return createDbCoreTable(tableSchema); });
+        var tableMap = {};
+        tables.forEach(function (table) { return tableMap[table.name] = table; });
+        return {
+            stack: "dbcore",
+            transaction: db.transaction.bind(db),
+            table: function (name) {
+                var result = tableMap[name];
+                if (!result)
+                    throw new Error("Table '" + name + "' not found");
+                return tableMap[name];
+            },
+            MIN_KEY: -Infinity,
+            MAX_KEY: getMaxKey(IdbKeyRange),
+            schema: schema
+        };
+    }
+
+    function createMiddlewareStack(stackImpl, middlewares) {
+        return middlewares.reduce(function (down, _a) {
+            var create = _a.create;
+            return (__assign(__assign({}, down), create(down)));
+        }, stackImpl);
+    }
+    function createMiddlewareStacks(middlewares, idbdb, _a, tmpTrans) {
+        var IDBKeyRange = _a.IDBKeyRange; _a.indexedDB;
+        var dbcore = createMiddlewareStack(createDBCore(idbdb, IDBKeyRange, tmpTrans), middlewares.dbcore);
+        return {
+            dbcore: dbcore
+        };
+    }
+    function generateMiddlewareStacks(_a, tmpTrans) {
+        var db = _a._novip;
+        var idbdb = tmpTrans.db;
+        var stacks = createMiddlewareStacks(db._middlewares, idbdb, db._deps, tmpTrans);
+        db.core = stacks.dbcore;
+        db.tables.forEach(function (table) {
+            var tableName = table.name;
+            if (db.core.schema.tables.some(function (tbl) { return tbl.name === tableName; })) {
+                table.core = db.core.table(tableName);
+                if (db[tableName] instanceof db.Table) {
+                    db[tableName].core = table.core;
+                }
+            }
+        });
+    }
+
+    function setApiOnPlace(_a, objs, tableNames, dbschema) {
+        var db = _a._novip;
+        tableNames.forEach(function (tableName) {
+            var schema = dbschema[tableName];
+            objs.forEach(function (obj) {
+                var propDesc = getPropertyDescriptor(obj, tableName);
+                if (!propDesc || ("value" in propDesc && propDesc.value === undefined)) {
+                    if (obj === db.Transaction.prototype || obj instanceof db.Transaction) {
+                        setProp(obj, tableName, {
+                            get: function () { return this.table(tableName); },
+                            set: function (value) {
+                                defineProperty(this, tableName, { value: value, writable: true, configurable: true, enumerable: true });
+                            }
+                        });
+                    }
+                    else {
+                        obj[tableName] = new db.Table(tableName, schema);
+                    }
+                }
+            });
+        });
+    }
+    function removeTablesApi(_a, objs) {
+        var db = _a._novip;
+        objs.forEach(function (obj) {
+            for (var key in obj) {
+                if (obj[key] instanceof db.Table)
+                    delete obj[key];
+            }
+        });
+    }
+    function lowerVersionFirst(a, b) {
+        return a._cfg.version - b._cfg.version;
+    }
+    function runUpgraders(db, oldVersion, idbUpgradeTrans, reject) {
+        var globalSchema = db._dbSchema;
+        var trans = db._createTransaction('readwrite', db._storeNames, globalSchema);
+        trans.create(idbUpgradeTrans);
+        trans._completion.catch(reject);
+        var rejectTransaction = trans._reject.bind(trans);
+        var transless = PSD.transless || PSD;
+        newScope(function () {
+            PSD.trans = trans;
+            PSD.transless = transless;
+            if (oldVersion === 0) {
+                keys(globalSchema).forEach(function (tableName) {
+                    createTable(idbUpgradeTrans, tableName, globalSchema[tableName].primKey, globalSchema[tableName].indexes);
+                });
+                generateMiddlewareStacks(db, idbUpgradeTrans);
+                DexiePromise.follow(function () { return db.on.populate.fire(trans); }).catch(rejectTransaction);
+            }
+            else
+                updateTablesAndIndexes(db, oldVersion, trans, idbUpgradeTrans).catch(rejectTransaction);
+        });
+    }
+    function updateTablesAndIndexes(_a, oldVersion, trans, idbUpgradeTrans) {
+        var db = _a._novip;
+        var queue = [];
+        var versions = db._versions;
+        var globalSchema = db._dbSchema = buildGlobalSchema(db, db.idbdb, idbUpgradeTrans);
+        var anyContentUpgraderHasRun = false;
+        var versToRun = versions.filter(function (v) { return v._cfg.version >= oldVersion; });
+        versToRun.forEach(function (version) {
+            queue.push(function () {
+                var oldSchema = globalSchema;
+                var newSchema = version._cfg.dbschema;
+                adjustToExistingIndexNames(db, oldSchema, idbUpgradeTrans);
+                adjustToExistingIndexNames(db, newSchema, idbUpgradeTrans);
+                globalSchema = db._dbSchema = newSchema;
+                var diff = getSchemaDiff(oldSchema, newSchema);
+                diff.add.forEach(function (tuple) {
+                    createTable(idbUpgradeTrans, tuple[0], tuple[1].primKey, tuple[1].indexes);
+                });
+                diff.change.forEach(function (change) {
+                    if (change.recreate) {
+                        throw new exceptions.Upgrade("Not yet support for changing primary key");
+                    }
+                    else {
+                        var store_1 = idbUpgradeTrans.objectStore(change.name);
+                        change.add.forEach(function (idx) { return addIndex(store_1, idx); });
+                        change.change.forEach(function (idx) {
+                            store_1.deleteIndex(idx.name);
+                            addIndex(store_1, idx);
+                        });
+                        change.del.forEach(function (idxName) { return store_1.deleteIndex(idxName); });
+                    }
+                });
+                var contentUpgrade = version._cfg.contentUpgrade;
+                if (contentUpgrade && version._cfg.version > oldVersion) {
+                    generateMiddlewareStacks(db, idbUpgradeTrans);
+                    trans._memoizedTables = {};
+                    anyContentUpgraderHasRun = true;
+                    var upgradeSchema_1 = shallowClone(newSchema);
+                    diff.del.forEach(function (table) {
+                        upgradeSchema_1[table] = oldSchema[table];
+                    });
+                    removeTablesApi(db, [db.Transaction.prototype]);
+                    setApiOnPlace(db, [db.Transaction.prototype], keys(upgradeSchema_1), upgradeSchema_1);
+                    trans.schema = upgradeSchema_1;
+                    var contentUpgradeIsAsync_1 = isAsyncFunction(contentUpgrade);
+                    if (contentUpgradeIsAsync_1) {
+                        incrementExpectedAwaits();
+                    }
+                    var returnValue_1;
+                    var promiseFollowed = DexiePromise.follow(function () {
+                        returnValue_1 = contentUpgrade(trans);
+                        if (returnValue_1) {
+                            if (contentUpgradeIsAsync_1) {
+                                var decrementor = decrementExpectedAwaits.bind(null, null);
+                                returnValue_1.then(decrementor, decrementor);
+                            }
+                        }
+                    });
+                    return (returnValue_1 && typeof returnValue_1.then === 'function' ?
+                        DexiePromise.resolve(returnValue_1) : promiseFollowed.then(function () { return returnValue_1; }));
+                }
+            });
+            queue.push(function (idbtrans) {
+                if (!anyContentUpgraderHasRun || !hasIEDeleteObjectStoreBug) {
+                    var newSchema = version._cfg.dbschema;
+                    deleteRemovedTables(newSchema, idbtrans);
+                }
+                removeTablesApi(db, [db.Transaction.prototype]);
+                setApiOnPlace(db, [db.Transaction.prototype], db._storeNames, db._dbSchema);
+                trans.schema = db._dbSchema;
+            });
+        });
+        function runQueue() {
+            return queue.length ? DexiePromise.resolve(queue.shift()(trans.idbtrans)).then(runQueue) :
+                DexiePromise.resolve();
+        }
+        return runQueue().then(function () {
+            createMissingTables(globalSchema, idbUpgradeTrans);
+        });
+    }
+    function getSchemaDiff(oldSchema, newSchema) {
+        var diff = {
+            del: [],
+            add: [],
+            change: []
+        };
+        var table;
+        for (table in oldSchema) {
+            if (!newSchema[table])
+                diff.del.push(table);
+        }
+        for (table in newSchema) {
+            var oldDef = oldSchema[table], newDef = newSchema[table];
+            if (!oldDef) {
+                diff.add.push([table, newDef]);
+            }
+            else {
+                var change = {
+                    name: table,
+                    def: newDef,
+                    recreate: false,
+                    del: [],
+                    add: [],
+                    change: []
+                };
+                if ((
+                '' + (oldDef.primKey.keyPath || '')) !== ('' + (newDef.primKey.keyPath || '')) ||
+                    (oldDef.primKey.auto !== newDef.primKey.auto && !isIEOrEdge))
+                 {
+                    change.recreate = true;
+                    diff.change.push(change);
+                }
+                else {
+                    var oldIndexes = oldDef.idxByName;
+                    var newIndexes = newDef.idxByName;
+                    var idxName = void 0;
+                    for (idxName in oldIndexes) {
+                        if (!newIndexes[idxName])
+                            change.del.push(idxName);
+                    }
+                    for (idxName in newIndexes) {
+                        var oldIdx = oldIndexes[idxName], newIdx = newIndexes[idxName];
+                        if (!oldIdx)
+                            change.add.push(newIdx);
+                        else if (oldIdx.src !== newIdx.src)
+                            change.change.push(newIdx);
+                    }
+                    if (change.del.length > 0 || change.add.length > 0 || change.change.length > 0) {
+                        diff.change.push(change);
+                    }
+                }
+            }
+        }
+        return diff;
+    }
+    function createTable(idbtrans, tableName, primKey, indexes) {
+        var store = idbtrans.db.createObjectStore(tableName, primKey.keyPath ?
+            { keyPath: primKey.keyPath, autoIncrement: primKey.auto } :
+            { autoIncrement: primKey.auto });
+        indexes.forEach(function (idx) { return addIndex(store, idx); });
+        return store;
+    }
+    function createMissingTables(newSchema, idbtrans) {
+        keys(newSchema).forEach(function (tableName) {
+            if (!idbtrans.db.objectStoreNames.contains(tableName)) {
+                createTable(idbtrans, tableName, newSchema[tableName].primKey, newSchema[tableName].indexes);
+            }
+        });
+    }
+    function deleteRemovedTables(newSchema, idbtrans) {
+        [].slice.call(idbtrans.db.objectStoreNames).forEach(function (storeName) {
+            return newSchema[storeName] == null && idbtrans.db.deleteObjectStore(storeName);
+        });
+    }
+    function addIndex(store, idx) {
+        store.createIndex(idx.name, idx.keyPath, { unique: idx.unique, multiEntry: idx.multi });
+    }
+    function buildGlobalSchema(db, idbdb, tmpTrans) {
+        var globalSchema = {};
+        var dbStoreNames = slice(idbdb.objectStoreNames, 0);
+        dbStoreNames.forEach(function (storeName) {
+            var store = tmpTrans.objectStore(storeName);
+            var keyPath = store.keyPath;
+            var primKey = createIndexSpec(nameFromKeyPath(keyPath), keyPath || "", false, false, !!store.autoIncrement, keyPath && typeof keyPath !== "string", true);
+            var indexes = [];
+            for (var j = 0; j < store.indexNames.length; ++j) {
+                var idbindex = store.index(store.indexNames[j]);
+                keyPath = idbindex.keyPath;
+                var index = createIndexSpec(idbindex.name, keyPath, !!idbindex.unique, !!idbindex.multiEntry, false, keyPath && typeof keyPath !== "string", false);
+                indexes.push(index);
+            }
+            globalSchema[storeName] = createTableSchema(storeName, primKey, indexes);
+        });
+        return globalSchema;
+    }
+    function readGlobalSchema(_a, idbdb, tmpTrans) {
+        var db = _a._novip;
+        db.verno = idbdb.version / 10;
+        var globalSchema = db._dbSchema = buildGlobalSchema(db, idbdb, tmpTrans);
+        db._storeNames = slice(idbdb.objectStoreNames, 0);
+        setApiOnPlace(db, [db._allTables], keys(globalSchema), globalSchema);
+    }
+    function verifyInstalledSchema(db, tmpTrans) {
+        var installedSchema = buildGlobalSchema(db, db.idbdb, tmpTrans);
+        var diff = getSchemaDiff(installedSchema, db._dbSchema);
+        return !(diff.add.length || diff.change.some(function (ch) { return ch.add.length || ch.change.length; }));
+    }
+    function adjustToExistingIndexNames(_a, schema, idbtrans) {
+        var db = _a._novip;
+        var storeNames = idbtrans.db.objectStoreNames;
+        for (var i = 0; i < storeNames.length; ++i) {
+            var storeName = storeNames[i];
+            var store = idbtrans.objectStore(storeName);
+            db._hasGetAll = 'getAll' in store;
+            for (var j = 0; j < store.indexNames.length; ++j) {
+                var indexName = store.indexNames[j];
+                var keyPath = store.index(indexName).keyPath;
+                var dexieName = typeof keyPath === 'string' ? keyPath : "[" + slice(keyPath).join('+') + "]";
+                if (schema[storeName]) {
+                    var indexSpec = schema[storeName].idxByName[dexieName];
+                    if (indexSpec) {
+                        indexSpec.name = indexName;
+                        delete schema[storeName].idxByName[dexieName];
+                        schema[storeName].idxByName[indexName] = indexSpec;
+                    }
+                }
+            }
+        }
+        if (typeof navigator !== 'undefined' && /Safari/.test(navigator.userAgent) &&
+            !/(Chrome\/|Edge\/)/.test(navigator.userAgent) &&
+            _global.WorkerGlobalScope && _global instanceof _global.WorkerGlobalScope &&
+            [].concat(navigator.userAgent.match(/Safari\/(\d*)/))[1] < 604) {
+            db._hasGetAll = false;
+        }
+    }
+    function parseIndexSyntax(primKeyAndIndexes) {
+        return primKeyAndIndexes.split(',').map(function (index, indexNum) {
+            index = index.trim();
+            var name = index.replace(/([&*]|\+\+)/g, "");
+            var keyPath = /^\[/.test(name) ? name.match(/^\[(.*)\]$/)[1].split('+') : name;
+            return createIndexSpec(name, keyPath || null, /\&/.test(index), /\*/.test(index), /\+\+/.test(index), isArray(keyPath), indexNum === 0);
+        });
+    }
+
+    var Version =  (function () {
+        function Version() {
+        }
+        Version.prototype._parseStoresSpec = function (stores, outSchema) {
+            keys(stores).forEach(function (tableName) {
+                if (stores[tableName] !== null) {
+                    var indexes = parseIndexSyntax(stores[tableName]);
+                    var primKey = indexes.shift();
+                    if (primKey.multi)
+                        throw new exceptions.Schema("Primary key cannot be multi-valued");
+                    indexes.forEach(function (idx) {
+                        if (idx.auto)
+                            throw new exceptions.Schema("Only primary key can be marked as autoIncrement (++)");
+                        if (!idx.keyPath)
+                            throw new exceptions.Schema("Index must have a name and cannot be an empty string");
+                    });
+                    outSchema[tableName] = createTableSchema(tableName, primKey, indexes);
+                }
+            });
+        };
+        Version.prototype.stores = function (stores) {
+            var db = this.db;
+            this._cfg.storesSource = this._cfg.storesSource ?
+                extend(this._cfg.storesSource, stores) :
+                stores;
+            var versions = db._versions;
+            var storesSpec = {};
+            var dbschema = {};
+            versions.forEach(function (version) {
+                extend(storesSpec, version._cfg.storesSource);
+                dbschema = (version._cfg.dbschema = {});
+                version._parseStoresSpec(storesSpec, dbschema);
+            });
+            db._dbSchema = dbschema;
+            removeTablesApi(db, [db._allTables, db, db.Transaction.prototype]);
+            setApiOnPlace(db, [db._allTables, db, db.Transaction.prototype, this._cfg.tables], keys(dbschema), dbschema);
+            db._storeNames = keys(dbschema);
+            return this;
+        };
+        Version.prototype.upgrade = function (upgradeFunction) {
+            this._cfg.contentUpgrade = promisableChain(this._cfg.contentUpgrade || nop, upgradeFunction);
+            return this;
+        };
+        return Version;
+    }());
+
+    function createVersionConstructor(db) {
+        return makeClassConstructor(Version.prototype, function Version(versionNumber) {
+            this.db = db;
+            this._cfg = {
+                version: versionNumber,
+                storesSource: null,
+                dbschema: {},
+                tables: {},
+                contentUpgrade: null
+            };
+        });
+    }
+
+    function getDbNamesTable(indexedDB, IDBKeyRange) {
+        var dbNamesDB = indexedDB["_dbNamesDB"];
+        if (!dbNamesDB) {
+            dbNamesDB = indexedDB["_dbNamesDB"] = new Dexie$1(DBNAMES_DB, {
+                addons: [],
+                indexedDB: indexedDB,
+                IDBKeyRange: IDBKeyRange,
+            });
+            dbNamesDB.version(1).stores({ dbnames: "name" });
+        }
+        return dbNamesDB.table("dbnames");
+    }
+    function hasDatabasesNative(indexedDB) {
+        return indexedDB && typeof indexedDB.databases === "function";
+    }
+    function getDatabaseNames(_a) {
+        var indexedDB = _a.indexedDB, IDBKeyRange = _a.IDBKeyRange;
+        return hasDatabasesNative(indexedDB)
+            ? Promise.resolve(indexedDB.databases()).then(function (infos) {
+                return infos
+                    .map(function (info) { return info.name; })
+                    .filter(function (name) { return name !== DBNAMES_DB; });
+            })
+            : getDbNamesTable(indexedDB, IDBKeyRange).toCollection().primaryKeys();
+    }
+    function _onDatabaseCreated(_a, name) {
+        var indexedDB = _a.indexedDB, IDBKeyRange = _a.IDBKeyRange;
+        !hasDatabasesNative(indexedDB) &&
+            name !== DBNAMES_DB &&
+            getDbNamesTable(indexedDB, IDBKeyRange).put({ name: name }).catch(nop);
+    }
+    function _onDatabaseDeleted(_a, name) {
+        var indexedDB = _a.indexedDB, IDBKeyRange = _a.IDBKeyRange;
+        !hasDatabasesNative(indexedDB) &&
+            name !== DBNAMES_DB &&
+            getDbNamesTable(indexedDB, IDBKeyRange).delete(name).catch(nop);
+    }
+
+    function vip(fn) {
+        return newScope(function () {
+            PSD.letThrough = true;
+            return fn();
+        });
+    }
+
+    function idbReady() {
+        var isSafari = !navigator.userAgentData &&
+            /Safari\//.test(navigator.userAgent) &&
+            !/Chrom(e|ium)\//.test(navigator.userAgent);
+        if (!isSafari || !indexedDB.databases)
+            return Promise.resolve();
+        var intervalId;
+        return new Promise(function (resolve) {
+            var tryIdb = function () { return indexedDB.databases().finally(resolve); };
+            intervalId = setInterval(tryIdb, 100);
+            tryIdb();
+        }).finally(function () { return clearInterval(intervalId); });
+    }
+
+    function dexieOpen(db) {
+        var state = db._state;
+        var indexedDB = db._deps.indexedDB;
+        if (state.isBeingOpened || db.idbdb)
+            return state.dbReadyPromise.then(function () { return state.dbOpenError ?
+                rejection(state.dbOpenError) :
+                db; });
+        debug && (state.openCanceller._stackHolder = getErrorWithStack());
+        state.isBeingOpened = true;
+        state.dbOpenError = null;
+        state.openComplete = false;
+        var openCanceller = state.openCanceller;
+        function throwIfCancelled() {
+            if (state.openCanceller !== openCanceller)
+                throw new exceptions.DatabaseClosed('db.open() was cancelled');
+        }
+        var resolveDbReady = state.dbReadyResolve,
+        upgradeTransaction = null, wasCreated = false;
+        return DexiePromise.race([openCanceller, (typeof navigator === 'undefined' ? DexiePromise.resolve() : idbReady()).then(function () { return new DexiePromise(function (resolve, reject) {
+                throwIfCancelled();
+                if (!indexedDB)
+                    throw new exceptions.MissingAPI();
+                var dbName = db.name;
+                var req = state.autoSchema ?
+                    indexedDB.open(dbName) :
+                    indexedDB.open(dbName, Math.round(db.verno * 10));
+                if (!req)
+                    throw new exceptions.MissingAPI();
+                req.onerror = eventRejectHandler(reject);
+                req.onblocked = wrap(db._fireOnBlocked);
+                req.onupgradeneeded = wrap(function (e) {
+                    upgradeTransaction = req.transaction;
+                    if (state.autoSchema && !db._options.allowEmptyDB) {
+                        req.onerror = preventDefault;
+                        upgradeTransaction.abort();
+                        req.result.close();
+                        var delreq = indexedDB.deleteDatabase(dbName);
+                        delreq.onsuccess = delreq.onerror = wrap(function () {
+                            reject(new exceptions.NoSuchDatabase("Database " + dbName + " doesnt exist"));
+                        });
+                    }
+                    else {
+                        upgradeTransaction.onerror = eventRejectHandler(reject);
+                        var oldVer = e.oldVersion > Math.pow(2, 62) ? 0 : e.oldVersion;
+                        wasCreated = oldVer < 1;
+                        db._novip.idbdb = req.result;
+                        runUpgraders(db, oldVer / 10, upgradeTransaction, reject);
+                    }
+                }, reject);
+                req.onsuccess = wrap(function () {
+                    upgradeTransaction = null;
+                    var idbdb = db._novip.idbdb = req.result;
+                    var objectStoreNames = slice(idbdb.objectStoreNames);
+                    if (objectStoreNames.length > 0)
+                        try {
+                            var tmpTrans = idbdb.transaction(safariMultiStoreFix(objectStoreNames), 'readonly');
+                            if (state.autoSchema)
+                                readGlobalSchema(db, idbdb, tmpTrans);
+                            else {
+                                adjustToExistingIndexNames(db, db._dbSchema, tmpTrans);
+                                if (!verifyInstalledSchema(db, tmpTrans)) {
+                                    console.warn("Dexie SchemaDiff: Schema was extended without increasing the number passed to db.version(). Some queries may fail.");
+                                }
+                            }
+                            generateMiddlewareStacks(db, tmpTrans);
+                        }
+                        catch (e) {
+                        }
+                    connections.push(db);
+                    idbdb.onversionchange = wrap(function (ev) {
+                        state.vcFired = true;
+                        db.on("versionchange").fire(ev);
+                    });
+                    idbdb.onclose = wrap(function (ev) {
+                        db.on("close").fire(ev);
+                    });
+                    if (wasCreated)
+                        _onDatabaseCreated(db._deps, dbName);
+                    resolve();
+                }, reject);
+            }); })]).then(function () {
+            throwIfCancelled();
+            state.onReadyBeingFired = [];
+            return DexiePromise.resolve(vip(function () { return db.on.ready.fire(db.vip); })).then(function fireRemainders() {
+                if (state.onReadyBeingFired.length > 0) {
+                    var remainders_1 = state.onReadyBeingFired.reduce(promisableChain, nop);
+                    state.onReadyBeingFired = [];
+                    return DexiePromise.resolve(vip(function () { return remainders_1(db.vip); })).then(fireRemainders);
+                }
+            });
+        }).finally(function () {
+            state.onReadyBeingFired = null;
+            state.isBeingOpened = false;
+        }).then(function () {
+            return db;
+        }).catch(function (err) {
+            state.dbOpenError = err;
+            try {
+                upgradeTransaction && upgradeTransaction.abort();
+            }
+            catch (_a) { }
+            if (openCanceller === state.openCanceller) {
+                db._close();
+            }
+            return rejection(err);
+        }).finally(function () {
+            state.openComplete = true;
+            resolveDbReady();
+        });
+    }
+
+    function awaitIterator(iterator) {
+        var callNext = function (result) { return iterator.next(result); }, doThrow = function (error) { return iterator.throw(error); }, onSuccess = step(callNext), onError = step(doThrow);
+        function step(getNext) {
+            return function (val) {
+                var next = getNext(val), value = next.value;
+                return next.done ? value :
+                    (!value || typeof value.then !== 'function' ?
+                        isArray(value) ? Promise.all(value).then(onSuccess, onError) : onSuccess(value) :
+                        value.then(onSuccess, onError));
+            };
+        }
+        return step(callNext)();
+    }
+
+    function extractTransactionArgs(mode, _tableArgs_, scopeFunc) {
+        var i = arguments.length;
+        if (i < 2)
+            throw new exceptions.InvalidArgument("Too few arguments");
+        var args = new Array(i - 1);
+        while (--i)
+            args[i - 1] = arguments[i];
+        scopeFunc = args.pop();
+        var tables = flatten(args);
+        return [mode, tables, scopeFunc];
+    }
+    function enterTransactionScope(db, mode, storeNames, parentTransaction, scopeFunc) {
+        return DexiePromise.resolve().then(function () {
+            var transless = PSD.transless || PSD;
+            var trans = db._createTransaction(mode, storeNames, db._dbSchema, parentTransaction);
+            var zoneProps = {
+                trans: trans,
+                transless: transless
+            };
+            if (parentTransaction) {
+                trans.idbtrans = parentTransaction.idbtrans;
+            }
+            else {
+                try {
+                    trans.create();
+                    db._state.PR1398_maxLoop = 3;
+                }
+                catch (ex) {
+                    if (ex.name === errnames.InvalidState && db.isOpen() && --db._state.PR1398_maxLoop > 0) {
+                        console.warn('Dexie: Need to reopen db');
+                        db._close();
+                        return db.open().then(function () { return enterTransactionScope(db, mode, storeNames, null, scopeFunc); });
+                    }
+                    return rejection(ex);
+                }
+            }
+            var scopeFuncIsAsync = isAsyncFunction(scopeFunc);
+            if (scopeFuncIsAsync) {
+                incrementExpectedAwaits();
+            }
+            var returnValue;
+            var promiseFollowed = DexiePromise.follow(function () {
+                returnValue = scopeFunc.call(trans, trans);
+                if (returnValue) {
+                    if (scopeFuncIsAsync) {
+                        var decrementor = decrementExpectedAwaits.bind(null, null);
+                        returnValue.then(decrementor, decrementor);
+                    }
+                    else if (typeof returnValue.next === 'function' && typeof returnValue.throw === 'function') {
+                        returnValue = awaitIterator(returnValue);
+                    }
+                }
+            }, zoneProps);
+            return (returnValue && typeof returnValue.then === 'function' ?
+                DexiePromise.resolve(returnValue).then(function (x) { return trans.active ?
+                    x
+                    : rejection(new exceptions.PrematureCommit("Transaction committed too early. See http://bit.ly/2kdckMn")); })
+                : promiseFollowed.then(function () { return returnValue; })).then(function (x) {
+                if (parentTransaction)
+                    trans._resolve();
+                return trans._completion.then(function () { return x; });
+            }).catch(function (e) {
+                trans._reject(e);
+                return rejection(e);
+            });
+        });
+    }
+
+    function pad(a, value, count) {
+        var result = isArray(a) ? a.slice() : [a];
+        for (var i = 0; i < count; ++i)
+            result.push(value);
+        return result;
+    }
+    function createVirtualIndexMiddleware(down) {
+        return __assign(__assign({}, down), { table: function (tableName) {
+                var table = down.table(tableName);
+                var schema = table.schema;
+                var indexLookup = {};
+                var allVirtualIndexes = [];
+                function addVirtualIndexes(keyPath, keyTail, lowLevelIndex) {
+                    var keyPathAlias = getKeyPathAlias(keyPath);
+                    var indexList = (indexLookup[keyPathAlias] = indexLookup[keyPathAlias] || []);
+                    var keyLength = keyPath == null ? 0 : typeof keyPath === 'string' ? 1 : keyPath.length;
+                    var isVirtual = keyTail > 0;
+                    var virtualIndex = __assign(__assign({}, lowLevelIndex), { isVirtual: isVirtual, keyTail: keyTail, keyLength: keyLength, extractKey: getKeyExtractor(keyPath), unique: !isVirtual && lowLevelIndex.unique });
+                    indexList.push(virtualIndex);
+                    if (!virtualIndex.isPrimaryKey) {
+                        allVirtualIndexes.push(virtualIndex);
+                    }
+                    if (keyLength > 1) {
+                        var virtualKeyPath = keyLength === 2 ?
+                            keyPath[0] :
+                            keyPath.slice(0, keyLength - 1);
+                        addVirtualIndexes(virtualKeyPath, keyTail + 1, lowLevelIndex);
+                    }
+                    indexList.sort(function (a, b) { return a.keyTail - b.keyTail; });
+                    return virtualIndex;
+                }
+                var primaryKey = addVirtualIndexes(schema.primaryKey.keyPath, 0, schema.primaryKey);
+                indexLookup[":id"] = [primaryKey];
+                for (var _i = 0, _a = schema.indexes; _i < _a.length; _i++) {
+                    var index = _a[_i];
+                    addVirtualIndexes(index.keyPath, 0, index);
+                }
+                function findBestIndex(keyPath) {
+                    var result = indexLookup[getKeyPathAlias(keyPath)];
+                    return result && result[0];
+                }
+                function translateRange(range, keyTail) {
+                    return {
+                        type: range.type === 1  ?
+                            2  :
+                            range.type,
+                        lower: pad(range.lower, range.lowerOpen ? down.MAX_KEY : down.MIN_KEY, keyTail),
+                        lowerOpen: true,
+                        upper: pad(range.upper, range.upperOpen ? down.MIN_KEY : down.MAX_KEY, keyTail),
+                        upperOpen: true
+                    };
+                }
+                function translateRequest(req) {
+                    var index = req.query.index;
+                    return index.isVirtual ? __assign(__assign({}, req), { query: {
+                            index: index,
+                            range: translateRange(req.query.range, index.keyTail)
+                        } }) : req;
+                }
+                var result = __assign(__assign({}, table), { schema: __assign(__assign({}, schema), { primaryKey: primaryKey, indexes: allVirtualIndexes, getIndexByKeyPath: findBestIndex }), count: function (req) {
+                        return table.count(translateRequest(req));
+                    }, query: function (req) {
+                        return table.query(translateRequest(req));
+                    }, openCursor: function (req) {
+                        var _a = req.query.index, keyTail = _a.keyTail, isVirtual = _a.isVirtual, keyLength = _a.keyLength;
+                        if (!isVirtual)
+                            return table.openCursor(req);
+                        function createVirtualCursor(cursor) {
+                            function _continue(key) {
+                                key != null ?
+                                    cursor.continue(pad(key, req.reverse ? down.MAX_KEY : down.MIN_KEY, keyTail)) :
+                                    req.unique ?
+                                        cursor.continue(cursor.key.slice(0, keyLength)
+                                            .concat(req.reverse
+                                            ? down.MIN_KEY
+                                            : down.MAX_KEY, keyTail)) :
+                                        cursor.continue();
+                            }
+                            var virtualCursor = Object.create(cursor, {
+                                continue: { value: _continue },
+                                continuePrimaryKey: {
+                                    value: function (key, primaryKey) {
+                                        cursor.continuePrimaryKey(pad(key, down.MAX_KEY, keyTail), primaryKey);
+                                    }
+                                },
+                                primaryKey: {
+                                    get: function () {
+                                        return cursor.primaryKey;
+                                    }
+                                },
+                                key: {
+                                    get: function () {
+                                        var key = cursor.key;
+                                        return keyLength === 1 ?
+                                            key[0] :
+                                            key.slice(0, keyLength);
+                                    }
+                                },
+                                value: {
+                                    get: function () {
+                                        return cursor.value;
+                                    }
+                                }
+                            });
+                            return virtualCursor;
+                        }
+                        return table.openCursor(translateRequest(req))
+                            .then(function (cursor) { return cursor && createVirtualCursor(cursor); });
+                    } });
+                return result;
+            } });
+    }
+    var virtualIndexMiddleware = {
+        stack: "dbcore",
+        name: "VirtualIndexMiddleware",
+        level: 1,
+        create: createVirtualIndexMiddleware
+    };
+
+    function getObjectDiff(a, b, rv, prfx) {
+        rv = rv || {};
+        prfx = prfx || '';
+        keys(a).forEach(function (prop) {
+            if (!hasOwn(b, prop)) {
+                rv[prfx + prop] = undefined;
+            }
+            else {
+                var ap = a[prop], bp = b[prop];
+                if (typeof ap === 'object' && typeof bp === 'object' && ap && bp) {
+                    var apTypeName = toStringTag(ap);
+                    var bpTypeName = toStringTag(bp);
+                    if (apTypeName !== bpTypeName) {
+                        rv[prfx + prop] = b[prop];
+                    }
+                    else if (apTypeName === 'Object') {
+                        getObjectDiff(ap, bp, rv, prfx + prop + '.');
+                    }
+                    else if (ap !== bp) {
+                        rv[prfx + prop] = b[prop];
+                    }
+                }
+                else if (ap !== bp)
+                    rv[prfx + prop] = b[prop];
+            }
+        });
+        keys(b).forEach(function (prop) {
+            if (!hasOwn(a, prop)) {
+                rv[prfx + prop] = b[prop];
+            }
+        });
+        return rv;
+    }
+
+    function getEffectiveKeys(primaryKey, req) {
+        if (req.type === 'delete')
+            return req.keys;
+        return req.keys || req.values.map(primaryKey.extractKey);
+    }
+
+    var hooksMiddleware = {
+        stack: "dbcore",
+        name: "HooksMiddleware",
+        level: 2,
+        create: function (downCore) { return (__assign(__assign({}, downCore), { table: function (tableName) {
+                var downTable = downCore.table(tableName);
+                var primaryKey = downTable.schema.primaryKey;
+                var tableMiddleware = __assign(__assign({}, downTable), { mutate: function (req) {
+                        var dxTrans = PSD.trans;
+                        var _a = dxTrans.table(tableName).hook, deleting = _a.deleting, creating = _a.creating, updating = _a.updating;
+                        switch (req.type) {
+                            case 'add':
+                                if (creating.fire === nop)
+                                    break;
+                                return dxTrans._promise('readwrite', function () { return addPutOrDelete(req); }, true);
+                            case 'put':
+                                if (creating.fire === nop && updating.fire === nop)
+                                    break;
+                                return dxTrans._promise('readwrite', function () { return addPutOrDelete(req); }, true);
+                            case 'delete':
+                                if (deleting.fire === nop)
+                                    break;
+                                return dxTrans._promise('readwrite', function () { return addPutOrDelete(req); }, true);
+                            case 'deleteRange':
+                                if (deleting.fire === nop)
+                                    break;
+                                return dxTrans._promise('readwrite', function () { return deleteRange(req); }, true);
+                        }
+                        return downTable.mutate(req);
+                        function addPutOrDelete(req) {
+                            var dxTrans = PSD.trans;
+                            var keys = req.keys || getEffectiveKeys(primaryKey, req);
+                            if (!keys)
+                                throw new Error("Keys missing");
+                            req = req.type === 'add' || req.type === 'put' ? __assign(__assign({}, req), { keys: keys }) : __assign({}, req);
+                            if (req.type !== 'delete')
+                                req.values = __spreadArray([], req.values, true);
+                            if (req.keys)
+                                req.keys = __spreadArray([], req.keys, true);
+                            return getExistingValues(downTable, req, keys).then(function (existingValues) {
+                                var contexts = keys.map(function (key, i) {
+                                    var existingValue = existingValues[i];
+                                    var ctx = { onerror: null, onsuccess: null };
+                                    if (req.type === 'delete') {
+                                        deleting.fire.call(ctx, key, existingValue, dxTrans);
+                                    }
+                                    else if (req.type === 'add' || existingValue === undefined) {
+                                        var generatedPrimaryKey = creating.fire.call(ctx, key, req.values[i], dxTrans);
+                                        if (key == null && generatedPrimaryKey != null) {
+                                            key = generatedPrimaryKey;
+                                            req.keys[i] = key;
+                                            if (!primaryKey.outbound) {
+                                                setByKeyPath(req.values[i], primaryKey.keyPath, key);
+                                            }
+                                        }
+                                    }
+                                    else {
+                                        var objectDiff = getObjectDiff(existingValue, req.values[i]);
+                                        var additionalChanges_1 = updating.fire.call(ctx, objectDiff, key, existingValue, dxTrans);
+                                        if (additionalChanges_1) {
+                                            var requestedValue_1 = req.values[i];
+                                            Object.keys(additionalChanges_1).forEach(function (keyPath) {
+                                                if (hasOwn(requestedValue_1, keyPath)) {
+                                                    requestedValue_1[keyPath] = additionalChanges_1[keyPath];
+                                                }
+                                                else {
+                                                    setByKeyPath(requestedValue_1, keyPath, additionalChanges_1[keyPath]);
+                                                }
+                                            });
+                                        }
+                                    }
+                                    return ctx;
+                                });
+                                return downTable.mutate(req).then(function (_a) {
+                                    var failures = _a.failures, results = _a.results, numFailures = _a.numFailures, lastResult = _a.lastResult;
+                                    for (var i = 0; i < keys.length; ++i) {
+                                        var primKey = results ? results[i] : keys[i];
+                                        var ctx = contexts[i];
+                                        if (primKey == null) {
+                                            ctx.onerror && ctx.onerror(failures[i]);
+                                        }
+                                        else {
+                                            ctx.onsuccess && ctx.onsuccess(req.type === 'put' && existingValues[i] ?
+                                                req.values[i] :
+                                                primKey
+                                            );
+                                        }
+                                    }
+                                    return { failures: failures, results: results, numFailures: numFailures, lastResult: lastResult };
+                                }).catch(function (error) {
+                                    contexts.forEach(function (ctx) { return ctx.onerror && ctx.onerror(error); });
+                                    return Promise.reject(error);
+                                });
+                            });
+                        }
+                        function deleteRange(req) {
+                            return deleteNextChunk(req.trans, req.range, 10000);
+                        }
+                        function deleteNextChunk(trans, range, limit) {
+                            return downTable.query({ trans: trans, values: false, query: { index: primaryKey, range: range }, limit: limit })
+                                .then(function (_a) {
+                                var result = _a.result;
+                                return addPutOrDelete({ type: 'delete', keys: result, trans: trans }).then(function (res) {
+                                    if (res.numFailures > 0)
+                                        return Promise.reject(res.failures[0]);
+                                    if (result.length < limit) {
+                                        return { failures: [], numFailures: 0, lastResult: undefined };
+                                    }
+                                    else {
+                                        return deleteNextChunk(trans, __assign(__assign({}, range), { lower: result[result.length - 1], lowerOpen: true }), limit);
+                                    }
+                                });
+                            });
+                        }
+                    } });
+                return tableMiddleware;
+            } })); }
+    };
+    function getExistingValues(table, req, effectiveKeys) {
+        return req.type === "add"
+            ? Promise.resolve([])
+            : table.getMany({ trans: req.trans, keys: effectiveKeys, cache: "immutable" });
+    }
+
+    function getFromTransactionCache(keys, cache, clone) {
+        try {
+            if (!cache)
+                return null;
+            if (cache.keys.length < keys.length)
+                return null;
+            var result = [];
+            for (var i = 0, j = 0; i < cache.keys.length && j < keys.length; ++i) {
+                if (cmp(cache.keys[i], keys[j]) !== 0)
+                    continue;
+                result.push(clone ? deepClone(cache.values[i]) : cache.values[i]);
+                ++j;
+            }
+            return result.length === keys.length ? result : null;
+        }
+        catch (_a) {
+            return null;
+        }
+    }
+    var cacheExistingValuesMiddleware = {
+        stack: "dbcore",
+        level: -1,
+        create: function (core) {
+            return {
+                table: function (tableName) {
+                    var table = core.table(tableName);
+                    return __assign(__assign({}, table), { getMany: function (req) {
+                            if (!req.cache) {
+                                return table.getMany(req);
+                            }
+                            var cachedResult = getFromTransactionCache(req.keys, req.trans["_cache"], req.cache === "clone");
+                            if (cachedResult) {
+                                return DexiePromise.resolve(cachedResult);
+                            }
+                            return table.getMany(req).then(function (res) {
+                                req.trans["_cache"] = {
+                                    keys: req.keys,
+                                    values: req.cache === "clone" ? deepClone(res) : res,
+                                };
+                                return res;
+                            });
+                        }, mutate: function (req) {
+                            if (req.type !== "add")
+                                req.trans["_cache"] = null;
+                            return table.mutate(req);
+                        } });
+                },
+            };
+        },
+    };
+
+    var _a;
+    function isEmptyRange(node) {
+        return !("from" in node);
+    }
+    var RangeSet = function (fromOrTree, to) {
+        if (this) {
+            extend(this, arguments.length ? { d: 1, from: fromOrTree, to: arguments.length > 1 ? to : fromOrTree } : { d: 0 });
+        }
+        else {
+            var rv = new RangeSet();
+            if (fromOrTree && ("d" in fromOrTree)) {
+                extend(rv, fromOrTree);
+            }
+            return rv;
+        }
+    };
+    props(RangeSet.prototype, (_a = {
+            add: function (rangeSet) {
+                mergeRanges(this, rangeSet);
+                return this;
+            },
+            addKey: function (key) {
+                addRange(this, key, key);
+                return this;
+            },
+            addKeys: function (keys) {
+                var _this = this;
+                keys.forEach(function (key) { return addRange(_this, key, key); });
+                return this;
+            }
+        },
+        _a[iteratorSymbol] = function () {
+            return getRangeSetIterator(this);
+        },
+        _a));
+    function addRange(target, from, to) {
+        var diff = cmp(from, to);
+        if (isNaN(diff))
+            return;
+        if (diff > 0)
+            throw RangeError();
+        if (isEmptyRange(target))
+            return extend(target, { from: from, to: to, d: 1 });
+        var left = target.l;
+        var right = target.r;
+        if (cmp(to, target.from) < 0) {
+            left
+                ? addRange(left, from, to)
+                : (target.l = { from: from, to: to, d: 1, l: null, r: null });
+            return rebalance(target);
+        }
+        if (cmp(from, target.to) > 0) {
+            right
+                ? addRange(right, from, to)
+                : (target.r = { from: from, to: to, d: 1, l: null, r: null });
+            return rebalance(target);
+        }
+        if (cmp(from, target.from) < 0) {
+            target.from = from;
+            target.l = null;
+            target.d = right ? right.d + 1 : 1;
+        }
+        if (cmp(to, target.to) > 0) {
+            target.to = to;
+            target.r = null;
+            target.d = target.l ? target.l.d + 1 : 1;
+        }
+        var rightWasCutOff = !target.r;
+        if (left && !target.l) {
+            mergeRanges(target, left);
+        }
+        if (right && rightWasCutOff) {
+            mergeRanges(target, right);
+        }
+    }
+    function mergeRanges(target, newSet) {
+        function _addRangeSet(target, _a) {
+            var from = _a.from, to = _a.to, l = _a.l, r = _a.r;
+            addRange(target, from, to);
+            if (l)
+                _addRangeSet(target, l);
+            if (r)
+                _addRangeSet(target, r);
+        }
+        if (!isEmptyRange(newSet))
+            _addRangeSet(target, newSet);
+    }
+    function rangesOverlap(rangeSet1, rangeSet2) {
+        var i1 = getRangeSetIterator(rangeSet2);
+        var nextResult1 = i1.next();
+        if (nextResult1.done)
+            return false;
+        var a = nextResult1.value;
+        var i2 = getRangeSetIterator(rangeSet1);
+        var nextResult2 = i2.next(a.from);
+        var b = nextResult2.value;
+        while (!nextResult1.done && !nextResult2.done) {
+            if (cmp(b.from, a.to) <= 0 && cmp(b.to, a.from) >= 0)
+                return true;
+            cmp(a.from, b.from) < 0
+                ? (a = (nextResult1 = i1.next(b.from)).value)
+                : (b = (nextResult2 = i2.next(a.from)).value);
+        }
+        return false;
+    }
+    function getRangeSetIterator(node) {
+        var state = isEmptyRange(node) ? null : { s: 0, n: node };
+        return {
+            next: function (key) {
+                var keyProvided = arguments.length > 0;
+                while (state) {
+                    switch (state.s) {
+                        case 0:
+                            state.s = 1;
+                            if (keyProvided) {
+                                while (state.n.l && cmp(key, state.n.from) < 0)
+                                    state = { up: state, n: state.n.l, s: 1 };
+                            }
+                            else {
+                                while (state.n.l)
+                                    state = { up: state, n: state.n.l, s: 1 };
+                            }
+                        case 1:
+                            state.s = 2;
+                            if (!keyProvided || cmp(key, state.n.to) <= 0)
+                                return { value: state.n, done: false };
+                        case 2:
+                            if (state.n.r) {
+                                state.s = 3;
+                                state = { up: state, n: state.n.r, s: 0 };
+                                continue;
+                            }
+                        case 3:
+                            state = state.up;
+                    }
+                }
+                return { done: true };
+            },
+        };
+    }
+    function rebalance(target) {
+        var _a, _b;
+        var diff = (((_a = target.r) === null || _a === void 0 ? void 0 : _a.d) || 0) - (((_b = target.l) === null || _b === void 0 ? void 0 : _b.d) || 0);
+        var r = diff > 1 ? "r" : diff < -1 ? "l" : "";
+        if (r) {
+            var l = r === "r" ? "l" : "r";
+            var rootClone = __assign({}, target);
+            var oldRootRight = target[r];
+            target.from = oldRootRight.from;
+            target.to = oldRootRight.to;
+            target[r] = oldRootRight[r];
+            rootClone[r] = oldRootRight[l];
+            target[l] = rootClone;
+            rootClone.d = computeDepth(rootClone);
+        }
+        target.d = computeDepth(target);
+    }
+    function computeDepth(_a) {
+        var r = _a.r, l = _a.l;
+        return (r ? (l ? Math.max(r.d, l.d) : r.d) : l ? l.d : 0) + 1;
+    }
+
+    var observabilityMiddleware = {
+        stack: "dbcore",
+        level: 0,
+        create: function (core) {
+            var dbName = core.schema.name;
+            var FULL_RANGE = new RangeSet(core.MIN_KEY, core.MAX_KEY);
+            return __assign(__assign({}, core), { table: function (tableName) {
+                    var table = core.table(tableName);
+                    var schema = table.schema;
+                    var primaryKey = schema.primaryKey;
+                    var extractKey = primaryKey.extractKey, outbound = primaryKey.outbound;
+                    var tableClone = __assign(__assign({}, table), { mutate: function (req) {
+                            var trans = req.trans;
+                            var mutatedParts = trans.mutatedParts || (trans.mutatedParts = {});
+                            var getRangeSet = function (indexName) {
+                                var part = "idb://" + dbName + "/" + tableName + "/" + indexName;
+                                return (mutatedParts[part] ||
+                                    (mutatedParts[part] = new RangeSet()));
+                            };
+                            var pkRangeSet = getRangeSet("");
+                            var delsRangeSet = getRangeSet(":dels");
+                            var type = req.type;
+                            var _a = req.type === "deleteRange"
+                                ? [req.range]
+                                : req.type === "delete"
+                                    ? [req.keys]
+                                    : req.values.length < 50
+                                        ? [[], req.values]
+                                        : [], keys = _a[0], newObjs = _a[1];
+                            var oldCache = req.trans["_cache"];
+                            return table.mutate(req).then(function (res) {
+                                if (isArray(keys)) {
+                                    if (type !== "delete")
+                                        keys = res.results;
+                                    pkRangeSet.addKeys(keys);
+                                    var oldObjs = getFromTransactionCache(keys, oldCache);
+                                    if (!oldObjs && type !== "add") {
+                                        delsRangeSet.addKeys(keys);
+                                    }
+                                    if (oldObjs || newObjs) {
+                                        trackAffectedIndexes(getRangeSet, schema, oldObjs, newObjs);
+                                    }
+                                }
+                                else if (keys) {
+                                    var range = { from: keys.lower, to: keys.upper };
+                                    delsRangeSet.add(range);
+                                    pkRangeSet.add(range);
+                                }
+                                else {
+                                    pkRangeSet.add(FULL_RANGE);
+                                    delsRangeSet.add(FULL_RANGE);
+                                    schema.indexes.forEach(function (idx) { return getRangeSet(idx.name).add(FULL_RANGE); });
+                                }
+                                return res;
+                            });
+                        } });
+                    var getRange = function (_a) {
+                        var _b, _c;
+                        var _d = _a.query, index = _d.index, range = _d.range;
+                        return [
+                            index,
+                            new RangeSet((_b = range.lower) !== null && _b !== void 0 ? _b : core.MIN_KEY, (_c = range.upper) !== null && _c !== void 0 ? _c : core.MAX_KEY),
+                        ];
+                    };
+                    var readSubscribers = {
+                        get: function (req) { return [primaryKey, new RangeSet(req.key)]; },
+                        getMany: function (req) { return [primaryKey, new RangeSet().addKeys(req.keys)]; },
+                        count: getRange,
+                        query: getRange,
+                        openCursor: getRange,
+                    };
+                    keys(readSubscribers).forEach(function (method) {
+                        tableClone[method] = function (req) {
+                            var subscr = PSD.subscr;
+                            if (subscr) {
+                                var getRangeSet = function (indexName) {
+                                    var part = "idb://" + dbName + "/" + tableName + "/" + indexName;
+                                    return (subscr[part] ||
+                                        (subscr[part] = new RangeSet()));
+                                };
+                                var pkRangeSet_1 = getRangeSet("");
+                                var delsRangeSet_1 = getRangeSet(":dels");
+                                var _a = readSubscribers[method](req), queriedIndex = _a[0], queriedRanges = _a[1];
+                                getRangeSet(queriedIndex.name || "").add(queriedRanges);
+                                if (!queriedIndex.isPrimaryKey) {
+                                    if (method === "count") {
+                                        delsRangeSet_1.add(FULL_RANGE);
+                                    }
+                                    else {
+                                        var keysPromise_1 = method === "query" &&
+                                            outbound &&
+                                            req.values &&
+                                            table.query(__assign(__assign({}, req), { values: false }));
+                                        return table[method].apply(this, arguments).then(function (res) {
+                                            if (method === "query") {
+                                                if (outbound && req.values) {
+                                                    return keysPromise_1.then(function (_a) {
+                                                        var resultingKeys = _a.result;
+                                                        pkRangeSet_1.addKeys(resultingKeys);
+                                                        return res;
+                                                    });
+                                                }
+                                                var pKeys = req.values
+                                                    ? res.result.map(extractKey)
+                                                    : res.result;
+                                                if (req.values) {
+                                                    pkRangeSet_1.addKeys(pKeys);
+                                                }
+                                                else {
+                                                    delsRangeSet_1.addKeys(pKeys);
+                                                }
+                                            }
+                                            else if (method === "openCursor") {
+                                                var cursor_1 = res;
+                                                var wantValues_1 = req.values;
+                                                return (cursor_1 &&
+                                                    Object.create(cursor_1, {
+                                                        key: {
+                                                            get: function () {
+                                                                delsRangeSet_1.addKey(cursor_1.primaryKey);
+                                                                return cursor_1.key;
+                                                            },
+                                                        },
+                                                        primaryKey: {
+                                                            get: function () {
+                                                                var pkey = cursor_1.primaryKey;
+                                                                delsRangeSet_1.addKey(pkey);
+                                                                return pkey;
+                                                            },
+                                                        },
+                                                        value: {
+                                                            get: function () {
+                                                                wantValues_1 && pkRangeSet_1.addKey(cursor_1.primaryKey);
+                                                                return cursor_1.value;
+                                                            },
+                                                        },
+                                                    }));
+                                            }
+                                            return res;
+                                        });
+                                    }
+                                }
+                            }
+                            return table[method].apply(this, arguments);
+                        };
+                    });
+                    return tableClone;
+                } });
+        },
+    };
+    function trackAffectedIndexes(getRangeSet, schema, oldObjs, newObjs) {
+        function addAffectedIndex(ix) {
+            var rangeSet = getRangeSet(ix.name || "");
+            function extractKey(obj) {
+                return obj != null ? ix.extractKey(obj) : null;
+            }
+            var addKeyOrKeys = function (key) { return ix.multiEntry && isArray(key)
+                ? key.forEach(function (key) { return rangeSet.addKey(key); })
+                : rangeSet.addKey(key); };
+            (oldObjs || newObjs).forEach(function (_, i) {
+                var oldKey = oldObjs && extractKey(oldObjs[i]);
+                var newKey = newObjs && extractKey(newObjs[i]);
+                if (cmp(oldKey, newKey) !== 0) {
+                    if (oldKey != null)
+                        addKeyOrKeys(oldKey);
+                    if (newKey != null)
+                        addKeyOrKeys(newKey);
+                }
+            });
+        }
+        schema.indexes.forEach(addAffectedIndex);
+    }
+
+    var Dexie$1 =  (function () {
+        function Dexie(name, options) {
+            var _this = this;
+            this._middlewares = {};
+            this.verno = 0;
+            var deps = Dexie.dependencies;
+            this._options = options = __assign({
+                addons: Dexie.addons, autoOpen: true,
+                indexedDB: deps.indexedDB, IDBKeyRange: deps.IDBKeyRange }, options);
+            this._deps = {
+                indexedDB: options.indexedDB,
+                IDBKeyRange: options.IDBKeyRange
+            };
+            var addons = options.addons;
+            this._dbSchema = {};
+            this._versions = [];
+            this._storeNames = [];
+            this._allTables = {};
+            this.idbdb = null;
+            this._novip = this;
+            var state = {
+                dbOpenError: null,
+                isBeingOpened: false,
+                onReadyBeingFired: null,
+                openComplete: false,
+                dbReadyResolve: nop,
+                dbReadyPromise: null,
+                cancelOpen: nop,
+                openCanceller: null,
+                autoSchema: true,
+                PR1398_maxLoop: 3
+            };
+            state.dbReadyPromise = new DexiePromise(function (resolve) {
+                state.dbReadyResolve = resolve;
+            });
+            state.openCanceller = new DexiePromise(function (_, reject) {
+                state.cancelOpen = reject;
+            });
+            this._state = state;
+            this.name = name;
+            this.on = Events(this, "populate", "blocked", "versionchange", "close", { ready: [promisableChain, nop] });
+            this.on.ready.subscribe = override(this.on.ready.subscribe, function (subscribe) {
+                return function (subscriber, bSticky) {
+                    Dexie.vip(function () {
+                        var state = _this._state;
+                        if (state.openComplete) {
+                            if (!state.dbOpenError)
+                                DexiePromise.resolve().then(subscriber);
+                            if (bSticky)
+                                subscribe(subscriber);
+                        }
+                        else if (state.onReadyBeingFired) {
+                            state.onReadyBeingFired.push(subscriber);
+                            if (bSticky)
+                                subscribe(subscriber);
+                        }
+                        else {
+                            subscribe(subscriber);
+                            var db_1 = _this;
+                            if (!bSticky)
+                                subscribe(function unsubscribe() {
+                                    db_1.on.ready.unsubscribe(subscriber);
+                                    db_1.on.ready.unsubscribe(unsubscribe);
+                                });
+                        }
+                    });
+                };
+            });
+            this.Collection = createCollectionConstructor(this);
+            this.Table = createTableConstructor(this);
+            this.Transaction = createTransactionConstructor(this);
+            this.Version = createVersionConstructor(this);
+            this.WhereClause = createWhereClauseConstructor(this);
+            this.on("versionchange", function (ev) {
+                if (ev.newVersion > 0)
+                    console.warn("Another connection wants to upgrade database '" + _this.name + "'. Closing db now to resume the upgrade.");
+                else
+                    console.warn("Another connection wants to delete database '" + _this.name + "'. Closing db now to resume the delete request.");
+                _this.close();
+            });
+            this.on("blocked", function (ev) {
+                if (!ev.newVersion || ev.newVersion < ev.oldVersion)
+                    console.warn("Dexie.delete('" + _this.name + "') was blocked");
+                else
+                    console.warn("Upgrade '" + _this.name + "' blocked by other connection holding version " + ev.oldVersion / 10);
+            });
+            this._maxKey = getMaxKey(options.IDBKeyRange);
+            this._createTransaction = function (mode, storeNames, dbschema, parentTransaction) { return new _this.Transaction(mode, storeNames, dbschema, _this._options.chromeTransactionDurability, parentTransaction); };
+            this._fireOnBlocked = function (ev) {
+                _this.on("blocked").fire(ev);
+                connections
+                    .filter(function (c) { return c.name === _this.name && c !== _this && !c._state.vcFired; })
+                    .map(function (c) { return c.on("versionchange").fire(ev); });
+            };
+            this.use(virtualIndexMiddleware);
+            this.use(hooksMiddleware);
+            this.use(observabilityMiddleware);
+            this.use(cacheExistingValuesMiddleware);
+            this.vip = Object.create(this, { _vip: { value: true } });
+            addons.forEach(function (addon) { return addon(_this); });
+        }
+        Dexie.prototype.version = function (versionNumber) {
+            if (isNaN(versionNumber) || versionNumber < 0.1)
+                throw new exceptions.Type("Given version is not a positive number");
+            versionNumber = Math.round(versionNumber * 10) / 10;
+            if (this.idbdb || this._state.isBeingOpened)
+                throw new exceptions.Schema("Cannot add version when database is open");
+            this.verno = Math.max(this.verno, versionNumber);
+            var versions = this._versions;
+            var versionInstance = versions.filter(function (v) { return v._cfg.version === versionNumber; })[0];
+            if (versionInstance)
+                return versionInstance;
+            versionInstance = new this.Version(versionNumber);
+            versions.push(versionInstance);
+            versions.sort(lowerVersionFirst);
+            versionInstance.stores({});
+            this._state.autoSchema = false;
+            return versionInstance;
+        };
+        Dexie.prototype._whenReady = function (fn) {
+            var _this = this;
+            return (this.idbdb && (this._state.openComplete || PSD.letThrough || this._vip)) ? fn() : new DexiePromise(function (resolve, reject) {
+                if (_this._state.openComplete) {
+                    return reject(new exceptions.DatabaseClosed(_this._state.dbOpenError));
+                }
+                if (!_this._state.isBeingOpened) {
+                    if (!_this._options.autoOpen) {
+                        reject(new exceptions.DatabaseClosed());
+                        return;
+                    }
+                    _this.open().catch(nop);
+                }
+                _this._state.dbReadyPromise.then(resolve, reject);
+            }).then(fn);
+        };
+        Dexie.prototype.use = function (_a) {
+            var stack = _a.stack, create = _a.create, level = _a.level, name = _a.name;
+            if (name)
+                this.unuse({ stack: stack, name: name });
+            var middlewares = this._middlewares[stack] || (this._middlewares[stack] = []);
+            middlewares.push({ stack: stack, create: create, level: level == null ? 10 : level, name: name });
+            middlewares.sort(function (a, b) { return a.level - b.level; });
+            return this;
+        };
+        Dexie.prototype.unuse = function (_a) {
+            var stack = _a.stack, name = _a.name, create = _a.create;
+            if (stack && this._middlewares[stack]) {
+                this._middlewares[stack] = this._middlewares[stack].filter(function (mw) {
+                    return create ? mw.create !== create :
+                        name ? mw.name !== name :
+                            false;
+                });
+            }
+            return this;
+        };
+        Dexie.prototype.open = function () {
+            return dexieOpen(this);
+        };
+        Dexie.prototype._close = function () {
+            var state = this._state;
+            var idx = connections.indexOf(this);
+            if (idx >= 0)
+                connections.splice(idx, 1);
+            if (this.idbdb) {
+                try {
+                    this.idbdb.close();
+                }
+                catch (e) { }
+                this._novip.idbdb = null;
+            }
+            state.dbReadyPromise = new DexiePromise(function (resolve) {
+                state.dbReadyResolve = resolve;
+            });
+            state.openCanceller = new DexiePromise(function (_, reject) {
+                state.cancelOpen = reject;
+            });
+        };
+        Dexie.prototype.close = function () {
+            this._close();
+            var state = this._state;
+            this._options.autoOpen = false;
+            state.dbOpenError = new exceptions.DatabaseClosed();
+            if (state.isBeingOpened)
+                state.cancelOpen(state.dbOpenError);
+        };
+        Dexie.prototype.delete = function () {
+            var _this = this;
+            var hasArguments = arguments.length > 0;
+            var state = this._state;
+            return new DexiePromise(function (resolve, reject) {
+                var doDelete = function () {
+                    _this.close();
+                    var req = _this._deps.indexedDB.deleteDatabase(_this.name);
+                    req.onsuccess = wrap(function () {
+                        _onDatabaseDeleted(_this._deps, _this.name);
+                        resolve();
+                    });
+                    req.onerror = eventRejectHandler(reject);
+                    req.onblocked = _this._fireOnBlocked;
+                };
+                if (hasArguments)
+                    throw new exceptions.InvalidArgument("Arguments not allowed in db.delete()");
+                if (state.isBeingOpened) {
+                    state.dbReadyPromise.then(doDelete);
+                }
+                else {
+                    doDelete();
+                }
+            });
+        };
+        Dexie.prototype.backendDB = function () {
+            return this.idbdb;
+        };
+        Dexie.prototype.isOpen = function () {
+            return this.idbdb !== null;
+        };
+        Dexie.prototype.hasBeenClosed = function () {
+            var dbOpenError = this._state.dbOpenError;
+            return dbOpenError && (dbOpenError.name === 'DatabaseClosed');
+        };
+        Dexie.prototype.hasFailed = function () {
+            return this._state.dbOpenError !== null;
+        };
+        Dexie.prototype.dynamicallyOpened = function () {
+            return this._state.autoSchema;
+        };
+        Object.defineProperty(Dexie.prototype, "tables", {
+            get: function () {
+                var _this = this;
+                return keys(this._allTables).map(function (name) { return _this._allTables[name]; });
+            },
+            enumerable: false,
+            configurable: true
+        });
+        Dexie.prototype.transaction = function () {
+            var args = extractTransactionArgs.apply(this, arguments);
+            return this._transaction.apply(this, args);
+        };
+        Dexie.prototype._transaction = function (mode, tables, scopeFunc) {
+            var _this = this;
+            var parentTransaction = PSD.trans;
+            if (!parentTransaction || parentTransaction.db !== this || mode.indexOf('!') !== -1)
+                parentTransaction = null;
+            var onlyIfCompatible = mode.indexOf('?') !== -1;
+            mode = mode.replace('!', '').replace('?', '');
+            var idbMode, storeNames;
+            try {
+                storeNames = tables.map(function (table) {
+                    var storeName = table instanceof _this.Table ? table.name : table;
+                    if (typeof storeName !== 'string')
+                        throw new TypeError("Invalid table argument to Dexie.transaction(). Only Table or String are allowed");
+                    return storeName;
+                });
+                if (mode == "r" || mode === READONLY)
+                    idbMode = READONLY;
+                else if (mode == "rw" || mode == READWRITE)
+                    idbMode = READWRITE;
+                else
+                    throw new exceptions.InvalidArgument("Invalid transaction mode: " + mode);
+                if (parentTransaction) {
+                    if (parentTransaction.mode === READONLY && idbMode === READWRITE) {
+                        if (onlyIfCompatible) {
+                            parentTransaction = null;
+                        }
+                        else
+                            throw new exceptions.SubTransaction("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY");
+                    }
+                    if (parentTransaction) {
+                        storeNames.forEach(function (storeName) {
+                            if (parentTransaction && parentTransaction.storeNames.indexOf(storeName) === -1) {
+                                if (onlyIfCompatible) {
+                                    parentTransaction = null;
+                                }
+                                else
+                                    throw new exceptions.SubTransaction("Table " + storeName +
+                                        " not included in parent transaction.");
+                            }
+                        });
+                    }
+                    if (onlyIfCompatible && parentTransaction && !parentTransaction.active) {
+                        parentTransaction = null;
+                    }
+                }
+            }
+            catch (e) {
+                return parentTransaction ?
+                    parentTransaction._promise(null, function (_, reject) { reject(e); }) :
+                    rejection(e);
+            }
+            var enterTransaction = enterTransactionScope.bind(null, this, idbMode, storeNames, parentTransaction, scopeFunc);
+            return (parentTransaction ?
+                parentTransaction._promise(idbMode, enterTransaction, "lock") :
+                PSD.trans ?
+                    usePSD(PSD.transless, function () { return _this._whenReady(enterTransaction); }) :
+                    this._whenReady(enterTransaction));
+        };
+        Dexie.prototype.table = function (tableName) {
+            if (!hasOwn(this._allTables, tableName)) {
+                throw new exceptions.InvalidTable("Table " + tableName + " does not exist");
+            }
+            return this._allTables[tableName];
+        };
+        return Dexie;
+    }());
+
+    var symbolObservable = typeof Symbol !== "undefined" && "observable" in Symbol
+        ? Symbol.observable
+        : "@@observable";
+    var Observable =  (function () {
+        function Observable(subscribe) {
+            this._subscribe = subscribe;
+        }
+        Observable.prototype.subscribe = function (x, error, complete) {
+            return this._subscribe(!x || typeof x === "function" ? { next: x, error: error, complete: complete } : x);
+        };
+        Observable.prototype[symbolObservable] = function () {
+            return this;
+        };
+        return Observable;
+    }());
+
+    function extendObservabilitySet(target, newSet) {
+        keys(newSet).forEach(function (part) {
+            var rangeSet = target[part] || (target[part] = new RangeSet());
+            mergeRanges(rangeSet, newSet[part]);
+        });
+        return target;
+    }
+
+    function liveQuery(querier) {
+        return new Observable(function (observer) {
+            var scopeFuncIsAsync = isAsyncFunction(querier);
+            function execute(subscr) {
+                if (scopeFuncIsAsync) {
+                    incrementExpectedAwaits();
+                }
+                var exec = function () { return newScope(querier, { subscr: subscr, trans: null }); };
+                var rv = PSD.trans
+                    ?
+                        usePSD(PSD.transless, exec)
+                    : exec();
+                if (scopeFuncIsAsync) {
+                    rv.then(decrementExpectedAwaits, decrementExpectedAwaits);
+                }
+                return rv;
+            }
+            var closed = false;
+            var accumMuts = {};
+            var currentObs = {};
+            var subscription = {
+                get closed() {
+                    return closed;
+                },
+                unsubscribe: function () {
+                    closed = true;
+                    globalEvents.storagemutated.unsubscribe(mutationListener);
+                },
+            };
+            observer.start && observer.start(subscription);
+            var querying = false, startedListening = false;
+            function shouldNotify() {
+                return keys(currentObs).some(function (key) {
+                    return accumMuts[key] && rangesOverlap(accumMuts[key], currentObs[key]);
+                });
+            }
+            var mutationListener = function (parts) {
+                extendObservabilitySet(accumMuts, parts);
+                if (shouldNotify()) {
+                    doQuery();
+                }
+            };
+            var doQuery = function () {
+                if (querying || closed)
+                    return;
+                accumMuts = {};
+                var subscr = {};
+                var ret = execute(subscr);
+                if (!startedListening) {
+                    globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME, mutationListener);
+                    startedListening = true;
+                }
+                querying = true;
+                Promise.resolve(ret).then(function (result) {
+                    querying = false;
+                    if (closed)
+                        return;
+                    if (shouldNotify()) {
+                        doQuery();
+                    }
+                    else {
+                        accumMuts = {};
+                        currentObs = subscr;
+                        observer.next && observer.next(result);
+                    }
+                }, function (err) {
+                    querying = false;
+                    observer.error && observer.error(err);
+                    subscription.unsubscribe();
+                });
+            };
+            doQuery();
+            return subscription;
+        });
+    }
+
+    var domDeps;
+    try {
+        domDeps = {
+            indexedDB: _global.indexedDB || _global.mozIndexedDB || _global.webkitIndexedDB || _global.msIndexedDB,
+            IDBKeyRange: _global.IDBKeyRange || _global.webkitIDBKeyRange
+        };
+    }
+    catch (e) {
+        domDeps = { indexedDB: null, IDBKeyRange: null };
+    }
+
+    var Dexie = Dexie$1;
+    props(Dexie, __assign(__assign({}, fullNameExceptions), {
+        delete: function (databaseName) {
+            var db = new Dexie(databaseName, { addons: [] });
+            return db.delete();
+        },
+        exists: function (name) {
+            return new Dexie(name, { addons: [] }).open().then(function (db) {
+                db.close();
+                return true;
+            }).catch('NoSuchDatabaseError', function () { return false; });
+        },
+        getDatabaseNames: function (cb) {
+            try {
+                return getDatabaseNames(Dexie.dependencies).then(cb);
+            }
+            catch (_a) {
+                return rejection(new exceptions.MissingAPI());
+            }
+        },
+        defineClass: function () {
+            function Class(content) {
+                extend(this, content);
+            }
+            return Class;
+        }, ignoreTransaction: function (scopeFunc) {
+            return PSD.trans ?
+                usePSD(PSD.transless, scopeFunc) :
+                scopeFunc();
+        }, vip: vip, async: function (generatorFn) {
+            return function () {
+                try {
+                    var rv = awaitIterator(generatorFn.apply(this, arguments));
+                    if (!rv || typeof rv.then !== 'function')
+                        return DexiePromise.resolve(rv);
+                    return rv;
+                }
+                catch (e) {
+                    return rejection(e);
+                }
+            };
+        }, spawn: function (generatorFn, args, thiz) {
+            try {
+                var rv = awaitIterator(generatorFn.apply(thiz, args || []));
+                if (!rv || typeof rv.then !== 'function')
+                    return DexiePromise.resolve(rv);
+                return rv;
+            }
+            catch (e) {
+                return rejection(e);
+            }
+        },
+        currentTransaction: {
+            get: function () { return PSD.trans || null; }
+        }, waitFor: function (promiseOrFunction, optionalTimeout) {
+            var promise = DexiePromise.resolve(typeof promiseOrFunction === 'function' ?
+                Dexie.ignoreTransaction(promiseOrFunction) :
+                promiseOrFunction)
+                .timeout(optionalTimeout || 60000);
+            return PSD.trans ?
+                PSD.trans.waitFor(promise) :
+                promise;
+        },
+        Promise: DexiePromise,
+        debug: {
+            get: function () { return debug; },
+            set: function (value) {
+                setDebug(value, value === 'dexie' ? function () { return true; } : dexieStackFrameFilter);
+            }
+        },
+        derive: derive, extend: extend, props: props, override: override,
+        Events: Events, on: globalEvents, liveQuery: liveQuery, extendObservabilitySet: extendObservabilitySet,
+        getByKeyPath: getByKeyPath, setByKeyPath: setByKeyPath, delByKeyPath: delByKeyPath, shallowClone: shallowClone, deepClone: deepClone, getObjectDiff: getObjectDiff, cmp: cmp, asap: asap$1,
+        minKey: minKey,
+        addons: [],
+        connections: connections,
+        errnames: errnames,
+        dependencies: domDeps,
+        semVer: DEXIE_VERSION, version: DEXIE_VERSION.split('.')
+            .map(function (n) { return parseInt(n); })
+            .reduce(function (p, c, i) { return p + (c / Math.pow(10, i * 2)); }) }));
+    Dexie.maxKey = getMaxKey(Dexie.dependencies.IDBKeyRange);
+
+    if (typeof dispatchEvent !== 'undefined' && typeof addEventListener !== 'undefined') {
+        globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME, function (updatedParts) {
+            if (!propagatingLocally) {
+                var event_1;
+                if (isIEOrEdge) {
+                    event_1 = document.createEvent('CustomEvent');
+                    event_1.initCustomEvent(STORAGE_MUTATED_DOM_EVENT_NAME, true, true, updatedParts);
+                }
+                else {
+                    event_1 = new CustomEvent(STORAGE_MUTATED_DOM_EVENT_NAME, {
+                        detail: updatedParts
+                    });
+                }
+                propagatingLocally = true;
+                dispatchEvent(event_1);
+                propagatingLocally = false;
+            }
+        });
+        addEventListener(STORAGE_MUTATED_DOM_EVENT_NAME, function (_a) {
+            var detail = _a.detail;
+            if (!propagatingLocally) {
+                propagateLocally(detail);
+            }
+        });
+    }
+    function propagateLocally(updateParts) {
+        var wasMe = propagatingLocally;
+        try {
+            propagatingLocally = true;
+            globalEvents.storagemutated.fire(updateParts);
+        }
+        finally {
+            propagatingLocally = wasMe;
+        }
+    }
+    var propagatingLocally = false;
+
+    if (typeof BroadcastChannel !== 'undefined') {
+        var bc_1 = new BroadcastChannel(STORAGE_MUTATED_DOM_EVENT_NAME);
+        if (typeof bc_1.unref === 'function') {
+            bc_1.unref();
+        }
+        globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME, function (changedParts) {
+            if (!propagatingLocally) {
+                bc_1.postMessage(changedParts);
+            }
+        });
+        bc_1.onmessage = function (ev) {
+            if (ev.data)
+                propagateLocally(ev.data);
+        };
+    }
+    else if (typeof self !== 'undefined' && typeof navigator !== 'undefined') {
+        globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME, function (changedParts) {
+            try {
+                if (!propagatingLocally) {
+                    if (typeof localStorage !== 'undefined') {
+                        localStorage.setItem(STORAGE_MUTATED_DOM_EVENT_NAME, JSON.stringify({
+                            trig: Math.random(),
+                            changedParts: changedParts,
+                        }));
+                    }
+                    if (typeof self['clients'] === 'object') {
+                        __spreadArray([], self['clients'].matchAll({ includeUncontrolled: true }), true).forEach(function (client) {
+                            return client.postMessage({
+                                type: STORAGE_MUTATED_DOM_EVENT_NAME,
+                                changedParts: changedParts,
+                            });
+                        });
+                    }
+                }
+            }
+            catch (_a) { }
+        });
+        if (typeof addEventListener !== 'undefined') {
+            addEventListener('storage', function (ev) {
+                if (ev.key === STORAGE_MUTATED_DOM_EVENT_NAME) {
+                    var data = JSON.parse(ev.newValue);
+                    if (data)
+                        propagateLocally(data.changedParts);
+                }
+            });
+        }
+        var swContainer = self.document && navigator.serviceWorker;
+        if (swContainer) {
+            swContainer.addEventListener('message', propagateMessageLocally);
+        }
+    }
+    function propagateMessageLocally(_a) {
+        var data = _a.data;
+        if (data && data.type === STORAGE_MUTATED_DOM_EVENT_NAME) {
+            propagateLocally(data.changedParts);
+        }
+    }
+
+    DexiePromise.rejectionMapper = mapError;
+    setDebug(debug, dexieStackFrameFilter);
+
+    var namedExports = /*#__PURE__*/Object.freeze({
+        __proto__: null,
+        Dexie: Dexie$1,
+        liveQuery: liveQuery,
+        'default': Dexie$1,
+        RangeSet: RangeSet,
+        mergeRanges: mergeRanges,
+        rangesOverlap: rangesOverlap
+    });
+
+    __assign(Dexie$1, namedExports, { default: Dexie$1 });
+
+    return Dexie$1;
+
+}));
+//# sourceMappingURL=dexie.js.map

+ 1 - 0
web/Music/img/delete.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M13.3 10.9v27.85-.65ZM22.05 41H13.9q-1.15 0-2-.85-.85-.85-.85-2.05V10.9H8.9V8.65h8.6v-1.4h12.35v1.4h8.55v2.25h-2.1v9.25q-.55-.15-1.15-.25-.6-.1-1.1-.1v-8.9H13.3v27.2q0 .25.2.45t.4.2H21q.1.4.425 1.075.325.675.625 1.175Zm-3.4-6.5h1.15q0-3.15.55-4.775l.55-1.625v-13h-2.25Zm7.8-12.7q.45-.3 1.1-.6.65-.3 1.2-.5v-5.6h-2.3Zm7.1 22.1q-4.25 0-7.25-3.025t-3-7.275q0-4.3 3-7.275 3-2.975 7.25-2.975 4.3 0 7.3 3t3 7.25q0 4.25-3 7.275-3 3.025-7.3 3.025Zm3.25-5.7 1.25-1.25-3.65-3.65v-5.55h-1.75V34Z"/></svg>

BIN
web/Music/img/nothumb.png


BIN
web/Music/img/nothumb.psd


+ 168 - 182
web/Music/index.html

@@ -14,11 +14,13 @@
 	<!-- Handle native playback on Chrome Andoird-->
 	<script src="native.js"></script>
 
+	<!-- Handle data saving local music cache on PWA-->
+	<script src="./dexie.js"></script>
 	<link rel="manifest" crossorigin="use-credentials" href="manifest.json">
 	<title>AirMusic</title>
 </head>
 <body>
-<div id="mainMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:80;position:fixed;position:top:0px;left:0px;width:100%;">
+<div id="mainMenu" class="ui basic fluid AMmenu menu bottomBlue" style="z-index:80; position:fixed; top:0px; left:0px; width:100%;">
     <button class="ui item icon noBorder AMmenu button" onClick="toggleLeftMenu();"><i class="content icon"></i></button>
 	<div class="item noBorder AMmenu" style="padding-right:0px;padding-top:12px;"><i id="AMmenuIcon" class="music icon large whiteFont"></i></div>
 	<div class="item noBorder AMmenu" style="padding-left:3px;padding-top:3px;padding-bottom:5px;min-width:50%;">
@@ -320,7 +322,7 @@
 <div id="settingInterface" class="quickMenu">
 	<div style="">
 		<div class="ui relaxed list" style="padding:0px !important;">
-			<div id="settingMenuTitle" class="item whiteFont" style="">N/A</div>
+			<div id="settingMenuTitle" class="item whiteFont" style="margin-bottom: 1em;">N/A</div>
 			<div class="item selectable whiteFont" onclick="showPlaylistInterface(); $('#settingInterface').fadeOut('fast');"><i class="add icon" style="margin-right:5px;"></i> Add to playlist</div>
 			<div class="item selectable whiteFont" onClick="openInFileExplorer(); hideAllquickMenu();"><i class="folder open icon" style="margin-right:5px;"></i> Open in File Explorer</div>
 			<div class="item selectable whiteFont" onClick="searchOnYoutube(); hideAllquickMenu();"><i class="youtube play icon" style="margin-right:5px;"></i>Search on Youtube</div>
@@ -389,29 +391,24 @@
 	var isAndroid = ua.indexOf("android") > -1; //&& ua.indexOf("mobile");
 	var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
 	var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
-	var cacheAvailable = 'caches' in self;
-	let cacheDb, cacheStore, cacheDbTx;
-	var dbExists = !(!window.indexedDB);
+	var dexiedb = new Dexie("AirMusic");
+	var dbExists = true;
 
 	//Init database connection if indexedDB Exists
 	if (dbExists){
-		let cacheDbConn = window.indexedDB.open('airmusic', 4);
-		cacheDbConn.onupgradeneeded = function(event) { 
-			cacheDb = event.target.result;
-			cacheDbTx = event.target.transaction;
-			cacheStore = cacheDb.createObjectStore("files",{keyPath:"filename"});
-			cacheStore = cacheDb.createObjectStore("thumblist",{keyPath:"filename"});
-		};
-		cacheDbConn.onerror = function(event) {
-			console.log("ERROR: " + event.target.errorCode)
-		};
-		cacheDbConn.onsuccess = function(event) {
-			cacheDb = event.target.result
+		dexiedb.version(2).stores({
+			files: `
+				filename,
+				cachetime,
+				content`,
+			thumbnails: `
+				filename,
+				cachetime,
+				content`,
+		});
 
-			//Database connection established.
-			//Clear old cache in the system if any
-			clearExpiredCache();
-		}
+		//Clear expire cache if exists
+		clearExpiredCache();
 	}
 
 	//Embed native mediaSession for any device that supports it 
@@ -468,12 +465,14 @@
 				//Create a dummy folder and trick the system to load to the previous states
 				var a = '<div></div>';
 				a = $(a).attr("filepath",currentPath);
-				openFolder(a[0],{playIDAfterOpen: playingFileDetail[0],startPaused: initPauseState});
+				openFolder(a[0],{
+					playIDAfterOpen: playingFileDetail[0],
+					startPaused: initPauseState}
+				);
 			}else{
 				//currentpath is empty, aka Music Mode
 				loadSongList();
 			}
-
 			
 		}else{
 			//No state to restore. Restore Viewing Tab instead.
@@ -509,7 +508,18 @@
 		$("#mainList").html("");
 		togglePagingMode(false);
 		//Render the elements
-		$("#mainList").append(`<div class="mainList item">HELLO WORLD</div>`);
+		$("#mainList").append(`
+			<div class="mainList item"  onclick="HandleClearAllCache();">
+				<div class="ui header selectable" style="margin:0px !important;">
+					<img class="ui small image" src="img/delete.svg" style="margin-right: 0.2em; filter: invert(100%);">
+					<div class="content whiteFont" style="padding-top: 2px; line-height:1em;width : 80%; font-weight: lighter;">
+					Clear All Local Cache
+					<div class="sub header fileinfo" style="color: #c7c7c7;">Free up application space on mobile devices</div>
+				</div>
+				</div>
+			 </div>
+
+		`);
 		hideLeftMenu();
 
 		//Update the headers
@@ -1255,24 +1265,25 @@
 	}
 
 	//Check if a music file thumbnail exists in cache
-	function getThumbnailFromCache(filepath, callback){
+	async function getThumbnailFromCache(filepath){
 		if (dbExists){
-			let dbTx = cacheDb.transaction("thumblist","readwrite");
-			let tstore = dbTx.objectStore("thumblist");
-			let retrv = tstore.get(filepath);
-			retrv.onsuccess = (event) => {
-				let cachefile = retrv.result;
-				if (cachefile == undefined || cachefile.content == undefined){
-					//thumbnail not exists in cache.
-					callback(undefined);
-				}else{
-					//load from cache
-					callback(cachefile);
-				}
-			}
-				
+			const thumbrecord = await dexiedb.thumbnails.get({
+				filename: filepath
+			});
+			return thumbrecord;
+		}
+		return undefined;
+	}
+
+	//Check if a music file exists in cache
+	async function getSongFromCache(filepath){
+		if (dbExists){
+			const songCache = await dexiedb.files.get({
+				filename: filepath
+			});
+			return songCache;
 		}
-		return callback(undefined);
+		return undefined;
 	}
 
 	function loadThumbnailToMusicList(selector = ".mainList.file.item"){
@@ -1286,8 +1297,8 @@
 			realVpath = realVpath.join("=");
 			//console.log(thisFileItemID, realVpath, rawname);
 
-			getThumbnailFromCache(realVpath, function(cachedThumb){
-				if (cachedThumb == undefined){
+			getThumbnailFromCache(realVpath).then(cachedThumb => {
+				if (cachedThumb == undefined || cachedThumb.content == undefined){
 					//Load the thumbnail for this item in list
 					fetch("../system/file_system/loadThumbnail?vpath=" + encodeURIComponent(realVpath))
 					.then((response) => response.json())
@@ -1306,29 +1317,28 @@
 
 						if (dbExists){
 							//Put this thumbnail into cache
-							let dbTx = cacheDb.transaction("thumblist","readwrite");
-							let tstore = dbTx.objectStore("thumblist");
-							let retrv = tstore.put({
+							dexiedb.thumbnails.put({
 								"filename": realVpath,
 								"cachetime":parseInt(Date.now() / 1000),
-								"content": data.content,
+								"content": data,
 							});
 						}
 					});
 				}else{
 					//Use the result as thumbnail
 					console.log("Loaded from cache" , realVpath)
-					$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + cachedThumb);
+					$("#" + thisFileItemID).find("img").attr("src","data:image/jpg;base64," + cachedThumb.content);
 					$(".dropdownList.file.item").each(function(){
 						var thisFilepath = JSON.parse(decodeURIComponent($(this).attr("filepath")));
 						if ($(this).attr("listid") == thisFileItemID && thisFilepath == filepath){
-							$(this).find("img").attr("src","data:image/jpg;base64," + cachedThumb);
+							$(this).find("img").attr("src","data:image/jpg;base64," + cachedThumb.content);
 						}
 					});
 				}
 			});
 			
 			
+			
 			/*
 			ao_module_agirun("Music/functions/getThumbnail.js", {
 				file: realVpath,
@@ -1351,16 +1361,17 @@
 
 	function loadThumbnail(filepath){
 		//Load the thumbnail
-		var realVpath = filepath.split("=");
+		let realVpath = filepath.split("=");
 		realVpath.shift();
 		realVpath = realVpath.join("=");
 		playingSongVpath = realVpath;
-		getThumbnailFromCache(realVpath, function(thumbdata){
+		let useDefaultTheme = false; //If set to false, pick from albumn art
+		getThumbnailFromCache(realVpath).then(thumbdata => {
 			if (playingSongVpath != realVpath){
 				//Already switch to another song
 				return;
 			}
-			if (thumbdata == undefined){
+			if (thumbdata == undefined || thumbdata.content == undefined){
 				//No thumbnail found. Load it from server
 				//console.log("Thumbnail cache not found", realVpath);
 				ao_module_agirun("Music/functions/getThumbnail.js", {
@@ -1379,6 +1390,7 @@
 								{ src: "img/default.png",   sizes: '512x512',   type: 'image/png' }
 							]
 						}
+						useDefaultTheme = true;
 					}else{
 						$("#albumnArtImage").attr("src","data:image/jpg;base64," + data);
 						$("#smallPlayerThumb").attr("src","data:image/jpg;base64," + data);
@@ -1389,7 +1401,10 @@
 							]
 						}
 					}
-					resizeQuickAdjust();
+					resizeQuickAdjust(useDefaultTheme);
+					
+					//Update theme color
+					updatePlayerThemeAndBackground(useDefaultTheme);
 				});
 			}else{
 				//Thumbnail found.
@@ -1402,9 +1417,11 @@
 						{ src: "data:image/jpg;base64," + thumbdata.content,   sizes: '480x480',   type: 'image/jpg' }
 					]
 				}
-
+				//Update theme color
+				updatePlayerThemeAndBackground(useDefaultTheme);
 			}
 			
+			
 		});
 		
 	}
@@ -1521,10 +1538,14 @@
 	function togglePlayMode(){
 	    if (currentPlaying){
 	        originalVol = audioElement[0].volume;
-	        fadeAudio();
+	        //fadeAudio(); //<- This cause some issue on PWA
+			audioElement[0].pause();
+			updateStateReferingURL();
 	        setPlaying(false);
 	    }else{
-	        gainAudio();
+	        //gainAudio();
+			audioElement[0].play();
+			updateStateReferingURL();
 	        setPlaying(true);
 	    }
 	}
@@ -1606,13 +1627,8 @@
 		var playbackURL = "../" + rootPath + "=" + encodeURIComponent(filename); //Convert absolute dir to relative
 		var ext = filename.split(".").pop();
 		playingSongVpath = filename;
-		if (dbExists && (!isFirefox)){
-			cacheDbTx = cacheDb.transaction("files","readwrite");
-			cacheStore = cacheDbTx.objectStore("files");
-
-			let retrvReq = cacheStore.get(filename);
-			retrvReq.onsuccess = (event) => {
-				let cachefile = retrvReq.result;
+		if (dbExists){
+			getSongFromCache(filename).then(cachefile => {
 				if (cachefile == undefined || cachefile.content == undefined){
 					//No cache. Play from streaming and cache this
 					$("#mainAudioPlayer").attr("src", playbackURL);
@@ -1620,11 +1636,10 @@
 
 					//Only cache non video audio tracks
 					if (isSupportedCachingAudioFormat(ext)){
+						
 						loadAudioFileURLAsBlob(playbackURL, function(fileBlob){
 							//Store the blob into indexDB
-							let cacheDbTx2 = cacheDb.transaction("files","readwrite");
-							let cacheStore2 = cacheDbTx2.objectStore("files");
-							cacheStore2.put({
+							dexiedb.files.put({
 								"filename": filename,
 								"cachetime": parseInt(Date.now() / 1000),
 								"content": fileBlob
@@ -1655,6 +1670,9 @@
 						//Put the final data into audio elements
 						$("#mainAudioPlayer").attr("src", adjustedAudioData);
 						startPlaybackAfterAudioLoaded(audio, playAfterLoad);
+
+						//Update the cachetime
+						dexiedb.files.update(filename, {cachetime:parseInt(Date.now() / 1000)});
 					};
 					reader.readAsDataURL(cachefile.content);
 				}else{
@@ -1662,7 +1680,8 @@
 					$("#mainAudioPlayer").attr("src", playbackURL);
 					startPlaybackAfterAudioLoaded(audio, playAfterLoad);
 				}
-			}
+			});
+			
 		}else{
 			//IndexedDB not found
 			$("#mainAudioPlayer").attr("src", playbackURL);
@@ -1946,6 +1965,67 @@
 	    });
 	    hideLeftMenu();
 	}
+
+	function updatePlayerThemeAndBackground(useDefault=true){
+		if (useDefault){
+			$("#playerInterface").css({
+				"background": "rgba(20,20,20,0.5)",
+			});
+
+		}else{
+			let avgc = getAverageRGB($("#albumnArtImage")[0]);
+			$("#playerInterface").css({
+				"background": `rgba(${avgc.r},${avgc.g},${avgc.b},0.5)`,
+			});
+
+			console.log(avgc);
+		}
+	}
+
+	function getAverageRGB(imgEl) {
+		var blockSize = 5, 
+			defaultRGB = {r:0,g:0,b:0}, 
+			canvas = document.createElement('canvas'),
+			context = canvas.getContext && canvas.getContext('2d'),
+			data, width, height,
+			i = -4,
+			length,
+			rgb = {r:0,g:0,b:0},
+			count = 0;
+
+		if (!context) {
+			return defaultRGB;
+		}
+
+		height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
+		width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
+
+		context.drawImage(imgEl, 0, 0);
+
+		try {
+			data = context.getImageData(0, 0, width, height);
+		} catch(e) {
+			/* security error, img on diff domain */
+			return defaultRGB;
+		}
+
+		length = data.data.length;
+
+		while ( (i += blockSize * 4) < length ) {
+			++count;
+			rgb.r += data.data[i];
+			rgb.g += data.data[i+1];
+			rgb.b += data.data[i+2];
+		}
+
+		// ~~ used to floor values
+		rgb.r = ~~(rgb.r/count);
+		rgb.g = ~~(rgb.g/count);
+		rgb.b = ~~(rgb.b/count);
+
+		return rgb;
+
+		}
 	
 	function isMobile(){
 		if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
@@ -1957,7 +2037,7 @@
 	function setWindowHash(hashValue){
 		hashValue = JSON.stringify(hashValue);
 
-		if (!isAndroid){
+		if (!isMobile()){
 			return;
 		}
 		
@@ -2383,8 +2463,6 @@
 			if (i > pageKeepRange[1]){
 				targetPage += 1;
 			}
-			
-		
 
 			$("#currentPlayingMainList").append(`<div class="dropdownList file item" style="${opacityShowing}" filepath="${ao_module_utils.objectToAttr(playingList[i][0])}" listid="${i + 1}" rawname="${ao_module_utils.objectToAttr(playingList[i][1])}">
 				<div class="ui header selectable" style="margin:0px !important;" onClick="playSongFromDropdownList(this);" targetPage="${targetPage}">
@@ -2420,14 +2498,18 @@
 		xhr.send();
 	}
 
+	function HandleClearAllCache(){
+		if (confirm("Confirm Clearing All Local Cache?")){
+			clearAllCache();
+			alert("All cache cleared")
+		}
+	}
+
 	//Clear all cached audio files
 	function clearAllCache(){
-		let dbtx = cacheDb.transaction("files","readwrite");
-		let fstore = dbtx.objectStore("files");
-		var clearReq = fstore.clear();
-		clearReq.onsuccess = function(e){
-			console.log("All cache file cleared");
-		}
+		dexiedb.files.clear();
+		dexiedb.thumbnails.clear();
+		console.log("All cached data cleared");
 	}
 
 	function removeCacheByFilename(filename, callback=undefined){
@@ -2443,91 +2525,24 @@
 
 	//Clear all expired cache
 	function clearExpiredCache(){
-		var expireTime = 604800; //1 week
-		
-		getAllFileCache(function(allCachedTracks){
-			var expiredFilenames = [];
-			//Check all the cache to see which is expired
-			allCachedTracks.forEach(function(track){
-				if (track.cachetime + expireTime < Date.now()/1000){
-					//Expired. Clear this cache
-					expiredFilenames.push(track.filename);
-					console.log("[AirMusic] Expired track cleared: ", track);
-				}
-				
-			});
-
-			
-			//Delete those cache that have expired
-			expiredFilenames.forEach(function(filenameToBeDeleted){
-				removeCacheByFilename(filenameToBeDeleted);
-			});
+		var expireTime = 604800; //604800 = 1 week
+		var expireTimestamp = Date.now()/1000 - expireTime; //Any cache time before this is expired
 
-			console.log("[AirMusic] File cache clearning cycle completed");
+		/*
+		dexiedb.files.where("cachetime").below(expireTimestamp).each(function(item){
+			console.log("Deleting File for" + item.filename);
 		});
 
-		getAllFileCache(function(allCachedTracks){
-			var expiredFilenames = [];
-			//Check all the cache to see which is expired
-			allCachedTracks.forEach(function(track){
-				if (track.cachetime + expireTime < Date.now()/1000){
-					//Expired. Clear this cache
-					expiredFilenames.push(track.filename);
-					console.log("Expired track cleared: ", track);
-				}
-				
-			});
-
-			//Delete those cache that have expired
-			expiredFilenames.forEach(function(filenameToBeDeleted){
-				removeCacheByFilename(filenameToBeDeleted);
-			});
-
-			console.log("[AirMusic] Thumbnail cache clearning cycle completed")
+		dexiedb.thumbnails.where("cachetime").below(expireTimestamp).each(function(item){
+			console.log("Deleting Thumbnail for" + item.filename);
 		});
-	}
-
-	function getAllFileCache(callback) {
-		var trans = cacheDb.transaction("files", IDBTransaction.READ_ONLY);
-		var store = trans.objectStore("files");
-		var items = [];
-		trans.oncomplete = function(evt) {  
-			callback(items);
-		};
-		var cursorRequest = store.openCursor();
-		cursorRequest.onerror = function(error) {
-			console.log(error);
-		};
-		cursorRequest.onsuccess = function(evt) {                    
-			var cursor = evt.target.result;
-			if (cursor) {
-				items.push(cursor.value);
-				cursor.continue();
-			}
-		};
-	}
+		*/
 
-	function getAllThumbCache(callback) {
-		var trans = cacheDb.transaction("thumblist", IDBTransaction.READ_ONLY);
-		var store = trans.objectStore("thumblist");
-		var items = [];
-		trans.oncomplete = function(evt) {  
-			callback(items);
-		};
-		var cursorRequest = store.openCursor();
-		cursorRequest.onerror = function(error) {
-			console.log(error);
-		};
-		cursorRequest.onsuccess = function(evt) {                    
-			var cursor = evt.target.result;
-			if (cursor) {
-				items.push(cursor.value);
-				cursor.continue();
-			}
-		};
+		dexiedb.files.where("cachetime").below(expireTimestamp).delete();
+		dexiedb.thumbnails.where("cachetime").below(expireTimestamp).delete();
+		console.log("[AirMusic] Expire cache cleared")
 	}
 
-
 	function replaceImageToDefault(target){
 		$(target).attr('src', "img/eq.svg");
 	}
@@ -2755,39 +2770,10 @@
 	
 	function setStorage(configName,configValue){
 		ao_module_storage.setStorage("AirMusic",configName,configValue);
-		/*
-    	$.ajax({
-    	  type: 'GET',
-    	  url: "../system/file_system/preference",
-    	  data: {key: "AirMusic/" + configName,value:configValue},
-    	  success: function(data){},
-    	  async:true
-		});
-		*/
     	return true;
     }
     
     function loadStorage(configName){
-		/*
-    	var result = "";
-    	$.ajax({
-    	  type: 'GET',
-    	  url: "../system/file_system/preference",
-    	  data: {key: "AirMusic/" + configName},
-    	  success: function(data){
-				if (data.error !== undefined){
-					result = "";
-				}else{
-					result = data;
-				}
-			  },
-    	  error: function(data){result = "";},
-    	  async:false,
-    	  timeout: 3000
-    	});
-		return result;
-		*/
-
 		return ao_module_storage.loadStorage("AirMusic",configName);
     }
 

+ 10 - 8
web/Music/main.css

@@ -6,14 +6,15 @@
 */
 
 body{
-    background-color: #474747;
+    background: rgb(20,22,25);
+    background: linear-gradient(90deg, rgba(20,22,25,1) 43%, rgba(35,39,46,1) 100%);
 }
 p,span,h1,h2,h3,h4,h5,h6,div,a,button{
     font-family: "Microsoft JhengHei","SimHei", "Apple LiGothic Medium", "STHeiti";
 }
 
 .AMmenu{
-    background-color: #303030 !important;
+    background-color: #16171a !important;
     color: white !important;
     box-shadow: 0px 0px 0px 0px transparent !important;
 }
@@ -27,14 +28,14 @@ p,span,h1,h2,h3,h4,h5,h6,div,a,button{
     background-color: #3f3f3f !important;
 }
 .bottomBlue{
-    border-bottom: 3px solid #4b75ff !important;
+    border-bottom: 3px solid #2d4771 !important;
 }
 .leftsb{
     position:fixed;
     top:0px;
     left:0px;
     width:60%;
-    background-color:#404040;
+    background-color:#141519;
 }
 .leftsbObject{
     padding: 5px;
@@ -236,7 +237,7 @@ p,span,h1,h2,h3,h4,h5,h6,div,a,button{
     overflow-x:hidden;
     display:none;
     z-index:120;
-    border-radius: 20px;
+    border-radius: 0.4em;
 }
 
 #fadeReturnScreen{
@@ -325,7 +326,8 @@ button{
     border: 1px solid #969696;
 }
 .dropdownMusicList{
-    background-color:rgb(66, 66, 66);
+    background: rgb(20,22,25);
+    background: linear-gradient(90deg, rgba(20,22,25,1) 43%, rgba(35,39,46,1) 100%);
     position:fixed;
     left:0px;
     top:0px;
@@ -336,7 +338,7 @@ button{
 .dropdownMusicListMiniMenu{
     width:100%;
     height:25px;
-    background-color:rgb(55, 55, 55);
+    background-color:#141519;
     padding-left:12px;
     padding-right:12px;
     padding-top:3px;
@@ -348,7 +350,7 @@ button{
     bottom:0px;
     width:100%;
     height:25px;
-    background-color:rgb(55, 55, 55);
+    background-color:#141519;
     padding-left:12px;
     padding-right:12px;
     padding-top:3px;