function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : factory(global.Fix = global.Fix || {});
})(this, function (exports) {
    'use strict';

    function noop(a, b, c) {}

    function isNative(Ctor) {
        return typeof Ctor === 'function' && /native code/.test(Ctor.toString());
    }

    var hasProto = '__proto__' in {};

    var _toString = Object.prototype.toString;

    function isPlainObject(obj) {
        return _toString.call(obj) === '[object Object]';
    }

    function isConfigurable(obj, key) {
        var configurable = true;
        var property = Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(obj, key);
        if (property && property.configurable === false) {
            configurable = false;
        }
        return configurable;
    }

    function isExtensible(obj) {
        if (Object.isExtensible) {
            return Object.isExtensible(obj);
        }
        var name = '';
        while (obj.hasOwnProperty(name)) {
            name += '?';
        }
        obj[name] = true;
        var returnValue = obj.hasOwnProperty(name);
        delete obj[name];
        return returnValue;
    }

    function remove(arr, item) {
        if (arr && arr.length) {
            var _index = arr.indexOf(item);
            if (_index > -1) {
                return arr.splice(_index, 1);
            }
        }
    }

    // const bailRE = /[^\w.$]/

    function parsePath(path) {
        // 正常表达式比较慢,能不要的就不要了
        // if (bailRE.test(path)) {
        //     return
        // }
        var segments = path.split('.');
        return function (obj) {
            for (var i = 0; i < segments.length; i++) {
                if (!obj) return;
                obj = obj[segments[i]];
            }
            return obj;
        };
    }

    var nextTick = function () {
        var callbacks = [];
        var pending = false;
        var timerFunc = void 0;

        function nextTickHandler() {
            pending = false;
            var copies = callbacks.slice(0);
            callbacks.length = 0;
            for (var i = 0; i < copies.length; i++) {
                copies[i]();
            }
        }

        // An asynchronous deferring mechanism.
        // In pre 2.4, we used to use microtasks (Promise/MutationObserver)
        // but microtasks actually has too high a priority and fires in between
        // supposedly sequential events (e.g. #4521, #6690) or even between
        // bubbling of the same event (#6566). Technically setImmediate should be
        // the ideal choice, but it's not available everywhere; and the only polyfill
        // that consistently queues the callback after all DOM events triggered in the
        // same loop is by using MessageChannel.
        /* istanbul ignore if */
        if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
            timerFunc = function timerFunc() {
                setImmediate(nextTickHandler);
            };
        } else if (typeof MessageChannel !== 'undefined' && (isNative(MessageChannel) ||
        // PhantomJS
        MessageChannel.toString() === '[object MessageChannelConstructor]')) {
            var channel = new MessageChannel();
            var port = channel.port2;
            channel.port1.onmessage = nextTickHandler;
            timerFunc = function timerFunc() {
                port.postMessage(1);
            };
        } else
            /* istanbul ignore next */
            if (typeof Promise !== 'undefined' && isNative(Promise)) {
                // use microtask in non-DOM environments, e.g. Weex
                var p = Promise.resolve();
                timerFunc = function timerFunc() {
                    p.then(nextTickHandler);
                };
            } else {
                // fallback to setTimeout
                timerFunc = function timerFunc() {
                    setTimeout(nextTickHandler, 0);
                };
            }

        return function queueNextTick(cb, ctx) {
            var _resolve = void 0;
            callbacks.push(function () {
                if (cb) {
                    try {
                        cb.call(ctx);
                    } catch (e) {
                        console.error(e);
                    }
                } else if (_resolve) {
                    _resolve(ctx);
                }
            });
            if (!pending) {
                pending = true;
                timerFunc();
            }
            // $flow-disable-line
            if (!cb && typeof Promise !== 'undefined') {
                return new Promise(function (resolve, reject) {
                    _resolve = resolve;
                });
            }
        };
    }();

    var falsy;
    var $$skipArray = {
        __ob__: falsy,
        $accessors: falsy,
        $vbthis: falsy,
        $vbsetter: falsy
    };

    var uid = 0;

    /**
     * A dep is an observable that can have multiple
     * directives subscribing to it.
     */

    var Dep = function () {
        function Dep() {
            _classCallCheck(this, Dep);

            this.id = uid++;
            this.subs = [];
        }

        Dep.prototype.addSub = function addSub(sub) {
            this.subs.push(sub);
        };

        Dep.prototype.removeSub = function removeSub(sub) {
            remove(this.subs, sub);
        };

        Dep.prototype.depend = function depend() {
            if (Dep.target) {
                Dep.target.addDep(this);
            }
        };

        Dep.prototype.notify = function notify(options) {
            // stabilize the subscriber list first
            var subs = this.subs.slice();
            for (var i = 0, l = subs.length; i < l; i++) {
                subs[i].update(options);
            }
        };

        return Dep;
    }();

    // the current target watcher being evaluated.
    // this is globally unique because there could be only one
    // watcher being evaluated at any time.


    Dep.target = null;
    var targetStack = [];

    function pushTarget(_target) {
        if (Dep.target) targetStack.push(Dep.target);
        Dep.target = _target;
    }

    function popTarget() {
        Dep.target = targetStack.pop();
    }

    //如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
    //标准浏览器使用__defineGetter__, __defineSetter__实现
    var canHideProperty = true;
    try {
        Object.defineProperty({}, '_', {
            value: 'x'
        });
        delete $$skipArray.$vbsetter;
        delete $$skipArray.$vbthis;
    } catch (e) {
        /* istanbul ignore next*/
        canHideProperty = false;
    }

    var createViewModel = Object.defineProperties;
    var defineProperty = void 0;

    /* istanbul ignore if*/
    if (!canHideProperty) {
        if ('__defineGetter__' in {}) {
            defineProperty = function defineProperty(obj, prop, desc) {
                if ('value' in desc) {
                    obj[prop] = desc.value;
                }
                if ('get' in desc) {
                    obj.__defineGetter__(prop, desc.get);
                }
                if ('set' in desc) {
                    obj.__defineSetter__(prop, desc.set);
                }
                return obj;
            };
            createViewModel = function createViewModel(obj, descs) {
                for (var prop in descs) {
                    if (descs.hasOwnProperty(prop)) {
                        defineProperty(obj, prop, descs[prop]);
                    }
                }
                return obj;
            };
        }
    }

    var createViewModel$1 = createViewModel;

    var queue = [];
    var activatedChildren = [];
    var has = {};
    var waiting = false;
    var flushing = false;
    var index = 0;

    function resetSchedulerState() {
        index = queue.length = activatedChildren.length = 0;
        has = {};
        waiting = flushing = false;
    }

    function flushSchedulerQueue() {
        flushing = true;
        var watcher = void 0,
            id = void 0,
            options = void 0;

        // Sort queue before flush.
        // This ensures that:
        // 1. Components are updated from parent to child. (because parent is always
        //    created before the child)
        // 2. A component's user watchers are run before its render watcher (because
        //    user watchers are created before the render watcher)
        // 3. If a component is destroyed during a parent component's watcher run,
        //    its watchers can be skipped.
        queue.sort(function (a, b) {
            return a.id - b.id;
        });

        // do not cache length because more watchers might be pushed
        // as we run existing watchers
        for (index = 0; index < queue.length; index++) {
            watcher = queue[index].watcher;
            options = queue[index].options;
            id = watcher.id;
            has[id] = null;
            watcher.run(options);
        }

        resetSchedulerState();
    }

    function queueWatcher(watcher, options) {
        var id = watcher.id;
        if (has[id] == null) {
            has[id] = true;
            if (!flushing) {
                queue.push({ watcher: watcher, options: options });
            } else {
                // if already flushing, splice the watcher based on its id
                // if already past its id, it will be run next immediately.
                var i = queue.length - 1;
                while (i > index && queue[i].watcher.id > watcher.id) {
                    i--;
                }
                queue.splice(i + 1, 0, { watcher: watcher, options: options });
            }
            // queue the flush
            if (!waiting) {
                waiting = true;
                nextTick(flushSchedulerQueue);
            }
        }
    }

    var uid$1 = 0;

    var Watcher = function () {
        function Watcher(vm, expOrFn, cb, options) {
            _classCallCheck(this, Watcher);

            this.vm = vm;
            // vm._watchers || (vm._watchers = [])
            // vm._watchers.push(this)
            // options
            if (options) {
                this.deep = !!options.deep;
                this.user = !!options.user;
                this.lazy = !!options.lazy;
                this.sync = !!options.sync;
            } else {
                this.deep = this.user = this.lazy = this.sync = false;
            }
            this.cb = cb;
            this.id = ++uid$1; // uid for batching
            this.active = true;
            this.dirty = this.lazy; // for lazy watchers
            this.deps = [];
            this.newDeps = [];
            this.depIds = new Set();
            this.newDepIds = new Set();
            this.expression = '';
            // parse expression for getter
            if (typeof expOrFn === 'function') {
                this.getter = expOrFn;
            } else {
                this.getter = parsePath(expOrFn);
                if (!this.getter) {
                    this.getter = function () {};
                }
            }
            this.value = this.lazy ? undefined : this.get();
        }

        Watcher.prototype.get = function get() {
            pushTarget(this);
            var value = void 0;
            var vm = this.vm;
            try {
                value = this.getter.call(vm, vm);
            } catch (e) {
                // if (this.user) {
                // } else {
                // console.error(e)
                // }
            } finally {
                // "touch" every property so they are all tracked as
                // dependencies for deep watching
                if (this.deep) {
                    traverse(value);
                }
                popTarget();
                this.cleanupDeps();
            }
            return value;
        };

        Watcher.prototype.addDep = function addDep(dep) {
            var id = dep.id;
            if (!this.newDepIds.has(id)) {
                this.newDepIds.add(id);
                this.newDeps.push(dep);
                if (!this.depIds.has(id)) {
                    dep.addSub(this);
                }
            }
        };

        Watcher.prototype.cleanupDeps = function cleanupDeps() {
            var i = this.deps.length;
            while (i--) {
                var dep = this.deps[i];
                if (!this.newDepIds.has(dep.id)) {
                    dep.removeSub(this);
                }
            }
            var tmp = this.depIds;
            this.depIds = this.newDepIds;
            this.newDepIds = tmp;
            this.newDepIds.clear();
            tmp = this.deps;
            this.deps = this.newDeps;
            this.newDeps = tmp;
            this.newDeps.length = 0;
        };

        Watcher.prototype.update = function update(options) {
            /* istanbul ignore else */
            if (this.lazy) {
                this.dirty = true;
            } else if (this.sync) {
                this.run(options);
            } else {
                queueWatcher(this, options);
            }
        };

        Watcher.prototype.run = function run(options) {
            if (this.active) {
                var value = this.get();
                if (value !== this.value ||
                // Deep watchers and watchers on Object/Arrays should fire even
                // when the value is the same, because the value may
                // have mutated.
                BI._.isObject(value) && options && options.refresh || this.deep) {
                    // set new value
                    var oldValue = this.value;
                    this.value = value;
                    if (this.user) {
                        try {
                            this.cb.call(this.vm, value, oldValue, options);
                        } catch (e) {
                            console.error(e);
                        }
                    } else {
                        try {
                            this.cb.call(this.vm, value, oldValue, options);
                        } catch (e) {
                            console.error(e);
                        }
                    }
                }
            }
        };

        Watcher.prototype.evaluate = function evaluate() {
            this.value = this.get();
            this.dirty = false;
        };

        Watcher.prototype.depend = function depend() {
            var i = this.deps.length;
            while (i--) {
                this.deps[i].depend();
            }
        };

        Watcher.prototype.teardown = function teardown() {
            if (this.active) {
                // remove self from vm's watcher list
                // this is a somewhat expensive operation so we skip it
                // if the vm is being destroyed.
                remove(this.vm && this.vm._watchers, this);
                var i = this.deps.length;
                while (i--) {
                    this.deps[i].removeSub(this);
                }
                this.active = false;
            }
        };

        return Watcher;
    }();

    var seenObjects = new Set();

    function traverse(val) {
        seenObjects.clear();
        _traverse(val, seenObjects);
    }

    function _traverse(val, seen) {
        var i = void 0,
            keys = void 0;
        var isA = BI._.isArray(val);
        if (!isA && !BI._.isObject(val)) {
            return;
        }
        if (val.__ob__) {
            var depId = val.__ob__.dep.id;
            if (seen.has(depId)) {
                return;
            }
            seen.add(depId);
        }
        if (isA) {
            i = val.length;
            while (i--) {
                _traverse(val[i], seen);
            }
        } else {
            keys = BI._.keys(val);
            i = keys.length;
            while (i--) {
                _traverse(val[keys[i]], seen);
            }
        }
    }

    var arrayProto = Array.prototype;
    var arrayMethods = [];
    BI._.each(['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'], function (method) {
        var original = arrayProto[method];
        arrayMethods[method] = function mutator() {
            for (var _len = arguments.length, args = Array(_len), _key2 = 0; _key2 < _len; _key2++) {
                args[_key2] = arguments[_key2];
            }

            var ob = this.__ob__;
            var inserted = void 0;
            switch (method) {
                case 'push':
                case 'unshift':
                    inserted = args;
                    break;
                case 'splice':
                    inserted = args.slice(2);
                    break;
            }
            if (inserted) inserted = ob.observeArray(inserted);
            switch (method) {
                case 'push':
                case 'unshift':
                    args = inserted;
                    break;
                case 'splice':
                    if (args.length > 2) {
                        args = [args[0], args[1]].concat(inserted ? inserted : []);
                    }
                    break;
            }
            var result = original.apply(this, args);
            notify(ob.parent, ob.parentKey, ob.dep, true);
            return result;
        };
    });

    var arrayKeys = BI._.keys(arrayMethods);

    var observerState = {
        shouldConvert: true
    };

    function def(obj, key, val, enumerable) {
        Object.defineProperty(obj, key, {
            value: val,
            enumerable: !!enumerable,
            writable: true,
            configurable: true
        });
    }

    /**
     * Observer class that are attached to each observed
     * object. Once attached, the observer converts target
     * object's property keys into getter/setters that
     * collect dependencies and dispatches updates.
     */

    var Observer = function () {
        function Observer(value) {
            _classCallCheck(this, Observer);

            this.value = value;
            this.dep = new Dep();
            this.vmCount = 0;
            if (BI._.isArray(value)) {
                var augment = hasProto ? protoAugment : copyAugment;
                augment(value, arrayMethods, arrayKeys);
                this.model = this.observeArray(value);
            } else {
                this.model = this.walk(value);
            }
            def(this.model, "__ob__", this);
        }

        Observer.prototype.walk = function walk(obj) {
            return defineReactive(obj, this);
        };

        Observer.prototype.observeArray = function observeArray(items) {
            for (var i = 0, l = items.length; i < l; i++) {
                var ob = observe(items[i], this, i);
                items[i] = ob ? ob.model : items[i];
            }
            return items;
        };

        return Observer;
    }();

    function protoAugment(target, src, keys) {
        /* eslint-disable no-proto */
        target.__proto__ = src;
        /* eslint-enable no-proto */
    }

    /* istanbul ignore next */
    function copyAugment(target, src, keys) {
        for (var i = 0, l = keys.length; i < l; i++) {
            var key = keys[i];
            target[key] = src[key];
        }
    }

    function observe(value, parentObserver, parentKey) {
        if (!BI._.isObject(value)) {
            return;
        }
        var ob = void 0;
        if (value.__ob__ instanceof Observer) {
            ob = value.__ob__;
        } else if (observerState.shouldConvert && isExtensible(value) && (BI._.isArray(value) || isPlainObject(value))) {
            ob = new Observer(value);
        }
        if (ob) {
            ob.parent = parentObserver || ob.parent;
            ob.parentKey = parentKey;
        }
        return ob;
    }

    function notify(observer, key, dep, refresh) {
        dep.notify({ observer: observer, key: key, refresh: refresh });
        if (observer) {
            //触发a.*绑定的依赖
            BI._.each(observer._deps, function (dep) {
                dep.notify({ observer: observer, key: key });
            });
            //触发a.**绑定的依赖
            var parent = observer,
                root = observer,
                route = key || "";
            while (parent) {
                BI._.each(parent._scopeDeps, function (dep) {
                    dep.notify({ observer: observer, key: key });
                });
                if (parent.parentKey != null) {
                    route = parent.parentKey + '.' + route;
                }
                root = parent;
                parent = parent.parent;
            }
            for (var _key in root._globalDeps) {
                var reg = new RegExp(_key);
                if (reg.test(route)) {
                    for (var i = 0; i < root._globalDeps[_key].length; i++) {
                        root._globalDeps[_key][i].notify({ observer: observer, key: _key });
                    }
                }
            }
        }
    }

    function defineReactive(obj, observer, shallow) {
        var props = {};
        var model = void 0;
        BI._.each(obj, function (val, key) {
            if (key in $$skipArray) {
                return;
            }
            var configurable = isConfigurable(obj, key);
            var dep = observer && observer['__dep' + key] || new Dep();
            observer && (observer['__dep' + key] = dep);
            var childOb = configurable && !shallow && observe(val, observer, key);
            props[key] = {
                enumerable: true,
                configurable: true,
                get: function reactiveGetter() {
                    var value = childOb ? childOb.model : val;
                    if (Dep.target) {
                        dep.depend();
                        if (childOb) {
                            childOb.dep.depend();
                            if (BI._.isArray(value)) {
                                dependArray(value);
                            }
                        }
                    }
                    return value;
                },
                set: function reactiveSetter(newVal) {
                    var value = childOb ? childOb.model : val;
                    if (newVal === value || newVal !== newVal && value !== value) {
                        return;
                    }
                    val = newVal;
                    childOb = configurable && !shallow && observe(newVal, observer, key);
                    if (childOb && value && value.__ob__) {
                        childOb._scopeDeps = value.__ob__._scopeDeps;
                        childOb._deps = value.__ob__._deps;
                    }
                    obj[key] = childOb ? childOb.model : newVal;
                    notify(model.__ob__, key, dep);
                }
            };
        });
        return model = createViewModel$1(obj, props);
    }

    function defineReactiveProperty(obj, key, val, shallow) {

        var dep = new Dep();

        var configurable = isConfigurable(obj, key);
        if (!configurable) {
            return;
        }

        if (arguments.length === 2) {
            val = obj[key];
        }

        var childOb = !shallow && observe(val);
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get: function reactiveGetter() {
                var value = childOb ? childOb.model : val;
                if (Dep.target) {
                    dep.depend();
                    if (childOb) {
                        childOb.dep.depend();
                        if (BI._.isArray(value)) {
                            dependArray(value);
                        }
                    }
                }
                return value;
            },
            set: function reactiveSetter(newVal) {
                var value = childOb ? childOb.model : val;
                if (newVal === value || newVal !== newVal && value !== value) {
                    return;
                }

                childOb = configurable && !shallow && observe(newVal);
                val = newVal;
                obj[key] = childOb ? childOb.model : newVal;
                dep.notify();
            }
        });
    }

    /**
     * Set a property on an object. Adds the new property and
     * triggers change notification if the property doesn't
     * already exist.
     */
    function set(target, key, val) {
        if (BI._.isArray(target)) {
            target.length = Math.max(target.length, key);
            target.splice(key, 1, val);
            return val;
        }
        if (BI._.has(target, key)) {
            target[key] = val;
            return val;
        }
        var ob = target.__ob__;
        if (!ob) {
            target[key] = val;
            return val;
        }
        ob.value[key] = val;
        target = defineReactive(ob.value, ob);
        notify(ob, key, ob.dep);
        return target;
    }

    function freeze() {
        return Object.freeze.apply(null, arguments);
    }

    /**
     * Delete a property and trigger change if necessary.
     */
    function del(target, key) {
        if (BI._.isArray(target)) {
            target.splice(key, 1);
            return;
        }
        var ob = target.__ob__;
        if (!BI._.has(target, key)) {
            return;
        }
        if (!ob) {
            delete target[key];
            return target;
        }
        delete ob.value[key];
        target = defineReactive(ob.value, ob);
        notify(ob, key, ob.dep);
        return target;
    }

    /**
     * Collect dependencies on array elements when the array is touched, since
     * we cannot intercept array element access like property getters.
     */
    function dependArray(value) {
        for (var e, i = 0, l = value.length; i < l; i++) {
            e = value[i];
            e && e.__ob__ && e.__ob__.dep.depend();
            if (BI._.isArray(e)) {
                dependArray(e);
            }
        }
    }

    var falsy$1;
    var operators = {
        '||': falsy$1,
        '&&': falsy$1,
        '(': falsy$1,
        ')': falsy$1
    };

    function runBinaryFunction(binarys) {
        var expr = '';
        for (var i = 0, len = binarys.length; i < len; i++) {
            if (BI._.isBoolean(binarys[i]) || BI._.has(operators, binarys[i])) {
                expr += binarys[i];
            } else {
                expr += 'false';
            }
        }
        return new Function('return ' + expr)();
    }

    function routeToRegExp(route) {
        route = route.replace(/\*\*/g, '[a-zA-Z0-9_]+').replace(/\*./g, '[a-zA-Z0-9_]+.');
        return '^' + route + '$';
    }

    function watch(model, expOrFn, cb, options) {
        if (isPlainObject(cb)) {
            options = cb;
            cb = cb.handler;
        }
        if (typeof cb === 'string') {
            cb = model[cb];
        }
        options = options || {};
        options.user = true;
        var exps = void 0;
        if (BI._.isFunction(expOrFn) || !(exps = expOrFn.match(/[a-zA-Z0-9BI._.*]+|[|][|]|[&][&]|[(]|[)]/g)) || exps.length === 1 && expOrFn.indexOf("*") < 0) {
            var watcher = new Watcher(model, expOrFn, cb, options);
            if (options.immediate) {
                cb(watcher.value);
            }
            return function unwatchFn() {
                watcher.teardown();
            };
        }
        var watchers = [];
        var fns = exps.slice();
        var complete = false,
            running = false;
        var callback = function callback(index, newValue, oldValue, attrs) {
            if (complete === true) {
                return;
            }
            fns[index] = true;
            if (runBinaryFunction(fns)) {
                complete = true;
                cb(newValue, oldValue, attrs);
            }
            if (options && options.sync) {
                complete = false;
                running = false;
                fns = exps.slice();
            } else {
                if (!running) {
                    running = true;
                    nextTick(function () {
                        complete = false;
                        running = false;
                        fns = exps.slice();
                    });
                }
            }
        };
        BI._.each(exps, function (exp, i) {
            if (BI._.has(operators, exp)) {
                return;
            }
            if (exp.indexOf("*") >= 0) {
                //a.**或a.*形式
                if (/^[1-9a-zA-Z.]+(\*\*$|\*$)/.test(exp) || exp === "**" || exp === "*") {
                    var isGlobal = exp.indexOf("**") >= 0;
                    if (isGlobal) {
                        //a.**的形式
                        exp = exp.replace(".**", "");
                    } else {
                        //a.*的形式
                        exp = exp.replace(".*", "");
                    }
                    var getter = exp === "**" || exp === "*" ? function (m) {
                        return m;
                    } : parsePath(exp);
                    var v = getter.call(model, model);
                    var _dep = new Dep();
                    if (isGlobal) {
                        (v.__ob__._scopeDeps || (v.__ob__._scopeDeps = [])).push(_dep);
                    } else {
                        (v.__ob__._deps || (v.__ob__._deps = [])).push(_dep);
                    }
                    var _w = new Watcher(model, function () {
                        _dep.depend();
                        return NaN;
                    }, function (newValue, oldValue, attrs) {
                        callback(i, newValue, oldValue, BI._.extend({ index: i }, attrs));
                    }, options);
                    watchers.push(function unwatchFn() {
                        _w.teardown();
                        v.__ob__._scopeDeps && remove(v.__ob__._scopeDeps, _dep);
                        v.__ob__._deps && remove(v.__ob__._deps, _dep);
                    });
                    return;
                }
                // **.a.**的情况,场景:a.b.c, 如果用b.**监听, a被重新赋值b上的_scopeDes就不存在了
                if (/^(\*\*\.)+[1-9a-zA-Z]+(\.\*\*$)/.test(exp)) {
                    //先获取到能获取到的对象
                    var _paths = exp.split(".");
                    var _currentModel = model[_paths[1]];
                    exp = _paths[1] + ".**";
                    //补全路径
                    var _parent = _currentModel.__ob__.parent,
                        _root = _currentModel.__ob__;
                    while (_parent) {
                        exp = '*.' + exp;
                        _root = _parent;
                        _parent = _parent.parent;
                    }
                    var _regStr = routeToRegExp(exp);
                    var _dep2 = new Dep();
                    _root._globalDeps || (_root._globalDeps = {});
                    if (BI._.isArray(_root._globalDeps[_regStr])) {
                        _root._globalDeps[_regStr].push(_dep2);
                    } else {
                        _root._globalDeps[_regStr] = [_dep2];
                    }

                    var _w2 = new Watcher(_currentModel, function () {
                        _dep2.depend();
                        return NaN;
                    }, function (newValue, oldValue, attrs) {
                        callback(i, newValue, oldValue, BI._.extend({ index: i }, attrs));
                    }, options);
                    watchers.push(function unwatchFn() {
                        if (_root._globalDeps) {
                            remove(_root._globalDeps[_regStr], _dep2);

                            if (_root._globalDeps[_regStr].length === 0) {
                                delete _root._globalDeps[_regStr];
                                _w2.teardown();
                            }
                        }
                    });
                    return;
                }
                // 再有结尾有*的就不支持了
                if (exp[exp.length - 1] === "*") {
                    throw new Error('not support');
                }
                //其他含有*的情况,如*.a,*.*.a,a.*.a
                var currentModel = model;
                //先获取到能获取到的对象
                var paths = exp.split(".");
                for (var _i = 0, len = paths.length; _i < len; _i++) {
                    if (paths[_i] === "*") {
                        break;
                    }
                    currentModel = model[paths[_i]];
                }
                exp = exp.substr(exp.indexOf("*"));
                //补全路径
                var parent = currentModel.__ob__.parent,
                    root = currentModel.__ob__;
                while (parent) {
                    exp = '*.' + exp;
                    root = parent;
                    parent = parent.parent;
                }
                var regStr = routeToRegExp(exp);
                var dep = new Dep();
                root._globalDeps || (root._globalDeps = {});
                if (BI._.isArray(root._globalDeps[regStr])) {
                    root._globalDeps[regStr].push(dep);
                } else {
                    root._globalDeps[regStr] = [dep];
                }

                var w = new Watcher(currentModel, function () {
                    dep.depend();
                    return NaN;
                }, function (newValue, oldValue, attrs) {
                    callback(i, newValue, oldValue, BI._.extend({ index: i }, attrs));
                }, options);
                watchers.push(function unwatchFn() {
                    if (root._globalDeps) {
                        remove(root._globalDeps[regStr], dep);
                        if (root._globalDeps[regStr].length === 0) {
                            delete root._globalDeps[regStr];
                            w.teardown();
                        }
                    }
                });
                return;
            }
            var watcher = new Watcher(model, exp, function (newValue, oldValue, attrs) {
                callback(i, newValue, oldValue, BI._.extend({ index: i }, attrs));
            }, options);
            watchers.push(function unwatchFn() {
                watcher.teardown();
            });
        });
        return watchers;
    }

    var mixinInjection = {};

    function getMixins(type) {
        return mixinInjection[type];
    }

    function mixin(xtype, cls) {
        mixinInjection[xtype] = BI._.cloneDeep(cls);
    }

    var computedWatcherOptions = { lazy: true };
    var REACTIVE = true;

    function initState(vm, state) {
        if (state) {
            vm.$$state = REACTIVE ? observe(state).model : state;
        }
    }

    function initComputed(vm, computed) {
        var watchers = vm._computedWatchers = {};
        defineComputed(vm, computed);
        for (var key in computed) {
            watchers[key] = defineComputedWatcher(vm, computed[key]);
        }
    }

    function defineComputedWatcher(vm, userDef) {
        var context = vm.$$model ? vm.model : vm;
        var getter = typeof userDef === "function" ? userDef : userDef.get;

        return new Watcher(context, getter || noop, noop, computedWatcherOptions);
    }

    function defineOneComputedGetter(vm, key, userDef) {
        var shouldCache = true;
        var sharedPropertyDefinition = {
            enumerable: true,
            configurable: true,
            get: noop,
            set: noop
        };
        if (typeof userDef === "function") {
            sharedPropertyDefinition.get = createComputedGetter(vm, key);
            sharedPropertyDefinition.set = noop;
        } else {
            sharedPropertyDefinition.get = userDef.get ? shouldCache && userDef.cache !== false ? createComputedGetter(vm, key) : userDef.get : noop;
            sharedPropertyDefinition.set = userDef.set ? userDef.set : noop;
        }
        return sharedPropertyDefinition;
    }

    function defineComputed(vm, computed) {
        var props = {};
        for (var key in computed) {
            if (!(key in vm)) {
                props[key] = defineOneComputedGetter(vm, key, computed[key]);
            }
        }
        vm.$$computed = createViewModel$1({}, props);
    }

    function createComputedGetter(vm, key) {
        return function computedGetter() {
            var watcher = vm._computedWatchers && vm._computedWatchers[key];
            if (watcher) {
                if (watcher.dirty) {
                    watcher.evaluate();
                }
                if (REACTIVE && Dep.target) {
                    watcher.depend();
                }
                return watcher.value;
            }
        };
    }

    function initWatch(vm, watch$$1) {
        vm._watchers || (vm._watchers = []);
        for (var key in watch$$1) {
            var handler = watch$$1[key];
            if (BI._.isArray(handler)) {
                for (var i = 0; i < handler.length; i++) {
                    vm._watchers.push(createWatcher(vm, key, handler[i]));
                }
            } else {
                vm._watchers.push(createWatcher(vm, key, handler));
            }
        }
    }

    function createWatcher(vm, keyOrFn, cb, options) {
        if (isPlainObject(cb)) {
            options = cb;
            cb = cb.handler;
        }
        if (typeof cb === 'string') {
            cb = vm[cb];
        }
        return watch(vm.model, keyOrFn, BI._.bind(cb, vm.$$model ? vm.model : vm), options);
    }

    function initMethods(vm, methods) {
        for (var key in methods) {
            vm[key] = methods[key] == null ? noop : BI._.bind(methods[key], vm.$$model ? vm.model : vm);
        }
    }

    function initMixins(vm, mixins) {
        mixins = (mixins || []).slice(0);

        BI._.each(mixins.reverse(), function (mixinType) {
            var mixin$$1 = getMixins(mixinType);

            for (var key in mixin$$1) {
                if (typeof mixin$$1[key] !== "function") continue;

                if (BI._.has(vm, key)) continue;

                vm[key] = BI._.bind(mixin$$1[key], vm.$$model ? vm.model : vm);
            }
        });
    }

    function defineProps(vm, keys) {
        var props = {};
        // if (typeof Proxy === 'function') {
        //     return vm.model = new Proxy(props, {
        //         has: function (target, key) {
        //             return keys.indexOf(key) > -1;
        //         },
        //         get: function (target, key) {
        //             if (key in $$skipArray) {
        //                 return props[key]
        //             }
        //             if (vm.$$computed && key in vm.$$computed) {
        //                 return vm.$$computed[key]
        //             }
        //             if (vm.$$state && key in vm.$$state) {
        //                 return vm.$$state[key]
        //             }
        //             return vm.$$model[key]
        //         },
        //         set: function (target, key, val) {
        //             if (key in $$skipArray) {
        //                 return props[key] = val
        //             }
        //             if (vm.$$state && key in vm.$$state) {
        //                 return vm.$$state[key] = val
        //             }
        //             if (vm.$$model && key in vm.$$model) {
        //                 return vm.$$model[key] = val
        //             }
        //         }
        //     })
        // }

        var _loop = function _loop(i, len) {
            var key = keys[i];
            if (!(key in $$skipArray)) {
                props[key] = {
                    enumerable: true,
                    configurable: true,
                    get: function get() {
                        if (vm.$$computed && key in vm.$$computed) {
                            return vm.$$computed[key];
                        }
                        if (vm.$$state && key in vm.$$state) {
                            return vm.$$state[key];
                        }
                        if (vm.$$model && key in vm.$$model) {
                            return vm.$$model[key];
                        }
                        var p = vm._parent;
                        while (p) {
                            if (p.$$context && key in p.$$context) {
                                return p.$$context[key];
                            }
                            p = p._parent;
                        }
                    },
                    set: function set(val) {
                        if (vm.$$state && key in vm.$$state) {
                            return vm.$$state[key] = val;
                        }
                        if (vm.$$model && key in vm.$$model) {
                            return vm.$$model[key] = val;
                        }
                        var p = vm._parent;
                        while (p) {
                            if (p.$$context && key in p.$$context) {
                                return p.$$context[key] = val;
                            }
                            p = p._parent;
                        }
                    }
                };
            }
        };

        for (var i = 0, len = keys.length; i < len; i++) {
            _loop(i, len);
        }
        vm.model = createViewModel$1({}, props);
    }

    function defineContext(vm, keys) {
        var props = {};

        var _loop2 = function _loop2(i, len) {
            var key = keys[i];
            if (!(key in $$skipArray)) {
                props[key] = {
                    enumerable: true,
                    configurable: true,
                    get: function get() {
                        return vm.model[key];
                    },
                    set: function set(val) {
                        return vm.model[key] = val;
                    }
                };
            }
        };

        for (var i = 0, len = keys.length; i < len; i++) {
            _loop2(i, len);
        }
        vm.$$context = createViewModel$1({}, props);
    }

    function getInjectValue(vm, key) {
        var p = vm._parent;
        while (p) {
            if (p.$$context && key in p.$$context) {
                return p.$$context[key];
            }
            p = p._parent;
        }
    }

    function getInjectValues(vm) {
        var inject = vm.inject || [];
        var result = {};
        BI._.each(inject, function (key) {
            result[key] = getInjectValue(vm, key);
        });
        return result;
    }

    var Model = function () {
        function Model() {
            _classCallCheck(this, Model);
        }

        Model.prototype._constructor = function _constructor(model, destroyHandler) {
            if (model instanceof Observer || model instanceof Model) {
                model = model.model;
            }
            if (model && model.__ob__) {
                this.$$model = model;
            } else {
                this.options = model || {};
            }
            this._parent = Model.target;
            var state = BI._.isFunction(this.state) ? this.state() : this.state;
            var computed = this.computed;
            var context = this.context;
            var inject = this.inject;
            var childContext = this.childContext;
            var provide = this.provide;
            var watch$$1 = this.watch;
            var actions = this.actions;
            var keys = BI._.keys(this.$$model).concat(BI._.keys(state)).concat(BI._.keys(computed)).concat(inject || []).concat(context || []);
            var mixins = this.mixins;
            defineProps(this, keys);
            // deprecated
            childContext && defineContext(this, childContext);
            provide && defineContext(this, provide);
            this.$$model && (this.model.__ob__ = this.$$model.__ob__);
            initMixins(this, mixins);
            this.init();
            initState(this, BI._.extend(getInjectValues(this), state));
            initComputed(this, computed);
            REACTIVE && initWatch(this, watch$$1);
            initMethods(this, actions);
            this.created && this.created();
            this._destroyHandler = destroyHandler;
            if (this.$$model) {
                return this.model;
            }
        };

        Model.prototype._init = function _init() {};

        Model.prototype.init = function init() {
            this._init();
        };

        Model.prototype.destroy = function destroy() {
            for (var _key3 in this._computedWatchers) {
                this._computedWatchers[_key3].teardown();
            }
            BI._.each(this._watchers, function (unwatches) {
                unwatches = BI._.isArray(unwatches) ? unwatches : [unwatches];
                BI._.each(unwatches, function (unwatch) {
                    unwatch();
                });
            });
            this._watchers && (this._watchers = []);
            this.destroyed && this.destroyed();
            this.$$model = null;
            this.$$computed = null;
            this.$$state = null;
            this._destroyHandler && this._destroyHandler();
        };

        return Model;
    }();

    function define(model) {
        return REACTIVE ? new Observer(model).model : model;
    }

    var reactive = define;

    function config(options) {
        options || (options = {});
        if ("reactive" in options) {
            REACTIVE = options.reactive;
        }
    }

    function toJSON(model) {
        var result = void 0;
        if (BI._.isArray(model)) {
            result = [];
            for (var i = 0, len = model.length; i < len; i++) {
                result[i] = toJSON(model[i]);
            }
        } else if (model && isPlainObject(model)) {
            result = {};
            for (var _key4 in model) {
                if (!BI._.has($$skipArray, _key4)) {
                    result[_key4] = toJSON(model[_key4]);
                }
            }
        } else {
            result = model;
        }
        return result;
    }

    var version = '2.0';

    exports.version = version;
    exports.$$skipArray = $$skipArray;
    exports.mixin = mixin;
    exports.Model = Model;
    exports.define = define;
    exports.reactive = reactive;
    exports.config = config;
    exports.observerState = observerState;
    exports.Observer = Observer;
    exports.observe = observe;
    exports.notify = notify;
    exports.defineReactive = defineReactive;
    exports.defineReactiveProperty = defineReactiveProperty;
    exports.set = set;
    exports.freeze = freeze;
    exports.del = del;
    exports.Watcher = Watcher;
    exports.pushTarget = pushTarget;
    exports.popTarget = popTarget;
    exports.watch = watch;
    exports.toJSON = toJSON;

    exports.__esModule = true;
});