UNPKG

saven

Version:
5,992 lines 214 kB
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('nervjs')) :
  typeof define === 'function' && define.amd ? define(['exports', 'nervjs'], factory) :
  (factory((global.TaroH5 = {}),global.Nerv));
}(this, (function (exports,Nerv) { 'use strict';

  Nerv = Nerv && Nerv.hasOwnProperty('default') ? Nerv['default'] : Nerv;

  function _typeof(obj) {
    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
      _typeof = function (obj) {
        return typeof obj;
      };
    } else {
      _typeof = function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
      };
    }

    return _typeof(obj);
  }

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

  function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
      var descriptor = props[i];
      descriptor.enumerable = descriptor.enumerable || false;
      descriptor.configurable = true;
      if ("value" in descriptor) descriptor.writable = true;
      Object.defineProperty(target, descriptor.key, descriptor);
    }
  }

  function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
  }

  function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
      throw new TypeError("Super expression must either be null or a function");
    }

    subClass.prototype = Object.create(superClass && superClass.prototype, {
      constructor: {
        value: subClass,
        writable: true,
        configurable: true
      }
    });
    if (superClass) _setPrototypeOf(subClass, superClass);
  }

  function _getPrototypeOf(o) {
    _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
      return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _getPrototypeOf(o);
  }

  function _setPrototypeOf(o, p) {
    _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
      o.__proto__ = p;
      return o;
    };

    return _setPrototypeOf(o, p);
  }

  function _assertThisInitialized(self) {
    if (self === void 0) {
      throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }

    return self;
  }

  function _possibleConstructorReturn(self, call) {
    if (call && (typeof call === "object" || typeof call === "function")) {
      return call;
    }

    return _assertThisInitialized(self);
  }

  /* eslint-disable */

  /**
   * lodash (Custom Build) <https://lodash.com/>
   * Build: `lodash modularize exports="npm" -o ./`
   * Copyright jQuery Foundation and other contributors <https://jquery.org/>
   * Released under MIT license <https://lodash.com/license>
   * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
   */

  /** Used as the `TypeError` message for "Functions" methods. */
  var FUNC_ERROR_TEXT = 'Expected a function';
  /** Used to stand-in for `undefined` hash values. */

  var HASH_UNDEFINED = '__lodash_hash_undefined__';
  /** Used as references for various `Number` constants. */

  var INFINITY = 1 / 0;
  /** `Object#toString` result references. */

  var funcTag = '[object Function]',
      genTag = '[object GeneratorFunction]',
      symbolTag = '[object Symbol]';
  /** Used to match property names within property paths. */

  var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
      reIsPlainProp = /^\w*$/,
      reLeadingDot = /^\./,
      rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
  /**
   * Used to match `RegExp`
   * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
   */

  var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
  /** Used to match backslashes in property paths. */

  var reEscapeChar = /\\(\\)?/g;
  /** Used to detect host constructors (Safari). */

  var reIsHostCtor = /^\[object .+?Constructor\]$/;
  /** Detect free variable `global` from Node.js. */

  var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) === 'object' && global && global.Object === Object && global;
  /** Detect free variable `self`. */

  var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) === 'object' && self && self.Object === Object && self;
  /** Used as a reference to the global object. */

  var root = freeGlobal || freeSelf || Function('return this')();
  /** Used as references for various `Number` constants. */

  var MAX_SAFE_INTEGER = 9007199254740991;
  /** Used to detect unsigned integer values. */

  var reIsUint = /^(?:0|[1-9]\d*)$/;
  /**
   * Gets the value at `key` of `object`.
   *
   * @private
   * @param {Object} [object] The object to query.
   * @param {string} key The key of the property to get.
   * @returns {*} Returns the property value.
   */

  function getValue(object, key) {
    return object == null ? undefined : object[key];
  }
  /**
   * Checks if `value` is a host object in IE < 9.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
   */


  function isHostObject(value) {
    // Many host objects are `Object` objects that can coerce to strings
    // despite having improperly defined `toString` methods.
    var result = false;

    if (value != null && typeof value.toString !== 'function') {
      try {
        result = !!(value + '');
      } catch (e) {}
    }

    return result;
  }
  /** Used for built-in method references. */


  var arrayProto = Array.prototype,
      funcProto = Function.prototype,
      objectProto = Object.prototype;
  /** Used to detect overreaching core-js shims. */

  var coreJsData = root['__core-js_shared__'];
  /** Used to detect methods masquerading as native. */

  var maskSrcKey = function () {
    var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
    return uid ? 'Symbol(src)_1.' + uid : '';
  }();
  /** Used to resolve the decompiled source of functions. */


  var funcToString = funcProto.toString;
  /** Used to check objects for own properties. */

  var hasOwnProperty = objectProto.hasOwnProperty;
  /**
   * Used to resolve the
   * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
   * of values.
   */

  var objectToString = objectProto.toString;
  /** Used to detect if a method is native. */

  var reIsNative = RegExp('^' + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&').replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$');
  /** Built-in value references. */

  var _Symbol = root.Symbol,
      splice = arrayProto.splice;
  /* Built-in method references that are verified to be native. */

  var Map$1 = getNative(root, 'Map'),
      nativeCreate = getNative(Object, 'create');
  /** Used to convert symbols to primitives and strings. */

  var symbolProto = _Symbol ? _Symbol.prototype : undefined,
      symbolToString = symbolProto ? symbolProto.toString : undefined;
  /**
   * Creates a hash object.
   *
   * @private
   * @constructor
   * @param {Array} [entries] The key-value pairs to cache.
   */

  function Hash(entries) {
    var index = -1,
        length = entries ? entries.length : 0;
    this.clear();

    while (++index < length) {
      var entry = entries[index];
      this.set(entry[0], entry[1]);
    }
  }
  /**
   * Removes all key-value entries from the hash.
   *
   * @private
   * @name clear
   * @memberOf Hash
   */


  function hashClear() {
    this.__data__ = nativeCreate ? nativeCreate(null) : {};
  }
  /**
   * Removes `key` and its value from the hash.
   *
   * @private
   * @name delete
   * @memberOf Hash
   * @param {Object} hash The hash to modify.
   * @param {string} key The key of the value to remove.
   * @returns {boolean} Returns `true` if the entry was removed, else `false`.
   */


  function hashDelete(key) {
    return this.has(key) && delete this.__data__[key];
  }
  /**
   * Gets the hash value for `key`.
   *
   * @private
   * @name get
   * @memberOf Hash
   * @param {string} key The key of the value to get.
   * @returns {*} Returns the entry value.
   */


  function hashGet(key) {
    var data = this.__data__;

    if (nativeCreate) {
      var result = data[key];
      return result === HASH_UNDEFINED ? undefined : result;
    }

    return hasOwnProperty.call(data, key) ? data[key] : undefined;
  }
  /**
   * Checks if a hash value for `key` exists.
   *
   * @private
   * @name has
   * @memberOf Hash
   * @param {string} key The key of the entry to check.
   * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
   */


  function hashHas(key) {
    var data = this.__data__;
    return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
  }
  /**
   * Sets the hash `key` to `value`.
   *
   * @private
   * @name set
   * @memberOf Hash
   * @param {string} key The key of the value to set.
   * @param {*} value The value to set.
   * @returns {Object} Returns the hash instance.
   */


  function hashSet(key, value) {
    var data = this.__data__;
    data[key] = nativeCreate && value === undefined ? HASH_UNDEFINED : value;
    return this;
  } // Add methods to `Hash`.


  Hash.prototype.clear = hashClear;
  Hash.prototype['delete'] = hashDelete;
  Hash.prototype.get = hashGet;
  Hash.prototype.has = hashHas;
  Hash.prototype.set = hashSet;
  /**
   * Creates an list cache object.
   *
   * @private
   * @constructor
   * @param {Array} [entries] The key-value pairs to cache.
   */

  function ListCache(entries) {
    var index = -1,
        length = entries ? entries.length : 0;
    this.clear();

    while (++index < length) {
      var entry = entries[index];
      this.set(entry[0], entry[1]);
    }
  }
  /**
   * Removes all key-value entries from the list cache.
   *
   * @private
   * @name clear
   * @memberOf ListCache
   */


  function listCacheClear() {
    this.__data__ = [];
  }
  /**
   * Removes `key` and its value from the list cache.
   *
   * @private
   * @name delete
   * @memberOf ListCache
   * @param {string} key The key of the value to remove.
   * @returns {boolean} Returns `true` if the entry was removed, else `false`.
   */


  function listCacheDelete(key) {
    var data = this.__data__,
        index = assocIndexOf(data, key);

    if (index < 0) {
      return false;
    }

    var lastIndex = data.length - 1;

    if (index == lastIndex) {
      data.pop();
    } else {
      splice.call(data, index, 1);
    }

    return true;
  }
  /**
   * Gets the list cache value for `key`.
   *
   * @private
   * @name get
   * @memberOf ListCache
   * @param {string} key The key of the value to get.
   * @returns {*} Returns the entry value.
   */


  function listCacheGet(key) {
    var data = this.__data__,
        index = assocIndexOf(data, key);
    return index < 0 ? undefined : data[index][1];
  }
  /**
   * Checks if a list cache value for `key` exists.
   *
   * @private
   * @name has
   * @memberOf ListCache
   * @param {string} key The key of the entry to check.
   * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
   */


  function listCacheHas(key) {
    return assocIndexOf(this.__data__, key) > -1;
  }
  /**
   * Sets the list cache `key` to `value`.
   *
   * @private
   * @name set
   * @memberOf ListCache
   * @param {string} key The key of the value to set.
   * @param {*} value The value to set.
   * @returns {Object} Returns the list cache instance.
   */


  function listCacheSet(key, value) {
    var data = this.__data__,
        index = assocIndexOf(data, key);

    if (index < 0) {
      data.push([key, value]);
    } else {
      data[index][1] = value;
    }

    return this;
  } // Add methods to `ListCache`.


  ListCache.prototype.clear = listCacheClear;
  ListCache.prototype['delete'] = listCacheDelete;
  ListCache.prototype.get = listCacheGet;
  ListCache.prototype.has = listCacheHas;
  ListCache.prototype.set = listCacheSet;
  /**
   * Creates a map cache object to store key-value pairs.
   *
   * @private
   * @constructor
   * @param {Array} [entries] The key-value pairs to cache.
   */

  function MapCache(entries) {
    var index = -1,
        length = entries ? entries.length : 0;
    this.clear();

    while (++index < length) {
      var entry = entries[index];
      this.set(entry[0], entry[1]);
    }
  }
  /**
   * Removes all key-value entries from the map.
   *
   * @private
   * @name clear
   * @memberOf MapCache
   */


  function mapCacheClear() {
    this.__data__ = {
      hash: new Hash(),
      map: new (Map$1 || ListCache)(),
      string: new Hash()
    };
  }
  /**
   * Removes `key` and its value from the map.
   *
   * @private
   * @name delete
   * @memberOf MapCache
   * @param {string} key The key of the value to remove.
   * @returns {boolean} Returns `true` if the entry was removed, else `false`.
   */


  function mapCacheDelete(key) {
    return getMapData(this, key)['delete'](key);
  }
  /**
   * Gets the map value for `key`.
   *
   * @private
   * @name get
   * @memberOf MapCache
   * @param {string} key The key of the value to get.
   * @returns {*} Returns the entry value.
   */


  function mapCacheGet(key) {
    return getMapData(this, key).get(key);
  }
  /**
   * Checks if a map value for `key` exists.
   *
   * @private
   * @name has
   * @memberOf MapCache
   * @param {string} key The key of the entry to check.
   * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
   */


  function mapCacheHas(key) {
    return getMapData(this, key).has(key);
  }
  /**
   * Sets the map `key` to `value`.
   *
   * @private
   * @name set
   * @memberOf MapCache
   * @param {string} key The key of the value to set.
   * @param {*} value The value to set.
   * @returns {Object} Returns the map cache instance.
   */


  function mapCacheSet(key, value) {
    getMapData(this, key).set(key, value);
    return this;
  } // Add methods to `MapCache`.


  MapCache.prototype.clear = mapCacheClear;
  MapCache.prototype['delete'] = mapCacheDelete;
  MapCache.prototype.get = mapCacheGet;
  MapCache.prototype.has = mapCacheHas;
  MapCache.prototype.set = mapCacheSet;
  /**
   * Gets the index at which the `key` is found in `array` of key-value pairs.
   *
   * @private
   * @param {Array} array The array to inspect.
   * @param {*} key The key to search for.
   * @returns {number} Returns the index of the matched value, else `-1`.
   */

  function assocIndexOf(array, key) {
    var length = array.length;

    while (length--) {
      if (eq(array[length][0], key)) {
        return length;
      }
    }

    return -1;
  }
  /**
   * The base implementation of `_.get` without support for default values.
   *
   * @private
   * @param {Object} object The object to query.
   * @param {Array|string} path The path of the property to get.
   * @returns {*} Returns the resolved value.
   */


  function baseGet(object, path) {
    path = isKey(path, object) ? [path] : castPath(path);
    var index = 0,
        length = path.length;

    while (object != null && index < length) {
      object = object[toKey(path[index++])];
    }

    return index && index == length ? object : undefined;
  }
  /**
   * The base implementation of `_.isNative` without bad shim checks.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is a native function,
   *  else `false`.
   */

  function baseIsNative(value) {
    if (!isObject(value) || isMasked(value)) {
      return false;
    }

    var pattern = isFunction(value) || isHostObject(value) ? reIsNative : reIsHostCtor;
    return pattern.test(toSource(value));
  }
  /**
   * The base implementation of `_.toString` which doesn't convert nullish
   * values to empty strings.
   *
   * @private
   * @param {*} value The value to process.
   * @returns {string} Returns the string.
   */


  function baseToString(value) {
    // Exit early for strings to avoid a performance hit in some environments.
    if (typeof value === 'string') {
      return value;
    }

    if (isSymbol(value)) {
      return symbolToString ? symbolToString.call(value) : '';
    }

    var result = value + '';
    return result == '0' && 1 / value == -INFINITY ? '-0' : result;
  }
  /**
   * Casts `value` to a path array if it's not one.
   *
   * @private
   * @param {*} value The value to inspect.
   * @returns {Array} Returns the cast property path array.
   */


  function castPath(value) {
    return isArray(value) ? value : stringToPath(value);
  }
  /**
   * Gets the data for `map`.
   *
   * @private
   * @param {Object} map The map to query.
   * @param {string} key The reference key.
   * @returns {*} Returns the map data.
   */


  function getMapData(map, key) {
    var data = map.__data__;
    return isKeyable(key) ? data[typeof key === 'string' ? 'string' : 'hash'] : data.map;
  }
  /**
   * Gets the native function at `key` of `object`.
   *
   * @private
   * @param {Object} object The object to query.
   * @param {string} key The key of the method to get.
   * @returns {*} Returns the function if it's native, else `undefined`.
   */


  function getNative(object, key) {
    var value = getValue(object, key);
    return baseIsNative(value) ? value : undefined;
  }
  /**
   * Checks if `value` is a property name and not a property path.
   *
   * @private
   * @param {*} value The value to check.
   * @param {Object} [object] The object to query keys on.
   * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
   */


  function isKey(value, object) {
    if (isArray(value)) {
      return false;
    }

    var type = _typeof(value);

    if (type == 'number' || type == 'symbol' || type == 'boolean' || value == null || isSymbol(value)) {
      return true;
    }

    return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || object != null && value in Object(object);
  }
  /**
   * Checks if `value` is suitable for use as unique object key.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
   */


  function isKeyable(value) {
    var type = _typeof(value);

    return type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean' ? value !== '__proto__' : value === null;
  }
  /**
   * Checks if `func` has its source masked.
   *
   * @private
   * @param {Function} func The function to check.
   * @returns {boolean} Returns `true` if `func` is masked, else `false`.
   */


  function isMasked(func) {
    return !!maskSrcKey && maskSrcKey in func;
  }
  /**
   * Converts `string` to a property path array.
   *
   * @private
   * @param {string} string The string to convert.
   * @returns {Array} Returns the property path array.
   */


  var stringToPath = memoize(function (string) {
    string = toString(string);
    var result = [];

    if (reLeadingDot.test(string)) {
      result.push('');
    }

    string.replace(rePropName, function (match, number, quote, string) {
      result.push(quote ? string.replace(reEscapeChar, '$1') : number || match);
    });
    return result;
  });
  /**
   * Converts `value` to a string key if it's not a string or symbol.
   *
   * @private
   * @param {*} value The value to inspect.
   * @returns {string|symbol} Returns the key.
   */

  function toKey(value) {
    if (typeof value === 'string' || isSymbol(value)) {
      return value;
    }

    var result = value + '';
    return result == '0' && 1 / value == -INFINITY ? '-0' : result;
  }
  /**
   * Converts `func` to its source code.
   *
   * @private
   * @param {Function} func The function to process.
   * @returns {string} Returns the source code.
   */


  function toSource(func) {
    if (func != null) {
      try {
        return funcToString.call(func);
      } catch (e) {}

      try {
        return func + '';
      } catch (e) {}
    }

    return '';
  }
  /**
   * Creates a function that memoizes the result of `func`. If `resolver` is
   * provided, it determines the cache key for storing the result based on the
   * arguments provided to the memoized function. By default, the first argument
   * provided to the memoized function is used as the map cache key. The `func`
   * is invoked with the `this` binding of the memoized function.
   *
   * **Note:** The cache is exposed as the `cache` property on the memoized
   * function. Its creation may be customized by replacing the `_.memoize.Cache`
   * constructor with one whose instances implement the
   * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
   * method interface of `delete`, `get`, `has`, and `set`.
   *
   * @static
   * @memberOf _
   * @since 0.1.0
   * @category Function
   * @param {Function} func The function to have its output memoized.
   * @param {Function} [resolver] The function to resolve the cache key.
   * @returns {Function} Returns the new memoized function.
   * @example
   *
   * var object = { 'a': 1, 'b': 2 };
   * var other = { 'c': 3, 'd': 4 };
   *
   * var values = _.memoize(_.values);
   * values(object);
   * // => [1, 2]
   *
   * values(other);
   * // => [3, 4]
   *
   * object.a = 2;
   * values(object);
   * // => [1, 2]
   *
   * // Modify the result cache.
   * values.cache.set(object, ['a', 'b']);
   * values(object);
   * // => ['a', 'b']
   *
   * // Replace `_.memoize.Cache`.
   * _.memoize.Cache = WeakMap;
   */


  function memoize(func, resolver) {
    if (typeof func !== 'function' || resolver && typeof resolver !== 'function') {
      throw new TypeError(FUNC_ERROR_TEXT);
    }

    var memoized = function memoized() {
      var args = arguments,
          key = resolver ? resolver.apply(this, args) : args[0],
          cache = memoized.cache;

      if (cache.has(key)) {
        return cache.get(key);
      }

      var result = func.apply(this, args);
      memoized.cache = cache.set(key, result);
      return result;
    };

    memoized.cache = new (memoize.Cache || MapCache)();
    return memoized;
  } // Assign cache to `_.memoize`.


  memoize.Cache = MapCache;
  /**
   * Performs a
   * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
   * comparison between two values to determine if they are equivalent.
   *
   * @static
   * @memberOf _
   * @since 4.0.0
   * @category Lang
   * @param {*} value The value to compare.
   * @param {*} other The other value to compare.
   * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
   * @example
   *
   * var object = { 'a': 1 };
   * var other = { 'a': 1 };
   *
   * _.eq(object, object);
   * // => true
   *
   * _.eq(object, other);
   * // => false
   *
   * _.eq('a', 'a');
   * // => true
   *
   * _.eq('a', Object('a'));
   * // => false
   *
   * _.eq(NaN, NaN);
   * // => true
   */

  function eq(value, other) {
    return value === other || value !== value && other !== other;
  }
  /**
   * Checks if `value` is classified as an `Array` object.
   *
   * @static
   * @memberOf _
   * @since 0.1.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is an array, else `false`.
   * @example
   *
   * _.isArray([1, 2, 3]);
   * // => true
   *
   * _.isArray(document.body.children);
   * // => false
   *
   * _.isArray('abc');
   * // => false
   *
   * _.isArray(_.noop);
   * // => false
   */


  var isArray = Array.isArray;
  /**
   * Checks if `value` is classified as a `Function` object.
   *
   * @static
   * @memberOf _
   * @since 0.1.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is a function, else `false`.
   * @example
   *
   * _.isFunction(_);
   * // => true
   *
   * _.isFunction(/abc/);
   * // => false
   */

  function isFunction(value) {
    // The use of `Object#toString` avoids issues with the `typeof` operator
    // in Safari 8-9 which returns 'object' for typed array and other constructors.
    var tag = isObject(value) ? objectToString.call(value) : '';
    return tag == funcTag || tag == genTag;
  }
  /**
   * Checks if `value` is the
   * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
   * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
   *
   * @static
   * @memberOf _
   * @since 0.1.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is an object, else `false`.
   * @example
   *
   * _.isObject({});
   * // => true
   *
   * _.isObject([1, 2, 3]);
   * // => true
   *
   * _.isObject(_.noop);
   * // => true
   *
   * _.isObject(null);
   * // => false
   */


  function isObject(value) {
    var type = _typeof(value);

    return !!value && (type == 'object' || type == 'function');
  }
  /**
   * Checks if `value` is object-like. A value is object-like if it's not `null`
   * and has a `typeof` result of "object".
   *
   * @static
   * @memberOf _
   * @since 4.0.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
   * @example
   *
   * _.isObjectLike({});
   * // => true
   *
   * _.isObjectLike([1, 2, 3]);
   * // => true
   *
   * _.isObjectLike(_.noop);
   * // => false
   *
   * _.isObjectLike(null);
   * // => false
   */


  function isObjectLike(value) {
    return !!value && _typeof(value) === 'object';
  }
  /**
   * Checks if `value` is classified as a `Symbol` primitive or object.
   *
   * @static
   * @memberOf _
   * @since 4.0.0
   * @category Lang
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
   * @example
   *
   * _.isSymbol(Symbol.iterator);
   * // => true
   *
   * _.isSymbol('abc');
   * // => false
   */


  function isSymbol(value) {
    return _typeof(value) === 'symbol' || isObjectLike(value) && objectToString.call(value) == symbolTag;
  }
  /**
   * Converts `value` to a string. An empty string is returned for `null`
   * and `undefined` values. The sign of `-0` is preserved.
   *
   * @static
   * @memberOf _
   * @since 4.0.0
   * @category Lang
   * @param {*} value The value to process.
   * @returns {string} Returns the string.
   * @example
   *
   * _.toString(null);
   * // => ''
   *
   * _.toString(-0);
   * // => '-0'
   *
   * _.toString([1, 2, 3]);
   * // => '1,2,3'
   */


  function toString(value) {
    return value == null ? '' : baseToString(value);
  }
  /**
   * Checks if `value` is a valid array-like index.
   *
   * @private
   * @param {*} value The value to check.
   * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
   * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
   */


  function isIndex(value, length) {
    var type = _typeof(value);

    length = length == null ? MAX_SAFE_INTEGER : length;
    return !!length && (type == 'number' || type != 'symbol' && reIsUint.test(value)) && value > -1 && value % 1 == 0 && value < length;
  }
  /**
   * The base implementation of `assignValue` and `assignMergeValue` without
   * value checks.
   *
   * @private
   * @param {Object} object The object to modify.
   * @param {string} key The key of the property to assign.
   * @param {*} value The value to assign.
   */


  function baseAssignValue(object, key, value) {
    if (key == '__proto__') {
      Object.defineProperty(object, key, {
        'configurable': true,
        'enumerable': true,
        'value': value,
        'writable': true
      });
    } else {
      object[key] = value;
    }
  }
  /** Used to check objects for own properties. */


  var hasOwnProperty = Object.prototype.hasOwnProperty;
  /**
   * Assigns `value` to `key` of `object` if the existing value is not equivalent
   * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
   * for equality comparisons.
   *
   * @private
   * @param {Object} object The object to modify.
   * @param {string} key The key of the property to assign.
   * @param {*} value The value to assign.
   */

  function assignValue(object, key, value) {
    var objValue = object[key];

    if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || value === undefined && !(key in object)) {
      baseAssignValue(object, key, value);
    }
  }
  /**
   * The base implementation of `set`.
   *
   * @private
   * @param {Object} object The object to modify.
   * @param {Array|string} path The path of the property to set.
   * @param {*} value The value to set.
   * @param {Function} [customizer] The function to customize path creation.
   * @returns {Object} Returns `object`.
   */


  function baseSet(object, path, value, customizer) {
    if (!isObject(object)) {
      return object;
    }

    path = castPath(path, object);
    var length = path.length;
    var lastIndex = length - 1;
    var index = -1;
    var nested = object;

    while (nested != null && ++index < length) {
      var key = toKey(path[index]);
      var newValue = value;

      if (index != lastIndex) {
        var objValue = nested[key];
        newValue = customizer ? customizer(objValue, key, nested) : undefined;

        if (newValue === undefined) {
          newValue = isObject(objValue) ? objValue : isIndex(path[index + 1]) ? [] : {};
        }
      }

      assignValue(nested, key, newValue);
      nested = nested[key];
    }

    return object;
  }

  /**
   * Gets the value at `path` of `object`. If the resolved value is
   * `undefined`, the `defaultValue` is returned in its place.
   *
   * @static
   * @memberOf _
   * @since 3.7.0
   * @category Object
   * @param {Object} object The object to query.
   * @param {Array|string} path The path of the property to get.
   * @param {*} [defaultValue] The value returned for `undefined` resolved values.
   * @returns {*} Returns the resolved value.
   * @example
   *
   * var object = { 'a': [{ 'b': { 'c': 3 } }] };
   *
   * _.get(object, 'a[0].b.c');
   * // => 3
   *
   * _.get(object, ['a', '0', 'b', 'c']);
   * // => 3
   *
   * _.get(object, 'a.b.c', 'default');
   * // => 'default'
   */

  function get(object, path, defaultValue) {
    var result = object == null ? undefined : baseGet(object, path);
    return result === undefined ? defaultValue : result;
  }

  /**
   * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
   * it's created. Arrays are created for missing index properties while objects
   * are created for all other missing properties. Use `setWith` to customize
   * `path` creation.
   *
   * **Note:** This method mutates `object`.
   *
   * @since 3.7.0
   * @category Object
   * @param {Object} object The object to modify.
   * @param {Array|string} path The path of the property to set.
   * @param {*} value The value to set.
   * @returns {Object} Returns `object`.
   * @see has, hasIn, get, unset
   * @example
   *
   * const object = { 'a': [{ 'b': { 'c': 3 } }] }
   *
   * set(object, 'a[0].b.c', 4)
   * console.log(object.a[0].b.c)
   * // => 4
   *
   * set(object, ['x', '0', 'y', 'z'], 5)
   * console.log(object.x[0].y.z)
   * // => 5
   */

  function set$1(object, path, value) {
    return object == null ? object : baseSet(object, path, value);
  }

  var ENV_TYPE = {
    WEAPP: 'WEAPP',
    WEB: 'WEB',
    RN: 'RN'
  };
  function getEnv() {
    if (typeof wx !== 'undefined' && wx.getSystemInfo) {
      return ENV_TYPE.WEAPP;
    }

    if (typeof global !== 'undefined' && global.__fbGenNativeModule) {
      return ENV_TYPE.RN;
    }

    if (typeof window !== 'undefined') {
      return ENV_TYPE.WEB;
    }

    return 'Unknown environment';
  }

  var Events =
  /*#__PURE__*/
  function () {
    function Events(opts) {
      _classCallCheck(this, Events);

      if (typeof opts !== 'undefined' && opts.callbacks) {
        this.callbacks = opts.callbacks;
      } else {
        this.callbacks = {};
      }
    }

    _createClass(Events, [{
      key: "on",
      value: function on(events, callback, context) {
        var calls, event, node, tail, list;

        if (!callback) {
          return this;
        }

        events = events.split(Events.eventSplitter);
        calls = this.callbacks;

        while (event = events.shift()) {
          list = calls[event];
          node = list ? list.tail : {};
          node.next = tail = {};
          node.context = context;
          node.callback = callback;
          calls[event] = {
            tail: tail,
            next: list ? list.next : node
          };
        }

        return this;
      }
    }, {
      key: "once",
      value: function once(events, callback, context) {
        var _this = this;

        var wrapper = function wrapper() {
          for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
            args[_key] = arguments[_key];
          }

          callback.apply(_this, args);

          _this.off(events, callback, context);
        };

        this.on(events, wrapper, context);
        return this;
      }
    }, {
      key: "off",
      value: function off(events, callback, context) {
        var event, calls, node, tail, cb, ctx;

        if (!(calls = this.callbacks)) {
          return this;
        }

        if (!(events || callback || context)) {
          delete this.callbacks;
          return this;
        }

        events = events ? events.split(Events.eventSplitter) : Object.keys(calls);

        while (event = events.shift()) {
          node = calls[event];
          delete calls[event];

          if (!node || !(callback || context)) {
            continue;
          }

          tail = node.tail;

          while ((node = node.next) !== tail) {
            cb = node.callback;
            ctx = node.context;

            if (callback && cb !== callback || context && ctx !== context) {
              this.on(event, cb, ctx);
            }
          }
        }

        return this;
      }
    }, {
      key: "trigger",
      value: function trigger(events) {
        var event, node, calls, tail, rest;

        if (!(calls = this.callbacks)) {
          return this;
        }

        events = events.split(Events.eventSplitter);
        rest = [].slice.call(arguments, 1);

        while (event = events.shift()) {
          if (node = calls[event]) {
            tail = node.tail;

            while ((node = node.next) !== tail) {
              node.callback.apply(node.context || this, rest);
            }
          }
        }

        return this;
      }
    }]);

    return Events;
  }();

  Events.eventSplitter = /\s+/;

  function render() {}

  var onAndSyncApis = {
    onSocketOpen: true,
    onSocketError: true,
    onSocketMessage: true,
    onSocketClose: true,
    onBackgroundAudioPlay: true,
    onBackgroundAudioPause: true,
    onBackgroundAudioStop: true,
    onNetworkStatusChange: true,
    onAccelerometerChange: true,
    onCompassChange: true,
    onBluetoothAdapterStateChange: true,
    onBluetoothDeviceFound: true,
    onBLEConnectionStateChange: true,
    onBLECharacteristicValueChange: true,
    onBeaconUpdate: true,
    onBeaconServiceChange: true,
    onUserCaptureScreen: true,
    onHCEMessage: true,
    onGetWifiList: true,
    onWifiConnected: true,
    setStorageSync: true,
    getStorageSync: true,
    getStorageInfoSync: true,
    removeStorageSync: true,
    clearStorageSync: true,
    getSystemInfoSync: true,
    getExtConfigSync: true,
    getLogManager: true
  };
  var noPromiseApis = {
    // 媒体
    stopRecord: true,
    getRecorderManager: true,
    pauseVoice: true,
    stopVoice: true,
    pauseBackgroundAudio: true,
    stopBackgroundAudio: true,
    getBackgroundAudioManager: true,
    createAudioContext: true,
    createInnerAudioContext: true,
    createVideoContext: true,
    createCameraContext: true,
    createLivePlayerContext: true,
    createLivePusherContext: true,
    // 位置
    createMapContext: true,
    // 设备
    canIUse: true,
    startAccelerometer: true,
    stopAccelerometer: true,
    startCompass: true,
    stopCompass: true,
    // 界面
    hideToast: true,
    hideLoading: true,
    showNavigationBarLoading: true,
    hideNavigationBarLoading: true,
    createAnimation: true,
    pageScrollTo: true,
    createSelectorQuery: true,
    createCanvasContext: true,
    createContext: true,
    drawCanvas: true,
    hideKeyboard: true,
    stopPullDownRefresh: true,
    createIntersectionObserver: true,
    onWindowResize: true,
    offWindowResize: true,
    // 拓展接口
    arrayBufferToBase64: true,
    base64ToArrayBuffer: true,
    getUpdateManager: true,
    createWorker: true
  };
  var otherApis = {
    // 网络
    uploadFile: true,
    downloadFile: true,
    connectSocket: true,
    sendSocketMessage: true,
    closeSocket: true,
    // 媒体
    chooseImage: true,
    previewImage: true,
    getImageInfo: true,
    saveImageToPhotosAlbum: true,
    startRecord: true,
    playVoice: true,
    getBackgroundAudioPlayerState: true,
    playBackgroundAudio: true,
    seekBackgroundAudio: true,
    chooseVideo: true,
    saveVideoToPhotosAlbum: true,
    loadFontFace: true,
    // 文件
    saveFile: true,
    getFileInfo: true,
    getSavedFileList: true,
    getSavedFileInfo: true,
    removeSavedFile: true,
    openDocument: true,
    // 数据缓存
    setStorage: true,
    getStorage: true,
    getStorageInfo: true,
    removeStorage: true,
    clearStorage: true,
    // 导航
    navigateBack: true,
    navigateTo: true,
    redirectTo: true,
    switchTab: true,
    reLaunch: true,
    // 位置
    getLocation: true,
    chooseLocation: true,
    openLocation: true,
    // 设备
    getSystemInfo: true,
    getNetworkType: true,
    makePhoneCall: true,
    scanCode: true,
    setClipboardData: true,
    getClipboardData: true,
    openBluetoothAdapter: true,
    closeBluetoothAdapter: true,
    getBluetoothAdapterState: true,
    startBluetoothDevicesDiscovery: true,
    stopBluetoothDevicesDiscovery: true,
    getBluetoothDevices: true,
    getConnectedBluetoothDevices: true,
    createBLEConnection: true,
    closeBLEConnection: true,
    getBLEDeviceServices: true,
    getBLEDeviceCharacteristics: true,
    readBLECharacteristicValue: true,
    writeBLECharacteristicValue: true,
    notifyBLECharacteristicValueChange: true,
    startBeaconDiscovery: true,
    stopBeaconDiscovery: true,
    getBeacons: true,
    setScreenBrightness: true,
    getScreenBrightness: true,
    setKeepScreenOn: true,
    vibrateLong: true,
    vibrateShort: true,
    addPhoneContact: true,
    getHCEState: true,
    startHCE: true,
    stopHCE: true,
    sendHCEMessage: true,
    startWifi: true,
    stopWifi: true,
    connectWifi: true,
    getWifiList: true,
    setWifiList: true,
    getConnectedWifi: true,
    // 界面
    showToast: true,
    showLoading: true,
    showModal: true,
    showActionSheet: true,
    setNavigationBarTitle: true,
    setNavigationBarColor: true,
    setTabBarBadge: true,
    removeTabBarBadge: true,
    showTabBarRedDot: true,
    hideTabBarRedDot: true,
    setTabBarStyle: true,
    setTabBarItem: true,
    showTabBar: true,
    hideTabBar: true,
    setTopBarText: true,
    startPullDownRefresh: true,
    canvasToTempFilePath: true,
    canvasGetImageData: true,
    canvasPutImageData: true,
    setBackgroundColor: true,
    setBackgroundTextStyle: true,
    // 第三方平台
    getExtConfig: true,
    // 开放接口
    login: true,
    checkSession: true,
    authorize: true,
    getUserInfo: true,
    checkIsSupportFacialRecognition: true,
    startFacialRecognitionVerify: true,
    startFacialRecognitionVerifyAndUploadVideo: true,
    faceVerifyForPay: true,
    requestPayment: true,
    showShareMenu: true,
    hideShareMenu: true,
    updateShareMenu: true,
    getShareInfo: true,
    chooseAddress: true,
    addCard: true,
    openCard: true,
    openSetting: true,
    getSetting: true,
    getWeRunData: true,
    navigateToMiniProgram: true,
    navigateBackMiniProgram: true,
    chooseInvoice: true,
    chooseInvoiceTitle: true,
    checkIsSupportSoterAuthentication: true,
    startSoterAuthentication: true,
    checkIsSoterEnrolledInDevice: true //

  };

  function initPxTransform(config) {
    var _config$designWidth = config.designWidth,
        designWidth = _config$designWidth === void 0 ? 700 : _config$designWidth,
        _config$deviceRatio = config.deviceRatio,
        deviceRatio = _config$deviceRatio === void 0 ? {
      '640': 2.34 / 2,
      '750': 1,
      '828': 1.81 / 2
    } : _config$deviceRatio;
    this.config = this.config || {};
    this.config.designWidth = designWidth;
    this.config.deviceRatio = deviceRatio;
  }

  /* eslint-disable camelcase */
  var eventCenter = new Events();

  /**
   * WXML节点信息API
   * @return {Object} SelectorQuery 对象实例
   */
  function queryBat(queue, cb) {
    var res = [];
    queue.forEach(function (item) {
      var selector = item.selector,
          single = item.single,
          fields = item.fields;
      var el = null;

      if (single) {
        el = document.querySelector(selector);
        res.push(filter(fields, el, selector));
      } else {
        el = Array.from(document.querySelectorAll(selector));
        res.push(el.map(function (dom) {
          return filter(fields, dom);
        }));
      }
    });
    cb(res);
  }

  function filter(fields, dom, selector) {
    if (!dom) return null;
    var id = fields.id,
        dataset = fields.dataset,
        rect = fields.rect,
        size = fields.size,
        scrollOffset = fields.scrollOffset,
        _fields$properties = fields.properties,
        properties = _fields$properties === void 0 ? [] : _fields$properties,
        _fields$computedStyle = fields.computedStyle,
        computedStyle = _fields$computedStyle === void 0 ? [] : _fields$computedStyle;

    var _dom$getBoundingClien = dom.getBoundingClientRect(),
        left = _dom$getBoundingClien.left,
        right = _dom$getBoundingClien.right,
        top = _dom$getBoundingClien.top,
        bottom = _dom$getBoundingClien.bottom,
        width = _dom$getBoundingClien.width,
        height = _dom$getBoundingClien.height;

    var isViewport = selector === 'html';
    var res = {};
    if (id) res.id = dom.id;
    if (dataset) res.dataset = Object.assign({}, dom.dataset);

    if (rect) {
      if (!isViewport) {
        res.left = left;
        res.right = right;
        res.top = top;
        res.bottom = bottom;
      } else {
        res.left = res.right = res.top = res.bottom = 0;
      }
    }

    if (size) {
      if (!isViewport) {
        res.width = width;
        res.height = height;
      } else {
        res.width = dom.clientWidth;
        res.height = dom.clientHeight;
      }
    }

    if (scrollOffset) {
      res.scrollLeft = dom.scrollLeft;
      res.scrollTop = dom.scrollTop;
    }

    if (properties.length) {
      properties.forEach(function (prop) {
        var attr = dom.getAttribute(prop);
        if (attr) res[prop] = attr;
      });
    }

    if (computedStyle.length) {
      var styles = window.getComputedStyle(dom);
      computedStyle.forEach(function (key) {
        var value = styles.getPropertyValue(key);
        if (value) res[key] = value;
      });
    }

    return res;
  }

  var Query =
  /*#__PURE__*/
  function () {
    function Query() {
      _classCallCheck(this, Query);

      this._defaultWebviewId = null;
      this._webviewId = null;
      this._queue = [];
      this._queueCb = [];
      this._component = null;
    }

    _createClass(Query, [{
      key: "in",
      value: function _in(component) {
        this._component = component;
        return this;
      }
    }, {
      key: "select",
      value: function select(selector) {
        // 小程序里跨自定义组件的后代选择器 '>>>' 在 h5 替换为普通后代选择器 '>'
        if (typeof selector === 'string') selector = selector.replace('>>>', '>');
        return new NodesRef(selector, this, true);
      }
    }, {
      key: "selectAll",
      value: function selectAll(selector) {
        // 小程序里跨自定义组件的后代选择器 '>>>' 在 h5 替换为普通后代选择器 '>'
        if (typeof selector === 'string') selector = selector.replace('>>>', '>');
        return new NodesRef(selector, this, false);
      }
    }, {
      key: "selectViewport",
      value: function selectViewport() {
        return new NodesRef('html', this, true);
      }
    }, {
      key: "exec",
      value: function exec(cb) {
        var _this = this;

        queryBat(this._queue, function (res) {
          var _queueCb = _this._queueCb;
          res.forEach(function (item, index) {
            typeof _queueCb[index] === 'function' && _queueCb[index].call(_this, item);
          });
          typeof cb === 'function' && cb.call(_this, res);
        });
      }
    }, {
      key: "_push",
      value: function _push(selector, component, single, fields) {
        var callback = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;

        this._queue.push({
          component: component,
          selector: selector,
          single: single,
          fields: fields
        });

        this._queueCb.push(callback);
      }
    }]);

    return Query;
  }();

  var NodesRef =
  /*#__PURE__*/
  function () {
    function NodesRef(selector, querySelectorQuery, single) {
      _classCallCheck(this, NodesRef);

      this._component = querySelectorQuery._component;
      this._selector = selector;
      this._selectorQuery = querySelectorQuery;
      this._single = single;
    }

    _createClass(NodesRef, [{
      key: "boundingClientRect",
      value: function boundingClientRect(cb) {
        var _selector = this._selector,
            _component = this._component,
            _single = this._single,
            _selectorQuery = this._selectorQuery;

        _selectorQuery._push(_selector, _component, _single, {
          id: !0,
          dataset: !0,
          rect: !0,
          size: !0
        }, cb);

        return _selectorQuery;
      }
    }, {
      key: "scrollOffset",
      value: function scrollOffset(cb) {
        var _selector = this._selector,
            _component = this._component,
            _single = this._single,
            _selectorQuery = this._selectorQuery;

        _selectorQuery._push(_selector, _component, _single, {
          id: !0,
          dataset: !0,
          scrollOffset: !0
        }, cb);

        return _selectorQuery;
      }
    }, {
      key: "fields",
      value: function fields(_fields, cb) {
        var _selector = this._selector,
            _component = this._component,
            _single = this._single,
            _selectorQuery = this._selectorQuery;
        var id = _fields.id,
            dataset = _fields.dataset,
            rect = _fields.rect,
            size = _fields.size,
            scrollOffset = _fields.scrollOffset,
            _fields$properties2 = _fields.properties,
            properties = _fields$properties2 === void 0 ? [] : _fields$properties2,
            _fields$computedStyle2 = _fields.computedStyle,
            computedStyle = _fields$computedStyle2 === void 0 ? [] : _fields$computedStyle2;

        _selectorQuery._push(_selector, _component, _single, {
          id: id,
          dataset: dataset,
          rect: rect,
          size: size,
          scrollOffset: scrollOffset,
          properties: properties,
          computedStyle: computedStyle
        }, cb);

        return _selectorQuery;
      }
    }]);

    return NodesRef;
  }();

  function createSelectorQuery() {
    return new Query();
  }

  /*
  object-assign
  (c) Sindre Sorhus
  @license MIT
  */
  var getOwnPropertySymbols = Object.getOwnPropertySymbols;
  var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
  var propIsEnumerable = Object.prototype.propertyIsEnumerable;

  function toObject(val) {
    if (val === null || val === undefined) {
      throw new TypeError('Object.assign cannot be called with null or undefined');
    }

    return Object(val);
  }

  function shouldUseNative() {
    try {
      if (!Object.assign) {
        return false;
      } // Detect buggy property enumeration order in older V8 versions.
      // https://bugs.chromium.org/p/v8/issues/detail?id=4118


      var test1 = new String('abc'); // eslint-disable-line no-new-wrappers

      test1[5] = 'de';

      if (Object.getOwnPropertyNames(test1)[0] === '5') {
        return false;
      } // https://bugs.chromium.org/p/v8/issues/detail?id=3056


      var test2 = {};

      for (var i = 0; i < 10; i++) {
        test2['_' + String.fromCharCode(i)] = i;
      }

      var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
        return test2[n];
      });

      if (order2.join('') !== '0123456789') {
        return false;
      } // https://bugs.chromium.org/p/v8/issues/detail?id=3056


      var test3 = {};
      'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
        test3[letter] = letter;
      });

      if (Object.keys(Object.assign({}, test3)).join('') !== 'abcdefghijklmnopqrst') {
        return false;
      }

      return true;
    } catch (err) {
      // We don't expect any of the above to throw, but better to be safe.
      return false;
    }
  }

  var objectAssign$1 = shouldUseNative() ? Object.assign : function (target, source) {
    var from;
    var to = toObject(target);
    var symbols;

    for (var s = 1; s < arguments.length; s++) {
      from = Object(arguments[s]);

      for (var key in from) {
        if (hasOwnProperty$1.call(from, key)) {
          to[key] = from[key];
        }
      }

      if (getOwnPropertySymbols) {
        symbols = getOwnPropertySymbols(from);

        for (var i = 0; i < symbols.length; i++) {
          if (propIsEnumerable.call(from, symbols[i])) {
            to[symbols[i]] = from[symbols[i]];
          }
        }
      }
    }

    return to;
  };
  var enc = encodeURIComponent;

  function serializeParams(params) {
    if (!params) {
      return '';
    }

    return Object.keys(params).map(function (item) {
      return item + '=' + enc(params[item]);
    }).join('&');
  }

  function isFunction$1(fn) {
    return typeof fn === 'function';
  }

  function getUrlQueryParamByName(url, name) {
    if (!url) {
      url = window.location.href;
    }

    name = name.replace(/[[]]/g, '\\$&');
    var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)');
    var results = regex.exec(url);

    if (!results) {
      return null;
    }

    if (!results[2]) {
      return '';
    }

    return decodeURIComponent(results[2].replace(/\+/g, ' '));
  }

  function updateQueryStringParamByName(url, name, value) {
    var re = new RegExp('([?&])' + name + '=.*?(&|$)', 'i');
    var separator = url.indexOf('?') !== -1 ? '&' : '?';

    if (url.match(re)) {
      return url.replace(re, '$1' + name + '=' + value + '$2');
    }

    return url + separator + name + '=' + value;
  }

  var win$1 = typeof window !== 'undefined' ? window : global;
  var localStorageName = 'localStorage';
  var storage = win$1[localStorageName];
  var store = {
    disabled: false,
    set: function set(key, val) {
      if (val === void 666) {
        return store.remove(key);
      }

      storage.setItem(key, store.serialize(val));
      return val;
    },
    get: function get(key, defaultVal) {
      var val = store.deserialize(storage.getItem(key));
      return val === undefined ? defaultVal : val;
    },
    remove: function remove(key) {
      storage.removeItem(key);
    },
    clear: function clear() {
      storage.clear();
    },
    has: function has(key) {
      return store.get(key) !== void 666;
    },
    forEach: function forEach(callback) {
      for (var i = 0; i < storage.length; i++) {
        var key = storage.key(i);
        callback(key, store.get(key));
      }
    },
    getAll: function getAll() {
      var ret = {};
      store.forEach(function (key, val) {
        ret[key] = val;
      });
      return ret;
    },
    serialize: function serialize(value) {
      return JSON.stringify(value);
    },
    deserialize: function deserialize(value) {
      if (typeof value !== 'string') {
        return;
      }

      try {
        return JSON.parse(value);
      } catch (err) {
        return value || void 666;
      }
    }
  };

  try {
    var testKey = '__store__';
    store.set(testKey, testKey);

    if (store.get(testKey) !== testKey) {
      store.disabled = true;
    }

    store.remove(testKey);
  } catch (err) {
    store.disabled = true;
  }

  store.enabled = !store.disabled;

  var _typeof$1 = typeof Symbol === "function" && _typeof(Symbol.iterator) === "symbol" ? function (obj) {
    return _typeof(obj);
  } : function (obj) {
    return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : _typeof(obj);
  };

  var win = typeof window !== 'undefined' ? window : global;

  var canUsePromise = function () {
    return 'Promise' in win && _typeof$1(isFunction$1(Promise));
  }();

  var noop = function noop() {};

  var encodeC = encodeURIComponent;
  var doc = win.document;
  var head = doc ? doc.head || doc.getElementsByTagName('head')[0] : null;
  var TIMEOUT_CONST = 2000;
  var defaultConfig = {
    timeout: TIMEOUT_CONST,
    retryTimes: 2,
    backup: null,
    params: {},
    jsonp: 'callback',
    name: null,
    cache: false,
    useStore: false,
    storeCheck: null,
    storeSign: null,
    storeCheckKey: null,
    dataCheck: null,
    charset: 'UTF-8'
  };
  var timestamp = new Date().getTime();

  function jsonp$1(url, opts, cb) {
    if (isFunction$1(url)) {
      cb = url;
      opts = {};
    } else if (url && (typeof url === 'undefined' ? 'undefined' : _typeof$1(url)) === 'object') {
      cb = opts;
      opts = url || {};
      url = opts.url;
    }

    if (isFunction$1(opts)) {
      cb = opts;
      opts = {};
    }

    if (!opts) {
      opts = {};
    }

    opts = objectAssign$1({}, defaultConfig, opts);
    url = url || opts.url;
    cb = cb || noop;

    if (!url || typeof url !== 'string') {
      cb(new Error('Param url is needed!'));

      if (!jsonp$1.promiseClose && canUsePromise) {
        return new Promise(function (resolve, reject) {
          return reject(new Error('Param url is needed!'));
        });
      }

      return;
    }

    var urlWithParams = generateJsonpUrlWithParams(url, opts.params); // first get data from store

    var datafromStore = getDataFromStore({
      useStore: opts.useStore,
      storeKey: urlWithParams,
      storeCheck: opts.storeCheck,
      storeCheckKey: opts.storeCheckKey,
      storeSign: opts.storeSign,
      dataCheck: opts.dataCheck
    });

    if (datafromStore) {
      cb(null, datafromStore);

      if (!jsonp$1.promiseClose && canUsePromise) {
        return new Promise(function (resolve) {
          return resolve(datafromStore);
        });
      }

      return;
    }

    opts.originalUrl = urlWithParams;

    if (!jsonp$1.promiseClose && canUsePromise) {
      return new Promise(function (resolve, reject) {
        fetchData(urlWithParams, opts, function (err, data) {
          if (err) {
            cb(err);
            return reject(err);
          }

          cb(null, data);
          resolve(data);
        });
      });
    }

    fetchData(urlWithParams, opts, cb);
  }

  function generateJsonpUrlWithParams(url, params) {
    params = typeof params === 'string' ? params : serializeParams(params);
    url += (~url.indexOf('?') ? '&' : '?') + ('' + params);
    url = url.replace('?&', '?');
    return url;
  }

  function fetchData(url, opts, cb) {
    var originalUrl = opts.originalUrl;
    var charset = opts.charset;
    var jsonpUrlQueryParam = getUrlQueryParamByName(url, opts.jsonp);
    var funcId = (jsonpUrlQueryParam === '?' ? false : jsonpUrlQueryParam) || opts.name || '__jsonp' + timestamp++;
    var gotoBackupInfo = arguments[3] || null;

    if (jsonpUrlQueryParam) {
      if (jsonpUrlQueryParam === '?') {
        url = updateQueryStringParamByName(url, opts.jsonp, encodeC(funcId));
      }
    } else {
      url += (url.split('').pop() === '&' ? '' : '&') + (opts.jsonp + '=' + encodeC(funcId));
    }

    if (!opts.cache) {
      url += (url.split('').pop() === '&' ? '' : '&') + ('_=' + new Date().getTime());
    } // move prev callback into next when fetch parallel with same funcId


    clearTimeout(win['timer_' + funcId]);
    var prevFunc = win[funcId];

    win[funcId] = function (data) {
      prevFunc && prevFunc(data);
      cleanup(funcId);

      if (gotoBackupInfo) {
        data.__$$backupCall = gotoBackupInfo;
      }

      if (opts.dataCheck) {
        if (opts.dataCheck(data) !== false) {
          // write data to store
          setDataToStore({
            useStore: opts.useStore,
            storeKey: originalUrl,
            data: data
          });
          return cb(null, data);
        }

        if (fallback(originalUrl, opts, cb) === false) {
          cb(new Error('Data check error, and no fallback'));
        }
      } else {
        // write data to store
        setDataToStore({
          useStore: opts.useStore,
          storeKey: originalUrl,
          data: data
        });
        cb(null, data);
      }
    };

    var script = appendScriptTagToHead({
      url: url,
      charset: charset
    });
    var timeout = opts.timeout != null ? opts.timeout : TIMEOUT_CONST; // when timeout, will try to retry

    win['timer_' + funcId] = setTimeout(function () {
      cleanup(funcId); // no retryTimes left, go to backup

      if (typeof opts.retryTimes === 'number' && opts.retryTimes > 0) {
        opts.retryTimes--;
        return fetchData(originalUrl, opts, cb);
      }

      if (fallback(originalUrl, opts, cb) === false) {
        return cb(new Error('Timeout and no data return'));
      }
    }, timeout);

    function cleanup(funcId) {
      if (script.parentNode) {
        script.parentNode.removeChild(script);
      }

      win[funcId] = noop;
      clearTimeout(win['timer_' + funcId]);
    }
  }

  function storeCheckFn(storeData, storeCheckKey, storeSign) {
    if (storeData && storeCheckKey && storeSign) {
      return storeData[storeCheckKey] && storeData[storeCheckKey] === storeSign;
    }

    return false;
  }

  function getDataFromStore(_ref) {
    var useStore = _ref.useStore,
        storeKey = _ref.storeKey,
        storeCheck = _ref.storeCheck,
        storeCheckKey = _ref.storeCheckKey,
        storeSign = _ref.storeSign,
        dataCheck = _ref.dataCheck;
    useStore = useStore ? store.enabled : false;

    if (useStore) {
      var storeData = store.get(storeKey);
      storeCheck = storeCheck || storeCheckFn;

      if (storeCheck(storeData, storeCheckKey, storeSign)) {
        if (!dataCheck || storeData && dataCheck && dataCheck(storeData) !== false) {
          return storeData;
        }
      }
    }

    return null;
  }

  function getDataFromStoreWithoutCheck(_ref2) {
    var useStore = _ref2.useStore,
        storeKey = _ref2.storeKey,
        dataCheck = _ref2.dataCheck;
    useStore = useStore ? store.enabled : false;

    if (useStore) {
      var storeData = store.get(storeKey);

      if (!dataCheck || storeData && dataCheck && dataCheck(storeData) !== false) {
        return storeData;
      }
    }

    return null;
  }

  function setDataToStore(_ref3) {
    var useStore = _ref3.useStore,
        storeKey = _ref3.storeKey,
        data = _ref3.data;
    useStore = useStore ? store.enabled : false;

    if (useStore) {
      store.set(storeKey, data);
    }
  }

  function fallback(url, opts, cb) {
    var backup = opts.backup;
    var backupWithParams = void 0;

    if (backup) {
      if (typeof backup === 'string') {
        delete opts.backup;
        backupWithParams = generateJsonpUrlWithParams(backup, opts.params);
        return fetchData(backupWithParams, opts, cb, {
          backup: backup
        });
      } else if (Array.isArray(backup)) {
        if (backup.length) {
          var backupUrl = backup.shift();
          backupWithParams = generateJsonpUrlWithParams(backupUrl, opts.params);
          return fetchData(backupWithParams, opts, cb, {
            backup: backupUrl
          });
        }
      }
    } // no backup to use, try to get data from store


    var dataFromStoreWithoutCheck = getDataFromStoreWithoutCheck({
      useStore: opts.useStore,
      storeKey: url,
      dataCheck: opts.dataCheck
    });

    if (dataFromStoreWithoutCheck) {
      cb(null, dataFromStoreWithoutCheck);
      return true;
    }

    return false;
  }

  function appendScriptTagToHead(_ref4) {
    var url = _ref4.url,
        charset = _ref4.charset;

    if (!doc) {
      return;
    }

    var script = doc.createElement('script');
    script.type = 'text/javascript';

    if (charset) {
      script.charset = charset;
    }

    script.src = url;
    head.appendChild(script);
    return script;
  }

  (function (self) {

    if (self.fetch) {
      return;
    }

    var support = {
      searchParams: 'URLSearchParams' in self,
      iterable: 'Symbol' in self && 'iterator' in Symbol,
      blob: 'FileReader' in self && 'Blob' in self && function () {
        try {
          new Blob();
          return true;
        } catch (e) {
          return false;
        }
      }(),
      formData: 'FormData' in self,
      arrayBuffer: 'ArrayBuffer' in self
    };

    if (support.arrayBuffer) {
      var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];

      var isDataView = function isDataView(obj) {
        return obj && DataView.prototype.isPrototypeOf(obj);
      };

      var isArrayBufferView = ArrayBuffer.isView || function (obj) {
        return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
      };
    }

    function normalizeName(name) {
      if (typeof name !== 'string') {
        name = String(name);
      }

      if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
        throw new TypeError('Invalid character in header field name');
      }

      return name.toLowerCase();
    }

    function normalizeValue(value) {
      if (typeof value !== 'string') {
        value = String(value);
      }

      return value;
    } // Build a destructive iterator for the value list


    function iteratorFor(items) {
      var iterator = {
        next: function next() {
          var value = items.shift();
          return {
            done: value === undefined,
            value: value
          };
        }
      };

      if (support.iterable) {
        iterator[Symbol.iterator] = function () {
          return iterator;
        };
      }

      return iterator;
    }

    function Headers(headers) {
      this.map = {};

      if (headers instanceof Headers) {
        headers.forEach(function (value, name) {
          this.append(name, value);
        }, this);
      } else if (Array.isArray(headers)) {
        headers.forEach(function (header) {
          this.append(header[0], header[1]);
        }, this);
      } else if (headers) {
        Object.getOwnPropertyNames(headers).forEach(function (name) {
          this.append(name, headers[name]);
        }, this);
      }
    }

    Headers.prototype.append = function (name, value) {
      name = normalizeName(name);
      value = normalizeValue(value);
      var oldValue = this.map[name];
      this.map[name] = oldValue ? oldValue + ',' + value : value;
    };

    Headers.prototype['delete'] = function (name) {
      delete this.map[normalizeName(name)];
    };

    Headers.prototype.get = function (name) {
      name = normalizeName(name);
      return this.has(name) ? this.map[name] : null;
    };

    Headers.prototype.has = function (name) {
      return this.map.hasOwnProperty(normalizeName(name));
    };

    Headers.prototype.set = function (name, value) {
      this.map[normalizeName(name)] = normalizeValue(value);
    };

    Headers.prototype.forEach = function (callback, thisArg) {
      for (var name in this.map) {
        if (this.map.hasOwnProperty(name)) {
          callback.call(thisArg, this.map[name], name, this);
        }
      }
    };

    Headers.prototype.keys = function () {
      var items = [];
      this.forEach(function (value, name) {
        items.push(name);
      });
      return iteratorFor(items);
    };

    Headers.prototype.values = function () {
      var items = [];
      this.forEach(function (value) {
        items.push(value);
      });
      return iteratorFor(items);
    };

    Headers.prototype.entries = function () {
      var items = [];
      this.forEach(function (value, name) {
        items.push([name, value]);
      });
      return iteratorFor(items);
    };

    if (support.iterable) {
      Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
    }

    function consumed(body) {
      if (body.bodyUsed) {
        return Promise.reject(new TypeError('Already read'));
      }

      body.bodyUsed = true;
    }

    function fileReaderReady(reader) {
      return new Promise(function (resolve, reject) {
        reader.onload = function () {
          resolve(reader.result);
        };

        reader.onerror = function () {
          reject(reader.error);
        };
      });
    }

    function readBlobAsArrayBuffer(blob) {
      var reader = new FileReader();
      var promise = fileReaderReady(reader);
      reader.readAsArrayBuffer(blob);
      return promise;
    }

    function readBlobAsText(blob) {
      var reader = new FileReader();
      var promise = fileReaderReady(reader);
      reader.readAsText(blob);
      return promise;
    }

    function readArrayBufferAsText(buf) {
      var view = new Uint8Array(buf);
      var chars = new Array(view.length);

      for (var i = 0; i < view.length; i++) {
        chars[i] = String.fromCharCode(view[i]);
      }

      return chars.join('');
    }

    function bufferClone(buf) {
      if (buf.slice) {
        return buf.slice(0);
      } else {
        var view = new Uint8Array(buf.byteLength);
        view.set(new Uint8Array(buf));
        return view.buffer;
      }
    }

    function Body() {
      this.bodyUsed = false;

      this._initBody = function (body) {
        this._bodyInit = body;

        if (!body) {
          this._bodyText = '';
        } else if (typeof body === 'string') {
          this._bodyText = body;
        } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
          this._bodyBlob = body;
        } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
          this._bodyFormData = body;
        } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
          this._bodyText = body.toString();
        } else if (support.arrayBuffer && support.blob && isDataView(body)) {
          this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.

          this._bodyInit = new Blob([this._bodyArrayBuffer]);
        } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
          this._bodyArrayBuffer = bufferClone(body);
        } else {
          throw new Error('unsupported BodyInit type');
        }

        if (!this.headers.get('content-type')) {
          if (typeof body === 'string') {
            this.headers.set('content-type', 'text/plain;charset=UTF-8');
          } else if (this._bodyBlob && this._bodyBlob.type) {
            this.headers.set('content-type', this._bodyBlob.type);
          } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
            this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
          }
        }
      };

      if (support.blob) {
        this.blob = function () {
          var rejected = consumed(this);

          if (rejected) {
            return rejected;
          }

          if (this._bodyBlob) {
            return Promise.resolve(this._bodyBlob);
          } else if (this._bodyArrayBuffer) {
            return Promise.resolve(new Blob([this._bodyArrayBuffer]));
          } else if (this._bodyFormData) {
            throw new Error('could not read FormData body as blob');
          } else {
            return Promise.resolve(new Blob([this._bodyText]));
          }
        };

        this.arrayBuffer = function () {
          if (this._bodyArrayBuffer) {
            return consumed(this) || Promise.resolve(this._bodyArrayBuffer);
          } else {
            return this.blob().then(readBlobAsArrayBuffer);
          }
        };
      }

      this.text = function () {
        var rejected = consumed(this);

        if (rejected) {
          return rejected;
        }

        if (this._bodyBlob) {
          return readBlobAsText(this._bodyBlob);
        } else if (this._bodyArrayBuffer) {
          return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
        } else if (this._bodyFormData) {
          throw new Error('could not read FormData body as text');
        } else {
          return Promise.resolve(this._bodyText);
        }
      };

      if (support.formData) {
        this.formData = function () {
          return this.text().then(decode);
        };
      }

      this.json = function () {
        return this.text().then(JSON.parse);
      };

      return this;
    } // HTTP methods whose capitalization should be normalized


    var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];

    function normalizeMethod(method) {
      var upcased = method.toUpperCase();
      return methods.indexOf(upcased) > -1 ? upcased : method;
    }

    function Request(input, options) {
      options = options || {};
      var body = options.body;

      if (input instanceof Request) {
        if (input.bodyUsed) {
          throw new TypeError('Already read');
        }

        this.url = input.url;
        this.credentials = input.credentials;

        if (!options.headers) {
          this.headers = new Headers(input.headers);
        }

        this.method = input.method;
        this.mode = input.mode;

        if (!body && input._bodyInit != null) {
          body = input._bodyInit;
          input.bodyUsed = true;
        }
      } else {
        this.url = String(input);
      }

      this.credentials = options.credentials || this.credentials || 'omit';

      if (options.headers || !this.headers) {
        this.headers = new Headers(options.headers);
      }

      this.method = normalizeMethod(options.method || this.method || 'GET');
      this.mode = options.mode || this.mode || null;
      this.referrer = null;

      if ((this.method === 'GET' || this.method === 'HEAD') && body) {
        throw new TypeError('Body not allowed for GET or HEAD requests');
      }

      this._initBody(body);
    }

    Request.prototype.clone = function () {
      return new Request(this, {
        body: this._bodyInit
      });
    };

    function decode(body) {
      var form = new FormData();
      body.trim().split('&').forEach(function (bytes) {
        if (bytes) {
          var split = bytes.split('=');
          var name = split.shift().replace(/\+/g, ' ');
          var value = split.join('=').replace(/\+/g, ' ');
          form.append(decodeURIComponent(name), decodeURIComponent(value));
        }
      });
      return form;
    }

    function parseHeaders(rawHeaders) {
      var headers = new Headers(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
      // https://tools.ietf.org/html/rfc7230#section-3.2

      var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ');
      preProcessedHeaders.split(/\r?\n/).forEach(function (line) {
        var parts = line.split(':');
        var key = parts.shift().trim();

        if (key) {
          var value = parts.join(':').trim();
          headers.append(key, value);
        }
      });
      return headers;
    }

    Body.call(Request.prototype);

    function Response(bodyInit, options) {
      if (!options) {
        options = {};
      }

      this.type = 'default';
      this.status = options.status === undefined ? 200 : options.status;
      this.ok = this.status >= 200 && this.status < 300;
      this.statusText = 'statusText' in options ? options.statusText : 'OK';
      this.headers = new Headers(options.headers);
      this.url = options.url || '';

      this._initBody(bodyInit);
    }

    Body.call(Response.prototype);

    Response.prototype.clone = function () {
      return new Response(this._bodyInit, {
        status: this.status,
        statusText: this.statusText,
        headers: new Headers(this.headers),
        url: this.url
      });
    };

    Response.error = function () {
      var response = new Response(null, {
        status: 0,
        statusText: ''
      });
      response.type = 'error';
      return response;
    };

    var redirectStatuses = [301, 302, 303, 307, 308];

    Response.redirect = function (url, status) {
      if (redirectStatuses.indexOf(status) === -1) {
        throw new RangeError('Invalid status code');
      }

      return new Response(null, {
        status: status,
        headers: {
          location: url
        }
      });
    };

    self.Headers = Headers;
    self.Request = Request;
    self.Response = Response;

    self.fetch = function (input, init) {
      return new Promise(function (resolve, reject) {
        var request = new Request(input, init);
        var xhr = new XMLHttpRequest();

        xhr.onload = function () {
          var options = {
            status: xhr.status,
            statusText: xhr.statusText,
            headers: parseHeaders(xhr.getAllResponseHeaders() || '')
          };
          options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
          var body = 'response' in xhr ? xhr.response : xhr.responseText;
          resolve(new Response(body, options));
        };

        xhr.onerror = function () {
          reject(new TypeError('Network request failed'));
        };

        xhr.ontimeout = function () {
          reject(new TypeError('Network request failed'));
        };

        xhr.open(request.method, request.url, true);

        if (request.credentials === 'include') {
          xhr.withCredentials = true;
        } else if (request.credentials === 'omit') {
          xhr.withCredentials = false;
        }

        if ('responseType' in xhr && support.blob) {
          xhr.responseType = 'blob';
        }

        request.headers.forEach(function (value, name) {
          xhr.setRequestHeader(name, value);
        });
        xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
      });
    };

    self.fetch.polyfill = true;
  })(typeof self !== 'undefined' ? self : undefined);

  function shouleBeObject(target) {
    if (target && _typeof(target) === 'object') return {
      res: true
    };
    return {
      res: false,
      msg: getParameterError({
        correct: 'Object',
        wrong: target
      })
    };
  }

  function getParameterError(_ref) {
    var _ref$name = _ref.name,
        name = _ref$name === void 0 ? '' : _ref$name,
        para = _ref.para,
        correct = _ref.correct,
        wrong = _ref.wrong;
    var parameter = para ? "parameter.".concat(para) : 'parameter';
    var errorType = upperCaseFirstLetter(wrong === null ? 'Null' : _typeof(wrong));
    return "".concat(name, ":fail parameter error: ").concat(parameter, " should be ").concat(correct, " instead of ").concat(errorType);
  }

  function upperCaseFirstLetter(string) {
    if (typeof string !== 'string') return string;
    string = string.replace(/^./, function (match) {
      return match.toUpperCase();
    });
    return string;
  }

  function inlineStyle$1(style) {
    var res = '';

    for (var attr in style) {
      res += "".concat(attr, ": ").concat(style[attr], ";");
    }

    if (res.indexOf('display: flex;') >= 0) res += 'display: -webkit-box;display: -webkit-flex;';
    res = res.replace(/transform:(.+?);/g, function (s, $1) {
      return "".concat(s, "-webkit-transform:").concat($1, ";");
    });
    res = res.replace(/flex-direction:(.+?);/g, function (s, $1) {
      return "".concat(s, "-webkit-flex-direction:").concat($1, ";");
    });
    return res;
  }

  function errorHandler(fail, complete) {
    return function (res) {
      typeof fail === 'function' && fail(res);
      typeof complete === 'function' && complete(res);
      return Promise.reject(res);
    };
  }

  var enc$1 = encodeURIComponent;

  function serializeParams$1(params) {
    if (!params) {
      return '';
    }

    return Object.keys(params).map(function (key) {
      return "".concat(enc$1(key), "=").concat(enc$1(params[key]));
    }).join('&');
  }

  function generateRequestUrlWithParams(url, params) {
    params = typeof params === 'string' ? params : serializeParams$1(params);
    url += (~url.indexOf('?') ? '&' : '?') + params;
    url = url.replace('?&', '?');
    return url;
  }

  function request(options) {
    options = options || {};

    if (typeof options === 'string') {
      options = {
        url: options
      };
    }

    var _options = options,
        success = _options.success,
        complete = _options.complete,
        fail = _options.fail;
    var url = options.url;
    var params = {};
    var res = {};

    if (options.jsonp) {
      params.params = options.data;
      params.cache = options.jsonpCache;

      if (typeof options.jsonp === 'string') {
        params.name = options.jsonp;
      }

      return jsonp$1(url, params).then(function (data) {
        res.statusCode = 200;
        res.data = data;
        typeof success === 'function' && success(res);
        typeof complete === 'function' && complete(res);
        return res;
      }).catch(function (err) {
        typeof fail === 'function' && fail(err);
        typeof complete === 'function' && complete(res);
        return Promise.reject(err);
      });
    }

    params.method = options.method || 'GET';
    var methodUpper = params.method.toUpperCase();
    params.cache = options.cache || 'default';

    if (methodUpper === 'GET' || methodUpper === 'HEAD') {
      url = generateRequestUrlWithParams(url, options.data);
    } else if (_typeof(options.data) === 'object') {
      var contentType = options.header && (options.header['Content-Type'] || options.header['content-type']);

      if (contentType === 'application/json') {
        params.body = JSON.stringify(options.data);
      } else if (contentType === 'application/x-www-form-urlencoded') {
        params.body = serializeParams$1(options.data);
      } else {
        params.body = options.data;
      }
    } else {
      params.body = options.data;
    }

    if (options.header) {
      params.headers = options.header;
    }

    if (options.mode) {
      params.mode = options.mode;
    }

    params.credentials = options.credentials;
    return fetch(url, params).then(function (response) {
      res.statusCode = response.status;
      res.header = {};
      response.headers.forEach(function (val, key) {
        res.header[key] = val;
      });

      if (options.responseType === 'arraybuffer') {
        return response.arrayBuffer();
      }

      if (options.dataType === 'json' || typeof options.dataType === 'undefined') {
        return response.json();
      }

      if (options.responseType === 'text') {
        return response.text();
      }

      return Promise.resolve(null);
    }).then(function (data) {
      res.data = data;
      typeof success === 'function' && success(res);
      typeof complete === 'function' && complete(res);
      return res;
    }).catch(function (err) {
      typeof fail === 'function' && fail(err);
      typeof complete === 'function' && complete(res);
      return Promise.reject(err);
    });
  }

  function setStorage(options) {
    // options must be an Object
    var isObject = shouleBeObject(options);

    if (!isObject.res) {
      var _res = {
        errMsg: "setStorage".concat(isObject.msg)
      };
      console.error(_res.errMsg);
      return Promise.reject(_res);
    }

    var key = options.key,
        data = options.data,
        success = options.success,
        fail = options.fail,
        complete = options.complete;
    var res = {
      errMsg: 'setStorage:ok'
    };

    if (typeof key !== 'string') {
      res.errMsg = getParameterError({
        name: 'setStorage',
        para: 'key',
        correct: 'String',
        wrong: key
      });
      console.error(res.errMsg);
      typeof fail === 'function' && fail(res);
      typeof complete === 'function' && complete(res);
      return Promise.reject(res);
    }

    setStorageSync(key, data);
    typeof success === 'function' && success(res);
    typeof complete === 'function' && complete(res);
    return Promise.resolve(res);
  }

  function setStorageSync(key) {
    var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';

    if (typeof key !== 'string') {
      console.error(getParameterError({
        name: 'setStorage',
        correct: 'String',
        wrong: key
      }));
      return;
    }

    var type = _typeof(data);

    var obj = {};

    if (type === 'symbol') {
      obj = {
        data: ''
      };
    } else {
      obj = {
        data: data
      };
    }

    localStorage.setItem(key, JSON.stringify(obj));
  }

  function getStorage(options) {
    // options must be an Object
    var isObject = shouleBeObject(options);

    if (!isObject.res) {
      var _res2 = {
        errMsg: "getStorage".concat(isObject.msg)
      };
      console.error(_res2.errMsg);
      return Promise.reject(_res2);
    }

    var key = options.key,
        success = options.success,
        fail = options.fail,
        complete = options.complete;
    var res = {
      errMsg: 'getStorage:ok'
    };

    if (typeof key !== 'string') {
      res.errMsg = getParameterError({
        name: 'getStorage',
        para: 'key',
        correct: 'String',
        wrong: key
      });
      console.error(res.errMsg);
      typeof fail === 'function' && fail(res);
      typeof complete === 'function' && complete(res);
      return Promise.reject(res);
    }

    var _getItem = getItem(key),
        result = _getItem.result,
        data = _getItem.data;

    if (result) {
      res.data = data;
    } else {
      res.errMsg = 'getStorage:fail data not found';
      typeof fail === 'function' && fail(res);
      typeof complete === 'function' && complete(res);
      return Promise.reject(res);
    }

    typeof success === 'function' && success(res);
    typeof complete === 'function' && complete(res);
    return Promise.resolve(res);
  }

  function getStorageSync(key) {
    if (typeof key !== 'string') {
      console.error(getParameterError({
        name: 'getStorage',
        correct: 'String',
        wrong: key
      }));
      return;
    }

    var res = getItem(key);
    if (res.result) return res.data;
    return '';
  }

  function getItem(key) {
    var item;

    try {
      item = JSON.parse(localStorage.getItem(key));
    } catch (e) {} // 只返回使用 Taro.setStorage API 存储的数据


    if (item && _typeof(item) === 'object' && item.hasOwnProperty('data')) {
      return {
        result: true,
        data: item.data
      };
    } else {
      return {
        result: false
      };
    }
  }

  function getStorageInfo() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var success = options.success,
        complete = options.complete;
    var res = {
      errMsg: 'getStorageInfo:ok'
    };
    var info = getStorageInfoSync();
    Object.assign(res, info);
    success && success(res);
    complete && complete(res);
    return Promise.resolve(res);
  }

  function getStorageInfoSync() {
    var res = {};
    res.keys = Object.keys(localStorage);
    res.limitSize = null;
    res.currentSize = null;
    return res;
  }

  function removeStorage(options) {
    // options must be an Object
    var isObject = shouleBeObject(options);

    if (!isObject.res) {
      var _res3 = {
        errMsg: "removeStorage".concat(isObject.msg)
      };
      console.error(_res3.errMsg);
      return Promise.reject(_res3);
    }

    var key = options.key,
        success = options.success,
        fail = options.fail,
        complete = options.complete;
    var res = {
      errMsg: 'removeStorage:ok'
    };

    if (typeof key !== 'string') {
      res.errMsg = getParameterError({
        name: 'removeStorage',
        para: 'key',
        correct: 'String',
        wrong: key
      });
      console.error(res.errMsg);
      typeof fail === 'function' && fail(res);
      typeof complete === 'function' && complete(res);
      return Promise.reject(res);
    }

    removeStorageSync(key);
    success && success(res);
    complete && complete(res);
    return Promise.resolve(res);
  }

  function removeStorageSync(key) {
    if (typeof key !== 'string') {
      console.error(getParameterError({
        name: 'removeStorage',
        correct: 'String',
        wrong: key
      }));
      return;
    }

    localStorage.removeItem(key);
  }

  function clearStorage() {
    localStorage.clear();
  }

  var storage$1 = /*#__PURE__*/Object.freeze({
    setStorage: setStorage,
    setStorageSync: setStorageSync,
    getStorage: getStorage,
    getStorageSync: getStorageSync,
    getStorageInfo: getStorageInfo,
    getStorageInfoSync: getStorageInfoSync,
    removeStorage: removeStorage,
    removeStorageSync: removeStorageSync,
    clearStorage: clearStorage,
    clearStorageSync: clearStorage
  });

  var Toast =
  /*#__PURE__*/
  function () {
    function Toast() {
      _classCallCheck(this, Toast);

      var noop = function noop() {};

      this.options = {
        title: '',
        icon: 'none',
        image: '',
        duration: 1500,
        mask: false,
        success: noop,
        fail: noop,
        complete: noop
      };
    }

    _createClass(Toast, [{
      key: "getstyle",
      value: function getstyle(name) {
        return {
          maskStyle: {
            'position': 'fixed',
            'z-index': '1000',
            'top': '0',
            'right': '0',
            'left': '0',
            'bottom': '0'
          },
          toastStyle: {
            'z-index': '5000',
            'box-sizing': 'border-box',
            'display': 'flex',
            'flex-direction': 'column',
            'justify-content': 'center',
            '-webkit-justify-content': 'center',
            'position': 'fixed',
            'top': '50%',
            'left': '50%',
            'min-width': '120px',
            'max-width': '200px',
            'min-height': '120px',
            'padding': '15px',
            'transform': 'translate(-50%, -50%)',
            'border-radius': '5px',
            'text-align': 'center',
            'line-height': '1.6',
            'color': '#FFFFFF',
            'background': 'rgba(17, 17, 17, 0.7)'
          },
          successStyle: {
            'margin': '0',
            'vertical-align': 'middle',
            'font-family': 'taro',
            '-webkit-font-smoothing': 'antialiased',
            'color': '#FFFFFF',
            'font-size': '55px',
            'line-height': '1'
          },
          loadingStyle: {
            'margin': '6px auto',
            'width': '38px',
            'height': '38px',
            '-webkit-animation': 'taroLoading 1s steps(12, end) infinite',
            'animation': 'taroLoading 1s steps(12, end) infinite',
            'background': 'transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=) no-repeat',
            'background-size': '100%'
          },
          imageStyle: {
            'margin': '6px auto',
            'width': '40px',
            'height': '40px',
            'background': 'transparent no-repeat',
            'background-size': '100%'
          },
          textStyle: {
            'margin': '0',
            'font-size': '16px'
          }
        };
      }
    }, {
      key: "create",
      value: function create() {
        var _this = this;

        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        // style
        var _this$getstyle = this.getstyle(),
            maskStyle = _this$getstyle.maskStyle,
            toastStyle = _this$getstyle.toastStyle,
            successStyle = _this$getstyle.successStyle,
            loadingStyle = _this$getstyle.loadingStyle,
            imageStyle = _this$getstyle.imageStyle,
            textStyle = _this$getstyle.textStyle; // configuration


        Object.assign(this.options, options);
        var config = this.options; // wrapper

        this.el = document.createElement('div');
        this.el.className = 'taro__toast';
        this.el.style.opacity = '0';
        this.el.style.transition = 'opacity 0.1s linear'; // mask

        this.mask = document.createElement('div');
        this.mask.setAttribute('style', inlineStyle$1(maskStyle));
        this.mask.style.display = config.mask ? 'block' : 'none'; // icon

        this.icon = document.createElement('p');

        if (config.image) {
          this.icon.setAttribute('style', inlineStyle$1(Object.assign({}, imageStyle, {
            'background-image': "url(".concat(config.image, ")")
          })));
        } else {
          var iconStyle = config.icon === 'loading' ? loadingStyle : successStyle;
          if (config.icon === 'none') Object.assign(iconStyle, {
            'display': 'none'
          });
          this.icon.setAttribute('style', inlineStyle$1(iconStyle));
          if (config.icon !== 'loading') this.icon.textContent = '';
        } // toast


        this.toast = document.createElement('div');

        if (config.icon === 'none') {
          Object.assign(toastStyle, {
            'min-height': '0',
            'padding': '10px 15px'
          });
        }

        this.toast.setAttribute('style', inlineStyle$1(toastStyle)); // title

        this.title = document.createElement('p');
        this.title.setAttribute('style', inlineStyle$1(textStyle));
        this.title.textContent = config.title; // result

        this.toast.appendChild(this.icon);
        this.toast.appendChild(this.title);
        this.el.appendChild(this.mask);
        this.el.appendChild(this.toast); // show immediately

        document.body.appendChild(this.el);
        setTimeout(function () {
          _this.el.style.opacity = '1';
        }, 0);
        this.type = config._type; // disappear after duration

        config.duration >= 0 && this.hide(config.duration, this.type);
        var errMsg = this.type === 'loading' ? 'showLoading:ok' : 'showToast:ok';
        config.success && config.success({
          errMsg: errMsg
        });
        config.complete && config.complete({
          errMsg: errMsg
        });
        return Promise.resolve({
          errMsg: errMsg
        });
      }
    }, {
      key: "show",
      value: function show() {
        var _this2 = this;

        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var config = this.options; // title

        if (config.title !== options.title) this.title.textContent = options.title; // mask

        if (config.mask !== options.mask) this.mask.style.display = options.mask ? 'block' : 'none'; // image

        var _this$getstyle2 = this.getstyle(),
            toastStyle = _this$getstyle2.toastStyle,
            successStyle = _this$getstyle2.successStyle,
            loadingStyle = _this$getstyle2.loadingStyle,
            imageStyle = _this$getstyle2.imageStyle;

        if (config.image !== options.image) {
          if (options.image) {
            this.icon.setAttribute('style', inlineStyle$1(Object.assign({}, imageStyle, {
              'background-image': "url(".concat(options.image, ")")
            })));
            this.icon.textContent = '';
          } else {
            var iconStyle = options.icon === 'loading' ? loadingStyle : successStyle;
            if (options.icon === 'none') Object.assign(iconStyle, {
              'display': 'none'
            });
            this.icon.setAttribute('style', inlineStyle$1(iconStyle));
            this.icon.textContent = options.icon === 'loading' ? '' : '';
          }
        } else {
          if (!options.image && config.icon !== options.icon) {
            var _iconStyle = options.icon === 'loading' ? loadingStyle : successStyle;

            if (options.icon === 'none') Object.assign(_iconStyle, {
              'display': 'none'
            });
            this.icon.setAttribute('style', inlineStyle$1(_iconStyle));
            this.icon.textContent = options.icon === 'loading' ? '' : '';
          }
        } // toast


        if (options.icon === 'none') {
          Object.assign(toastStyle, {
            'min-height': '0',
            'padding': '10px 15px'
          });
        }

        this.toast.setAttribute('style', inlineStyle$1(toastStyle));
        Object.assign(config, options); // show

        this.el.style.display = 'block';
        setTimeout(function () {
          _this2.el.style.opacity = '1';
        }, 0);
        this.type = config._type; // disappear after duration

        config.duration >= 0 && this.hide(config.duration, this.type);
        var errMsg = this.type === 'loading' ? 'showLoading:ok' : 'showToast:ok';
        config.success && config.success({
          errMsg: errMsg
        });
        config.complete && config.complete({
          errMsg: errMsg
        });
        return Promise.resolve({
          errMsg: errMsg
        });
      }
    }, {
      key: "hide",
      value: function hide() {
        var _this3 = this;

        var duration = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        var type = arguments.length > 1 ? arguments[1] : undefined;
        if (this.type !== type) return;
        if (this.hideTimer) clearTimeout(this.hideTimer);
        this.hideTimer = setTimeout(function () {
          _this3.el.style.opacity = '0';
          setTimeout(function () {
            _this3.el.style.display = 'none';
          }, 100);
        }, duration);
      }
    }]);

    return Toast;
  }();

  var Modal =
  /*#__PURE__*/
  function () {
    function Modal() {
      _classCallCheck(this, Modal);

      var noop = function noop() {};

      this.options = {
        title: '',
        content: '',
        showCancel: true,
        cancelText: '取消',
        cancelColor: '#000000',
        confirmText: '确定',
        confirmColor: '#3CC51F',
        success: noop,
        fail: noop,
        complete: noop
      };
    }

    _createClass(Modal, [{
      key: "getstyle",
      value: function getstyle(name) {
        return {
          maskStyle: {
            'position': 'fixed',
            'z-index': '1000',
            'top': '0',
            'right': '0',
            'left': '0',
            'bottom': '0',
            'background': 'rgba(0,0,0,0.6)'
          },
          modalStyle: {
            'z-index': '4999',
            'position': 'fixed',
            'top': '50%',
            'left': '50%',
            'transform': 'translate(-50%, -50%)',
            'width': '80%',
            'max-width': '300px',
            'border-radius': '3px',
            'text-align': 'center',
            'line-height': '1.6',
            'overflow': 'hidden',
            'background': '#FFFFFF'
          },
          titleStyle: {
            'padding': '20px 24px 9px',
            'font-size': '18px'
          },
          textStyle: {
            'padding': '0 24px 12px',
            'min-height': '40px',
            'font-size': '15px',
            'line-height': '1.3',
            'color': '#808080'
          },
          footStyle: {
            'position': 'relative',
            'line-height': '48px',
            'font-size': '18px',
            'display': 'flex'
          },
          btnStyle: {
            'position': 'relative',
            '-webkit-box-flex': '1',
            '-webkit-flex': '1',
            'flex': '1'
          }
        };
      }
    }, {
      key: "create",
      value: function create() {
        var _this = this;

        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        // style
        var _this$getstyle = this.getstyle(),
            maskStyle = _this$getstyle.maskStyle,
            modalStyle = _this$getstyle.modalStyle,
            titleStyle = _this$getstyle.titleStyle,
            textStyle = _this$getstyle.textStyle,
            footStyle = _this$getstyle.footStyle,
            btnStyle = _this$getstyle.btnStyle; // configuration


        Object.assign(this.options, options);
        var config = this.options; // wrapper

        this.el = document.createElement('div');
        this.el.className = 'taro__modal';
        this.el.style.opacity = '0';
        this.el.style.transition = 'opacity 0.2s linear'; // mask

        var mask = document.createElement('div');
        mask.setAttribute('style', inlineStyle$1(maskStyle)); // modal

        var modal = document.createElement('div');
        modal.setAttribute('style', inlineStyle$1(modalStyle)); // title

        var titleCSS = config.title ? titleStyle : Object.assign({}, titleStyle, {
          display: 'none'
        });
        this.title = document.createElement('div');
        this.title.setAttribute('style', inlineStyle$1(titleCSS));
        this.title.textContent = config.title; // text

        var textCSS = config.title ? textStyle : Object.assign({}, textStyle, {
          padding: '40px 20px 26px',
          color: '#353535'
        });
        this.text = document.createElement('div');
        this.text.setAttribute('style', inlineStyle$1(textCSS));
        this.text.textContent = config.content; // foot

        var foot = document.createElement('div');
        foot.className = 'taro-modal__foot';
        foot.setAttribute('style', inlineStyle$1(footStyle)); // cancel button

        var cancelCSS = Object.assign({}, btnStyle, {
          color: config.cancelColor,
          display: config.showCancel ? 'block' : 'none'
        });
        this.cancel = document.createElement('div');
        this.cancel.className = 'taro-model__btn';
        this.cancel.setAttribute('style', inlineStyle$1(cancelCSS));
        this.cancel.textContent = config.cancelText;

        this.cancel.onclick = function () {
          _this.hide();

          var res = _this.getRes('cancel');

          config.success(res);
          config.complete(res);

          _this.resolveHandler(res);
        }; // confirm button


        this.confirm = document.createElement('div');
        this.confirm.className = 'taro-model__btn';
        this.confirm.setAttribute('style', inlineStyle$1(btnStyle));
        this.confirm.style.color = config.confirmColor;
        this.confirm.textContent = config.confirmText;

        this.confirm.onclick = function () {
          _this.hide();

          var res = _this.getRes('confirm');

          config.success(res);
          config.complete(res);

          _this.resolveHandler(res);
        }; // result


        foot.appendChild(this.cancel);
        foot.appendChild(this.confirm);
        modal.appendChild(this.title);
        modal.appendChild(this.text);
        modal.appendChild(foot);
        this.el.appendChild(mask);
        this.el.appendChild(modal); // show immediately

        document.body.appendChild(this.el);
        setTimeout(function () {
          _this.el.style.opacity = '1';
        }, 0);
        return new Promise(function (resolve) {
          return _this.resolveHandler = resolve;
        });
      }
    }, {
      key: "getRes",
      value: function getRes(type) {
        var res = {
          errMsg: 'showModal:ok',
          cancel: false,
          confirm: false
        };
        res[type] = true;
        return res;
      }
    }, {
      key: "show",
      value: function show() {
        var _this2 = this;

        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var config = this.options; // title & text

        var _this$getstyle2 = this.getstyle(),
            textStyle = _this$getstyle2.textStyle;

        if (config.title !== options.title) {
          this.title.textContent = options.title;

          if (!options.title) {
            // block => none
            this.title.style.display = 'none';
            var textCSS = Object.assign({}, textStyle, {
              padding: '40px 20px 26px',
              color: '#353535'
            });
            this.text.setAttribute('style', inlineStyle$1(textCSS));
          } else if (!config.title) {
            // none => block
            this.title.style.display = 'block';
            this.text.setAttribute('style', inlineStyle$1(textStyle));
          }
        }

        if (config.content !== options.content) this.text.textContent = options.content; // showCancel

        if (config.showCancel !== options.showCancel) this.cancel.style.display = options.showCancel ? 'block' : 'none'; // cancelText

        if (config.cancelText !== options.cancelText) this.cancel.textContent = options.cancelText; // cancelColor

        if (config.cancelColor !== options.cancelColor) this.cancel.style.color = options.cancelColor; // confirmText

        if (config.confirmText !== options.confirmText) this.confirm.textContent = options.confirmText; // confirmColor

        if (config.confirmColor !== options.confirmColor) this.confirm.style.color = options.confirmColor;
        Object.assign(config, options); // cbs

        this.cancel.onclick = function () {
          _this2.hide();

          var res = _this2.getRes('cancel');

          config.success(res);
          config.complete(res);

          _this2.resolveHandler(res);
        };

        this.confirm.onclick = function () {
          _this2.hide();

          var res = _this2.getRes('confirm');

          config.success(res);
          config.complete(res);

          _this2.resolveHandler(res);
        }; // show


        this.el.style.display = 'block';
        setTimeout(function () {
          _this2.el.style.opacity = '1';
        }, 0);
        return new Promise(function (resolve) {
          return _this2.resolveHandler = resolve;
        });
      }
    }, {
      key: "hide",
      value: function hide() {
        var _this3 = this;

        setTimeout(function () {
          _this3.el.style.opacity = '0';
          setTimeout(function () {
            _this3.el.style.display = 'none';
          }, 200);
        }, 0);
      }
    }]);

    return Modal;
  }();

  var ActionSheet =
  /*#__PURE__*/
  function () {
    function ActionSheet() {
      _classCallCheck(this, ActionSheet);

      var noop = function noop() {};

      this.options = {
        itemList: [],
        itemColor: '#000000',
        success: noop,
        fail: noop,
        complete: noop
      };
    }

    _createClass(ActionSheet, [{
      key: "getstyle",
      value: function getstyle(name) {
        return {
          maskStyle: {
            'position': 'fixed',
            'z-index': '1000',
            'top': '0',
            'right': '0',
            'left': '0',
            'bottom': '0',
            'background': 'rgba(0,0,0,0.6)'
          },
          actionSheetStyle: {
            'z-index': '4999',
            'position': 'fixed',
            'left': '0',
            'bottom': '0',
            '-webkit-transform': 'translate(0, 100%)',
            'transform': 'translate(0, 100%)',
            'width': '100%',
            'line-height': '1.6',
            'background': '#EFEFF4',
            '-webkit-transition': '-webkit-transform .3s',
            'transition': 'transform .3s'
          },
          menuStyle: {
            'background-color': '#FCFCFD'
          },
          cellStyle: {
            'position': 'relative',
            'padding': '10px 0',
            'text-align': 'center',
            'font-size': '18px'
          },
          cancelStyle: {
            'margin-top': '6px',
            'padding': '10px 0',
            'text-align': 'center',
            'font-size': '18px',
            'color': '#000000',
            'background-color': '#FCFCFD'
          }
        };
      }
    }, {
      key: "create",
      value: function create() {
        var _this = this;

        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

        // style
        var _this$getstyle = this.getstyle(),
            maskStyle = _this$getstyle.maskStyle,
            actionSheetStyle = _this$getstyle.actionSheetStyle,
            menuStyle = _this$getstyle.menuStyle,
            cellStyle = _this$getstyle.cellStyle,
            cancelStyle = _this$getstyle.cancelStyle; // configuration


        Object.assign(this.options, options);
        var config = this.options; // wrapper

        this.el = document.createElement('div');
        this.el.className = 'taro__actionSheet';
        this.el.style.opacity = '0';
        this.el.style.transition = 'opacity 0.2s linear'; // mask

        var mask = document.createElement('div');
        mask.setAttribute('style', inlineStyle$1(maskStyle)); // actionSheet

        this.actionSheet = document.createElement('div');
        this.actionSheet.setAttribute('style', inlineStyle$1(actionSheetStyle)); // menu

        this.menu = document.createElement('div');
        this.menu.setAttribute('style', inlineStyle$1(Object.assign({}, menuStyle, {
          color: config.itemColor
        }))); // cells

        this.cells = options.itemList.map(function (item, index) {
          var cell = document.createElement('div');
          cell.className = 'taro-actionsheet__cell';
          cell.setAttribute('style', inlineStyle$1(cellStyle));
          cell.textContent = item;
          cell.dataset.tapIndex = index;

          cell.onclick = function (e) {
            return _this.onCellClick(e);
          };

          return cell;
        }); // cancel

        this.cancel = document.createElement('div');
        this.cancel.setAttribute('style', inlineStyle$1(cancelStyle));
        this.cancel.textContent = '取消'; // result

        this.cells.forEach(function (item) {
          return _this.menu.appendChild(item);
        });
        this.actionSheet.appendChild(this.menu);
        this.actionSheet.appendChild(this.cancel);
        this.el.appendChild(mask);
        this.el.appendChild(this.actionSheet); // callbacks

        var cb = function cb() {
          _this.hide();

          var res = {
            errMsg: 'showActionSheet:fail cancel'
          };
          config.fail(res);
          config.complete(res);

          _this.rejectHandler(res);
        };

        mask.onclick = cb;
        this.cancel.onclick = cb; // show immediately

        document.body.appendChild(this.el);
        setTimeout(function () {
          _this.el.style.opacity = '1';
          _this.actionSheet.style.transform = 'translate(0, 0)';
        }, 0);
        return new Promise(function (resolve, reject) {
          _this.resolveHandler = resolve;
          _this.rejectHandler = reject;
        });
      }
    }, {
      key: "show",
      value: function show() {
        var _this2 = this;

        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var config = this.options; // itemColor

        if (config.itemColor !== options.itemColor) this.menu.style.color = options.itemColor;
        Object.assign(config, options); // cells

        var _this$getstyle2 = this.getstyle(),
            cellStyle = _this$getstyle2.cellStyle;

        options.itemList.forEach(function (item, index) {
          if (_this2.cells[index]) {
            if (_this2.cells[index].textContent === item) {// content no change
            } else {
              // assign new content
              _this2.cells[index].textContent = item;
            }
          } else {
            // create new cell
            var cell = document.createElement('div');
            cell.className = 'taro-actionsheet__cell';
            cell.setAttribute('style', inlineStyle$1(cellStyle));
            cell.textContent = item;
            cell.dataset.tapIndex = index;

            cell.onclick = function (e) {
              return _this2.onCellClick(e);
            };

            _this2.cells.push(cell);

            _this2.menu.appendChild(cell);
          }
        });
        var cellsLen = this.cells.length;
        var itemListLen = options.itemList.length;

        if (cellsLen > itemListLen) {
          for (var i = itemListLen; i < cellsLen; i++) {
            this.menu.removeChild(this.cells[i]);
          }

          this.cells.splice(itemListLen, cellsLen - itemListLen);
        } // show


        this.el.style.display = 'block';
        setTimeout(function () {
          _this2.el.style.opacity = '1';
          _this2.actionSheet.style.transform = 'translate(0, 0)';
        }, 0);
        return new Promise(function (resolve, reject) {
          _this2.resolveHandler = resolve;
          _this2.rejectHandler = reject;
        });
      }
    }, {
      key: "onCellClick",
      value: function onCellClick(e) {
        this.hide();
        var res = {
          errMsg: 'showActionSheet:ok',
          tapIndex: +e.currentTarget.dataset.tapIndex
        };
        this.options.success(res);
        this.options.complete(res);
        this.resolveHandler(res);
      }
    }, {
      key: "hide",
      value: function hide() {
        var _this3 = this;

        setTimeout(function () {
          _this3.el.style.opacity = '0';
          _this3.actionSheet.style.transform = 'translate(0, 100%)';
          setTimeout(function () {
            _this3.el.style.display = 'none';
          }, 200);
        }, 0);
      }
    }]);

    return ActionSheet;
  }();

  var status = 'default'; // inject necessary style

  function init(doc) {
    if (status === 'ready') return;
    var taroStyle = doc.createElement('style');
    taroStyle.textContent = '@font-face{font-weight:normal;font-style:normal;font-family:"taro";src:url("data:application/x-font-ttf;charset=utf-8;base64, AAEAAAALAIAAAwAwR1NVQrD+s+0AAAE4AAAAQk9TLzJWs0t/AAABfAAAAFZjbWFwqVgGvgAAAeAAAAGGZ2x5Zph7qG0AAANwAAAAdGhlYWQRFoGhAAAA4AAAADZoaGVhCCsD7AAAALwAAAAkaG10eAg0AAAAAAHUAAAADGxvY2EADAA6AAADaAAAAAhtYXhwAQ4AJAAAARgAAAAgbmFtZYrphEEAAAPkAAACVXBvc3S3shtSAAAGPAAAADUAAQAAA+gAAABaA+gAAAAAA+gAAQAAAAAAAAAAAAAAAAAAAAMAAQAAAAEAAADih+FfDzz1AAsD6AAAAADXB57LAAAAANcHnssAAP/sA+gDOgAAAAgAAgAAAAAAAAABAAAAAwAYAAEAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKAB4ALAABREZMVAAIAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAAAAQK8AZAABQAIAnoCvAAAAIwCegK8AAAB4AAxAQIAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABAAHjqCAPoAAAAWgPoABQAAAABAAAAAAAAA+gAAABkAAAD6AAAAAAABQAAAAMAAAAsAAAABAAAAV4AAQAAAAAAWAADAAEAAAAsAAMACgAAAV4ABAAsAAAABgAEAAEAAgB46gj//wAAAHjqCP//AAAAAAABAAYABgAAAAEAAgAAAQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAKAAAAAAAAAACAAAAeAAAAHgAAAABAADqCAAA6ggAAAACAAAAAAAAAAwAOgABAAD/7AAyABQAAgAANzMVFB4UKAAAAAABAAAAAAO7AzoAFwAAEy4BPwE+AR8BFjY3ATYWFycWFAcBBiInPQoGBwUHGgzLDCELAh0LHwsNCgr9uQoeCgGzCyEOCw0HCZMJAQoBvgkCCg0LHQv9sQsKAAAAAAAAEgDeAAEAAAAAAAAAHQAAAAEAAAAAAAEABAAdAAEAAAAAAAIABwAhAAEAAAAAAAMABAAoAAEAAAAAAAQABAAsAAEAAAAAAAUACwAwAAEAAAAAAAYABAA7AAEAAAAAAAoAKwA/AAEAAAAAAAsAEwBqAAMAAQQJAAAAOgB9AAMAAQQJAAEACAC3AAMAAQQJAAIADgC/AAMAAQQJAAMACADNAAMAAQQJAAQACADVAAMAAQQJAAUAFgDdAAMAAQQJAAYACADzAAMAAQQJAAoAVgD7AAMAAQQJAAsAJgFRCiAgQ3JlYXRlZCBieSBmb250LWNhcnJpZXIKICB3ZXVpUmVndWxhcndldWl3ZXVpVmVyc2lvbiAxLjB3ZXVpR2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20ACgAgACAAQwByAGUAYQB0AGUAZAAgAGIAeQAgAGYAbwBuAHQALQBjAGEAcgByAGkAZQByAAoAIAAgAHcAZQB1AGkAUgBlAGcAdQBsAGEAcgB3AGUAdQBpAHcAZQB1AGkAVgBlAHIAcwBpAG8AbgAgADEALgAwAHcAZQB1AGkARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAAAAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwECAQMBBAABeAd1bmlFQTA4AAAAAAA=") format("truetype");}@-webkit-keyframes taroLoading{0%{-webkit-transform:rotate3d(0, 0, 1, 0deg);}100%{-webkit-transform:rotate3d(0, 0, 1, 360deg);transform:rotate3d(0, 0, 1, 360deg);}}@keyframes taroLoading{0%{-webkit-transform:rotate3d(0, 0, 1, 0deg);}100%{-webkit-transform:rotate3d(0, 0, 1, 360deg);transform:rotate3d(0, 0, 1, 360deg);}}.taro-modal__foot:after {content: "";position: absolute;left: 0;top: 0;right: 0;height: 1px;border-top: 1px solid #D5D5D6;color: #D5D5D6;-webkit-transform-origin: 0 0;transform-origin: 0 0;-webkit-transform: scaleY(0.5);transform: scaleY(0.5);} .taro-model__btn:active {background-color: #EEEEEE}.taro-model__btn:not(:first-child):after {content: "";position: absolute;left: 0;top: 0;width: 1px;bottom: 0;border-left: 1px solid #D5D5D6;color: #D5D5D6;-webkit-transform-origin: 0 0;transform-origin: 0 0;-webkit-transform: scaleX(0.5);transform: scaleX(0.5);}.taro-actionsheet__cell:not(:first-child):after {content: "";position: absolute;left: 0;top: 0;right: 0;height: 1px;border-top: 1px solid #e5e5e5;color: #e5e5e5;-webkit-transform-origin: 0 0;transform-origin: 0 0;-webkit-transform: scaleY(0.5);transform: scaleY(0.5);}';
    doc.querySelector('head').appendChild(taroStyle);
    status = 'ready';
  }

  var toast = new Toast();
  var modal = new Modal();
  var actionSheet = new ActionSheet();

  function showToast() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    init(document);
    var _default = {
      title: '',
      icon: 'success',
      image: '',
      duration: 1500,
      mask: false
    };
    options = Object.assign({}, _default, options);
    options._type = 'toast'; // verify options

    var handler = errorHandler(options.fail, options.complete);

    if (typeof options.title !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showToast',
          para: 'title',
          correct: 'String',
          wrong: options.title
        })
      });
    }

    if (typeof options.duration !== 'number') {
      return handler({
        errMsg: getParameterError({
          name: 'showToast',
          para: 'duration',
          correct: 'Number',
          wrong: options.duration
        })
      });
    }

    if (options.image && typeof options.image !== 'string') options.image = '';
    options.mask = !!options.mask;
    if (!toast.el) return toast.create(options);
    return toast.show(options);
  }

  function hideToast() {
    if (!toast.el) return;
    toast.hide(0, 'toast');
  }

  function showLoading() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    init(document);
    var _default = {
      title: '',
      mask: false
    };
    var config = {
      icon: 'loading',
      image: '',
      duration: -1
    };
    options = Object.assign({}, _default, options, config);
    options._type = 'loading'; // verify options

    var handler = errorHandler(options.fail, options.complete);

    if (typeof options.title !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showLoading',
          para: 'title',
          correct: 'String',
          wrong: options.title
        })
      });
    }

    options.mask = !!options.mask;
    if (!toast.el) return toast.create(options);
    return toast.show(options);
  }

  function hideLoading() {
    if (!toast.el) return;
    toast.hide(0, 'loading');
  }

  function showModal() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    init(document);
    var _default = {
      title: '',
      content: '',
      showCancel: true,
      cancelText: '取消',
      cancelColor: '#000000',
      confirmText: '确定',
      confirmColor: '#3CC51F'
    };
    options = Object.assign({}, _default, options); // verify options

    var handler = errorHandler(options.fail, options.complete);

    if (typeof options.title !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showModal',
          para: 'title',
          correct: 'String',
          wrong: options.title
        })
      });
    }

    if (typeof options.content !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showModal',
          para: 'content',
          correct: 'String',
          wrong: options.content
        })
      });
    }

    if (typeof options.cancelText !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showModal',
          para: 'cancelText',
          correct: 'String',
          wrong: options.cancelText
        })
      });
    }

    if (options.cancelText.replace(/[\u0391-\uFFE5]/g, 'aa').length > 8) {
      return handler({
        errMsg: 'showModal:fail cancelText length should not larger then 4 Chinese characters'
      });
    }

    if (typeof options.confirmText !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showModal',
          para: 'confirmText',
          correct: 'String',
          wrong: options.confirmText
        })
      });
    }

    if (options.confirmText.replace(/[\u0391-\uFFE5]/g, 'aa').length > 8) {
      return handler({
        errMsg: 'showModal:fail confirmText length should not larger then 4 Chinese characters'
      });
    }

    if (typeof options.cancelColor !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showModal',
          para: 'cancelColor',
          correct: 'String',
          wrong: options.cancelColor
        })
      });
    }

    if (typeof options.confirmColor !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showModal',
          para: 'confirmColor',
          correct: 'String',
          wrong: options.confirmColor
        })
      });
    }

    options.showCancel = !!options.showCancel;
    if (!modal.el) return modal.create(options);
    return modal.show(options);
  }

  function showActionSheet() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    init(document);
    var _default = {
      itemColor: '#000000'
    };
    options = Object.assign({}, _default, options); // verify options

    var handler = errorHandler(options.fail, options.complete); // list item String

    if (!Array.isArray(options.itemList)) {
      return handler({
        errMsg: getParameterError({
          name: 'showActionSheet',
          para: 'itemList',
          correct: 'Array',
          wrong: options.itemList
        })
      });
    }

    if (options.itemList.length < 1) {
      return handler({
        errMsg: 'showActionSheet:fail parameter error: parameter.itemList should have at least 1 item'
      });
    }

    if (options.itemList.length > 6) {
      return handler({
        errMsg: 'showActionSheet:fail parameter error: parameter.itemList should not be large than 6'
      });
    }

    for (var i = 0; i < options.itemList.length; i++) {
      if (typeof options.itemList[i] !== 'string') {
        return handler({
          errMsg: getParameterError({
            name: 'showActionSheet',
            para: "itemList[".concat(i, "]"),
            correct: 'String',
            wrong: options.itemList[i]
          })
        });
      }
    }

    if (typeof options.itemColor !== 'string') {
      return handler({
        errMsg: getParameterError({
          name: 'showActionSheet',
          para: 'itemColor',
          correct: 'String',
          wrong: options.itemColor
        })
      });
    }

    if (!actionSheet.el) return actionSheet.create(options);
    return actionSheet.show(options);
  }

  var interactive = /*#__PURE__*/Object.freeze({
    showToast: showToast,
    hideToast: hideToast,
    showLoading: showLoading,
    hideLoading: hideLoading,
    showModal: showModal,
    showActionSheet: showActionSheet
  });

  var SocketTask =
  /*#__PURE__*/
  function () {
    function SocketTask(url, protocols) {
      _classCallCheck(this, SocketTask);

      if (protocols && protocols.length) {
        this.ws = new WebSocket(url, protocols);
      } else {
        this.ws = new WebSocket(url);
      }

      this.CONNECTING = 0;
      this.OPEN = 1;
      this.CLOSING = 2;
      this.CLOSED = 3;
    }

    _createClass(SocketTask, [{
      key: "send",
      value: function send() {
        var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        if (_typeof(obj) !== 'object' || !obj) obj = {};
        var _obj = obj,
            _obj$data = _obj.data,
            data = _obj$data === void 0 ? '' : _obj$data,
            success = _obj.success,
            fail = _obj.fail,
            complete = _obj.complete;

        if (this.readyState !== 1) {
          var _res = {
            errMsg: 'SocketTask.send:fail SocketTask.readState is not OPEN'
          };
          console.error(_res.errMsg);
          typeof fail === 'function' && fail(_res);
          typeof complete === 'function' && complete(_res);
          return Promise.reject(_res);
        }

        this.ws.send(data);
        var res = {
          errMsg: 'sendSocketMessage:ok'
        };
        typeof success === 'function' && success(res);
        typeof complete === 'function' && complete(res);
        return Promise.resolve(res);
      }
    }, {
      key: "close",
      value: function close() {
        var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        if (_typeof(obj) !== 'object' || !obj) obj = {};
        var _obj2 = obj,
            _obj2$code = _obj2.code,
            code = _obj2$code === void 0 ? 1000 : _obj2$code,
            _obj2$reason = _obj2.reason,
            reason = _obj2$reason === void 0 ? 'server complete,close' : _obj2$reason,
            success = _obj2.success,
            complete = _obj2.complete;
        this.closeDetail = {
          code: code,
          reason: reason // 主动断开时需要重置链接数

        };
        this._destroyWhenClose && this._destroyWhenClose();
        this.ws.close();
        var res = {
          errMsg: 'closeSocket:ok'
        };
        typeof success === 'function' && success(res);
        typeof complete === 'function' && complete(res);
        return Promise.resolve(res);
      }
    }, {
      key: "onOpen",
      value: function onOpen(func) {
        this.ws.onopen = func;
      }
    }, {
      key: "onMessage",
      value: function onMessage(func) {
        this.ws.onmessage = func;
      }
    }, {
      key: "onClose",
      value: function onClose(func) {
        var _this = this;

        this.ws.onclose = function () {
          // 若服务器方断掉也需要重置链接数
          _this._destroyWhenClose && _this._destroyWhenClose();
          func(_this.closeDetail || {
            code: 1006,
            reason: 'abnormal closure'
          });
        };
      }
    }, {
      key: "onError",
      value: function onError(func) {
        this.ws.onerror = func;
      }
    }, {
      key: "readyState",
      get: function get() {
        return this.ws.readyState;
      }
    }]);

    return SocketTask;
  }();

  var socketTasks = [];
  var socketsCounter = 1;

  function connectSocket(options) {
    var name = 'connectSocket';
    return new Promise(function (resolve, reject) {
      // options must be an Object
      var isObject = shouleBeObject(options);

      if (!isObject.res) {
        var _res = {
          errMsg: "".concat(name).concat(isObject.msg)
        };
        console.error(_res.errMsg);
        return reject(_res);
      }

      var url = options.url,
          protocols = options.protocols,
          success = options.success,
          fail = options.fail,
          complete = options.complete;
      var res = {
        errMsg: 'connectSocket:ok' // options.url must be String

      };

      if (typeof url !== 'string') {
        res.errMsg = getParameterError({
          name: name,
          para: 'url',
          correct: 'String',
          wrong: url
        });
        console.error(res.errMsg);
        typeof fail === 'function' && fail(res);
        typeof complete === 'function' && complete(res);
        return reject(res);
      } // options.url must be invalid


      if (!url.startsWith('ws://') && !url.startsWith('wss://')) {
        res.errMsg = "request:fail invalid url \"".concat(url, "\"");
        console.error(res.errMsg);
        typeof fail === 'function' && fail(res);
        typeof complete === 'function' && complete(res);
        return reject(res);
      } // protocols must be array


      var _protocols = Array.isArray(protocols) ? protocols : null; // 2 connection at most


      if (socketTasks.length > 1) {
        res.errMsg = '同时最多发起 2 个 socket 请求,更多请参考文档。';
        console.error(res.errMsg);
        typeof fail === 'function' && fail(res);
        typeof complete === 'function' && complete(res);
        return reject(res);
      }

      var task = new SocketTask(url, _protocols);

      task._destroyWhenClose = function () {
        var _this = this;

        socketTasks = socketTasks.filter(function (socketTask) {
          return socketTask !== _this;
        });
      };

      socketTasks.push(task);
      res.socketTaskId = socketsCounter++;
      typeof success === 'function' && success(res);
      typeof complete === 'function' && complete(res);
      return resolve(task);
    });
  }

  function onSocketOpen() {
    console.warn('Deprecated.Please use socketTask.onOpen instead.');
  }

  function onSocketError() {
    console.warn('Deprecated.Please use socketTask.onError instead.');
  }

  function sendSocketMessage() {
    console.warn('Deprecated.Please use socketTask.send instead.');
  }

  function onSocketMessage() {
    console.warn('Deprecated.Please use socketTask.onMessage instead.');
  }

  function closeSocket() {
    console.warn('Deprecated.Please use socketTask.close instead.');
  }

  function onSocketClose() {
    console.warn('Deprecated.Please use socketTask.onClose instead.');
  }

  var webSocket = {
    connectSocket: connectSocket,
    onSocketOpen: onSocketOpen,
    onSocketError: onSocketError,
    sendSocketMessage: sendSocketMessage,
    onSocketMessage: onSocketMessage,
    closeSocket: closeSocket,
    onSocketClose: onSocketClose
  };

  function initTabBarApis() {
    var App = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var Taro = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    function setTabBarStyle() {
      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      // options must be an Object
      var isObject = shouleBeObject(options);

      if (!isObject.res) {
        var _res7 = {
          errMsg: "setTabBarStyle".concat(isObject.msg)
        };
        console.error(_res7.errMsg);
        return Promise.reject(_res7);
      }

      var color = options.color,
          selectedColor = options.selectedColor,
          backgroundColor = options.backgroundColor,
          borderStyle = options.borderStyle,
          success = options.success,
          fail = options.fail,
          complete = options.complete;
      var res = {
        errMsg: 'setTabBarStyle:ok'
      };
      var errMsg;

      if (color && !/^#\d{6}$/.test(color)) {
        errMsg = 'color';
      } else if (selectedColor && !/^#\d{6}$/.test(selectedColor)) {
        errMsg = 'selectedColor';
      } else if (backgroundColor && !/^#\d{6}$/.test(backgroundColor)) {
        errMsg = 'backgroundColor';
      } else if (borderStyle && !/^(black|white)$/.test(borderStyle)) {
        errMsg = 'borderStyle';
      }

      if (errMsg) {
        res.errMsg = "setTabBarStyle:fail invalid ".concat(errMsg);
        typeof fail === 'function' && fail(res);
        typeof complete === 'function' && complete(res);
        return Promise.reject(res);
      }

      if (!App.state.__tabs) {
        res.errMsg = 'setTabBarStyle:fail';
        return Promise.reject(res);
      }

      var obj = {};
      if (color) obj.color = color;
      if (selectedColor) obj.selectedColor = selectedColor;
      if (backgroundColor) obj.backgroundColor = backgroundColor;
      if (borderStyle) obj.borderStyle = borderStyle;
      var temp = Object.assign({}, App.state.__tabs, obj);
      App.setState && App.setState({
        __tabs: temp
      });
      typeof success === 'function' && success(res);
      typeof complete === 'function' && complete(res);
      return Promise.resolve(res);
    }

    function setTabBarItem() {
      var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      // options must be an Object
      var isObject = shouleBeObject(options);

      if (!isObject.res) {
        var _res8 = {
          errMsg: "setTabBarItem".concat(isObject.msg)
        };
        console.error(_res8.errMsg);
        return Promise.reject(_res8);
      }

      var index = options.index,
          text = options.text,
          iconPath = options.iconPath,
          selectedIconPath = options.selectedIconPath,
          success = options.success,
          fail = options.fail,
          complete = options.complete;
      var res = {
        errMsg: 'setTabBarItem:ok'
      };

      if (typeof index !== 'number') {
        res.errMsg = getParameterError({
          name: 'setTabBarItem',
          para: 'index',
          correct: 'Number',
          wrong: index
        });
        console.error(res.errMsg);
        typeof fail === 'function' && fail(res);
        typeof complete === 'function' && complete(res);
        return Promise.reject(res);
      }

      if (!App.state.__tabs || !App.state.__tabs.list || !App.state.__tabs.list[index]) {
        res.errMsg = 'setTabBarItem:fail tabbar item not found';
        typeof fail === 'function' && fail(res);
        typeof complete === 'function' && complete(res);
        return Promise.reject(res);
      }

      var obj = {};
      if (text) obj.text = text;
      if (iconPath) obj.iconPath = iconPath;
      if (selectedIconPath) obj.selectedIconPath = selectedIconPath;
      var temp = Object.assign({}, App.state.__tabs);
      temp.list[index] = Object.assign({}, temp.list[index], obj);
      App.setState && App.setState({
        __tabs: temp
      });
      typeof success === 'function' && success(res);
      typeof complete === 'function' && complete(res);
      return Promise.resolve(res);
    } // Taro.setTabBarBadge = setTabBarBadge
    // Taro.removeTabBarBadge = removeTabBarBadge
    // Taro.showTabBarRedDot = showTabBarRedDot
    // Taro.hideTabBarRedDot = hideTabBarRedDot
    // Taro.showTabBar = showTabBar
    // Taro.hideTabBar = hideTabBar


    Taro.setTabBarStyle = setTabBarStyle;
    Taro.setTabBarItem = setTabBarItem;
  }

  var tabBar = /*#__PURE__*/Object.freeze({
    initTabBarApis: initTabBarApis
  });

  function createCommonjsModule(fn, module) {
  	return module = { exports: {} }, fn(module, module.exports), module.exports;
  }

  var mobileDetect = createCommonjsModule(function (module) {
  // THIS FILE IS GENERATED - DO NOT EDIT!

  /*!mobile-detect v1.4.3 2018-09-08*/

  /*global module:false, define:false*/

  /*jshint latedef:false*/

  /*!@license Copyright 2013, Heinrich Goebl, License: MIT, see https://github.com/hgoebl/mobile-detect.js*/
  (function (define, undefined) {
    define(function () {

      var impl = {};
      impl.mobileDetectRules = {
        "phones": {
          "iPhone": "\\biPhone\\b|\\biPod\\b",
          "BlackBerry": "BlackBerry|\\bBB10\\b|rim[0-9]+",
          "HTC": "HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel",
          "Nexus": "Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6",
          "Dell": "Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b",
          "Motorola": "Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b|XT1068|XT1092|XT1052",
          "Samsung": "\\bSamsung\\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F",
          "LG": "\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)",
          "Sony": "SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533",
          "Asus": "Asus.*Galaxy|PadFone.*Mobile",
          "NokiaLumia": "Lumia [0-9]{3,4}",
          "Micromax": "Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b",
          "Palm": "PalmSource|Palm",
          "Vertu": "Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature",
          "Pantech": "PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790",
          "Fly": "IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250",
          "Wiko": "KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM",
          "iMobile": "i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)",
          "SimValley": "\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b",
          "Wolfgang": "AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q",
          "Alcatel": "Alcatel",
          "Nintendo": "Nintendo (3DS|Switch)",
          "Amoi": "Amoi",
          "INQ": "INQ",
          "GenericPhone": "Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"
        },
        "tablets": {
          "iPad": "iPad|iPad.*Mobile",
          "NexusTablet": "Android.*Nexus[\\s]+(7|9|10)",
          "GoogleTablet": "Android.*Pixel C",
          "SamsungTablet": "SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835",
          "Kindle": "Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\\b|Android.*Silk\/[0-9.]+ like Chrome\/[0-9.]+ (?!Mobile)",
          "SurfaceTablet": "Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)",
          "HPTablet": "HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10",
          "AsusTablet": "^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\\bP027\\b|\\bP024\\b|\\bP00C\\b",
          "BlackBerryTablet": "PlayBook|RIM Tablet",
          "HTCtablet": "HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410",
          "MotorolaTablet": "xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617",
          "NookTablet": "Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2",
          "AcerTablet": "Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20\\b|\\bA3-A30",
          "ToshibaTablet": "Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO",
          "LGTablet": "\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b",
          "FujitsuTablet": "Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b",
          "PrestigioTablet": "PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002",
          "LenovoTablet": "Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304F|TB-X304L|TB-8703F|Tab2A7-10F|TB2-X30L",
          "DellTablet": "Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7",
          "YarvikTablet": "Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b",
          "MedionTablet": "Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB",
          "ArnovaTablet": "97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2",
          "IntensoTablet": "INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004",
          "IRUTablet": "M702pro",
          "MegafonTablet": "MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b",
          "EbodaTablet": "E-Boda (Supreme|Impresspeed|Izzycomm|Essential)",
          "AllViewTablet": "Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)",
          "ArchosTablet": "\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b",
          "AinolTablet": "NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark",
          "NokiaLumiaTablet": "Lumia 2520",
          "SonyTablet": "Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712",
          "PhilipsTablet": "\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b",
          "CubeTablet": "Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT",
          "CobyTablet": "MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010",
          "MIDTablet": "M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10",
          "MSITablet": "MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b",
          "SMiTTablet": "Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)",
          "RockChipTablet": "Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A",
          "FlyTablet": "IQ310|Fly Vision",
          "bqTablet": "Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))|Maxwell.*Lite|Maxwell.*Plus",
          "HuaweiTablet": "MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09",
          "NecTablet": "\\bN-06D|\\bN-08D",
          "PantechTablet": "Pantech.*P4100",
          "BronchoTablet": "Broncho.*(N701|N708|N802|a710)",
          "VersusTablet": "TOUCHPAD.*[78910]|\\bTOUCHTAB\\b",
          "ZyncTablet": "z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900",
          "PositivoTablet": "TB07STA|TB10STA|TB07FTA|TB10FTA",
          "NabiTablet": "Android.*\\bNabi",
          "KoboTablet": "Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build",
          "DanewTablet": "DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b",
          "TexetTablet": "NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE",
          "PlaystationTablet": "Playstation.*(Portable|Vita)",
          "TrekstorTablet": "ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab",
          "PyleAudioTablet": "\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b",
          "AdvanTablet": "Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ",
          "DanyTechTablet": "Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1",
          "GalapadTablet": "Android.*\\bG1\\b(?!\\))",
          "MicromaxTablet": "Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b",
          "KarbonnTablet": "Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b",
          "AllFineTablet": "Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide",
          "PROSCANTablet": "\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b",
          "YONESTablet": "BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026",
          "ChangJiaTablet": "TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503",
          "GUTablet": "TX-A1301|TX-M9002|Q702|kf026",
          "PointOfViewTablet": "TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10",
          "OvermaxTablet": "OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027",
          "HCLTablet": "HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync",
          "DPSTablet": "DPS Dream 9|DPS Dual 7",
          "VistureTablet": "V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10",
          "CrestaTablet": "CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989",
          "MediatekTablet": "\\bMT8125|MT8389|MT8135|MT8377\\b",
          "ConcordeTablet": "Concorde([ ]+)?Tab|ConCorde ReadMan",
          "GoCleverTablet": "GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042",
          "ModecomTablet": "FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003",
          "VoninoTablet": "\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b",
          "ECSTablet": "V07OT2|TM105A|S10OT1|TR10CS1",
          "StorexTablet": "eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab",
          "VodafoneTablet": "SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497",
          "EssentielBTablet": "Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2",
          "RossMoorTablet": "RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711",
          "iMobileTablet": "i-mobile i-note",
          "TolinoTablet": "tolino tab [0-9.]+|tolino shine",
          "AudioSonicTablet": "\\bC-22Q|T7-QC|T-17B|T-17P\\b",
          "AMPETablet": "Android.* A78 ",
          "SkkTablet": "Android.* (SKYPAD|PHOENIX|CYCLOPS)",
          "TecnoTablet": "TECNO P9|TECNO DP8D",
          "JXDTablet": "Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b",
          "iJoyTablet": "Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)",
          "FX2Tablet": "FX2 PAD7|FX2 PAD10",
          "XoroTablet": "KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151",
          "ViewsonicTablet": "ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a",
          "VerizonTablet": "QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1",
          "OdysTablet": "LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10",
          "CaptivaTablet": "CAPTIVA PAD",
          "IconbitTablet": "NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S",
          "TeclastTablet": "T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi",
          "OndaTablet": "\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+|V10 \\b4G\\b",
          "JaytechTablet": "TPC-PA762",
          "BlaupunktTablet": "Endeavour 800NG|Endeavour 1010",
          "DigmaTablet": "\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b",
          "EvolioTablet": "ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b",
          "LavaTablet": "QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b",
          "AocTablet": "MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712",
          "MpmanTablet": "MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010",
          "CelkonTablet": "CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b",
          "WolderTablet": "miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b",
          "MediacomTablet": "M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA",
          "MiTablet": "\\bMI PAD\\b|\\bHM NOTE 1W\\b",
          "NibiruTablet": "Nibiru M1|Nibiru Jupiter One",
          "NexoTablet": "NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI",
          "LeaderTablet": "TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100",
          "UbislateTablet": "UbiSlate[\\s]?7C",
          "PocketBookTablet": "Pocketbook",
          "KocasoTablet": "\\b(TB-1207)\\b",
          "HisenseTablet": "\\b(F5281|E2371)\\b",
          "Hudl": "Hudl HT7S3|Hudl 2",
          "TelstraTablet": "T-Hub2",
          "GenericTablet": "Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bTP750\\b|\\bQTAQZ3\\b|WVT101|TM1088|KT107"
        },
        "oss": {
          "AndroidOS": "Android",
          "BlackBerryOS": "blackberry|\\bBB10\\b|rim tablet os",
          "PalmOS": "PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino",
          "SymbianOS": "Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b",
          "WindowsMobileOS": "Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;",
          "WindowsPhoneOS": "Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;",
          "iOS": "\\biPhone.*Mobile|\\biPod|\\biPad|AppleCoreMedia",
          "MeeGoOS": "MeeGo",
          "MaemoOS": "Maemo",
          "JavaOS": "J2ME\/|\\bMIDP\\b|\\bCLDC\\b",
          "webOS": "webOS|hpwOS",
          "badaOS": "\\bBada\\b",
          "BREWOS": "BREW"
        },
        "uas": {
          "Chrome": "\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?",
          "Dolfin": "\\bDolfin\\b",
          "Opera": "Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+$|Coast\/[0-9.]+",
          "Skyfire": "Skyfire",
          "Edge": "Mobile Safari\/[.0-9]* Edge",
          "IE": "IEMobile|MSIEMobile",
          "Firefox": "fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS",
          "Bolt": "bolt",
          "TeaShark": "teashark",
          "Blazer": "Blazer",
          "Safari": "Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari",
          "WeChat": "\\bMicroMessenger\\b",
          "UCBrowser": "UC.*Browser|UCWEB",
          "baiduboxapp": "baiduboxapp",
          "baidubrowser": "baidubrowser",
          "DiigoBrowser": "DiigoBrowser",
          "Puffin": "Puffin",
          "Mercury": "\\bMercury\\b",
          "ObigoBrowser": "Obigo",
          "NetFront": "NF-Browser",
          "GenericBrowser": "NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger",
          "PaleMoon": "Android.*PaleMoon|Mobile.*PaleMoon"
        },
        "props": {
          "Mobile": "Mobile\/[VER]",
          "Build": "Build\/[VER]",
          "Version": "Version\/[VER]",
          "VendorID": "VendorID\/[VER]",
          "iPad": "iPad.*CPU[a-z ]+[VER]",
          "iPhone": "iPhone.*CPU[a-z ]+[VER]",
          "iPod": "iPod.*CPU[a-z ]+[VER]",
          "Kindle": "Kindle\/[VER]",
          "Chrome": ["Chrome\/[VER]", "CriOS\/[VER]", "CrMo\/[VER]"],
          "Coast": ["Coast\/[VER]"],
          "Dolfin": "Dolfin\/[VER]",
          "Firefox": ["Firefox\/[VER]", "FxiOS\/[VER]"],
          "Fennec": "Fennec\/[VER]",
          "Edge": "Edge\/[VER]",
          "IE": ["IEMobile\/[VER];", "IEMobile [VER]", "MSIE [VER];", "Trident\/[0-9.]+;.*rv:[VER]"],
          "NetFront": "NetFront\/[VER]",
          "NokiaBrowser": "NokiaBrowser\/[VER]",
          "Opera": [" OPR\/[VER]", "Opera Mini\/[VER]", "Version\/[VER]"],
          "Opera Mini": "Opera Mini\/[VER]",
          "Opera Mobi": "Version\/[VER]",
          "UCBrowser": ["UCWEB[VER]", "UC.*Browser\/[VER]"],
          "MQQBrowser": "MQQBrowser\/[VER]",
          "MicroMessenger": "MicroMessenger\/[VER]",
          "baiduboxapp": "baiduboxapp\/[VER]",
          "baidubrowser": "baidubrowser\/[VER]",
          "SamsungBrowser": "SamsungBrowser\/[VER]",
          "Iron": "Iron\/[VER]",
          "Safari": ["Version\/[VER]", "Safari\/[VER]"],
          "Skyfire": "Skyfire\/[VER]",
          "Tizen": "Tizen\/[VER]",
          "Webkit": "webkit[ \/][VER]",
          "PaleMoon": "PaleMoon\/[VER]",
          "Gecko": "Gecko\/[VER]",
          "Trident": "Trident\/[VER]",
          "Presto": "Presto\/[VER]",
          "Goanna": "Goanna\/[VER]",
          "iOS": " \\bi?OS\\b [VER][ ;]{1}",
          "Android": "Android [VER]",
          "BlackBerry": ["BlackBerry[\\w]+\/[VER]", "BlackBerry.*Version\/[VER]", "Version\/[VER]"],
          "BREW": "BREW [VER]",
          "Java": "Java\/[VER]",
          "Windows Phone OS": ["Windows Phone OS [VER]", "Windows Phone [VER]"],
          "Windows Phone": "Windows Phone [VER]",
          "Windows CE": "Windows CE\/[VER]",
          "Windows NT": "Windows NT [VER]",
          "Symbian": ["SymbianOS\/[VER]", "Symbian\/[VER]"],
          "webOS": ["webOS\/[VER]", "hpwOS\/[VER];"]
        },
        "utils": {
          "Bot": "Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom",
          "MobileBot": "Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2",
          "DesktopMode": "WPDesktop",
          "TV": "SonyDTV|HbbTV",
          "WebKit": "(webkit)[ \/]([\\w.]+)",
          "Console": "\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\\b",
          "Watch": "SM-V700"
        }
      }; // following patterns come from http://detectmobilebrowsers.com/

      impl.detectMobileBrowsers = {
        fullPattern: /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i,
        shortPattern: /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i,
        tabletPattern: /android|ipad|playbook|silk/i
      };
      var hasOwnProp = Object.prototype.hasOwnProperty,
          isArray;
      impl.FALLBACK_PHONE = 'UnknownPhone';
      impl.FALLBACK_TABLET = 'UnknownTablet';
      impl.FALLBACK_MOBILE = 'UnknownMobile';
      isArray = 'isArray' in Array ? Array.isArray : function (value) {
        return Object.prototype.toString.call(value) === '[object Array]';
      };

      function equalIC(a, b) {
        return a != null && b != null && a.toLowerCase() === b.toLowerCase();
      }

      function containsIC(array, value) {
        var valueLC,
            i,
            len = array.length;

        if (!len || !value) {
          return false;
        }

        valueLC = value.toLowerCase();

        for (i = 0; i < len; ++i) {
          if (valueLC === array[i].toLowerCase()) {
            return true;
          }
        }

        return false;
      }

      function convertPropsToRegExp(object) {
        for (var key in object) {
          if (hasOwnProp.call(object, key)) {
            object[key] = new RegExp(object[key], 'i');
          }
        }
      }

      function prepareUserAgent(userAgent) {
        return (userAgent || '').substr(0, 500); // mitigate vulnerable to ReDoS
      }

      (function init() {
        var key,
            values,
            value,
            i,
            len,
            verPos,
            mobileDetectRules = impl.mobileDetectRules;

        for (key in mobileDetectRules.props) {
          if (hasOwnProp.call(mobileDetectRules.props, key)) {
            values = mobileDetectRules.props[key];

            if (!isArray(values)) {
              values = [values];
            }

            len = values.length;

            for (i = 0; i < len; ++i) {
              value = values[i];
              verPos = value.indexOf('[VER]');

              if (verPos >= 0) {
                value = value.substring(0, verPos) + '([\\w._\\+]+)' + value.substring(verPos + 5);
              }

              values[i] = new RegExp(value, 'i');
            }

            mobileDetectRules.props[key] = values;
          }
        }

        convertPropsToRegExp(mobileDetectRules.oss);
        convertPropsToRegExp(mobileDetectRules.phones);
        convertPropsToRegExp(mobileDetectRules.tablets);
        convertPropsToRegExp(mobileDetectRules.uas);
        convertPropsToRegExp(mobileDetectRules.utils); // copy some patterns to oss0 which are tested first (see issue#15)

        mobileDetectRules.oss0 = {
          WindowsPhoneOS: mobileDetectRules.oss.WindowsPhoneOS,
          WindowsMobileOS: mobileDetectRules.oss.WindowsMobileOS
        };
      })();
      /**
       * Test userAgent string against a set of rules and find the first matched key.
       * @param {Object} rules (key is String, value is RegExp)
       * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent').
       * @returns {String|null} the matched key if found, otherwise <tt>null</tt>
       * @private
       */


      impl.findMatch = function (rules, userAgent) {
        for (var key in rules) {
          if (hasOwnProp.call(rules, key)) {
            if (rules[key].test(userAgent)) {
              return key;
            }
          }
        }

        return null;
      };
      /**
       * Test userAgent string against a set of rules and return an array of matched keys.
       * @param {Object} rules (key is String, value is RegExp)
       * @param {String} userAgent the navigator.userAgent (or HTTP-Header 'User-Agent').
       * @returns {Array} an array of matched keys, may be empty when there is no match, but not <tt>null</tt>
       * @private
       */


      impl.findMatches = function (rules, userAgent) {
        var result = [];

        for (var key in rules) {
          if (hasOwnProp.call(rules, key)) {
            if (rules[key].test(userAgent)) {
              result.push(key);
            }
          }
        }

        return result;
      };
      /**
       * Check the version of the given property in the User-Agent.
       *
       * @param {String} propertyName
       * @param {String} userAgent
       * @return {String} version or <tt>null</tt> if version not found
       * @private
       */


      impl.getVersionStr = function (propertyName, userAgent) {
        var props = impl.mobileDetectRules.props,
            patterns,
            i,
            len,
            match;

        if (hasOwnProp.call(props, propertyName)) {
          patterns = props[propertyName];
          len = patterns.length;

          for (i = 0; i < len; ++i) {
            match = patterns[i].exec(userAgent);

            if (match !== null) {
              return match[1];
            }
          }
        }

        return null;
      };
      /**
       * Check the version of the given property in the User-Agent.
       * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
       *
       * @param {String} propertyName
       * @param {String} userAgent
       * @return {Number} version or <tt>NaN</tt> if version not found
       * @private
       */


      impl.getVersion = function (propertyName, userAgent) {
        var version = impl.getVersionStr(propertyName, userAgent);
        return version ? impl.prepareVersionNo(version) : NaN;
      };
      /**
       * Prepare the version number.
       *
       * @param {String} version
       * @return {Number} the version number as a floating number
       * @private
       */


      impl.prepareVersionNo = function (version) {
        var numbers;
        numbers = version.split(/[a-z._ \/\-]/i);

        if (numbers.length === 1) {
          version = numbers[0];
        }

        if (numbers.length > 1) {
          version = numbers[0] + '.';
          numbers.shift();
          version += numbers.join('');
        }

        return Number(version);
      };

      impl.isMobileFallback = function (userAgent) {
        return impl.detectMobileBrowsers.fullPattern.test(userAgent) || impl.detectMobileBrowsers.shortPattern.test(userAgent.substr(0, 4));
      };

      impl.isTabletFallback = function (userAgent) {
        return impl.detectMobileBrowsers.tabletPattern.test(userAgent);
      };

      impl.prepareDetectionCache = function (cache, userAgent, maxPhoneWidth) {
        if (cache.mobile !== undefined) {
          return;
        }

        var phone, tablet, phoneSized; // first check for stronger tablet rules, then phone (see issue#5)

        tablet = impl.findMatch(impl.mobileDetectRules.tablets, userAgent);

        if (tablet) {
          cache.mobile = cache.tablet = tablet;
          cache.phone = null;
          return; // unambiguously identified as tablet
        }

        phone = impl.findMatch(impl.mobileDetectRules.phones, userAgent);

        if (phone) {
          cache.mobile = cache.phone = phone;
          cache.tablet = null;
          return; // unambiguously identified as phone
        } // our rules haven't found a match -> try more general fallback rules


        if (impl.isMobileFallback(userAgent)) {
          phoneSized = MobileDetect.isPhoneSized(maxPhoneWidth);

          if (phoneSized === undefined) {
            cache.mobile = impl.FALLBACK_MOBILE;
            cache.tablet = cache.phone = null;
          } else if (phoneSized) {
            cache.mobile = cache.phone = impl.FALLBACK_PHONE;
            cache.tablet = null;
          } else {
            cache.mobile = cache.tablet = impl.FALLBACK_TABLET;
            cache.phone = null;
          }
        } else if (impl.isTabletFallback(userAgent)) {
          cache.mobile = cache.tablet = impl.FALLBACK_TABLET;
          cache.phone = null;
        } else {
          // not mobile at all!
          cache.mobile = cache.tablet = cache.phone = null;
        }
      }; // t is a reference to a MobileDetect instance


      impl.mobileGrade = function (t) {
        // impl note:
        // To keep in sync w/ Mobile_Detect.php easily, the following code is tightly aligned to the PHP version.
        // When changes are made in Mobile_Detect.php, copy this method and replace:
        //     $this-> / t.
        //     self::MOBILE_GRADE_(.) / '$1'
        //     , self::VERSION_TYPE_FLOAT / (nothing)
        //     isIOS() / os('iOS')
        //     [reg] / (nothing)   <-- jsdelivr complaining about unescaped unicode character U+00AE
        var $isMobile = t.mobile() !== null;

        if ( // Apple iOS 3.2-5.1 - Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3), iPad 3 (5.1), original iPhone (3.1), iPhone 3 (3.2), 3GS (4.3), 4 (4.3 / 5.0), and 4S (5.1)
        t.os('iOS') && t.version('iPad') >= 4.3 || t.os('iOS') && t.version('iPhone') >= 3.1 || t.os('iOS') && t.version('iPod') >= 3.1 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
        // Android 3.1 (Honeycomb)  - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
        // Android 4.0 (ICS)  - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
        // Android 4.1 (Jelly Bean)  - Tested on a Galaxy Nexus and Galaxy 7
        t.version('Android') > 2.1 && t.is('Webkit') || // Windows Phone 7-7.5 - Tested on the HTC Surround (7.0) HTC Trophy (7.5), LG-E900 (7.5), Nokia Lumia 800
        t.version('Windows Phone OS') >= 7.0 || // Blackberry 7 - Tested on BlackBerry Torch 9810
        // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670
        t.is('BlackBerry') && t.version('BlackBerry') >= 6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook
        t.match('Playbook.*Tablet') || // Palm WebOS (1.4-2.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0)
        t.version('webOS') >= 1.4 && t.match('Palm|Pre|Pixi') || // Palm WebOS 3.0  - Tested on HP TouchPad
        t.match('hp.*TouchPad') || // Firefox Mobile (12 Beta) - Tested on Android 2.3 device
        t.is('Firefox') && t.version('Firefox') >= 12 || // Chrome for Android - Tested on Android 4.0, 4.1 device
        t.is('Chrome') && t.is('AndroidOS') && t.version('Android') >= 4.0 || // Skyfire 4.1 - Tested on Android 2.3 device
        t.is('Skyfire') && t.version('Skyfire') >= 4.1 && t.is('AndroidOS') && t.version('Android') >= 2.3 || // Opera Mobile 11.5-12: Tested on Android 2.3
        t.is('Opera') && t.version('Opera Mobi') > 11 && t.is('AndroidOS') || // Meego 1.2 - Tested on Nokia 950 and N9
        t.is('MeeGoOS') || // Tizen (pre-release) - Tested on early hardware
        t.is('Tizen') || // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
        // @todo: more tests here!
        t.is('Dolfin') && t.version('Bada') >= 2.0 || // UC Browser - Tested on Android 2.3 device
        (t.is('UC Browser') || t.is('Dolfin')) && t.version('Android') >= 2.3 || // Kindle 3 and Fire  - Tested on the built-in WebKit browser for each
        t.match('Kindle Fire') || t.is('Kindle') && t.version('Kindle') >= 3.0 || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
        t.is('AndroidOS') && t.is('NookTablet') || // Chrome Desktop 11-21 - Tested on OS X 10.7 and Windows 7
        t.version('Chrome') >= 11 && !$isMobile || // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7
        t.version('Safari') >= 5.0 && !$isMobile || // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7
        t.version('Firefox') >= 4.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
        t.version('MSIE') >= 7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
        // @reference: http://my.opera.com/community/openweb/idopera/
        t.version('Opera') >= 10 && !$isMobile) {
          return 'A';
        }

        if (t.os('iOS') && t.version('iPad') < 4.3 || t.os('iOS') && t.version('iPhone') < 3.1 || t.os('iOS') && t.version('iPod') < 3.1 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
        t.is('Blackberry') && t.version('BlackBerry') >= 5 && t.version('BlackBerry') < 6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
        t.version('Opera Mini') >= 5.0 && t.version('Opera Mini') <= 6.5 && (t.version('Android') >= 2.3 || t.is('iOS')) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
        t.match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71)
        t.version('Opera Mobi') >= 11 && t.is('SymbianOS')) {
          return 'B';
        }

        if ( // Blackberry 4.x - Tested on the Curve 8330
        t.version('BlackBerry') < 5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
        t.match('MSIEMobile|Windows CE.*Mobile') || t.version('Windows Mobile') <= 5.2) {
          return 'C';
        } //All older smartphone platforms and featurephones - Any device that doesn't support media queries
        //will receive the basic, C grade experience.


        return 'C';
      };

      impl.detectOS = function (ua) {
        return impl.findMatch(impl.mobileDetectRules.oss0, ua) || impl.findMatch(impl.mobileDetectRules.oss, ua);
      };

      impl.getDeviceSmallerSide = function () {
        return window.screen.width < window.screen.height ? window.screen.width : window.screen.height;
      };
      /**
       * Constructor for MobileDetect object.
       * <br>
       * Such an object will keep a reference to the given user-agent string and cache most of the detect queries.<br>
       * <div style="background-color: #d9edf7; border: 1px solid #bce8f1; color: #3a87ad; padding: 14px; border-radius: 2px; margin-top: 20px">
       *     <strong>Find information how to download and install:</strong>
       *     <a href="https://github.com/hgoebl/mobile-detect.js/">github.com/hgoebl/mobile-detect.js/</a>
       * </div>
       *
       * @example <pre>
       *     var md = new MobileDetect(window.navigator.userAgent);
       *     if (md.mobile()) {
       *         location.href = (md.mobileGrade() === 'A') ? '/mobile/' : '/lynx/';
       *     }
       * </pre>
       *
       * @param {string} userAgent typically taken from window.navigator.userAgent or http_header['User-Agent']
       * @param {number} [maxPhoneWidth=600] <strong>only for browsers</strong> specify a value for the maximum
       *        width of smallest device side (in logical "CSS" pixels) until a device detected as mobile will be handled
       *        as phone.
       *        This is only used in cases where the device cannot be classified as phone or tablet.<br>
       *        See <a href="http://developer.android.com/guide/practices/screens_support.html">Declaring Tablet Layouts
       *        for Android</a>.<br>
       *        If you provide a value < 0, then this "fuzzy" check is disabled.
       * @constructor
       * @global
       */


      function MobileDetect(userAgent, maxPhoneWidth) {
        this.ua = prepareUserAgent(userAgent);
        this._cache = {}; //600dp is typical 7" tablet minimum width

        this.maxPhoneWidth = maxPhoneWidth || 600;
      }

      MobileDetect.prototype = {
        constructor: MobileDetect,

        /**
         * Returns the detected phone or tablet type or <tt>null</tt> if it is not a mobile device.
         * <br>
         * For a list of possible return values see {@link MobileDetect#phone} and {@link MobileDetect#tablet}.<br>
         * <br>
         * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
         * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
         * is positive, a value of <code>UnknownPhone</code>, <code>UnknownTablet</code> or
         * <code>UnknownMobile</code> is returned.<br>
         * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br>
         * <br>
         * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code>
         * and <code>UnknownMobile</code>, so you will get <code>UnknownMobile</code> here.<br>
         * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for:
         * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
         * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use.
         * <br>
         * In most cases you will use the return value just as a boolean.
         *
         * @returns {String} the key for the phone family or tablet family, e.g. "Nexus".
         * @function MobileDetect#mobile
         */
        mobile: function mobile() {
          impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
          return this._cache.mobile;
        },

        /**
         * Returns the detected phone type/family string or <tt>null</tt>.
         * <br>
         * The returned tablet (family or producer) is one of following keys:<br>
         * <br><tt>iPhone, BlackBerry, HTC, Nexus, Dell, Motorola, Samsung, LG, Sony, Asus,
         * NokiaLumia, Micromax, Palm, Vertu, Pantech, Fly, Wiko, iMobile, SimValley,
         * Wolfgang, Alcatel, Nintendo, Amoi, INQ, GenericPhone</tt><br>
         * <br>
         * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
         * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
         * is positive, a value of <code>UnknownPhone</code> or <code>UnknownMobile</code> is returned.<br>
         * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br>
         * <br>
         * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code>
         * and <code>UnknownMobile</code>, so you will get <code>null</code> here, while {@link MobileDetect#mobile}
         * will return <code>UnknownMobile</code>.<br>
         * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for:
         * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
         * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use.
         * <br>
         * In most cases you will use the return value just as a boolean.
         *
         * @returns {String} the key of the phone family or producer, e.g. "iPhone"
         * @function MobileDetect#phone
         */
        phone: function phone() {
          impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
          return this._cache.phone;
        },

        /**
         * Returns the detected tablet type/family string or <tt>null</tt>.
         * <br>
         * The returned tablet (family or producer) is one of following keys:<br>
         * <br><tt>iPad, NexusTablet, GoogleTablet, SamsungTablet, Kindle, SurfaceTablet,
         * HPTablet, AsusTablet, BlackBerryTablet, HTCtablet, MotorolaTablet, NookTablet,
         * AcerTablet, ToshibaTablet, LGTablet, FujitsuTablet, PrestigioTablet,
         * LenovoTablet, DellTablet, YarvikTablet, MedionTablet, ArnovaTablet,
         * IntensoTablet, IRUTablet, MegafonTablet, EbodaTablet, AllViewTablet,
         * ArchosTablet, AinolTablet, NokiaLumiaTablet, SonyTablet, PhilipsTablet,
         * CubeTablet, CobyTablet, MIDTablet, MSITablet, SMiTTablet, RockChipTablet,
         * FlyTablet, bqTablet, HuaweiTablet, NecTablet, PantechTablet, BronchoTablet,
         * VersusTablet, ZyncTablet, PositivoTablet, NabiTablet, KoboTablet, DanewTablet,
         * TexetTablet, PlaystationTablet, TrekstorTablet, PyleAudioTablet, AdvanTablet,
         * DanyTechTablet, GalapadTablet, MicromaxTablet, KarbonnTablet, AllFineTablet,
         * PROSCANTablet, YONESTablet, ChangJiaTablet, GUTablet, PointOfViewTablet,
         * OvermaxTablet, HCLTablet, DPSTablet, VistureTablet, CrestaTablet,
         * MediatekTablet, ConcordeTablet, GoCleverTablet, ModecomTablet, VoninoTablet,
         * ECSTablet, StorexTablet, VodafoneTablet, EssentielBTablet, RossMoorTablet,
         * iMobileTablet, TolinoTablet, AudioSonicTablet, AMPETablet, SkkTablet,
         * TecnoTablet, JXDTablet, iJoyTablet, FX2Tablet, XoroTablet, ViewsonicTablet,
         * VerizonTablet, OdysTablet, CaptivaTablet, IconbitTablet, TeclastTablet,
         * OndaTablet, JaytechTablet, BlaupunktTablet, DigmaTablet, EvolioTablet,
         * LavaTablet, AocTablet, MpmanTablet, CelkonTablet, WolderTablet, MediacomTablet,
         * MiTablet, NibiruTablet, NexoTablet, LeaderTablet, UbislateTablet,
         * PocketBookTablet, KocasoTablet, HisenseTablet, Hudl, TelstraTablet,
         * GenericTablet</tt><br>
         * <br>
         * If the device is not detected by the regular expressions from Mobile-Detect, a test is made against
         * the patterns of <a href="http://detectmobilebrowsers.com/">detectmobilebrowsers.com</a>. If this test
         * is positive, a value of <code>UnknownTablet</code> or <code>UnknownMobile</code> is returned.<br>
         * When used in browser, the decision whether phone or tablet is made based on <code>screen.width/height</code>.<br>
         * <br>
         * When used server-side (node.js), there is no way to tell the difference between <code>UnknownTablet</code>
         * and <code>UnknownMobile</code>, so you will get <code>null</code> here, while {@link MobileDetect#mobile}
         * will return <code>UnknownMobile</code>.<br>
         * Be aware that since v1.0.0 in this special case you will get <code>UnknownMobile</code> only for:
         * {@link MobileDetect#mobile}, not for {@link MobileDetect#phone} and {@link MobileDetect#tablet}.
         * In versions before v1.0.0 all 3 methods returned <code>UnknownMobile</code> which was tedious to use.
         * <br>
         * In most cases you will use the return value just as a boolean.
         *
         * @returns {String} the key of the tablet family or producer, e.g. "SamsungTablet"
         * @function MobileDetect#tablet
         */
        tablet: function tablet() {
          impl.prepareDetectionCache(this._cache, this.ua, this.maxPhoneWidth);
          return this._cache.tablet;
        },

        /**
         * Returns the (first) detected user-agent string or <tt>null</tt>.
         * <br>
         * The returned user-agent is one of following keys:<br>
         * <br><tt>Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, Blazer,
         * Safari, WeChat, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, Puffin,
         * Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon</tt><br>
         * <br>
         * In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare
         * cases where a mobile device pretends to be more than one particular browser. You can get the
         * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by
         * providing one of the defined keys as first argument to {@link MobileDetect#is}.
         *
         * @returns {String} the key for the detected user-agent or <tt>null</tt>
         * @function MobileDetect#userAgent
         */
        userAgent: function userAgent() {
          if (this._cache.userAgent === undefined) {
            this._cache.userAgent = impl.findMatch(impl.mobileDetectRules.uas, this.ua);
          }

          return this._cache.userAgent;
        },

        /**
         * Returns all detected user-agent strings.
         * <br>
         * The array is empty or contains one or more of following keys:<br>
         * <br><tt>Chrome, Dolfin, Opera, Skyfire, Edge, IE, Firefox, Bolt, TeaShark, Blazer,
         * Safari, WeChat, UCBrowser, baiduboxapp, baidubrowser, DiigoBrowser, Puffin,
         * Mercury, ObigoBrowser, NetFront, GenericBrowser, PaleMoon</tt><br>
         * <br>
         * In most cases calling {@link MobileDetect#userAgent} will be sufficient. But there are rare
         * cases where a mobile device pretends to be more than one particular browser. You can get the
         * list of all matches with {@link MobileDetect#userAgents} or check for a particular value by
         * providing one of the defined keys as first argument to {@link MobileDetect#is}.
         *
         * @returns {Array} the array of detected user-agent keys or <tt>[]</tt>
         * @function MobileDetect#userAgents
         */
        userAgents: function userAgents() {
          if (this._cache.userAgents === undefined) {
            this._cache.userAgents = impl.findMatches(impl.mobileDetectRules.uas, this.ua);
          }

          return this._cache.userAgents;
        },

        /**
         * Returns the detected operating system string or <tt>null</tt>.
         * <br>
         * The operating system is one of following keys:<br>
         * <br><tt>AndroidOS, BlackBerryOS, PalmOS, SymbianOS, WindowsMobileOS, WindowsPhoneOS,
         * iOS, MeeGoOS, MaemoOS, JavaOS, webOS, badaOS, BREWOS</tt><br>
         *
         * @returns {String} the key for the detected operating system.
         * @function MobileDetect#os
         */
        os: function os() {
          if (this._cache.os === undefined) {
            this._cache.os = impl.detectOS(this.ua);
          }

          return this._cache.os;
        },

        /**
         * Get the version (as Number) of the given property in the User-Agent.
         * <br>
         * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
         *
         * @param {String} key a key defining a thing which has a version.<br>
         *        You can use one of following keys:<br>
         * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast,
         * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini,
         * Opera Mobi, UCBrowser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser,
         * SamsungBrowser, Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident,
         * Presto, Goanna, iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows
         * Phone, Windows CE, Windows NT, Symbian, webOS</tt><br>
         *
         * @returns {Number} the version as float or <tt>NaN</tt> if User-Agent doesn't contain this version.
         *          Be careful when comparing this value with '==' operator!
         * @function MobileDetect#version
         */
        version: function version(key) {
          return impl.getVersion(key, this.ua);
        },

        /**
         * Get the version (as String) of the given property in the User-Agent.
         * <br>
         *
         * @param {String} key a key defining a thing which has a version.<br>
         *        You can use one of following keys:<br>
         * <br><tt>Mobile, Build, Version, VendorID, iPad, iPhone, iPod, Kindle, Chrome, Coast,
         * Dolfin, Firefox, Fennec, Edge, IE, NetFront, NokiaBrowser, Opera, Opera Mini,
         * Opera Mobi, UCBrowser, MQQBrowser, MicroMessenger, baiduboxapp, baidubrowser,
         * SamsungBrowser, Iron, Safari, Skyfire, Tizen, Webkit, PaleMoon, Gecko, Trident,
         * Presto, Goanna, iOS, Android, BlackBerry, BREW, Java, Windows Phone OS, Windows
         * Phone, Windows CE, Windows NT, Symbian, webOS</tt><br>
         *
         * @returns {String} the "raw" version as String or <tt>null</tt> if User-Agent doesn't contain this version.
         *
         * @function MobileDetect#versionStr
         */
        versionStr: function versionStr(key) {
          return impl.getVersionStr(key, this.ua);
        },

        /**
         * Global test key against userAgent, os, phone, tablet and some other properties of userAgent string.
         *
         * @param {String} key the key (case-insensitive) of a userAgent, an operating system, phone or
         *        tablet family.<br>
         *        For a complete list of possible values, see {@link MobileDetect#userAgent},
         *        {@link MobileDetect#os}, {@link MobileDetect#phone}, {@link MobileDetect#tablet}.<br>
         *        Additionally you have following keys:<br>
         * <br><tt>Bot, MobileBot, DesktopMode, TV, WebKit, Console, Watch</tt><br>
         *
         * @returns {boolean} <tt>true</tt> when the given key is one of the defined keys of userAgent, os, phone,
         *                    tablet or one of the listed additional keys, otherwise <tt>false</tt>
         * @function MobileDetect#is
         */
        is: function is(key) {
          return containsIC(this.userAgents(), key) || equalIC(key, this.os()) || equalIC(key, this.phone()) || equalIC(key, this.tablet()) || containsIC(impl.findMatches(impl.mobileDetectRules.utils, this.ua), key);
        },

        /**
         * Do a quick test against navigator::userAgent.
         *
         * @param {String|RegExp} pattern the pattern, either as String or RegExp
         *                        (a string will be converted to a case-insensitive RegExp).
         * @returns {boolean} <tt>true</tt> when the pattern matches, otherwise <tt>false</tt>
         * @function MobileDetect#match
         */
        match: function match(pattern) {
          if (!(pattern instanceof RegExp)) {
            pattern = new RegExp(pattern, 'i');
          }

          return pattern.test(this.ua);
        },

        /**
         * Checks whether the mobile device can be considered as phone regarding <code>screen.width</code>.
         * <br>
         * Obviously this method makes sense in browser environments only (not for Node.js)!
         * @param {number} [maxPhoneWidth] the maximum logical pixels (aka. CSS-pixels) to be considered as phone.<br>
         *        The argument is optional and if not present or falsy, the value of the constructor is taken.
         * @returns {boolean|undefined} <code>undefined</code> if screen size wasn't detectable, else <code>true</code>
         *          when screen.width is less or equal to maxPhoneWidth, otherwise <code>false</code>.<br>
         *          Will always return <code>undefined</code> server-side.
         */
        isPhoneSized: function isPhoneSized(maxPhoneWidth) {
          return MobileDetect.isPhoneSized(maxPhoneWidth || this.maxPhoneWidth);
        },

        /**
         * Returns the mobile grade ('A', 'B', 'C').
         *
         * @returns {String} one of the mobile grades ('A', 'B', 'C').
         * @function MobileDetect#mobileGrade
         */
        mobileGrade: function mobileGrade() {
          if (this._cache.grade === undefined) {
            this._cache.grade = impl.mobileGrade(this);
          }

          return this._cache.grade;
        }
      }; // environment-dependent

      if (typeof window !== 'undefined' && window.screen) {
        MobileDetect.isPhoneSized = function (maxPhoneWidth) {
          return maxPhoneWidth < 0 ? undefined : impl.getDeviceSmallerSide() <= maxPhoneWidth;
        };
      } else {
        MobileDetect.isPhoneSized = function () {};
      } // should not be replaced by a completely new object - just overwrite existing methods


      MobileDetect._impl = impl;
      MobileDetect.version = '1.4.3 2018-09-08';
      return MobileDetect;
    }); // end of call of define()
  })(function (undefined) {
    if ('object' !== 'undefined' && module.exports) {
      return function (factory) {
        module.exports = factory();
      };
    } else if (typeof undefined === 'function' && undefined.amd) {
      return undefined;
    } else if (typeof window !== 'undefined') {
      return function (factory) {
        window.MobileDetect = factory();
      };
    } else {
      // please file a bug if you get this error!
      throw new Error('unknown environment');
    }
  }());
  });

  function getSystemInfoSync() {
    var md = new mobileDetect(navigator.userAgent);
    var info = {
      brand: md.mobile(),
      // 手机品牌
      model: md.mobile(),
      // 手机型号
      system: md.os(),
      // 操作系统版本
      pixelRatio: window.devicePixelRatio,
      // 设备像素比
      screenWidth: window.screen.width,
      // 屏幕宽度
      screenHeight: window.screen.height,
      // 屏幕高度
      windowWidth: document.documentElement.clientWidth,
      // 可使用窗口宽度
      windowHeight: document.documentElement.clientHeight,
      // 可使用窗口高度
      version: '',
      // 微信版本号
      statusBarHeight: '',
      // 状态栏的高度
      platform: navigator.platform,
      // 客户端平台
      language: navigator.language,
      // 微信设置的语言
      fontSizeSetting: '',
      // 用户字体大小设置。以“我-设置-通用-字体大小”中的设置为准,单位:px
      SDKVersion: '' // 客户端基础库版本

    };
    return info;
  }

  function getSystemInfo() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var success = options.success,
        complete = options.complete;
    return new Promise(function (resolve) {
      var info = getSystemInfoSync();
      typeof success === 'function' && success(info);
      typeof complete === 'function' && complete(info);
      resolve(info);
    });
  }

  function getConnection() {
    return navigator.connection || navigator.mozConnection || navigator.webkitConnection || navigator.msConnection;
  }

  function getNetworkType() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var connection = getConnection();
    var success = options.success,
        complete = options.complete;
    var res = {
      errMsg: 'getNetworkType:ok' // 浏览器不支持获取网络状态

    };

    if (!connection) {
      res.networkType = 'unknown';
      typeof success === 'function' && success(res);
      typeof complete === 'function' && complete(res);
      return Promise.resolve(res);
    }

    var type = 'unknown'; // Supports only the navigator.connection.type value which doesn't match the latest spec.
    // https://www.davidbcalhoun.com/2010/using-navigator-connection-android/

    if (!isNaN(Number(connection.type))) {
      switch (connection.type) {
        case connection.WIFI:
          type = 'wifi';
          break;

        case connection.CELL_3G:
          type = '3g';
          break;

        case connection.CELL_2G:
          type = '2g';
          break;

        default:
          // ETHERNET, UNKNOWN
          type = 'unknown';
      }
    } else if (connection.type) {
      // Only supports the type value.
      type = connection.type;
    } else if (connection.effectiveType) {
      //  effectiveType
      type = connection.effectiveType;
    }

    res.networkType = type;
    typeof success === 'function' && success(res);
    typeof complete === 'function' && complete(res);
    return Promise.resolve(res);
  }

  function onNetworkStatusChange(cb) {
    var connection = getConnection();

    if (connection) {
      connection.addEventListener('change', function () {
        getNetworkType().then(function (res) {
          var networkType = res.networkType;
          var isConnected = networkType !== 'none';
          var obj = {
            isConnected: isConnected,
            networkType: networkType
          };
          cb(obj);
        });
      });
    }
  }



  var system = /*#__PURE__*/Object.freeze({
    getSystemInfo: getSystemInfo,
    getSystemInfoSync: getSystemInfoSync,
    getNetworkType: getNetworkType,
    onNetworkStatusChange: onNetworkStatusChange
  });

  var toByteArray_1 = toByteArray;
  var fromByteArray_1 = fromByteArray;
  var lookup = [];
  var revLookup = [];
  var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
  var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

  for (var i = 0, len = code.length; i < len; ++i) {
    lookup[i] = code[i];
    revLookup[code.charCodeAt(i)] = i;
  } // Support decoding URL-safe base64 strings, as Node.js does.
  // See: https://en.wikipedia.org/wiki/Base64#URL_applications


  revLookup['-'.charCodeAt(0)] = 62;
  revLookup['_'.charCodeAt(0)] = 63;

  function getLens(b64) {
    var len = b64.length;

    if (len % 4 > 0) {
      throw new Error('Invalid string. Length must be a multiple of 4');
    } // Trim off extra bytes after placeholder bytes are found
    // See: https://github.com/beatgammit/base64-js/issues/42


    var validLen = b64.indexOf('=');
    if (validLen === -1) validLen = len;
    var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4;
    return [validLen, placeHoldersLen];
  } // base64 is 4/3 + up to two characters of the original data

  function _byteLength(b64, validLen, placeHoldersLen) {
    return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;
  }

  function toByteArray(b64) {
    var tmp;
    var lens = getLens(b64);
    var validLen = lens[0];
    var placeHoldersLen = lens[1];
    var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));
    var curByte = 0; // if there are placeholders, only get up to the last complete 4 chars

    var len = placeHoldersLen > 0 ? validLen - 4 : validLen;

    for (var i = 0; i < len; i += 4) {
      tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];
      arr[curByte++] = tmp >> 16 & 0xFF;
      arr[curByte++] = tmp >> 8 & 0xFF;
      arr[curByte++] = tmp & 0xFF;
    }

    if (placeHoldersLen === 2) {
      tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;
      arr[curByte++] = tmp & 0xFF;
    }

    if (placeHoldersLen === 1) {
      tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;
      arr[curByte++] = tmp >> 8 & 0xFF;
      arr[curByte++] = tmp & 0xFF;
    }

    return arr;
  }

  function tripletToBase64(num) {
    return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F];
  }

  function encodeChunk(uint8, start, end) {
    var tmp;
    var output = [];

    for (var i = start; i < end; i += 3) {
      tmp = (uint8[i] << 16 & 0xFF0000) + (uint8[i + 1] << 8 & 0xFF00) + (uint8[i + 2] & 0xFF);
      output.push(tripletToBase64(tmp));
    }

    return output.join('');
  }

  function fromByteArray(uint8) {
    var tmp;
    var len = uint8.length;
    var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes

    var parts = [];
    var maxChunkLength = 16383; // must be multiple of 3
    // go through the array every three bytes, we'll deal with trailing stuff later

    for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
      parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength));
    } // pad the end with zeros, but make sure to not forget the extra bytes


    if (extraBytes === 1) {
      tmp = uint8[len - 1];
      parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 0x3F] + '==');
    } else if (extraBytes === 2) {
      tmp = (uint8[len - 2] << 8) + uint8[len - 1];
      parts.push(lookup[tmp >> 10] + lookup[tmp >> 4 & 0x3F] + lookup[tmp << 2 & 0x3F] + '=');
    }

    return parts.join('');
  }

  function arrayBufferToBase64(arrayBuffer) {
    return fromByteArray_1(arrayBuffer);
  }
  function base64ToArrayBuffer(base64) {
    return toByteArray_1(base64);
  }

  var others = /*#__PURE__*/Object.freeze({
    arrayBufferToBase64: arrayBufferToBase64,
    base64ToArrayBuffer: base64ToArrayBuffer
  });

  function processApis(taro) {
    var weApis = Object.assign({}, onAndSyncApis, noPromiseApis, otherApis);
    Object.keys(weApis).forEach(function (key) {
      taro[key] = function () {
        console.log("\u6682\u65F6\u4E0D\u652F\u6301 ".concat(key));
      };
    });
  }

  function pxTransform(size) {
    var designWidth = this.config.designWidth;
    return Math.ceil(parseInt(size, 10) / 40 * 640 / designWidth * 10000) / 10000 + 'rem';
  }

  function canIUseWebp() {
    var canvas = document.createElement('canvas');
    return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
  }

  function initNativeApi(taro) {
    processApis(taro);
    taro.request = request;
    taro.createSelectorQuery = createSelectorQuery;
    taro.initPxTransform = initPxTransform.bind(taro);
    taro.pxTransform = pxTransform.bind(taro);

    taro.requirePlugin = function () {
      console.error('不支持 API requirePlugin');
    };

    taro.canIUseWebp = canIUseWebp;
    Object.assign(taro, storage$1, interactive, webSocket, tabBar, system, others);
  }

  var Component$1 =
  /*#__PURE__*/
  function (_Nerv$Component) {
    _inherits(Component, _Nerv$Component);

    function Component(props, context) {
      var _this;

      _classCallCheck(this, Component);

      _this = _possibleConstructorReturn(this, _getPrototypeOf(Component).call(this, props, context));

      if (props._$router) {
        _this.$router = props._$router;
      }

      return _this;
    }

    _createClass(Component, [{
      key: "$app",
      get: function get() {
        if (!this.vnode) return {};
        if (!this._$app) this._$app = getApp(this);
        return this._$app;
      },
      set: function set(app) {
        console.warn('Please try not to set $app.');
      }
    }]);

    return Component;
  }(Nerv.Component);
  /**
   * 往上遍历直到找到根节点
   * @param  {Nerv Component} component 当前的组件实例
   * @return {Nerv Component}           根节点实例
   */


  function getApp(component) {
    var vnode = component.vnode;
    if (!vnode) return {};
    if (vnode._owner) return getApp(vnode._owner);
    return component;
  }

  /* eslint-disable camelcase */
  var Saven = {
    initNativeApi: initNativeApi,
    Component: Component$1,
    getEnv: getEnv,
    ENV_TYPE: ENV_TYPE,
    Events: Events,
    eventCenter: eventCenter,
    render: render,
    internal_safe_get: get,
    internal_safe_set: set$1
  };
  initNativeApi(Saven);

  exports.Saven = Saven;
  exports.default = Saven;

  Object.defineProperty(exports, '__esModule', { value: true });

})));
//# sourceMappingURL=taro-h5.js.map