%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /proc/1857783/root/var/www/cwg/wp-content/plugins/searchwp-metrics/assets/js/dist/
Upload File :
Create Path :
Current File : //proc/1857783/root/var/www/cwg/wp-content/plugins/searchwp-metrics/assets/js/dist/main.js

(function () {
	'use strict';

	var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

	function unwrapExports (x) {
		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
	}

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

	function commonjsRequire () {
		throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
	}

	var vue = createCommonjsModule(function (module, exports) {
	/*!
	 * Vue.js v2.6.12
	 * (c) 2014-2020 Evan You
	 * Released under the MIT License.
	 */
	(function (global, factory) {
	   module.exports = factory() ;
	}(commonjsGlobal, function () {
	  /*  */

	  var emptyObject = Object.freeze({});

	  // These helpers produce better VM code in JS engines due to their
	  // explicitness and function inlining.
	  function isUndef (v) {
	    return v === undefined || v === null
	  }

	  function isDef (v) {
	    return v !== undefined && v !== null
	  }

	  function isTrue (v) {
	    return v === true
	  }

	  function isFalse (v) {
	    return v === false
	  }

	  /**
	   * Check if value is primitive.
	   */
	  function isPrimitive (value) {
	    return (
	      typeof value === 'string' ||
	      typeof value === 'number' ||
	      // $flow-disable-line
	      typeof value === 'symbol' ||
	      typeof value === 'boolean'
	    )
	  }

	  /**
	   * Quick object check - this is primarily used to tell
	   * Objects from primitive values when we know the value
	   * is a JSON-compliant type.
	   */
	  function isObject (obj) {
	    return obj !== null && typeof obj === 'object'
	  }

	  /**
	   * Get the raw type string of a value, e.g., [object Object].
	   */
	  var _toString = Object.prototype.toString;

	  function toRawType (value) {
	    return _toString.call(value).slice(8, -1)
	  }

	  /**
	   * Strict object type check. Only returns true
	   * for plain JavaScript objects.
	   */
	  function isPlainObject (obj) {
	    return _toString.call(obj) === '[object Object]'
	  }

	  function isRegExp (v) {
	    return _toString.call(v) === '[object RegExp]'
	  }

	  /**
	   * Check if val is a valid array index.
	   */
	  function isValidArrayIndex (val) {
	    var n = parseFloat(String(val));
	    return n >= 0 && Math.floor(n) === n && isFinite(val)
	  }

	  function isPromise (val) {
	    return (
	      isDef(val) &&
	      typeof val.then === 'function' &&
	      typeof val.catch === 'function'
	    )
	  }

	  /**
	   * Convert a value to a string that is actually rendered.
	   */
	  function toString (val) {
	    return val == null
	      ? ''
	      : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString)
	        ? JSON.stringify(val, null, 2)
	        : String(val)
	  }

	  /**
	   * Convert an input value to a number for persistence.
	   * If the conversion fails, return original string.
	   */
	  function toNumber (val) {
	    var n = parseFloat(val);
	    return isNaN(n) ? val : n
	  }

	  /**
	   * Make a map and return a function for checking if a key
	   * is in that map.
	   */
	  function makeMap (
	    str,
	    expectsLowerCase
	  ) {
	    var map = Object.create(null);
	    var list = str.split(',');
	    for (var i = 0; i < list.length; i++) {
	      map[list[i]] = true;
	    }
	    return expectsLowerCase
	      ? function (val) { return map[val.toLowerCase()]; }
	      : function (val) { return map[val]; }
	  }

	  /**
	   * Check if a tag is a built-in tag.
	   */
	  var isBuiltInTag = makeMap('slot,component', true);

	  /**
	   * Check if an attribute is a reserved attribute.
	   */
	  var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is');

	  /**
	   * Remove an item from an array.
	   */
	  function remove (arr, item) {
	    if (arr.length) {
	      var index = arr.indexOf(item);
	      if (index > -1) {
	        return arr.splice(index, 1)
	      }
	    }
	  }

	  /**
	   * Check whether an object has the property.
	   */
	  var hasOwnProperty = Object.prototype.hasOwnProperty;
	  function hasOwn (obj, key) {
	    return hasOwnProperty.call(obj, key)
	  }

	  /**
	   * Create a cached version of a pure function.
	   */
	  function cached (fn) {
	    var cache = Object.create(null);
	    return (function cachedFn (str) {
	      var hit = cache[str];
	      return hit || (cache[str] = fn(str))
	    })
	  }

	  /**
	   * Camelize a hyphen-delimited string.
	   */
	  var camelizeRE = /-(\w)/g;
	  var camelize = cached(function (str) {
	    return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; })
	  });

	  /**
	   * Capitalize a string.
	   */
	  var capitalize = cached(function (str) {
	    return str.charAt(0).toUpperCase() + str.slice(1)
	  });

	  /**
	   * Hyphenate a camelCase string.
	   */
	  var hyphenateRE = /\B([A-Z])/g;
	  var hyphenate = cached(function (str) {
	    return str.replace(hyphenateRE, '-$1').toLowerCase()
	  });

	  /**
	   * Simple bind polyfill for environments that do not support it,
	   * e.g., PhantomJS 1.x. Technically, we don't need this anymore
	   * since native bind is now performant enough in most browsers.
	   * But removing it would mean breaking code that was able to run in
	   * PhantomJS 1.x, so this must be kept for backward compatibility.
	   */

	  /* istanbul ignore next */
	  function polyfillBind (fn, ctx) {
	    function boundFn (a) {
	      var l = arguments.length;
	      return l
	        ? l > 1
	          ? fn.apply(ctx, arguments)
	          : fn.call(ctx, a)
	        : fn.call(ctx)
	    }

	    boundFn._length = fn.length;
	    return boundFn
	  }

	  function nativeBind (fn, ctx) {
	    return fn.bind(ctx)
	  }

	  var bind = Function.prototype.bind
	    ? nativeBind
	    : polyfillBind;

	  /**
	   * Convert an Array-like object to a real Array.
	   */
	  function toArray (list, start) {
	    start = start || 0;
	    var i = list.length - start;
	    var ret = new Array(i);
	    while (i--) {
	      ret[i] = list[i + start];
	    }
	    return ret
	  }

	  /**
	   * Mix properties into target object.
	   */
	  function extend (to, _from) {
	    for (var key in _from) {
	      to[key] = _from[key];
	    }
	    return to
	  }

	  /**
	   * Merge an Array of Objects into a single Object.
	   */
	  function toObject (arr) {
	    var res = {};
	    for (var i = 0; i < arr.length; i++) {
	      if (arr[i]) {
	        extend(res, arr[i]);
	      }
	    }
	    return res
	  }

	  /* eslint-disable no-unused-vars */

	  /**
	   * Perform no operation.
	   * Stubbing args to make Flow happy without leaving useless transpiled code
	   * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/).
	   */
	  function noop (a, b, c) {}

	  /**
	   * Always return false.
	   */
	  var no = function (a, b, c) { return false; };

	  /* eslint-enable no-unused-vars */

	  /**
	   * Return the same value.
	   */
	  var identity = function (_) { return _; };

	  /**
	   * Generate a string containing static keys from compiler modules.
	   */
	  function genStaticKeys (modules) {
	    return modules.reduce(function (keys, m) {
	      return keys.concat(m.staticKeys || [])
	    }, []).join(',')
	  }

	  /**
	   * Check if two values are loosely equal - that is,
	   * if they are plain objects, do they have the same shape?
	   */
	  function looseEqual (a, b) {
	    if (a === b) { return true }
	    var isObjectA = isObject(a);
	    var isObjectB = isObject(b);
	    if (isObjectA && isObjectB) {
	      try {
	        var isArrayA = Array.isArray(a);
	        var isArrayB = Array.isArray(b);
	        if (isArrayA && isArrayB) {
	          return a.length === b.length && a.every(function (e, i) {
	            return looseEqual(e, b[i])
	          })
	        } else if (a instanceof Date && b instanceof Date) {
	          return a.getTime() === b.getTime()
	        } else if (!isArrayA && !isArrayB) {
	          var keysA = Object.keys(a);
	          var keysB = Object.keys(b);
	          return keysA.length === keysB.length && keysA.every(function (key) {
	            return looseEqual(a[key], b[key])
	          })
	        } else {
	          /* istanbul ignore next */
	          return false
	        }
	      } catch (e) {
	        /* istanbul ignore next */
	        return false
	      }
	    } else if (!isObjectA && !isObjectB) {
	      return String(a) === String(b)
	    } else {
	      return false
	    }
	  }

	  /**
	   * Return the first index at which a loosely equal value can be
	   * found in the array (if value is a plain object, the array must
	   * contain an object of the same shape), or -1 if it is not present.
	   */
	  function looseIndexOf (arr, val) {
	    for (var i = 0; i < arr.length; i++) {
	      if (looseEqual(arr[i], val)) { return i }
	    }
	    return -1
	  }

	  /**
	   * Ensure a function is called only once.
	   */
	  function once (fn) {
	    var called = false;
	    return function () {
	      if (!called) {
	        called = true;
	        fn.apply(this, arguments);
	      }
	    }
	  }

	  var SSR_ATTR = 'data-server-rendered';

	  var ASSET_TYPES = [
	    'component',
	    'directive',
	    'filter'
	  ];

	  var LIFECYCLE_HOOKS = [
	    'beforeCreate',
	    'created',
	    'beforeMount',
	    'mounted',
	    'beforeUpdate',
	    'updated',
	    'beforeDestroy',
	    'destroyed',
	    'activated',
	    'deactivated',
	    'errorCaptured',
	    'serverPrefetch'
	  ];

	  /*  */



	  var config = ({
	    /**
	     * Option merge strategies (used in core/util/options)
	     */
	    // $flow-disable-line
	    optionMergeStrategies: Object.create(null),

	    /**
	     * Whether to suppress warnings.
	     */
	    silent: false,

	    /**
	     * Show production mode tip message on boot?
	     */
	    productionTip: "development" !== 'production',

	    /**
	     * Whether to enable devtools
	     */
	    devtools: "development" !== 'production',

	    /**
	     * Whether to record perf
	     */
	    performance: false,

	    /**
	     * Error handler for watcher errors
	     */
	    errorHandler: null,

	    /**
	     * Warn handler for watcher warns
	     */
	    warnHandler: null,

	    /**
	     * Ignore certain custom elements
	     */
	    ignoredElements: [],

	    /**
	     * Custom user key aliases for v-on
	     */
	    // $flow-disable-line
	    keyCodes: Object.create(null),

	    /**
	     * Check if a tag is reserved so that it cannot be registered as a
	     * component. This is platform-dependent and may be overwritten.
	     */
	    isReservedTag: no,

	    /**
	     * Check if an attribute is reserved so that it cannot be used as a component
	     * prop. This is platform-dependent and may be overwritten.
	     */
	    isReservedAttr: no,

	    /**
	     * Check if a tag is an unknown element.
	     * Platform-dependent.
	     */
	    isUnknownElement: no,

	    /**
	     * Get the namespace of an element
	     */
	    getTagNamespace: noop,

	    /**
	     * Parse the real tag name for the specific platform.
	     */
	    parsePlatformTagName: identity,

	    /**
	     * Check if an attribute must be bound using property, e.g. value
	     * Platform-dependent.
	     */
	    mustUseProp: no,

	    /**
	     * Perform updates asynchronously. Intended to be used by Vue Test Utils
	     * This will significantly reduce performance if set to false.
	     */
	    async: true,

	    /**
	     * Exposed for legacy reasons
	     */
	    _lifecycleHooks: LIFECYCLE_HOOKS
	  });

	  /*  */

	  /**
	   * unicode letters used for parsing html tags, component names and property paths.
	   * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname
	   * skipping \u10000-\uEFFFF due to it freezing up PhantomJS
	   */
	  var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/;

	  /**
	   * Check if a string starts with $ or _
	   */
	  function isReserved (str) {
	    var c = (str + '').charCodeAt(0);
	    return c === 0x24 || c === 0x5F
	  }

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

	  /**
	   * Parse simple path.
	   */
	  var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\\d]"));
	  function parsePath (path) {
	    if (bailRE.test(path)) {
	      return
	    }
	    var segments = path.split('.');
	    return function (obj) {
	      for (var i = 0; i < segments.length; i++) {
	        if (!obj) { return }
	        obj = obj[segments[i]];
	      }
	      return obj
	    }
	  }

	  /*  */

	  // can we use __proto__?
	  var hasProto = '__proto__' in {};

	  // Browser environment sniffing
	  var inBrowser = typeof window !== 'undefined';
	  var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform;
	  var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase();
	  var UA = inBrowser && window.navigator.userAgent.toLowerCase();
	  var isIE = UA && /msie|trident/.test(UA);
	  var isIE9 = UA && UA.indexOf('msie 9.0') > 0;
	  var isEdge = UA && UA.indexOf('edge/') > 0;
	  var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android');
	  var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios');
	  var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge;
	  var isPhantomJS = UA && /phantomjs/.test(UA);
	  var isFF = UA && UA.match(/firefox\/(\d+)/);

	  // Firefox has a "watch" function on Object.prototype...
	  var nativeWatch = ({}).watch;

	  var supportsPassive = false;
	  if (inBrowser) {
	    try {
	      var opts = {};
	      Object.defineProperty(opts, 'passive', ({
	        get: function get () {
	          /* istanbul ignore next */
	          supportsPassive = true;
	        }
	      })); // https://github.com/facebook/flow/issues/285
	      window.addEventListener('test-passive', null, opts);
	    } catch (e) {}
	  }

	  // this needs to be lazy-evaled because vue may be required before
	  // vue-server-renderer can set VUE_ENV
	  var _isServer;
	  var isServerRendering = function () {
	    if (_isServer === undefined) {
	      /* istanbul ignore if */
	      if (!inBrowser && !inWeex && typeof commonjsGlobal !== 'undefined') {
	        // detect presence of vue-server-renderer and avoid
	        // Webpack shimming the process
	        _isServer = commonjsGlobal['process'] && commonjsGlobal['process'].env.VUE_ENV === 'server';
	      } else {
	        _isServer = false;
	      }
	    }
	    return _isServer
	  };

	  // detect devtools
	  var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;

	  /* istanbul ignore next */
	  function isNative (Ctor) {
	    return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
	  }

	  var hasSymbol =
	    typeof Symbol !== 'undefined' && isNative(Symbol) &&
	    typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys);

	  var _Set;
	  /* istanbul ignore if */ // $flow-disable-line
	  if (typeof Set !== 'undefined' && isNative(Set)) {
	    // use native Set when available.
	    _Set = Set;
	  } else {
	    // a non-standard Set polyfill that only works with primitive keys.
	    _Set = /*@__PURE__*/(function () {
	      function Set () {
	        this.set = Object.create(null);
	      }
	      Set.prototype.has = function has (key) {
	        return this.set[key] === true
	      };
	      Set.prototype.add = function add (key) {
	        this.set[key] = true;
	      };
	      Set.prototype.clear = function clear () {
	        this.set = Object.create(null);
	      };

	      return Set;
	    }());
	  }

	  /*  */

	  var warn = noop;
	  var tip = noop;
	  var generateComponentTrace = (noop); // work around flow check
	  var formatComponentName = (noop);

	  {
	    var hasConsole = typeof console !== 'undefined';
	    var classifyRE = /(?:^|[-_])(\w)/g;
	    var classify = function (str) { return str
	      .replace(classifyRE, function (c) { return c.toUpperCase(); })
	      .replace(/[-_]/g, ''); };

	    warn = function (msg, vm) {
	      var trace = vm ? generateComponentTrace(vm) : '';

	      if (config.warnHandler) {
	        config.warnHandler.call(null, msg, vm, trace);
	      } else if (hasConsole && (!config.silent)) {
	        console.error(("[Vue warn]: " + msg + trace));
	      }
	    };

	    tip = function (msg, vm) {
	      if (hasConsole && (!config.silent)) {
	        console.warn("[Vue tip]: " + msg + (
	          vm ? generateComponentTrace(vm) : ''
	        ));
	      }
	    };

	    formatComponentName = function (vm, includeFile) {
	      if (vm.$root === vm) {
	        return '<Root>'
	      }
	      var options = typeof vm === 'function' && vm.cid != null
	        ? vm.options
	        : vm._isVue
	          ? vm.$options || vm.constructor.options
	          : vm;
	      var name = options.name || options._componentTag;
	      var file = options.__file;
	      if (!name && file) {
	        var match = file.match(/([^/\\]+)\.vue$/);
	        name = match && match[1];
	      }

	      return (
	        (name ? ("<" + (classify(name)) + ">") : "<Anonymous>") +
	        (file && includeFile !== false ? (" at " + file) : '')
	      )
	    };

	    var repeat = function (str, n) {
	      var res = '';
	      while (n) {
	        if (n % 2 === 1) { res += str; }
	        if (n > 1) { str += str; }
	        n >>= 1;
	      }
	      return res
	    };

	    generateComponentTrace = function (vm) {
	      if (vm._isVue && vm.$parent) {
	        var tree = [];
	        var currentRecursiveSequence = 0;
	        while (vm) {
	          if (tree.length > 0) {
	            var last = tree[tree.length - 1];
	            if (last.constructor === vm.constructor) {
	              currentRecursiveSequence++;
	              vm = vm.$parent;
	              continue
	            } else if (currentRecursiveSequence > 0) {
	              tree[tree.length - 1] = [last, currentRecursiveSequence];
	              currentRecursiveSequence = 0;
	            }
	          }
	          tree.push(vm);
	          vm = vm.$parent;
	        }
	        return '\n\nfound in\n\n' + tree
	          .map(function (vm, i) { return ("" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm)
	              ? ((formatComponentName(vm[0])) + "... (" + (vm[1]) + " recursive calls)")
	              : formatComponentName(vm))); })
	          .join('\n')
	      } else {
	        return ("\n\n(found in " + (formatComponentName(vm)) + ")")
	      }
	    };
	  }

	  /*  */

	  var uid = 0;

	  /**
	   * A dep is an observable that can have multiple
	   * directives subscribing to it.
	   */
	  var Dep = function Dep () {
	    this.id = uid++;
	    this.subs = [];
	  };

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

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

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

	  Dep.prototype.notify = function notify () {
	    // stabilize the subscriber list first
	    var subs = this.subs.slice();
	    if (!config.async) {
	      // subs aren't sorted in scheduler if not running async
	      // we need to sort them now to make sure they fire in correct
	      // order
	      subs.sort(function (a, b) { return a.id - b.id; });
	    }
	    for (var i = 0, l = subs.length; i < l; i++) {
	      subs[i].update();
	    }
	  };

	  // The current target watcher being evaluated.
	  // This is globally unique because only one watcher
	  // can be evaluated at a time.
	  Dep.target = null;
	  var targetStack = [];

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

	  function popTarget () {
	    targetStack.pop();
	    Dep.target = targetStack[targetStack.length - 1];
	  }

	  /*  */

	  var VNode = function VNode (
	    tag,
	    data,
	    children,
	    text,
	    elm,
	    context,
	    componentOptions,
	    asyncFactory
	  ) {
	    this.tag = tag;
	    this.data = data;
	    this.children = children;
	    this.text = text;
	    this.elm = elm;
	    this.ns = undefined;
	    this.context = context;
	    this.fnContext = undefined;
	    this.fnOptions = undefined;
	    this.fnScopeId = undefined;
	    this.key = data && data.key;
	    this.componentOptions = componentOptions;
	    this.componentInstance = undefined;
	    this.parent = undefined;
	    this.raw = false;
	    this.isStatic = false;
	    this.isRootInsert = true;
	    this.isComment = false;
	    this.isCloned = false;
	    this.isOnce = false;
	    this.asyncFactory = asyncFactory;
	    this.asyncMeta = undefined;
	    this.isAsyncPlaceholder = false;
	  };

	  var prototypeAccessors = { child: { configurable: true } };

	  // DEPRECATED: alias for componentInstance for backwards compat.
	  /* istanbul ignore next */
	  prototypeAccessors.child.get = function () {
	    return this.componentInstance
	  };

	  Object.defineProperties( VNode.prototype, prototypeAccessors );

	  var createEmptyVNode = function (text) {
	    if ( text === void 0 ) text = '';

	    var node = new VNode();
	    node.text = text;
	    node.isComment = true;
	    return node
	  };

	  function createTextVNode (val) {
	    return new VNode(undefined, undefined, undefined, String(val))
	  }

	  // optimized shallow clone
	  // used for static nodes and slot nodes because they may be reused across
	  // multiple renders, cloning them avoids errors when DOM manipulations rely
	  // on their elm reference.
	  function cloneVNode (vnode) {
	    var cloned = new VNode(
	      vnode.tag,
	      vnode.data,
	      // #7975
	      // clone children array to avoid mutating original in case of cloning
	      // a child.
	      vnode.children && vnode.children.slice(),
	      vnode.text,
	      vnode.elm,
	      vnode.context,
	      vnode.componentOptions,
	      vnode.asyncFactory
	    );
	    cloned.ns = vnode.ns;
	    cloned.isStatic = vnode.isStatic;
	    cloned.key = vnode.key;
	    cloned.isComment = vnode.isComment;
	    cloned.fnContext = vnode.fnContext;
	    cloned.fnOptions = vnode.fnOptions;
	    cloned.fnScopeId = vnode.fnScopeId;
	    cloned.asyncMeta = vnode.asyncMeta;
	    cloned.isCloned = true;
	    return cloned
	  }

	  /*
	   * not type checking this file because flow doesn't play well with
	   * dynamically accessing methods on Array prototype
	   */

	  var arrayProto = Array.prototype;
	  var arrayMethods = Object.create(arrayProto);

	  var methodsToPatch = [
	    'push',
	    'pop',
	    'shift',
	    'unshift',
	    'splice',
	    'sort',
	    'reverse'
	  ];

	  /**
	   * Intercept mutating methods and emit events
	   */
	  methodsToPatch.forEach(function (method) {
	    // cache original method
	    var original = arrayProto[method];
	    def(arrayMethods, method, function mutator () {
	      var args = [], len = arguments.length;
	      while ( len-- ) args[ len ] = arguments[ len ];

	      var result = original.apply(this, args);
	      var ob = this.__ob__;
	      var inserted;
	      switch (method) {
	        case 'push':
	        case 'unshift':
	          inserted = args;
	          break
	        case 'splice':
	          inserted = args.slice(2);
	          break
	      }
	      if (inserted) { ob.observeArray(inserted); }
	      // notify change
	      ob.dep.notify();
	      return result
	    });
	  });

	  /*  */

	  var arrayKeys = Object.getOwnPropertyNames(arrayMethods);

	  /**
	   * In some cases we may want to disable observation inside a component's
	   * update computation.
	   */
	  var shouldObserve = true;

	  function toggleObserving (value) {
	    shouldObserve = value;
	  }

	  /**
	   * Observer class that is attached to each observed
	   * object. Once attached, the observer converts the target
	   * object's property keys into getter/setters that
	   * collect dependencies and dispatch updates.
	   */
	  var Observer = function Observer (value) {
	    this.value = value;
	    this.dep = new Dep();
	    this.vmCount = 0;
	    def(value, '__ob__', this);
	    if (Array.isArray(value)) {
	      if (hasProto) {
	        protoAugment(value, arrayMethods);
	      } else {
	        copyAugment(value, arrayMethods, arrayKeys);
	      }
	      this.observeArray(value);
	    } else {
	      this.walk(value);
	    }
	  };

	  /**
	   * Walk through all properties and convert them into
	   * getter/setters. This method should only be called when
	   * value type is Object.
	   */
	  Observer.prototype.walk = function walk (obj) {
	    var keys = Object.keys(obj);
	    for (var i = 0; i < keys.length; i++) {
	      defineReactive$$1(obj, keys[i]);
	    }
	  };

	  /**
	   * Observe a list of Array items.
	   */
	  Observer.prototype.observeArray = function observeArray (items) {
	    for (var i = 0, l = items.length; i < l; i++) {
	      observe(items[i]);
	    }
	  };

	  // helpers

	  /**
	   * Augment a target Object or Array by intercepting
	   * the prototype chain using __proto__
	   */
	  function protoAugment (target, src) {
	    /* eslint-disable no-proto */
	    target.__proto__ = src;
	    /* eslint-enable no-proto */
	  }

	  /**
	   * Augment a target Object or Array by defining
	   * hidden properties.
	   */
	  /* istanbul ignore next */
	  function copyAugment (target, src, keys) {
	    for (var i = 0, l = keys.length; i < l; i++) {
	      var key = keys[i];
	      def(target, key, src[key]);
	    }
	  }

	  /**
	   * Attempt to create an observer instance for a value,
	   * returns the new observer if successfully observed,
	   * or the existing observer if the value already has one.
	   */
	  function observe (value, asRootData) {
	    if (!isObject(value) || value instanceof VNode) {
	      return
	    }
	    var ob;
	    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
	      ob = value.__ob__;
	    } else if (
	      shouldObserve &&
	      !isServerRendering() &&
	      (Array.isArray(value) || isPlainObject(value)) &&
	      Object.isExtensible(value) &&
	      !value._isVue
	    ) {
	      ob = new Observer(value);
	    }
	    if (asRootData && ob) {
	      ob.vmCount++;
	    }
	    return ob
	  }

	  /**
	   * Define a reactive property on an Object.
	   */
	  function defineReactive$$1 (
	    obj,
	    key,
	    val,
	    customSetter,
	    shallow
	  ) {
	    var dep = new Dep();

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

	    // cater for pre-defined getter/setters
	    var getter = property && property.get;
	    var setter = property && property.set;
	    if ((!getter || setter) && arguments.length === 2) {
	      val = obj[key];
	    }

	    var childOb = !shallow && observe(val);
	    Object.defineProperty(obj, key, {
	      enumerable: true,
	      configurable: true,
	      get: function reactiveGetter () {
	        var value = getter ? getter.call(obj) : val;
	        if (Dep.target) {
	          dep.depend();
	          if (childOb) {
	            childOb.dep.depend();
	            if (Array.isArray(value)) {
	              dependArray(value);
	            }
	          }
	        }
	        return value
	      },
	      set: function reactiveSetter (newVal) {
	        var value = getter ? getter.call(obj) : val;
	        /* eslint-disable no-self-compare */
	        if (newVal === value || (newVal !== newVal && value !== value)) {
	          return
	        }
	        /* eslint-enable no-self-compare */
	        if (customSetter) {
	          customSetter();
	        }
	        // #7981: for accessor properties without setter
	        if (getter && !setter) { return }
	        if (setter) {
	          setter.call(obj, newVal);
	        } else {
	          val = newVal;
	        }
	        childOb = !shallow && observe(newVal);
	        dep.notify();
	      }
	    });
	  }

	  /**
	   * Set a property on an object. Adds the new property and
	   * triggers change notification if the property doesn't
	   * already exist.
	   */
	  function set (target, key, val) {
	    if (isUndef(target) || isPrimitive(target)
	    ) {
	      warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target))));
	    }
	    if (Array.isArray(target) && isValidArrayIndex(key)) {
	      target.length = Math.max(target.length, key);
	      target.splice(key, 1, val);
	      return val
	    }
	    if (key in target && !(key in Object.prototype)) {
	      target[key] = val;
	      return val
	    }
	    var ob = (target).__ob__;
	    if (target._isVue || (ob && ob.vmCount)) {
	      warn(
	        'Avoid adding reactive properties to a Vue instance or its root $data ' +
	        'at runtime - declare it upfront in the data option.'
	      );
	      return val
	    }
	    if (!ob) {
	      target[key] = val;
	      return val
	    }
	    defineReactive$$1(ob.value, key, val);
	    ob.dep.notify();
	    return val
	  }

	  /**
	   * Delete a property and trigger change if necessary.
	   */
	  function del (target, key) {
	    if (isUndef(target) || isPrimitive(target)
	    ) {
	      warn(("Cannot delete reactive property on undefined, null, or primitive value: " + ((target))));
	    }
	    if (Array.isArray(target) && isValidArrayIndex(key)) {
	      target.splice(key, 1);
	      return
	    }
	    var ob = (target).__ob__;
	    if (target._isVue || (ob && ob.vmCount)) {
	      warn(
	        'Avoid deleting properties on a Vue instance or its root $data ' +
	        '- just set it to null.'
	      );
	      return
	    }
	    if (!hasOwn(target, key)) {
	      return
	    }
	    delete target[key];
	    if (!ob) {
	      return
	    }
	    ob.dep.notify();
	  }

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

	  /*  */

	  /**
	   * Option overwriting strategies are functions that handle
	   * how to merge a parent option value and a child option
	   * value into the final value.
	   */
	  var strats = config.optionMergeStrategies;

	  /**
	   * Options with restrictions
	   */
	  {
	    strats.el = strats.propsData = function (parent, child, vm, key) {
	      if (!vm) {
	        warn(
	          "option \"" + key + "\" can only be used during instance " +
	          'creation with the `new` keyword.'
	        );
	      }
	      return defaultStrat(parent, child)
	    };
	  }

	  /**
	   * Helper that recursively merges two data objects together.
	   */
	  function mergeData (to, from) {
	    if (!from) { return to }
	    var key, toVal, fromVal;

	    var keys = hasSymbol
	      ? Reflect.ownKeys(from)
	      : Object.keys(from);

	    for (var i = 0; i < keys.length; i++) {
	      key = keys[i];
	      // in case the object is already observed...
	      if (key === '__ob__') { continue }
	      toVal = to[key];
	      fromVal = from[key];
	      if (!hasOwn(to, key)) {
	        set(to, key, fromVal);
	      } else if (
	        toVal !== fromVal &&
	        isPlainObject(toVal) &&
	        isPlainObject(fromVal)
	      ) {
	        mergeData(toVal, fromVal);
	      }
	    }
	    return to
	  }

	  /**
	   * Data
	   */
	  function mergeDataOrFn (
	    parentVal,
	    childVal,
	    vm
	  ) {
	    if (!vm) {
	      // in a Vue.extend merge, both should be functions
	      if (!childVal) {
	        return parentVal
	      }
	      if (!parentVal) {
	        return childVal
	      }
	      // when parentVal & childVal are both present,
	      // we need to return a function that returns the
	      // merged result of both functions... no need to
	      // check if parentVal is a function here because
	      // it has to be a function to pass previous merges.
	      return function mergedDataFn () {
	        return mergeData(
	          typeof childVal === 'function' ? childVal.call(this, this) : childVal,
	          typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal
	        )
	      }
	    } else {
	      return function mergedInstanceDataFn () {
	        // instance merge
	        var instanceData = typeof childVal === 'function'
	          ? childVal.call(vm, vm)
	          : childVal;
	        var defaultData = typeof parentVal === 'function'
	          ? parentVal.call(vm, vm)
	          : parentVal;
	        if (instanceData) {
	          return mergeData(instanceData, defaultData)
	        } else {
	          return defaultData
	        }
	      }
	    }
	  }

	  strats.data = function (
	    parentVal,
	    childVal,
	    vm
	  ) {
	    if (!vm) {
	      if (childVal && typeof childVal !== 'function') {
	        warn(
	          'The "data" option should be a function ' +
	          'that returns a per-instance value in component ' +
	          'definitions.',
	          vm
	        );

	        return parentVal
	      }
	      return mergeDataOrFn(parentVal, childVal)
	    }

	    return mergeDataOrFn(parentVal, childVal, vm)
	  };

	  /**
	   * Hooks and props are merged as arrays.
	   */
	  function mergeHook (
	    parentVal,
	    childVal
	  ) {
	    var res = childVal
	      ? parentVal
	        ? parentVal.concat(childVal)
	        : Array.isArray(childVal)
	          ? childVal
	          : [childVal]
	      : parentVal;
	    return res
	      ? dedupeHooks(res)
	      : res
	  }

	  function dedupeHooks (hooks) {
	    var res = [];
	    for (var i = 0; i < hooks.length; i++) {
	      if (res.indexOf(hooks[i]) === -1) {
	        res.push(hooks[i]);
	      }
	    }
	    return res
	  }

	  LIFECYCLE_HOOKS.forEach(function (hook) {
	    strats[hook] = mergeHook;
	  });

	  /**
	   * Assets
	   *
	   * When a vm is present (instance creation), we need to do
	   * a three-way merge between constructor options, instance
	   * options and parent options.
	   */
	  function mergeAssets (
	    parentVal,
	    childVal,
	    vm,
	    key
	  ) {
	    var res = Object.create(parentVal || null);
	    if (childVal) {
	      assertObjectType(key, childVal, vm);
	      return extend(res, childVal)
	    } else {
	      return res
	    }
	  }

	  ASSET_TYPES.forEach(function (type) {
	    strats[type + 's'] = mergeAssets;
	  });

	  /**
	   * Watchers.
	   *
	   * Watchers hashes should not overwrite one
	   * another, so we merge them as arrays.
	   */
	  strats.watch = function (
	    parentVal,
	    childVal,
	    vm,
	    key
	  ) {
	    // work around Firefox's Object.prototype.watch...
	    if (parentVal === nativeWatch) { parentVal = undefined; }
	    if (childVal === nativeWatch) { childVal = undefined; }
	    /* istanbul ignore if */
	    if (!childVal) { return Object.create(parentVal || null) }
	    {
	      assertObjectType(key, childVal, vm);
	    }
	    if (!parentVal) { return childVal }
	    var ret = {};
	    extend(ret, parentVal);
	    for (var key$1 in childVal) {
	      var parent = ret[key$1];
	      var child = childVal[key$1];
	      if (parent && !Array.isArray(parent)) {
	        parent = [parent];
	      }
	      ret[key$1] = parent
	        ? parent.concat(child)
	        : Array.isArray(child) ? child : [child];
	    }
	    return ret
	  };

	  /**
	   * Other object hashes.
	   */
	  strats.props =
	  strats.methods =
	  strats.inject =
	  strats.computed = function (
	    parentVal,
	    childVal,
	    vm,
	    key
	  ) {
	    if (childVal && "development" !== 'production') {
	      assertObjectType(key, childVal, vm);
	    }
	    if (!parentVal) { return childVal }
	    var ret = Object.create(null);
	    extend(ret, parentVal);
	    if (childVal) { extend(ret, childVal); }
	    return ret
	  };
	  strats.provide = mergeDataOrFn;

	  /**
	   * Default strategy.
	   */
	  var defaultStrat = function (parentVal, childVal) {
	    return childVal === undefined
	      ? parentVal
	      : childVal
	  };

	  /**
	   * Validate component names
	   */
	  function checkComponents (options) {
	    for (var key in options.components) {
	      validateComponentName(key);
	    }
	  }

	  function validateComponentName (name) {
	    if (!new RegExp(("^[a-zA-Z][\\-\\.0-9_" + (unicodeRegExp.source) + "]*$")).test(name)) {
	      warn(
	        'Invalid component name: "' + name + '". Component names ' +
	        'should conform to valid custom element name in html5 specification.'
	      );
	    }
	    if (isBuiltInTag(name) || config.isReservedTag(name)) {
	      warn(
	        'Do not use built-in or reserved HTML elements as component ' +
	        'id: ' + name
	      );
	    }
	  }

	  /**
	   * Ensure all props option syntax are normalized into the
	   * Object-based format.
	   */
	  function normalizeProps (options, vm) {
	    var props = options.props;
	    if (!props) { return }
	    var res = {};
	    var i, val, name;
	    if (Array.isArray(props)) {
	      i = props.length;
	      while (i--) {
	        val = props[i];
	        if (typeof val === 'string') {
	          name = camelize(val);
	          res[name] = { type: null };
	        } else {
	          warn('props must be strings when using array syntax.');
	        }
	      }
	    } else if (isPlainObject(props)) {
	      for (var key in props) {
	        val = props[key];
	        name = camelize(key);
	        res[name] = isPlainObject(val)
	          ? val
	          : { type: val };
	      }
	    } else {
	      warn(
	        "Invalid value for option \"props\": expected an Array or an Object, " +
	        "but got " + (toRawType(props)) + ".",
	        vm
	      );
	    }
	    options.props = res;
	  }

	  /**
	   * Normalize all injections into Object-based format
	   */
	  function normalizeInject (options, vm) {
	    var inject = options.inject;
	    if (!inject) { return }
	    var normalized = options.inject = {};
	    if (Array.isArray(inject)) {
	      for (var i = 0; i < inject.length; i++) {
	        normalized[inject[i]] = { from: inject[i] };
	      }
	    } else if (isPlainObject(inject)) {
	      for (var key in inject) {
	        var val = inject[key];
	        normalized[key] = isPlainObject(val)
	          ? extend({ from: key }, val)
	          : { from: val };
	      }
	    } else {
	      warn(
	        "Invalid value for option \"inject\": expected an Array or an Object, " +
	        "but got " + (toRawType(inject)) + ".",
	        vm
	      );
	    }
	  }

	  /**
	   * Normalize raw function directives into object format.
	   */
	  function normalizeDirectives (options) {
	    var dirs = options.directives;
	    if (dirs) {
	      for (var key in dirs) {
	        var def$$1 = dirs[key];
	        if (typeof def$$1 === 'function') {
	          dirs[key] = { bind: def$$1, update: def$$1 };
	        }
	      }
	    }
	  }

	  function assertObjectType (name, value, vm) {
	    if (!isPlainObject(value)) {
	      warn(
	        "Invalid value for option \"" + name + "\": expected an Object, " +
	        "but got " + (toRawType(value)) + ".",
	        vm
	      );
	    }
	  }

	  /**
	   * Merge two option objects into a new one.
	   * Core utility used in both instantiation and inheritance.
	   */
	  function mergeOptions (
	    parent,
	    child,
	    vm
	  ) {
	    {
	      checkComponents(child);
	    }

	    if (typeof child === 'function') {
	      child = child.options;
	    }

	    normalizeProps(child, vm);
	    normalizeInject(child, vm);
	    normalizeDirectives(child);

	    // Apply extends and mixins on the child options,
	    // but only if it is a raw options object that isn't
	    // the result of another mergeOptions call.
	    // Only merged options has the _base property.
	    if (!child._base) {
	      if (child.extends) {
	        parent = mergeOptions(parent, child.extends, vm);
	      }
	      if (child.mixins) {
	        for (var i = 0, l = child.mixins.length; i < l; i++) {
	          parent = mergeOptions(parent, child.mixins[i], vm);
	        }
	      }
	    }

	    var options = {};
	    var key;
	    for (key in parent) {
	      mergeField(key);
	    }
	    for (key in child) {
	      if (!hasOwn(parent, key)) {
	        mergeField(key);
	      }
	    }
	    function mergeField (key) {
	      var strat = strats[key] || defaultStrat;
	      options[key] = strat(parent[key], child[key], vm, key);
	    }
	    return options
	  }

	  /**
	   * Resolve an asset.
	   * This function is used because child instances need access
	   * to assets defined in its ancestor chain.
	   */
	  function resolveAsset (
	    options,
	    type,
	    id,
	    warnMissing
	  ) {
	    /* istanbul ignore if */
	    if (typeof id !== 'string') {
	      return
	    }
	    var assets = options[type];
	    // check local registration variations first
	    if (hasOwn(assets, id)) { return assets[id] }
	    var camelizedId = camelize(id);
	    if (hasOwn(assets, camelizedId)) { return assets[camelizedId] }
	    var PascalCaseId = capitalize(camelizedId);
	    if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] }
	    // fallback to prototype chain
	    var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
	    if (warnMissing && !res) {
	      warn(
	        'Failed to resolve ' + type.slice(0, -1) + ': ' + id,
	        options
	      );
	    }
	    return res
	  }

	  /*  */



	  function validateProp (
	    key,
	    propOptions,
	    propsData,
	    vm
	  ) {
	    var prop = propOptions[key];
	    var absent = !hasOwn(propsData, key);
	    var value = propsData[key];
	    // boolean casting
	    var booleanIndex = getTypeIndex(Boolean, prop.type);
	    if (booleanIndex > -1) {
	      if (absent && !hasOwn(prop, 'default')) {
	        value = false;
	      } else if (value === '' || value === hyphenate(key)) {
	        // only cast empty string / same name to boolean if
	        // boolean has higher priority
	        var stringIndex = getTypeIndex(String, prop.type);
	        if (stringIndex < 0 || booleanIndex < stringIndex) {
	          value = true;
	        }
	      }
	    }
	    // check default value
	    if (value === undefined) {
	      value = getPropDefaultValue(vm, prop, key);
	      // since the default value is a fresh copy,
	      // make sure to observe it.
	      var prevShouldObserve = shouldObserve;
	      toggleObserving(true);
	      observe(value);
	      toggleObserving(prevShouldObserve);
	    }
	    {
	      assertProp(prop, key, value, vm, absent);
	    }
	    return value
	  }

	  /**
	   * Get the default value of a prop.
	   */
	  function getPropDefaultValue (vm, prop, key) {
	    // no default, return undefined
	    if (!hasOwn(prop, 'default')) {
	      return undefined
	    }
	    var def = prop.default;
	    // warn against non-factory defaults for Object & Array
	    if (isObject(def)) {
	      warn(
	        'Invalid default value for prop "' + key + '": ' +
	        'Props with type Object/Array must use a factory function ' +
	        'to return the default value.',
	        vm
	      );
	    }
	    // the raw prop value was also undefined from previous render,
	    // return previous default value to avoid unnecessary watcher trigger
	    if (vm && vm.$options.propsData &&
	      vm.$options.propsData[key] === undefined &&
	      vm._props[key] !== undefined
	    ) {
	      return vm._props[key]
	    }
	    // call factory function for non-Function types
	    // a value is Function if its prototype is function even across different execution context
	    return typeof def === 'function' && getType(prop.type) !== 'Function'
	      ? def.call(vm)
	      : def
	  }

	  /**
	   * Assert whether a prop is valid.
	   */
	  function assertProp (
	    prop,
	    name,
	    value,
	    vm,
	    absent
	  ) {
	    if (prop.required && absent) {
	      warn(
	        'Missing required prop: "' + name + '"',
	        vm
	      );
	      return
	    }
	    if (value == null && !prop.required) {
	      return
	    }
	    var type = prop.type;
	    var valid = !type || type === true;
	    var expectedTypes = [];
	    if (type) {
	      if (!Array.isArray(type)) {
	        type = [type];
	      }
	      for (var i = 0; i < type.length && !valid; i++) {
	        var assertedType = assertType(value, type[i]);
	        expectedTypes.push(assertedType.expectedType || '');
	        valid = assertedType.valid;
	      }
	    }

	    if (!valid) {
	      warn(
	        getInvalidTypeMessage(name, value, expectedTypes),
	        vm
	      );
	      return
	    }
	    var validator = prop.validator;
	    if (validator) {
	      if (!validator(value)) {
	        warn(
	          'Invalid prop: custom validator check failed for prop "' + name + '".',
	          vm
	        );
	      }
	    }
	  }

	  var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/;

	  function assertType (value, type) {
	    var valid;
	    var expectedType = getType(type);
	    if (simpleCheckRE.test(expectedType)) {
	      var t = typeof value;
	      valid = t === expectedType.toLowerCase();
	      // for primitive wrapper objects
	      if (!valid && t === 'object') {
	        valid = value instanceof type;
	      }
	    } else if (expectedType === 'Object') {
	      valid = isPlainObject(value);
	    } else if (expectedType === 'Array') {
	      valid = Array.isArray(value);
	    } else {
	      valid = value instanceof type;
	    }
	    return {
	      valid: valid,
	      expectedType: expectedType
	    }
	  }

	  /**
	   * Use function string name to check built-in types,
	   * because a simple equality check will fail when running
	   * across different vms / iframes.
	   */
	  function getType (fn) {
	    var match = fn && fn.toString().match(/^\s*function (\w+)/);
	    return match ? match[1] : ''
	  }

	  function isSameType (a, b) {
	    return getType(a) === getType(b)
	  }

	  function getTypeIndex (type, expectedTypes) {
	    if (!Array.isArray(expectedTypes)) {
	      return isSameType(expectedTypes, type) ? 0 : -1
	    }
	    for (var i = 0, len = expectedTypes.length; i < len; i++) {
	      if (isSameType(expectedTypes[i], type)) {
	        return i
	      }
	    }
	    return -1
	  }

	  function getInvalidTypeMessage (name, value, expectedTypes) {
	    var message = "Invalid prop: type check failed for prop \"" + name + "\"." +
	      " Expected " + (expectedTypes.map(capitalize).join(', '));
	    var expectedType = expectedTypes[0];
	    var receivedType = toRawType(value);
	    var expectedValue = styleValue(value, expectedType);
	    var receivedValue = styleValue(value, receivedType);
	    // check if we need to specify expected value
	    if (expectedTypes.length === 1 &&
	        isExplicable(expectedType) &&
	        !isBoolean(expectedType, receivedType)) {
	      message += " with value " + expectedValue;
	    }
	    message += ", got " + receivedType + " ";
	    // check if we need to specify received value
	    if (isExplicable(receivedType)) {
	      message += "with value " + receivedValue + ".";
	    }
	    return message
	  }

	  function styleValue (value, type) {
	    if (type === 'String') {
	      return ("\"" + value + "\"")
	    } else if (type === 'Number') {
	      return ("" + (Number(value)))
	    } else {
	      return ("" + value)
	    }
	  }

	  function isExplicable (value) {
	    var explicitTypes = ['string', 'number', 'boolean'];
	    return explicitTypes.some(function (elem) { return value.toLowerCase() === elem; })
	  }

	  function isBoolean () {
	    var args = [], len = arguments.length;
	    while ( len-- ) args[ len ] = arguments[ len ];

	    return args.some(function (elem) { return elem.toLowerCase() === 'boolean'; })
	  }

	  /*  */

	  function handleError (err, vm, info) {
	    // Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
	    // See: https://github.com/vuejs/vuex/issues/1505
	    pushTarget();
	    try {
	      if (vm) {
	        var cur = vm;
	        while ((cur = cur.$parent)) {
	          var hooks = cur.$options.errorCaptured;
	          if (hooks) {
	            for (var i = 0; i < hooks.length; i++) {
	              try {
	                var capture = hooks[i].call(cur, err, vm, info) === false;
	                if (capture) { return }
	              } catch (e) {
	                globalHandleError(e, cur, 'errorCaptured hook');
	              }
	            }
	          }
	        }
	      }
	      globalHandleError(err, vm, info);
	    } finally {
	      popTarget();
	    }
	  }

	  function invokeWithErrorHandling (
	    handler,
	    context,
	    args,
	    vm,
	    info
	  ) {
	    var res;
	    try {
	      res = args ? handler.apply(context, args) : handler.call(context);
	      if (res && !res._isVue && isPromise(res) && !res._handled) {
	        res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); });
	        // issue #9511
	        // avoid catch triggering multiple times when nested calls
	        res._handled = true;
	      }
	    } catch (e) {
	      handleError(e, vm, info);
	    }
	    return res
	  }

	  function globalHandleError (err, vm, info) {
	    if (config.errorHandler) {
	      try {
	        return config.errorHandler.call(null, err, vm, info)
	      } catch (e) {
	        // if the user intentionally throws the original error in the handler,
	        // do not log it twice
	        if (e !== err) {
	          logError(e, null, 'config.errorHandler');
	        }
	      }
	    }
	    logError(err, vm, info);
	  }

	  function logError (err, vm, info) {
	    {
	      warn(("Error in " + info + ": \"" + (err.toString()) + "\""), vm);
	    }
	    /* istanbul ignore else */
	    if ((inBrowser || inWeex) && typeof console !== 'undefined') {
	      console.error(err);
	    } else {
	      throw err
	    }
	  }

	  /*  */

	  var isUsingMicroTask = false;

	  var callbacks = [];
	  var pending = false;

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

	  // Here we have async deferring wrappers using microtasks.
	  // In 2.5 we used (macro) tasks (in combination with microtasks).
	  // However, it has subtle problems when state is changed right before repaint
	  // (e.g. #6813, out-in transitions).
	  // Also, using (macro) tasks in event handler would cause some weird behaviors
	  // that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109).
	  // So we now use microtasks everywhere, again.
	  // A major drawback of this tradeoff is that there are some scenarios
	  // where microtasks have too high a priority and fire in between supposedly
	  // sequential events (e.g. #4521, #6690, which have workarounds)
	  // or even between bubbling of the same event (#6566).
	  var timerFunc;

	  // The nextTick behavior leverages the microtask queue, which can be accessed
	  // via either native Promise.then or MutationObserver.
	  // MutationObserver has wider support, however it is seriously bugged in
	  // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
	  // completely stops working after triggering a few times... so, if native
	  // Promise is available, we will use it:
	  /* istanbul ignore next, $flow-disable-line */
	  if (typeof Promise !== 'undefined' && isNative(Promise)) {
	    var p = Promise.resolve();
	    timerFunc = function () {
	      p.then(flushCallbacks);
	      // In problematic UIWebViews, Promise.then doesn't completely break, but
	      // it can get stuck in a weird state where callbacks are pushed into the
	      // microtask queue but the queue isn't being flushed, until the browser
	      // needs to do some other work, e.g. handle a timer. Therefore we can
	      // "force" the microtask queue to be flushed by adding an empty timer.
	      if (isIOS) { setTimeout(noop); }
	    };
	    isUsingMicroTask = true;
	  } else if (!isIE && typeof MutationObserver !== 'undefined' && (
	    isNative(MutationObserver) ||
	    // PhantomJS and iOS 7.x
	    MutationObserver.toString() === '[object MutationObserverConstructor]'
	  )) {
	    // Use MutationObserver where native Promise is not available,
	    // e.g. PhantomJS, iOS7, Android 4.4
	    // (#6466 MutationObserver is unreliable in IE11)
	    var counter = 1;
	    var observer = new MutationObserver(flushCallbacks);
	    var textNode = document.createTextNode(String(counter));
	    observer.observe(textNode, {
	      characterData: true
	    });
	    timerFunc = function () {
	      counter = (counter + 1) % 2;
	      textNode.data = String(counter);
	    };
	    isUsingMicroTask = true;
	  } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
	    // Fallback to setImmediate.
	    // Technically it leverages the (macro) task queue,
	    // but it is still a better choice than setTimeout.
	    timerFunc = function () {
	      setImmediate(flushCallbacks);
	    };
	  } else {
	    // Fallback to setTimeout.
	    timerFunc = function () {
	      setTimeout(flushCallbacks, 0);
	    };
	  }

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

	  /*  */

	  var mark;
	  var measure;

	  {
	    var perf = inBrowser && window.performance;
	    /* istanbul ignore if */
	    if (
	      perf &&
	      perf.mark &&
	      perf.measure &&
	      perf.clearMarks &&
	      perf.clearMeasures
	    ) {
	      mark = function (tag) { return perf.mark(tag); };
	      measure = function (name, startTag, endTag) {
	        perf.measure(name, startTag, endTag);
	        perf.clearMarks(startTag);
	        perf.clearMarks(endTag);
	        // perf.clearMeasures(name)
	      };
	    }
	  }

	  /* not type checking this file because flow doesn't play well with Proxy */

	  var initProxy;

	  {
	    var allowedGlobals = makeMap(
	      'Infinity,undefined,NaN,isFinite,isNaN,' +
	      'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
	      'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' +
	      'require' // for Webpack/Browserify
	    );

	    var warnNonPresent = function (target, key) {
	      warn(
	        "Property or method \"" + key + "\" is not defined on the instance but " +
	        'referenced during render. Make sure that this property is reactive, ' +
	        'either in the data option, or for class-based components, by ' +
	        'initializing the property. ' +
	        'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
	        target
	      );
	    };

	    var warnReservedPrefix = function (target, key) {
	      warn(
	        "Property \"" + key + "\" must be accessed with \"$data." + key + "\" because " +
	        'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
	        'prevent conflicts with Vue internals. ' +
	        'See: https://vuejs.org/v2/api/#data',
	        target
	      );
	    };

	    var hasProxy =
	      typeof Proxy !== 'undefined' && isNative(Proxy);

	    if (hasProxy) {
	      var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact');
	      config.keyCodes = new Proxy(config.keyCodes, {
	        set: function set (target, key, value) {
	          if (isBuiltInModifier(key)) {
	            warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key));
	            return false
	          } else {
	            target[key] = value;
	            return true
	          }
	        }
	      });
	    }

	    var hasHandler = {
	      has: function has (target, key) {
	        var has = key in target;
	        var isAllowed = allowedGlobals(key) ||
	          (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data));
	        if (!has && !isAllowed) {
	          if (key in target.$data) { warnReservedPrefix(target, key); }
	          else { warnNonPresent(target, key); }
	        }
	        return has || !isAllowed
	      }
	    };

	    var getHandler = {
	      get: function get (target, key) {
	        if (typeof key === 'string' && !(key in target)) {
	          if (key in target.$data) { warnReservedPrefix(target, key); }
	          else { warnNonPresent(target, key); }
	        }
	        return target[key]
	      }
	    };

	    initProxy = function initProxy (vm) {
	      if (hasProxy) {
	        // determine which proxy handler to use
	        var options = vm.$options;
	        var handlers = options.render && options.render._withStripped
	          ? getHandler
	          : hasHandler;
	        vm._renderProxy = new Proxy(vm, handlers);
	      } else {
	        vm._renderProxy = vm;
	      }
	    };
	  }

	  /*  */

	  var seenObjects = new _Set();

	  /**
	   * Recursively traverse an object to evoke all converted
	   * getters, so that every nested property inside the object
	   * is collected as a "deep" dependency.
	   */
	  function traverse (val) {
	    _traverse(val, seenObjects);
	    seenObjects.clear();
	  }

	  function _traverse (val, seen) {
	    var i, keys;
	    var isA = Array.isArray(val);
	    if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) {
	      return
	    }
	    if (val.__ob__) {
	      var depId = val.__ob__.dep.id;
	      if (seen.has(depId)) {
	        return
	      }
	      seen.add(depId);
	    }
	    if (isA) {
	      i = val.length;
	      while (i--) { _traverse(val[i], seen); }
	    } else {
	      keys = Object.keys(val);
	      i = keys.length;
	      while (i--) { _traverse(val[keys[i]], seen); }
	    }
	  }

	  /*  */

	  var normalizeEvent = cached(function (name) {
	    var passive = name.charAt(0) === '&';
	    name = passive ? name.slice(1) : name;
	    var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first
	    name = once$$1 ? name.slice(1) : name;
	    var capture = name.charAt(0) === '!';
	    name = capture ? name.slice(1) : name;
	    return {
	      name: name,
	      once: once$$1,
	      capture: capture,
	      passive: passive
	    }
	  });

	  function createFnInvoker (fns, vm) {
	    function invoker () {
	      var arguments$1 = arguments;

	      var fns = invoker.fns;
	      if (Array.isArray(fns)) {
	        var cloned = fns.slice();
	        for (var i = 0; i < cloned.length; i++) {
	          invokeWithErrorHandling(cloned[i], null, arguments$1, vm, "v-on handler");
	        }
	      } else {
	        // return handler return value for single handlers
	        return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler")
	      }
	    }
	    invoker.fns = fns;
	    return invoker
	  }

	  function updateListeners (
	    on,
	    oldOn,
	    add,
	    remove$$1,
	    createOnceHandler,
	    vm
	  ) {
	    var name, def$$1, cur, old, event;
	    for (name in on) {
	      def$$1 = cur = on[name];
	      old = oldOn[name];
	      event = normalizeEvent(name);
	      if (isUndef(cur)) {
	        warn(
	          "Invalid handler for event \"" + (event.name) + "\": got " + String(cur),
	          vm
	        );
	      } else if (isUndef(old)) {
	        if (isUndef(cur.fns)) {
	          cur = on[name] = createFnInvoker(cur, vm);
	        }
	        if (isTrue(event.once)) {
	          cur = on[name] = createOnceHandler(event.name, cur, event.capture);
	        }
	        add(event.name, cur, event.capture, event.passive, event.params);
	      } else if (cur !== old) {
	        old.fns = cur;
	        on[name] = old;
	      }
	    }
	    for (name in oldOn) {
	      if (isUndef(on[name])) {
	        event = normalizeEvent(name);
	        remove$$1(event.name, oldOn[name], event.capture);
	      }
	    }
	  }

	  /*  */

	  function mergeVNodeHook (def, hookKey, hook) {
	    if (def instanceof VNode) {
	      def = def.data.hook || (def.data.hook = {});
	    }
	    var invoker;
	    var oldHook = def[hookKey];

	    function wrappedHook () {
	      hook.apply(this, arguments);
	      // important: remove merged hook to ensure it's called only once
	      // and prevent memory leak
	      remove(invoker.fns, wrappedHook);
	    }

	    if (isUndef(oldHook)) {
	      // no existing hook
	      invoker = createFnInvoker([wrappedHook]);
	    } else {
	      /* istanbul ignore if */
	      if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {
	        // already a merged invoker
	        invoker = oldHook;
	        invoker.fns.push(wrappedHook);
	      } else {
	        // existing plain hook
	        invoker = createFnInvoker([oldHook, wrappedHook]);
	      }
	    }

	    invoker.merged = true;
	    def[hookKey] = invoker;
	  }

	  /*  */

	  function extractPropsFromVNodeData (
	    data,
	    Ctor,
	    tag
	  ) {
	    // we are only extracting raw values here.
	    // validation and default values are handled in the child
	    // component itself.
	    var propOptions = Ctor.options.props;
	    if (isUndef(propOptions)) {
	      return
	    }
	    var res = {};
	    var attrs = data.attrs;
	    var props = data.props;
	    if (isDef(attrs) || isDef(props)) {
	      for (var key in propOptions) {
	        var altKey = hyphenate(key);
	        {
	          var keyInLowerCase = key.toLowerCase();
	          if (
	            key !== keyInLowerCase &&
	            attrs && hasOwn(attrs, keyInLowerCase)
	          ) {
	            tip(
	              "Prop \"" + keyInLowerCase + "\" is passed to component " +
	              (formatComponentName(tag || Ctor)) + ", but the declared prop name is" +
	              " \"" + key + "\". " +
	              "Note that HTML attributes are case-insensitive and camelCased " +
	              "props need to use their kebab-case equivalents when using in-DOM " +
	              "templates. You should probably use \"" + altKey + "\" instead of \"" + key + "\"."
	            );
	          }
	        }
	        checkProp(res, props, key, altKey, true) ||
	        checkProp(res, attrs, key, altKey, false);
	      }
	    }
	    return res
	  }

	  function checkProp (
	    res,
	    hash,
	    key,
	    altKey,
	    preserve
	  ) {
	    if (isDef(hash)) {
	      if (hasOwn(hash, key)) {
	        res[key] = hash[key];
	        if (!preserve) {
	          delete hash[key];
	        }
	        return true
	      } else if (hasOwn(hash, altKey)) {
	        res[key] = hash[altKey];
	        if (!preserve) {
	          delete hash[altKey];
	        }
	        return true
	      }
	    }
	    return false
	  }

	  /*  */

	  // The template compiler attempts to minimize the need for normalization by
	  // statically analyzing the template at compile time.
	  //
	  // For plain HTML markup, normalization can be completely skipped because the
	  // generated render function is guaranteed to return Array<VNode>. There are
	  // two cases where extra normalization is needed:

	  // 1. When the children contains components - because a functional component
	  // may return an Array instead of a single root. In this case, just a simple
	  // normalization is needed - if any child is an Array, we flatten the whole
	  // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
	  // because functional components already normalize their own children.
	  function simpleNormalizeChildren (children) {
	    for (var i = 0; i < children.length; i++) {
	      if (Array.isArray(children[i])) {
	        return Array.prototype.concat.apply([], children)
	      }
	    }
	    return children
	  }

	  // 2. When the children contains constructs that always generated nested Arrays,
	  // e.g. <template>, <slot>, v-for, or when the children is provided by user
	  // with hand-written render functions / JSX. In such cases a full normalization
	  // is needed to cater to all possible types of children values.
	  function normalizeChildren (children) {
	    return isPrimitive(children)
	      ? [createTextVNode(children)]
	      : Array.isArray(children)
	        ? normalizeArrayChildren(children)
	        : undefined
	  }

	  function isTextNode (node) {
	    return isDef(node) && isDef(node.text) && isFalse(node.isComment)
	  }

	  function normalizeArrayChildren (children, nestedIndex) {
	    var res = [];
	    var i, c, lastIndex, last;
	    for (i = 0; i < children.length; i++) {
	      c = children[i];
	      if (isUndef(c) || typeof c === 'boolean') { continue }
	      lastIndex = res.length - 1;
	      last = res[lastIndex];
	      //  nested
	      if (Array.isArray(c)) {
	        if (c.length > 0) {
	          c = normalizeArrayChildren(c, ((nestedIndex || '') + "_" + i));
	          // merge adjacent text nodes
	          if (isTextNode(c[0]) && isTextNode(last)) {
	            res[lastIndex] = createTextVNode(last.text + (c[0]).text);
	            c.shift();
	          }
	          res.push.apply(res, c);
	        }
	      } else if (isPrimitive(c)) {
	        if (isTextNode(last)) {
	          // merge adjacent text nodes
	          // this is necessary for SSR hydration because text nodes are
	          // essentially merged when rendered to HTML strings
	          res[lastIndex] = createTextVNode(last.text + c);
	        } else if (c !== '') {
	          // convert primitive to vnode
	          res.push(createTextVNode(c));
	        }
	      } else {
	        if (isTextNode(c) && isTextNode(last)) {
	          // merge adjacent text nodes
	          res[lastIndex] = createTextVNode(last.text + c.text);
	        } else {
	          // default key for nested array children (likely generated by v-for)
	          if (isTrue(children._isVList) &&
	            isDef(c.tag) &&
	            isUndef(c.key) &&
	            isDef(nestedIndex)) {
	            c.key = "__vlist" + nestedIndex + "_" + i + "__";
	          }
	          res.push(c);
	        }
	      }
	    }
	    return res
	  }

	  /*  */

	  function initProvide (vm) {
	    var provide = vm.$options.provide;
	    if (provide) {
	      vm._provided = typeof provide === 'function'
	        ? provide.call(vm)
	        : provide;
	    }
	  }

	  function initInjections (vm) {
	    var result = resolveInject(vm.$options.inject, vm);
	    if (result) {
	      toggleObserving(false);
	      Object.keys(result).forEach(function (key) {
	        /* istanbul ignore else */
	        {
	          defineReactive$$1(vm, key, result[key], function () {
	            warn(
	              "Avoid mutating an injected value directly since the changes will be " +
	              "overwritten whenever the provided component re-renders. " +
	              "injection being mutated: \"" + key + "\"",
	              vm
	            );
	          });
	        }
	      });
	      toggleObserving(true);
	    }
	  }

	  function resolveInject (inject, vm) {
	    if (inject) {
	      // inject is :any because flow is not smart enough to figure out cached
	      var result = Object.create(null);
	      var keys = hasSymbol
	        ? Reflect.ownKeys(inject)
	        : Object.keys(inject);

	      for (var i = 0; i < keys.length; i++) {
	        var key = keys[i];
	        // #6574 in case the inject object is observed...
	        if (key === '__ob__') { continue }
	        var provideKey = inject[key].from;
	        var source = vm;
	        while (source) {
	          if (source._provided && hasOwn(source._provided, provideKey)) {
	            result[key] = source._provided[provideKey];
	            break
	          }
	          source = source.$parent;
	        }
	        if (!source) {
	          if ('default' in inject[key]) {
	            var provideDefault = inject[key].default;
	            result[key] = typeof provideDefault === 'function'
	              ? provideDefault.call(vm)
	              : provideDefault;
	          } else {
	            warn(("Injection \"" + key + "\" not found"), vm);
	          }
	        }
	      }
	      return result
	    }
	  }

	  /*  */



	  /**
	   * Runtime helper for resolving raw children VNodes into a slot object.
	   */
	  function resolveSlots (
	    children,
	    context
	  ) {
	    if (!children || !children.length) {
	      return {}
	    }
	    var slots = {};
	    for (var i = 0, l = children.length; i < l; i++) {
	      var child = children[i];
	      var data = child.data;
	      // remove slot attribute if the node is resolved as a Vue slot node
	      if (data && data.attrs && data.attrs.slot) {
	        delete data.attrs.slot;
	      }
	      // named slots should only be respected if the vnode was rendered in the
	      // same context.
	      if ((child.context === context || child.fnContext === context) &&
	        data && data.slot != null
	      ) {
	        var name = data.slot;
	        var slot = (slots[name] || (slots[name] = []));
	        if (child.tag === 'template') {
	          slot.push.apply(slot, child.children || []);
	        } else {
	          slot.push(child);
	        }
	      } else {
	        (slots.default || (slots.default = [])).push(child);
	      }
	    }
	    // ignore slots that contains only whitespace
	    for (var name$1 in slots) {
	      if (slots[name$1].every(isWhitespace)) {
	        delete slots[name$1];
	      }
	    }
	    return slots
	  }

	  function isWhitespace (node) {
	    return (node.isComment && !node.asyncFactory) || node.text === ' '
	  }

	  /*  */

	  function normalizeScopedSlots (
	    slots,
	    normalSlots,
	    prevSlots
	  ) {
	    var res;
	    var hasNormalSlots = Object.keys(normalSlots).length > 0;
	    var isStable = slots ? !!slots.$stable : !hasNormalSlots;
	    var key = slots && slots.$key;
	    if (!slots) {
	      res = {};
	    } else if (slots._normalized) {
	      // fast path 1: child component re-render only, parent did not change
	      return slots._normalized
	    } else if (
	      isStable &&
	      prevSlots &&
	      prevSlots !== emptyObject &&
	      key === prevSlots.$key &&
	      !hasNormalSlots &&
	      !prevSlots.$hasNormal
	    ) {
	      // fast path 2: stable scoped slots w/ no normal slots to proxy,
	      // only need to normalize once
	      return prevSlots
	    } else {
	      res = {};
	      for (var key$1 in slots) {
	        if (slots[key$1] && key$1[0] !== '$') {
	          res[key$1] = normalizeScopedSlot(normalSlots, key$1, slots[key$1]);
	        }
	      }
	    }
	    // expose normal slots on scopedSlots
	    for (var key$2 in normalSlots) {
	      if (!(key$2 in res)) {
	        res[key$2] = proxyNormalSlot(normalSlots, key$2);
	      }
	    }
	    // avoriaz seems to mock a non-extensible $scopedSlots object
	    // and when that is passed down this would cause an error
	    if (slots && Object.isExtensible(slots)) {
	      (slots)._normalized = res;
	    }
	    def(res, '$stable', isStable);
	    def(res, '$key', key);
	    def(res, '$hasNormal', hasNormalSlots);
	    return res
	  }

	  function normalizeScopedSlot(normalSlots, key, fn) {
	    var normalized = function () {
	      var res = arguments.length ? fn.apply(null, arguments) : fn({});
	      res = res && typeof res === 'object' && !Array.isArray(res)
	        ? [res] // single vnode
	        : normalizeChildren(res);
	      return res && (
	        res.length === 0 ||
	        (res.length === 1 && res[0].isComment) // #9658
	      ) ? undefined
	        : res
	    };
	    // this is a slot using the new v-slot syntax without scope. although it is
	    // compiled as a scoped slot, render fn users would expect it to be present
	    // on this.$slots because the usage is semantically a normal slot.
	    if (fn.proxy) {
	      Object.defineProperty(normalSlots, key, {
	        get: normalized,
	        enumerable: true,
	        configurable: true
	      });
	    }
	    return normalized
	  }

	  function proxyNormalSlot(slots, key) {
	    return function () { return slots[key]; }
	  }

	  /*  */

	  /**
	   * Runtime helper for rendering v-for lists.
	   */
	  function renderList (
	    val,
	    render
	  ) {
	    var ret, i, l, keys, key;
	    if (Array.isArray(val) || typeof val === 'string') {
	      ret = new Array(val.length);
	      for (i = 0, l = val.length; i < l; i++) {
	        ret[i] = render(val[i], i);
	      }
	    } else if (typeof val === 'number') {
	      ret = new Array(val);
	      for (i = 0; i < val; i++) {
	        ret[i] = render(i + 1, i);
	      }
	    } else if (isObject(val)) {
	      if (hasSymbol && val[Symbol.iterator]) {
	        ret = [];
	        var iterator = val[Symbol.iterator]();
	        var result = iterator.next();
	        while (!result.done) {
	          ret.push(render(result.value, ret.length));
	          result = iterator.next();
	        }
	      } else {
	        keys = Object.keys(val);
	        ret = new Array(keys.length);
	        for (i = 0, l = keys.length; i < l; i++) {
	          key = keys[i];
	          ret[i] = render(val[key], key, i);
	        }
	      }
	    }
	    if (!isDef(ret)) {
	      ret = [];
	    }
	    (ret)._isVList = true;
	    return ret
	  }

	  /*  */

	  /**
	   * Runtime helper for rendering <slot>
	   */
	  function renderSlot (
	    name,
	    fallback,
	    props,
	    bindObject
	  ) {
	    var scopedSlotFn = this.$scopedSlots[name];
	    var nodes;
	    if (scopedSlotFn) { // scoped slot
	      props = props || {};
	      if (bindObject) {
	        if (!isObject(bindObject)) {
	          warn(
	            'slot v-bind without argument expects an Object',
	            this
	          );
	        }
	        props = extend(extend({}, bindObject), props);
	      }
	      nodes = scopedSlotFn(props) || fallback;
	    } else {
	      nodes = this.$slots[name] || fallback;
	    }

	    var target = props && props.slot;
	    if (target) {
	      return this.$createElement('template', { slot: target }, nodes)
	    } else {
	      return nodes
	    }
	  }

	  /*  */

	  /**
	   * Runtime helper for resolving filters
	   */
	  function resolveFilter (id) {
	    return resolveAsset(this.$options, 'filters', id, true) || identity
	  }

	  /*  */

	  function isKeyNotMatch (expect, actual) {
	    if (Array.isArray(expect)) {
	      return expect.indexOf(actual) === -1
	    } else {
	      return expect !== actual
	    }
	  }

	  /**
	   * Runtime helper for checking keyCodes from config.
	   * exposed as Vue.prototype._k
	   * passing in eventKeyName as last argument separately for backwards compat
	   */
	  function checkKeyCodes (
	    eventKeyCode,
	    key,
	    builtInKeyCode,
	    eventKeyName,
	    builtInKeyName
	  ) {
	    var mappedKeyCode = config.keyCodes[key] || builtInKeyCode;
	    if (builtInKeyName && eventKeyName && !config.keyCodes[key]) {
	      return isKeyNotMatch(builtInKeyName, eventKeyName)
	    } else if (mappedKeyCode) {
	      return isKeyNotMatch(mappedKeyCode, eventKeyCode)
	    } else if (eventKeyName) {
	      return hyphenate(eventKeyName) !== key
	    }
	  }

	  /*  */

	  /**
	   * Runtime helper for merging v-bind="object" into a VNode's data.
	   */
	  function bindObjectProps (
	    data,
	    tag,
	    value,
	    asProp,
	    isSync
	  ) {
	    if (value) {
	      if (!isObject(value)) {
	        warn(
	          'v-bind without argument expects an Object or Array value',
	          this
	        );
	      } else {
	        if (Array.isArray(value)) {
	          value = toObject(value);
	        }
	        var hash;
	        var loop = function ( key ) {
	          if (
	            key === 'class' ||
	            key === 'style' ||
	            isReservedAttribute(key)
	          ) {
	            hash = data;
	          } else {
	            var type = data.attrs && data.attrs.type;
	            hash = asProp || config.mustUseProp(tag, type, key)
	              ? data.domProps || (data.domProps = {})
	              : data.attrs || (data.attrs = {});
	          }
	          var camelizedKey = camelize(key);
	          var hyphenatedKey = hyphenate(key);
	          if (!(camelizedKey in hash) && !(hyphenatedKey in hash)) {
	            hash[key] = value[key];

	            if (isSync) {
	              var on = data.on || (data.on = {});
	              on[("update:" + key)] = function ($event) {
	                value[key] = $event;
	              };
	            }
	          }
	        };

	        for (var key in value) loop( key );
	      }
	    }
	    return data
	  }

	  /*  */

	  /**
	   * Runtime helper for rendering static trees.
	   */
	  function renderStatic (
	    index,
	    isInFor
	  ) {
	    var cached = this._staticTrees || (this._staticTrees = []);
	    var tree = cached[index];
	    // if has already-rendered static tree and not inside v-for,
	    // we can reuse the same tree.
	    if (tree && !isInFor) {
	      return tree
	    }
	    // otherwise, render a fresh tree.
	    tree = cached[index] = this.$options.staticRenderFns[index].call(
	      this._renderProxy,
	      null,
	      this // for render fns generated for functional component templates
	    );
	    markStatic(tree, ("__static__" + index), false);
	    return tree
	  }

	  /**
	   * Runtime helper for v-once.
	   * Effectively it means marking the node as static with a unique key.
	   */
	  function markOnce (
	    tree,
	    index,
	    key
	  ) {
	    markStatic(tree, ("__once__" + index + (key ? ("_" + key) : "")), true);
	    return tree
	  }

	  function markStatic (
	    tree,
	    key,
	    isOnce
	  ) {
	    if (Array.isArray(tree)) {
	      for (var i = 0; i < tree.length; i++) {
	        if (tree[i] && typeof tree[i] !== 'string') {
	          markStaticNode(tree[i], (key + "_" + i), isOnce);
	        }
	      }
	    } else {
	      markStaticNode(tree, key, isOnce);
	    }
	  }

	  function markStaticNode (node, key, isOnce) {
	    node.isStatic = true;
	    node.key = key;
	    node.isOnce = isOnce;
	  }

	  /*  */

	  function bindObjectListeners (data, value) {
	    if (value) {
	      if (!isPlainObject(value)) {
	        warn(
	          'v-on without argument expects an Object value',
	          this
	        );
	      } else {
	        var on = data.on = data.on ? extend({}, data.on) : {};
	        for (var key in value) {
	          var existing = on[key];
	          var ours = value[key];
	          on[key] = existing ? [].concat(existing, ours) : ours;
	        }
	      }
	    }
	    return data
	  }

	  /*  */

	  function resolveScopedSlots (
	    fns, // see flow/vnode
	    res,
	    // the following are added in 2.6
	    hasDynamicKeys,
	    contentHashKey
	  ) {
	    res = res || { $stable: !hasDynamicKeys };
	    for (var i = 0; i < fns.length; i++) {
	      var slot = fns[i];
	      if (Array.isArray(slot)) {
	        resolveScopedSlots(slot, res, hasDynamicKeys);
	      } else if (slot) {
	        // marker for reverse proxying v-slot without scope on this.$slots
	        if (slot.proxy) {
	          slot.fn.proxy = true;
	        }
	        res[slot.key] = slot.fn;
	      }
	    }
	    if (contentHashKey) {
	      (res).$key = contentHashKey;
	    }
	    return res
	  }

	  /*  */

	  function bindDynamicKeys (baseObj, values) {
	    for (var i = 0; i < values.length; i += 2) {
	      var key = values[i];
	      if (typeof key === 'string' && key) {
	        baseObj[values[i]] = values[i + 1];
	      } else if (key !== '' && key !== null) {
	        // null is a special value for explicitly removing a binding
	        warn(
	          ("Invalid value for dynamic directive argument (expected string or null): " + key),
	          this
	        );
	      }
	    }
	    return baseObj
	  }

	  // helper to dynamically append modifier runtime markers to event names.
	  // ensure only append when value is already string, otherwise it will be cast
	  // to string and cause the type check to miss.
	  function prependModifier (value, symbol) {
	    return typeof value === 'string' ? symbol + value : value
	  }

	  /*  */

	  function installRenderHelpers (target) {
	    target._o = markOnce;
	    target._n = toNumber;
	    target._s = toString;
	    target._l = renderList;
	    target._t = renderSlot;
	    target._q = looseEqual;
	    target._i = looseIndexOf;
	    target._m = renderStatic;
	    target._f = resolveFilter;
	    target._k = checkKeyCodes;
	    target._b = bindObjectProps;
	    target._v = createTextVNode;
	    target._e = createEmptyVNode;
	    target._u = resolveScopedSlots;
	    target._g = bindObjectListeners;
	    target._d = bindDynamicKeys;
	    target._p = prependModifier;
	  }

	  /*  */

	  function FunctionalRenderContext (
	    data,
	    props,
	    children,
	    parent,
	    Ctor
	  ) {
	    var this$1 = this;

	    var options = Ctor.options;
	    // ensure the createElement function in functional components
	    // gets a unique context - this is necessary for correct named slot check
	    var contextVm;
	    if (hasOwn(parent, '_uid')) {
	      contextVm = Object.create(parent);
	      // $flow-disable-line
	      contextVm._original = parent;
	    } else {
	      // the context vm passed in is a functional context as well.
	      // in this case we want to make sure we are able to get a hold to the
	      // real context instance.
	      contextVm = parent;
	      // $flow-disable-line
	      parent = parent._original;
	    }
	    var isCompiled = isTrue(options._compiled);
	    var needNormalization = !isCompiled;

	    this.data = data;
	    this.props = props;
	    this.children = children;
	    this.parent = parent;
	    this.listeners = data.on || emptyObject;
	    this.injections = resolveInject(options.inject, parent);
	    this.slots = function () {
	      if (!this$1.$slots) {
	        normalizeScopedSlots(
	          data.scopedSlots,
	          this$1.$slots = resolveSlots(children, parent)
	        );
	      }
	      return this$1.$slots
	    };

	    Object.defineProperty(this, 'scopedSlots', ({
	      enumerable: true,
	      get: function get () {
	        return normalizeScopedSlots(data.scopedSlots, this.slots())
	      }
	    }));

	    // support for compiled functional template
	    if (isCompiled) {
	      // exposing $options for renderStatic()
	      this.$options = options;
	      // pre-resolve slots for renderSlot()
	      this.$slots = this.slots();
	      this.$scopedSlots = normalizeScopedSlots(data.scopedSlots, this.$slots);
	    }

	    if (options._scopeId) {
	      this._c = function (a, b, c, d) {
	        var vnode = createElement(contextVm, a, b, c, d, needNormalization);
	        if (vnode && !Array.isArray(vnode)) {
	          vnode.fnScopeId = options._scopeId;
	          vnode.fnContext = parent;
	        }
	        return vnode
	      };
	    } else {
	      this._c = function (a, b, c, d) { return createElement(contextVm, a, b, c, d, needNormalization); };
	    }
	  }

	  installRenderHelpers(FunctionalRenderContext.prototype);

	  function createFunctionalComponent (
	    Ctor,
	    propsData,
	    data,
	    contextVm,
	    children
	  ) {
	    var options = Ctor.options;
	    var props = {};
	    var propOptions = options.props;
	    if (isDef(propOptions)) {
	      for (var key in propOptions) {
	        props[key] = validateProp(key, propOptions, propsData || emptyObject);
	      }
	    } else {
	      if (isDef(data.attrs)) { mergeProps(props, data.attrs); }
	      if (isDef(data.props)) { mergeProps(props, data.props); }
	    }

	    var renderContext = new FunctionalRenderContext(
	      data,
	      props,
	      children,
	      contextVm,
	      Ctor
	    );

	    var vnode = options.render.call(null, renderContext._c, renderContext);

	    if (vnode instanceof VNode) {
	      return cloneAndMarkFunctionalResult(vnode, data, renderContext.parent, options, renderContext)
	    } else if (Array.isArray(vnode)) {
	      var vnodes = normalizeChildren(vnode) || [];
	      var res = new Array(vnodes.length);
	      for (var i = 0; i < vnodes.length; i++) {
	        res[i] = cloneAndMarkFunctionalResult(vnodes[i], data, renderContext.parent, options, renderContext);
	      }
	      return res
	    }
	  }

	  function cloneAndMarkFunctionalResult (vnode, data, contextVm, options, renderContext) {
	    // #7817 clone node before setting fnContext, otherwise if the node is reused
	    // (e.g. it was from a cached normal slot) the fnContext causes named slots
	    // that should not be matched to match.
	    var clone = cloneVNode(vnode);
	    clone.fnContext = contextVm;
	    clone.fnOptions = options;
	    {
	      (clone.devtoolsMeta = clone.devtoolsMeta || {}).renderContext = renderContext;
	    }
	    if (data.slot) {
	      (clone.data || (clone.data = {})).slot = data.slot;
	    }
	    return clone
	  }

	  function mergeProps (to, from) {
	    for (var key in from) {
	      to[camelize(key)] = from[key];
	    }
	  }

	  /*  */

	  /*  */

	  /*  */

	  /*  */

	  // inline hooks to be invoked on component VNodes during patch
	  var componentVNodeHooks = {
	    init: function init (vnode, hydrating) {
	      if (
	        vnode.componentInstance &&
	        !vnode.componentInstance._isDestroyed &&
	        vnode.data.keepAlive
	      ) {
	        // kept-alive components, treat as a patch
	        var mountedNode = vnode; // work around flow
	        componentVNodeHooks.prepatch(mountedNode, mountedNode);
	      } else {
	        var child = vnode.componentInstance = createComponentInstanceForVnode(
	          vnode,
	          activeInstance
	        );
	        child.$mount(hydrating ? vnode.elm : undefined, hydrating);
	      }
	    },

	    prepatch: function prepatch (oldVnode, vnode) {
	      var options = vnode.componentOptions;
	      var child = vnode.componentInstance = oldVnode.componentInstance;
	      updateChildComponent(
	        child,
	        options.propsData, // updated props
	        options.listeners, // updated listeners
	        vnode, // new parent vnode
	        options.children // new children
	      );
	    },

	    insert: function insert (vnode) {
	      var context = vnode.context;
	      var componentInstance = vnode.componentInstance;
	      if (!componentInstance._isMounted) {
	        componentInstance._isMounted = true;
	        callHook(componentInstance, 'mounted');
	      }
	      if (vnode.data.keepAlive) {
	        if (context._isMounted) {
	          // vue-router#1212
	          // During updates, a kept-alive component's child components may
	          // change, so directly walking the tree here may call activated hooks
	          // on incorrect children. Instead we push them into a queue which will
	          // be processed after the whole patch process ended.
	          queueActivatedComponent(componentInstance);
	        } else {
	          activateChildComponent(componentInstance, true /* direct */);
	        }
	      }
	    },

	    destroy: function destroy (vnode) {
	      var componentInstance = vnode.componentInstance;
	      if (!componentInstance._isDestroyed) {
	        if (!vnode.data.keepAlive) {
	          componentInstance.$destroy();
	        } else {
	          deactivateChildComponent(componentInstance, true /* direct */);
	        }
	      }
	    }
	  };

	  var hooksToMerge = Object.keys(componentVNodeHooks);

	  function createComponent (
	    Ctor,
	    data,
	    context,
	    children,
	    tag
	  ) {
	    if (isUndef(Ctor)) {
	      return
	    }

	    var baseCtor = context.$options._base;

	    // plain options object: turn it into a constructor
	    if (isObject(Ctor)) {
	      Ctor = baseCtor.extend(Ctor);
	    }

	    // if at this stage it's not a constructor or an async component factory,
	    // reject.
	    if (typeof Ctor !== 'function') {
	      {
	        warn(("Invalid Component definition: " + (String(Ctor))), context);
	      }
	      return
	    }

	    // async component
	    var asyncFactory;
	    if (isUndef(Ctor.cid)) {
	      asyncFactory = Ctor;
	      Ctor = resolveAsyncComponent(asyncFactory, baseCtor);
	      if (Ctor === undefined) {
	        // return a placeholder node for async component, which is rendered
	        // as a comment node but preserves all the raw information for the node.
	        // the information will be used for async server-rendering and hydration.
	        return createAsyncPlaceholder(
	          asyncFactory,
	          data,
	          context,
	          children,
	          tag
	        )
	      }
	    }

	    data = data || {};

	    // resolve constructor options in case global mixins are applied after
	    // component constructor creation
	    resolveConstructorOptions(Ctor);

	    // transform component v-model data into props & events
	    if (isDef(data.model)) {
	      transformModel(Ctor.options, data);
	    }

	    // extract props
	    var propsData = extractPropsFromVNodeData(data, Ctor, tag);

	    // functional component
	    if (isTrue(Ctor.options.functional)) {
	      return createFunctionalComponent(Ctor, propsData, data, context, children)
	    }

	    // extract listeners, since these needs to be treated as
	    // child component listeners instead of DOM listeners
	    var listeners = data.on;
	    // replace with listeners with .native modifier
	    // so it gets processed during parent component patch.
	    data.on = data.nativeOn;

	    if (isTrue(Ctor.options.abstract)) {
	      // abstract components do not keep anything
	      // other than props & listeners & slot

	      // work around flow
	      var slot = data.slot;
	      data = {};
	      if (slot) {
	        data.slot = slot;
	      }
	    }

	    // install component management hooks onto the placeholder node
	    installComponentHooks(data);

	    // return a placeholder vnode
	    var name = Ctor.options.name || tag;
	    var vnode = new VNode(
	      ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')),
	      data, undefined, undefined, undefined, context,
	      { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children },
	      asyncFactory
	    );

	    return vnode
	  }

	  function createComponentInstanceForVnode (
	    vnode, // we know it's MountedComponentVNode but flow doesn't
	    parent // activeInstance in lifecycle state
	  ) {
	    var options = {
	      _isComponent: true,
	      _parentVnode: vnode,
	      parent: parent
	    };
	    // check inline-template render functions
	    var inlineTemplate = vnode.data.inlineTemplate;
	    if (isDef(inlineTemplate)) {
	      options.render = inlineTemplate.render;
	      options.staticRenderFns = inlineTemplate.staticRenderFns;
	    }
	    return new vnode.componentOptions.Ctor(options)
	  }

	  function installComponentHooks (data) {
	    var hooks = data.hook || (data.hook = {});
	    for (var i = 0; i < hooksToMerge.length; i++) {
	      var key = hooksToMerge[i];
	      var existing = hooks[key];
	      var toMerge = componentVNodeHooks[key];
	      if (existing !== toMerge && !(existing && existing._merged)) {
	        hooks[key] = existing ? mergeHook$1(toMerge, existing) : toMerge;
	      }
	    }
	  }

	  function mergeHook$1 (f1, f2) {
	    var merged = function (a, b) {
	      // flow complains about extra args which is why we use any
	      f1(a, b);
	      f2(a, b);
	    };
	    merged._merged = true;
	    return merged
	  }

	  // transform component v-model info (value and callback) into
	  // prop and event handler respectively.
	  function transformModel (options, data) {
	    var prop = (options.model && options.model.prop) || 'value';
	    var event = (options.model && options.model.event) || 'input'
	    ;(data.attrs || (data.attrs = {}))[prop] = data.model.value;
	    var on = data.on || (data.on = {});
	    var existing = on[event];
	    var callback = data.model.callback;
	    if (isDef(existing)) {
	      if (
	        Array.isArray(existing)
	          ? existing.indexOf(callback) === -1
	          : existing !== callback
	      ) {
	        on[event] = [callback].concat(existing);
	      }
	    } else {
	      on[event] = callback;
	    }
	  }

	  /*  */

	  var SIMPLE_NORMALIZE = 1;
	  var ALWAYS_NORMALIZE = 2;

	  // wrapper function for providing a more flexible interface
	  // without getting yelled at by flow
	  function createElement (
	    context,
	    tag,
	    data,
	    children,
	    normalizationType,
	    alwaysNormalize
	  ) {
	    if (Array.isArray(data) || isPrimitive(data)) {
	      normalizationType = children;
	      children = data;
	      data = undefined;
	    }
	    if (isTrue(alwaysNormalize)) {
	      normalizationType = ALWAYS_NORMALIZE;
	    }
	    return _createElement(context, tag, data, children, normalizationType)
	  }

	  function _createElement (
	    context,
	    tag,
	    data,
	    children,
	    normalizationType
	  ) {
	    if (isDef(data) && isDef((data).__ob__)) {
	      warn(
	        "Avoid using observed data object as vnode data: " + (JSON.stringify(data)) + "\n" +
	        'Always create fresh vnode data objects in each render!',
	        context
	      );
	      return createEmptyVNode()
	    }
	    // object syntax in v-bind
	    if (isDef(data) && isDef(data.is)) {
	      tag = data.is;
	    }
	    if (!tag) {
	      // in case of component :is set to falsy value
	      return createEmptyVNode()
	    }
	    // warn against non-primitive key
	    if (isDef(data) && isDef(data.key) && !isPrimitive(data.key)
	    ) {
	      {
	        warn(
	          'Avoid using non-primitive value as key, ' +
	          'use string/number value instead.',
	          context
	        );
	      }
	    }
	    // support single function children as default scoped slot
	    if (Array.isArray(children) &&
	      typeof children[0] === 'function'
	    ) {
	      data = data || {};
	      data.scopedSlots = { default: children[0] };
	      children.length = 0;
	    }
	    if (normalizationType === ALWAYS_NORMALIZE) {
	      children = normalizeChildren(children);
	    } else if (normalizationType === SIMPLE_NORMALIZE) {
	      children = simpleNormalizeChildren(children);
	    }
	    var vnode, ns;
	    if (typeof tag === 'string') {
	      var Ctor;
	      ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag);
	      if (config.isReservedTag(tag)) {
	        // platform built-in elements
	        if (isDef(data) && isDef(data.nativeOn)) {
	          warn(
	            ("The .native modifier for v-on is only valid on components but it was used on <" + tag + ">."),
	            context
	          );
	        }
	        vnode = new VNode(
	          config.parsePlatformTagName(tag), data, children,
	          undefined, undefined, context
	        );
	      } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
	        // component
	        vnode = createComponent(Ctor, data, context, children, tag);
	      } else {
	        // unknown or unlisted namespaced elements
	        // check at runtime because it may get assigned a namespace when its
	        // parent normalizes children
	        vnode = new VNode(
	          tag, data, children,
	          undefined, undefined, context
	        );
	      }
	    } else {
	      // direct component options / constructor
	      vnode = createComponent(tag, data, context, children);
	    }
	    if (Array.isArray(vnode)) {
	      return vnode
	    } else if (isDef(vnode)) {
	      if (isDef(ns)) { applyNS(vnode, ns); }
	      if (isDef(data)) { registerDeepBindings(data); }
	      return vnode
	    } else {
	      return createEmptyVNode()
	    }
	  }

	  function applyNS (vnode, ns, force) {
	    vnode.ns = ns;
	    if (vnode.tag === 'foreignObject') {
	      // use default namespace inside foreignObject
	      ns = undefined;
	      force = true;
	    }
	    if (isDef(vnode.children)) {
	      for (var i = 0, l = vnode.children.length; i < l; i++) {
	        var child = vnode.children[i];
	        if (isDef(child.tag) && (
	          isUndef(child.ns) || (isTrue(force) && child.tag !== 'svg'))) {
	          applyNS(child, ns, force);
	        }
	      }
	    }
	  }

	  // ref #5318
	  // necessary to ensure parent re-render when deep bindings like :style and
	  // :class are used on slot nodes
	  function registerDeepBindings (data) {
	    if (isObject(data.style)) {
	      traverse(data.style);
	    }
	    if (isObject(data.class)) {
	      traverse(data.class);
	    }
	  }

	  /*  */

	  function initRender (vm) {
	    vm._vnode = null; // the root of the child tree
	    vm._staticTrees = null; // v-once cached trees
	    var options = vm.$options;
	    var parentVnode = vm.$vnode = options._parentVnode; // the placeholder node in parent tree
	    var renderContext = parentVnode && parentVnode.context;
	    vm.$slots = resolveSlots(options._renderChildren, renderContext);
	    vm.$scopedSlots = emptyObject;
	    // bind the createElement fn to this instance
	    // so that we get proper render context inside it.
	    // args order: tag, data, children, normalizationType, alwaysNormalize
	    // internal version is used by render functions compiled from templates
	    vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };
	    // normalization is always applied for the public version, used in
	    // user-written render functions.
	    vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };

	    // $attrs & $listeners are exposed for easier HOC creation.
	    // they need to be reactive so that HOCs using them are always updated
	    var parentData = parentVnode && parentVnode.data;

	    /* istanbul ignore else */
	    {
	      defineReactive$$1(vm, '$attrs', parentData && parentData.attrs || emptyObject, function () {
	        !isUpdatingChildComponent && warn("$attrs is readonly.", vm);
	      }, true);
	      defineReactive$$1(vm, '$listeners', options._parentListeners || emptyObject, function () {
	        !isUpdatingChildComponent && warn("$listeners is readonly.", vm);
	      }, true);
	    }
	  }

	  var currentRenderingInstance = null;

	  function renderMixin (Vue) {
	    // install runtime convenience helpers
	    installRenderHelpers(Vue.prototype);

	    Vue.prototype.$nextTick = function (fn) {
	      return nextTick(fn, this)
	    };

	    Vue.prototype._render = function () {
	      var vm = this;
	      var ref = vm.$options;
	      var render = ref.render;
	      var _parentVnode = ref._parentVnode;

	      if (_parentVnode) {
	        vm.$scopedSlots = normalizeScopedSlots(
	          _parentVnode.data.scopedSlots,
	          vm.$slots,
	          vm.$scopedSlots
	        );
	      }

	      // set parent vnode. this allows render functions to have access
	      // to the data on the placeholder node.
	      vm.$vnode = _parentVnode;
	      // render self
	      var vnode;
	      try {
	        // There's no need to maintain a stack because all render fns are called
	        // separately from one another. Nested component's render fns are called
	        // when parent component is patched.
	        currentRenderingInstance = vm;
	        vnode = render.call(vm._renderProxy, vm.$createElement);
	      } catch (e) {
	        handleError(e, vm, "render");
	        // return error render result,
	        // or previous vnode to prevent render error causing blank component
	        /* istanbul ignore else */
	        if (vm.$options.renderError) {
	          try {
	            vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e);
	          } catch (e) {
	            handleError(e, vm, "renderError");
	            vnode = vm._vnode;
	          }
	        } else {
	          vnode = vm._vnode;
	        }
	      } finally {
	        currentRenderingInstance = null;
	      }
	      // if the returned array contains only a single node, allow it
	      if (Array.isArray(vnode) && vnode.length === 1) {
	        vnode = vnode[0];
	      }
	      // return empty vnode in case the render function errored out
	      if (!(vnode instanceof VNode)) {
	        if (Array.isArray(vnode)) {
	          warn(
	            'Multiple root nodes returned from render function. Render function ' +
	            'should return a single root node.',
	            vm
	          );
	        }
	        vnode = createEmptyVNode();
	      }
	      // set parent
	      vnode.parent = _parentVnode;
	      return vnode
	    };
	  }

	  /*  */

	  function ensureCtor (comp, base) {
	    if (
	      comp.__esModule ||
	      (hasSymbol && comp[Symbol.toStringTag] === 'Module')
	    ) {
	      comp = comp.default;
	    }
	    return isObject(comp)
	      ? base.extend(comp)
	      : comp
	  }

	  function createAsyncPlaceholder (
	    factory,
	    data,
	    context,
	    children,
	    tag
	  ) {
	    var node = createEmptyVNode();
	    node.asyncFactory = factory;
	    node.asyncMeta = { data: data, context: context, children: children, tag: tag };
	    return node
	  }

	  function resolveAsyncComponent (
	    factory,
	    baseCtor
	  ) {
	    if (isTrue(factory.error) && isDef(factory.errorComp)) {
	      return factory.errorComp
	    }

	    if (isDef(factory.resolved)) {
	      return factory.resolved
	    }

	    var owner = currentRenderingInstance;
	    if (owner && isDef(factory.owners) && factory.owners.indexOf(owner) === -1) {
	      // already pending
	      factory.owners.push(owner);
	    }

	    if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
	      return factory.loadingComp
	    }

	    if (owner && !isDef(factory.owners)) {
	      var owners = factory.owners = [owner];
	      var sync = true;
	      var timerLoading = null;
	      var timerTimeout = null

	      ;(owner).$on('hook:destroyed', function () { return remove(owners, owner); });

	      var forceRender = function (renderCompleted) {
	        for (var i = 0, l = owners.length; i < l; i++) {
	          (owners[i]).$forceUpdate();
	        }

	        if (renderCompleted) {
	          owners.length = 0;
	          if (timerLoading !== null) {
	            clearTimeout(timerLoading);
	            timerLoading = null;
	          }
	          if (timerTimeout !== null) {
	            clearTimeout(timerTimeout);
	            timerTimeout = null;
	          }
	        }
	      };

	      var resolve = once(function (res) {
	        // cache resolved
	        factory.resolved = ensureCtor(res, baseCtor);
	        // invoke callbacks only if this is not a synchronous resolve
	        // (async resolves are shimmed as synchronous during SSR)
	        if (!sync) {
	          forceRender(true);
	        } else {
	          owners.length = 0;
	        }
	      });

	      var reject = once(function (reason) {
	        warn(
	          "Failed to resolve async component: " + (String(factory)) +
	          (reason ? ("\nReason: " + reason) : '')
	        );
	        if (isDef(factory.errorComp)) {
	          factory.error = true;
	          forceRender(true);
	        }
	      });

	      var res = factory(resolve, reject);

	      if (isObject(res)) {
	        if (isPromise(res)) {
	          // () => Promise
	          if (isUndef(factory.resolved)) {
	            res.then(resolve, reject);
	          }
	        } else if (isPromise(res.component)) {
	          res.component.then(resolve, reject);

	          if (isDef(res.error)) {
	            factory.errorComp = ensureCtor(res.error, baseCtor);
	          }

	          if (isDef(res.loading)) {
	            factory.loadingComp = ensureCtor(res.loading, baseCtor);
	            if (res.delay === 0) {
	              factory.loading = true;
	            } else {
	              timerLoading = setTimeout(function () {
	                timerLoading = null;
	                if (isUndef(factory.resolved) && isUndef(factory.error)) {
	                  factory.loading = true;
	                  forceRender(false);
	                }
	              }, res.delay || 200);
	            }
	          }

	          if (isDef(res.timeout)) {
	            timerTimeout = setTimeout(function () {
	              timerTimeout = null;
	              if (isUndef(factory.resolved)) {
	                reject(
	                  "timeout (" + (res.timeout) + "ms)"
	                );
	              }
	            }, res.timeout);
	          }
	        }
	      }

	      sync = false;
	      // return in case resolved synchronously
	      return factory.loading
	        ? factory.loadingComp
	        : factory.resolved
	    }
	  }

	  /*  */

	  function isAsyncPlaceholder (node) {
	    return node.isComment && node.asyncFactory
	  }

	  /*  */

	  function getFirstComponentChild (children) {
	    if (Array.isArray(children)) {
	      for (var i = 0; i < children.length; i++) {
	        var c = children[i];
	        if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
	          return c
	        }
	      }
	    }
	  }

	  /*  */

	  /*  */

	  function initEvents (vm) {
	    vm._events = Object.create(null);
	    vm._hasHookEvent = false;
	    // init parent attached events
	    var listeners = vm.$options._parentListeners;
	    if (listeners) {
	      updateComponentListeners(vm, listeners);
	    }
	  }

	  var target;

	  function add (event, fn) {
	    target.$on(event, fn);
	  }

	  function remove$1 (event, fn) {
	    target.$off(event, fn);
	  }

	  function createOnceHandler (event, fn) {
	    var _target = target;
	    return function onceHandler () {
	      var res = fn.apply(null, arguments);
	      if (res !== null) {
	        _target.$off(event, onceHandler);
	      }
	    }
	  }

	  function updateComponentListeners (
	    vm,
	    listeners,
	    oldListeners
	  ) {
	    target = vm;
	    updateListeners(listeners, oldListeners || {}, add, remove$1, createOnceHandler, vm);
	    target = undefined;
	  }

	  function eventsMixin (Vue) {
	    var hookRE = /^hook:/;
	    Vue.prototype.$on = function (event, fn) {
	      var vm = this;
	      if (Array.isArray(event)) {
	        for (var i = 0, l = event.length; i < l; i++) {
	          vm.$on(event[i], fn);
	        }
	      } else {
	        (vm._events[event] || (vm._events[event] = [])).push(fn);
	        // optimize hook:event cost by using a boolean flag marked at registration
	        // instead of a hash lookup
	        if (hookRE.test(event)) {
	          vm._hasHookEvent = true;
	        }
	      }
	      return vm
	    };

	    Vue.prototype.$once = function (event, fn) {
	      var vm = this;
	      function on () {
	        vm.$off(event, on);
	        fn.apply(vm, arguments);
	      }
	      on.fn = fn;
	      vm.$on(event, on);
	      return vm
	    };

	    Vue.prototype.$off = function (event, fn) {
	      var vm = this;
	      // all
	      if (!arguments.length) {
	        vm._events = Object.create(null);
	        return vm
	      }
	      // array of events
	      if (Array.isArray(event)) {
	        for (var i$1 = 0, l = event.length; i$1 < l; i$1++) {
	          vm.$off(event[i$1], fn);
	        }
	        return vm
	      }
	      // specific event
	      var cbs = vm._events[event];
	      if (!cbs) {
	        return vm
	      }
	      if (!fn) {
	        vm._events[event] = null;
	        return vm
	      }
	      // specific handler
	      var cb;
	      var i = cbs.length;
	      while (i--) {
	        cb = cbs[i];
	        if (cb === fn || cb.fn === fn) {
	          cbs.splice(i, 1);
	          break
	        }
	      }
	      return vm
	    };

	    Vue.prototype.$emit = function (event) {
	      var vm = this;
	      {
	        var lowerCaseEvent = event.toLowerCase();
	        if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
	          tip(
	            "Event \"" + lowerCaseEvent + "\" is emitted in component " +
	            (formatComponentName(vm)) + " but the handler is registered for \"" + event + "\". " +
	            "Note that HTML attributes are case-insensitive and you cannot use " +
	            "v-on to listen to camelCase events when using in-DOM templates. " +
	            "You should probably use \"" + (hyphenate(event)) + "\" instead of \"" + event + "\"."
	          );
	        }
	      }
	      var cbs = vm._events[event];
	      if (cbs) {
	        cbs = cbs.length > 1 ? toArray(cbs) : cbs;
	        var args = toArray(arguments, 1);
	        var info = "event handler for \"" + event + "\"";
	        for (var i = 0, l = cbs.length; i < l; i++) {
	          invokeWithErrorHandling(cbs[i], vm, args, vm, info);
	        }
	      }
	      return vm
	    };
	  }

	  /*  */

	  var activeInstance = null;
	  var isUpdatingChildComponent = false;

	  function setActiveInstance(vm) {
	    var prevActiveInstance = activeInstance;
	    activeInstance = vm;
	    return function () {
	      activeInstance = prevActiveInstance;
	    }
	  }

	  function initLifecycle (vm) {
	    var options = vm.$options;

	    // locate first non-abstract parent
	    var parent = options.parent;
	    if (parent && !options.abstract) {
	      while (parent.$options.abstract && parent.$parent) {
	        parent = parent.$parent;
	      }
	      parent.$children.push(vm);
	    }

	    vm.$parent = parent;
	    vm.$root = parent ? parent.$root : vm;

	    vm.$children = [];
	    vm.$refs = {};

	    vm._watcher = null;
	    vm._inactive = null;
	    vm._directInactive = false;
	    vm._isMounted = false;
	    vm._isDestroyed = false;
	    vm._isBeingDestroyed = false;
	  }

	  function lifecycleMixin (Vue) {
	    Vue.prototype._update = function (vnode, hydrating) {
	      var vm = this;
	      var prevEl = vm.$el;
	      var prevVnode = vm._vnode;
	      var restoreActiveInstance = setActiveInstance(vm);
	      vm._vnode = vnode;
	      // Vue.prototype.__patch__ is injected in entry points
	      // based on the rendering backend used.
	      if (!prevVnode) {
	        // initial render
	        vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
	      } else {
	        // updates
	        vm.$el = vm.__patch__(prevVnode, vnode);
	      }
	      restoreActiveInstance();
	      // update __vue__ reference
	      if (prevEl) {
	        prevEl.__vue__ = null;
	      }
	      if (vm.$el) {
	        vm.$el.__vue__ = vm;
	      }
	      // if parent is an HOC, update its $el as well
	      if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
	        vm.$parent.$el = vm.$el;
	      }
	      // updated hook is called by the scheduler to ensure that children are
	      // updated in a parent's updated hook.
	    };

	    Vue.prototype.$forceUpdate = function () {
	      var vm = this;
	      if (vm._watcher) {
	        vm._watcher.update();
	      }
	    };

	    Vue.prototype.$destroy = function () {
	      var vm = this;
	      if (vm._isBeingDestroyed) {
	        return
	      }
	      callHook(vm, 'beforeDestroy');
	      vm._isBeingDestroyed = true;
	      // remove self from parent
	      var parent = vm.$parent;
	      if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
	        remove(parent.$children, vm);
	      }
	      // teardown watchers
	      if (vm._watcher) {
	        vm._watcher.teardown();
	      }
	      var i = vm._watchers.length;
	      while (i--) {
	        vm._watchers[i].teardown();
	      }
	      // remove reference from data ob
	      // frozen object may not have observer.
	      if (vm._data.__ob__) {
	        vm._data.__ob__.vmCount--;
	      }
	      // call the last hook...
	      vm._isDestroyed = true;
	      // invoke destroy hooks on current rendered tree
	      vm.__patch__(vm._vnode, null);
	      // fire destroyed hook
	      callHook(vm, 'destroyed');
	      // turn off all instance listeners.
	      vm.$off();
	      // remove __vue__ reference
	      if (vm.$el) {
	        vm.$el.__vue__ = null;
	      }
	      // release circular reference (#6759)
	      if (vm.$vnode) {
	        vm.$vnode.parent = null;
	      }
	    };
	  }

	  function mountComponent (
	    vm,
	    el,
	    hydrating
	  ) {
	    vm.$el = el;
	    if (!vm.$options.render) {
	      vm.$options.render = createEmptyVNode;
	      {
	        /* istanbul ignore if */
	        if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||
	          vm.$options.el || el) {
	          warn(
	            'You are using the runtime-only build of Vue where the template ' +
	            'compiler is not available. Either pre-compile the templates into ' +
	            'render functions, or use the compiler-included build.',
	            vm
	          );
	        } else {
	          warn(
	            'Failed to mount component: template or render function not defined.',
	            vm
	          );
	        }
	      }
	    }
	    callHook(vm, 'beforeMount');

	    var updateComponent;
	    /* istanbul ignore if */
	    if (config.performance && mark) {
	      updateComponent = function () {
	        var name = vm._name;
	        var id = vm._uid;
	        var startTag = "vue-perf-start:" + id;
	        var endTag = "vue-perf-end:" + id;

	        mark(startTag);
	        var vnode = vm._render();
	        mark(endTag);
	        measure(("vue " + name + " render"), startTag, endTag);

	        mark(startTag);
	        vm._update(vnode, hydrating);
	        mark(endTag);
	        measure(("vue " + name + " patch"), startTag, endTag);
	      };
	    } else {
	      updateComponent = function () {
	        vm._update(vm._render(), hydrating);
	      };
	    }

	    // we set this to vm._watcher inside the watcher's constructor
	    // since the watcher's initial patch may call $forceUpdate (e.g. inside child
	    // component's mounted hook), which relies on vm._watcher being already defined
	    new Watcher(vm, updateComponent, noop, {
	      before: function before () {
	        if (vm._isMounted && !vm._isDestroyed) {
	          callHook(vm, 'beforeUpdate');
	        }
	      }
	    }, true /* isRenderWatcher */);
	    hydrating = false;

	    // manually mounted instance, call mounted on self
	    // mounted is called for render-created child components in its inserted hook
	    if (vm.$vnode == null) {
	      vm._isMounted = true;
	      callHook(vm, 'mounted');
	    }
	    return vm
	  }

	  function updateChildComponent (
	    vm,
	    propsData,
	    listeners,
	    parentVnode,
	    renderChildren
	  ) {
	    {
	      isUpdatingChildComponent = true;
	    }

	    // determine whether component has slot children
	    // we need to do this before overwriting $options._renderChildren.

	    // check if there are dynamic scopedSlots (hand-written or compiled but with
	    // dynamic slot names). Static scoped slots compiled from template has the
	    // "$stable" marker.
	    var newScopedSlots = parentVnode.data.scopedSlots;
	    var oldScopedSlots = vm.$scopedSlots;
	    var hasDynamicScopedSlot = !!(
	      (newScopedSlots && !newScopedSlots.$stable) ||
	      (oldScopedSlots !== emptyObject && !oldScopedSlots.$stable) ||
	      (newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key)
	    );

	    // Any static slot children from the parent may have changed during parent's
	    // update. Dynamic scoped slots may also have changed. In such cases, a forced
	    // update is necessary to ensure correctness.
	    var needsForceUpdate = !!(
	      renderChildren ||               // has new static slots
	      vm.$options._renderChildren ||  // has old static slots
	      hasDynamicScopedSlot
	    );

	    vm.$options._parentVnode = parentVnode;
	    vm.$vnode = parentVnode; // update vm's placeholder node without re-render

	    if (vm._vnode) { // update child tree's parent
	      vm._vnode.parent = parentVnode;
	    }
	    vm.$options._renderChildren = renderChildren;

	    // update $attrs and $listeners hash
	    // these are also reactive so they may trigger child update if the child
	    // used them during render
	    vm.$attrs = parentVnode.data.attrs || emptyObject;
	    vm.$listeners = listeners || emptyObject;

	    // update props
	    if (propsData && vm.$options.props) {
	      toggleObserving(false);
	      var props = vm._props;
	      var propKeys = vm.$options._propKeys || [];
	      for (var i = 0; i < propKeys.length; i++) {
	        var key = propKeys[i];
	        var propOptions = vm.$options.props; // wtf flow?
	        props[key] = validateProp(key, propOptions, propsData, vm);
	      }
	      toggleObserving(true);
	      // keep a copy of raw propsData
	      vm.$options.propsData = propsData;
	    }

	    // update listeners
	    listeners = listeners || emptyObject;
	    var oldListeners = vm.$options._parentListeners;
	    vm.$options._parentListeners = listeners;
	    updateComponentListeners(vm, listeners, oldListeners);

	    // resolve slots + force update if has children
	    if (needsForceUpdate) {
	      vm.$slots = resolveSlots(renderChildren, parentVnode.context);
	      vm.$forceUpdate();
	    }

	    {
	      isUpdatingChildComponent = false;
	    }
	  }

	  function isInInactiveTree (vm) {
	    while (vm && (vm = vm.$parent)) {
	      if (vm._inactive) { return true }
	    }
	    return false
	  }

	  function activateChildComponent (vm, direct) {
	    if (direct) {
	      vm._directInactive = false;
	      if (isInInactiveTree(vm)) {
	        return
	      }
	    } else if (vm._directInactive) {
	      return
	    }
	    if (vm._inactive || vm._inactive === null) {
	      vm._inactive = false;
	      for (var i = 0; i < vm.$children.length; i++) {
	        activateChildComponent(vm.$children[i]);
	      }
	      callHook(vm, 'activated');
	    }
	  }

	  function deactivateChildComponent (vm, direct) {
	    if (direct) {
	      vm._directInactive = true;
	      if (isInInactiveTree(vm)) {
	        return
	      }
	    }
	    if (!vm._inactive) {
	      vm._inactive = true;
	      for (var i = 0; i < vm.$children.length; i++) {
	        deactivateChildComponent(vm.$children[i]);
	      }
	      callHook(vm, 'deactivated');
	    }
	  }

	  function callHook (vm, hook) {
	    // #7573 disable dep collection when invoking lifecycle hooks
	    pushTarget();
	    var handlers = vm.$options[hook];
	    var info = hook + " hook";
	    if (handlers) {
	      for (var i = 0, j = handlers.length; i < j; i++) {
	        invokeWithErrorHandling(handlers[i], vm, null, vm, info);
	      }
	    }
	    if (vm._hasHookEvent) {
	      vm.$emit('hook:' + hook);
	    }
	    popTarget();
	  }

	  /*  */

	  var MAX_UPDATE_COUNT = 100;

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

	  /**
	   * Reset the scheduler's state.
	   */
	  function resetSchedulerState () {
	    index = queue.length = activatedChildren.length = 0;
	    has = {};
	    {
	      circular = {};
	    }
	    waiting = flushing = false;
	  }

	  // Async edge case #6566 requires saving the timestamp when event listeners are
	  // attached. However, calling performance.now() has a perf overhead especially
	  // if the page has thousands of event listeners. Instead, we take a timestamp
	  // every time the scheduler flushes and use that for all event listeners
	  // attached during that flush.
	  var currentFlushTimestamp = 0;

	  // Async edge case fix requires storing an event listener's attach timestamp.
	  var getNow = Date.now;

	  // Determine what event timestamp the browser is using. Annoyingly, the
	  // timestamp can either be hi-res (relative to page load) or low-res
	  // (relative to UNIX epoch), so in order to compare time we have to use the
	  // same timestamp type when saving the flush timestamp.
	  // All IE versions use low-res event timestamps, and have problematic clock
	  // implementations (#9632)
	  if (inBrowser && !isIE) {
	    var performance = window.performance;
	    if (
	      performance &&
	      typeof performance.now === 'function' &&
	      getNow() > document.createEvent('Event').timeStamp
	    ) {
	      // if the event timestamp, although evaluated AFTER the Date.now(), is
	      // smaller than it, it means the event is using a hi-res timestamp,
	      // and we need to use the hi-res version for event listener timestamps as
	      // well.
	      getNow = function () { return performance.now(); };
	    }
	  }

	  /**
	   * Flush both queues and run the watchers.
	   */
	  function flushSchedulerQueue () {
	    currentFlushTimestamp = getNow();
	    flushing = true;
	    var watcher, id;

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

	    // do not cache length because more watchers might be pushed
	    // as we run existing watchers
	    for (index = 0; index < queue.length; index++) {
	      watcher = queue[index];
	      if (watcher.before) {
	        watcher.before();
	      }
	      id = watcher.id;
	      has[id] = null;
	      watcher.run();
	      // in dev build, check and stop circular updates.
	      if (has[id] != null) {
	        circular[id] = (circular[id] || 0) + 1;
	        if (circular[id] > MAX_UPDATE_COUNT) {
	          warn(
	            'You may have an infinite update loop ' + (
	              watcher.user
	                ? ("in watcher with expression \"" + (watcher.expression) + "\"")
	                : "in a component render function."
	            ),
	            watcher.vm
	          );
	          break
	        }
	      }
	    }

	    // keep copies of post queues before resetting state
	    var activatedQueue = activatedChildren.slice();
	    var updatedQueue = queue.slice();

	    resetSchedulerState();

	    // call component updated and activated hooks
	    callActivatedHooks(activatedQueue);
	    callUpdatedHooks(updatedQueue);

	    // devtool hook
	    /* istanbul ignore if */
	    if (devtools && config.devtools) {
	      devtools.emit('flush');
	    }
	  }

	  function callUpdatedHooks (queue) {
	    var i = queue.length;
	    while (i--) {
	      var watcher = queue[i];
	      var vm = watcher.vm;
	      if (vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) {
	        callHook(vm, 'updated');
	      }
	    }
	  }

	  /**
	   * Queue a kept-alive component that was activated during patch.
	   * The queue will be processed after the entire tree has been patched.
	   */
	  function queueActivatedComponent (vm) {
	    // setting _inactive to false here so that a render function can
	    // rely on checking whether it's in an inactive tree (e.g. router-view)
	    vm._inactive = false;
	    activatedChildren.push(vm);
	  }

	  function callActivatedHooks (queue) {
	    for (var i = 0; i < queue.length; i++) {
	      queue[i]._inactive = true;
	      activateChildComponent(queue[i], true /* true */);
	    }
	  }

	  /**
	   * Push a watcher into the watcher queue.
	   * Jobs with duplicate IDs will be skipped unless it's
	   * pushed when the queue is being flushed.
	   */
	  function queueWatcher (watcher) {
	    var id = watcher.id;
	    if (has[id] == null) {
	      has[id] = true;
	      if (!flushing) {
	        queue.push(watcher);
	      } else {
	        // if already flushing, splice the watcher based on its id
	        // if already past its id, it will be run next immediately.
	        var i = queue.length - 1;
	        while (i > index && queue[i].id > watcher.id) {
	          i--;
	        }
	        queue.splice(i + 1, 0, watcher);
	      }
	      // queue the flush
	      if (!waiting) {
	        waiting = true;

	        if (!config.async) {
	          flushSchedulerQueue();
	          return
	        }
	        nextTick(flushSchedulerQueue);
	      }
	    }
	  }

	  /*  */



	  var uid$2 = 0;

	  /**
	   * A watcher parses an expression, collects dependencies,
	   * and fires callback when the expression value changes.
	   * This is used for both the $watch() api and directives.
	   */
	  var Watcher = function Watcher (
	    vm,
	    expOrFn,
	    cb,
	    options,
	    isRenderWatcher
	  ) {
	    this.vm = vm;
	    if (isRenderWatcher) {
	      vm._watcher = this;
	    }
	    vm._watchers.push(this);
	    // options
	    if (options) {
	      this.deep = !!options.deep;
	      this.user = !!options.user;
	      this.lazy = !!options.lazy;
	      this.sync = !!options.sync;
	      this.before = options.before;
	    } else {
	      this.deep = this.user = this.lazy = this.sync = false;
	    }
	    this.cb = cb;
	    this.id = ++uid$2; // uid for batching
	    this.active = true;
	    this.dirty = this.lazy; // for lazy watchers
	    this.deps = [];
	    this.newDeps = [];
	    this.depIds = new _Set();
	    this.newDepIds = new _Set();
	    this.expression = expOrFn.toString();
	    // parse expression for getter
	    if (typeof expOrFn === 'function') {
	      this.getter = expOrFn;
	    } else {
	      this.getter = parsePath(expOrFn);
	      if (!this.getter) {
	        this.getter = noop;
	        warn(
	          "Failed watching path: \"" + expOrFn + "\" " +
	          'Watcher only accepts simple dot-delimited paths. ' +
	          'For full control, use a function instead.',
	          vm
	        );
	      }
	    }
	    this.value = this.lazy
	      ? undefined
	      : this.get();
	  };

	  /**
	   * Evaluate the getter, and re-collect dependencies.
	   */
	  Watcher.prototype.get = function get () {
	    pushTarget(this);
	    var value;
	    var vm = this.vm;
	    try {
	      value = this.getter.call(vm, vm);
	    } catch (e) {
	      if (this.user) {
	        handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));
	      } else {
	        throw e
	      }
	    } finally {
	      // "touch" every property so they are all tracked as
	      // dependencies for deep watching
	      if (this.deep) {
	        traverse(value);
	      }
	      popTarget();
	      this.cleanupDeps();
	    }
	    return value
	  };

	  /**
	   * Add a dependency to this directive.
	   */
	  Watcher.prototype.addDep = function addDep (dep) {
	    var id = dep.id;
	    if (!this.newDepIds.has(id)) {
	      this.newDepIds.add(id);
	      this.newDeps.push(dep);
	      if (!this.depIds.has(id)) {
	        dep.addSub(this);
	      }
	    }
	  };

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

	  /**
	   * Subscriber interface.
	   * Will be called when a dependency changes.
	   */
	  Watcher.prototype.update = function update () {
	    /* istanbul ignore else */
	    if (this.lazy) {
	      this.dirty = true;
	    } else if (this.sync) {
	      this.run();
	    } else {
	      queueWatcher(this);
	    }
	  };

	  /**
	   * Scheduler job interface.
	   * Will be called by the scheduler.
	   */
	  Watcher.prototype.run = function run () {
	    if (this.active) {
	      var value = this.get();
	      if (
	        value !== this.value ||
	        // Deep watchers and watchers on Object/Arrays should fire even
	        // when the value is the same, because the value may
	        // have mutated.
	        isObject(value) ||
	        this.deep
	      ) {
	        // set new value
	        var oldValue = this.value;
	        this.value = value;
	        if (this.user) {
	          try {
	            this.cb.call(this.vm, value, oldValue);
	          } catch (e) {
	            handleError(e, this.vm, ("callback for watcher \"" + (this.expression) + "\""));
	          }
	        } else {
	          this.cb.call(this.vm, value, oldValue);
	        }
	      }
	    }
	  };

	  /**
	   * Evaluate the value of the watcher.
	   * This only gets called for lazy watchers.
	   */
	  Watcher.prototype.evaluate = function evaluate () {
	    this.value = this.get();
	    this.dirty = false;
	  };

	  /**
	   * Depend on all deps collected by this watcher.
	   */
	  Watcher.prototype.depend = function depend () {
	    var i = this.deps.length;
	    while (i--) {
	      this.deps[i].depend();
	    }
	  };

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

	  /*  */

	  var sharedPropertyDefinition = {
	    enumerable: true,
	    configurable: true,
	    get: noop,
	    set: noop
	  };

	  function proxy (target, sourceKey, key) {
	    sharedPropertyDefinition.get = function proxyGetter () {
	      return this[sourceKey][key]
	    };
	    sharedPropertyDefinition.set = function proxySetter (val) {
	      this[sourceKey][key] = val;
	    };
	    Object.defineProperty(target, key, sharedPropertyDefinition);
	  }

	  function initState (vm) {
	    vm._watchers = [];
	    var opts = vm.$options;
	    if (opts.props) { initProps(vm, opts.props); }
	    if (opts.methods) { initMethods(vm, opts.methods); }
	    if (opts.data) {
	      initData(vm);
	    } else {
	      observe(vm._data = {}, true /* asRootData */);
	    }
	    if (opts.computed) { initComputed(vm, opts.computed); }
	    if (opts.watch && opts.watch !== nativeWatch) {
	      initWatch(vm, opts.watch);
	    }
	  }

	  function initProps (vm, propsOptions) {
	    var propsData = vm.$options.propsData || {};
	    var props = vm._props = {};
	    // cache prop keys so that future props updates can iterate using Array
	    // instead of dynamic object key enumeration.
	    var keys = vm.$options._propKeys = [];
	    var isRoot = !vm.$parent;
	    // root instance props should be converted
	    if (!isRoot) {
	      toggleObserving(false);
	    }
	    var loop = function ( key ) {
	      keys.push(key);
	      var value = validateProp(key, propsOptions, propsData, vm);
	      /* istanbul ignore else */
	      {
	        var hyphenatedKey = hyphenate(key);
	        if (isReservedAttribute(hyphenatedKey) ||
	            config.isReservedAttr(hyphenatedKey)) {
	          warn(
	            ("\"" + hyphenatedKey + "\" is a reserved attribute and cannot be used as component prop."),
	            vm
	          );
	        }
	        defineReactive$$1(props, key, value, function () {
	          if (!isRoot && !isUpdatingChildComponent) {
	            warn(
	              "Avoid mutating a prop directly since the value will be " +
	              "overwritten whenever the parent component re-renders. " +
	              "Instead, use a data or computed property based on the prop's " +
	              "value. Prop being mutated: \"" + key + "\"",
	              vm
	            );
	          }
	        });
	      }
	      // static props are already proxied on the component's prototype
	      // during Vue.extend(). We only need to proxy props defined at
	      // instantiation here.
	      if (!(key in vm)) {
	        proxy(vm, "_props", key);
	      }
	    };

	    for (var key in propsOptions) loop( key );
	    toggleObserving(true);
	  }

	  function initData (vm) {
	    var data = vm.$options.data;
	    data = vm._data = typeof data === 'function'
	      ? getData(data, vm)
	      : data || {};
	    if (!isPlainObject(data)) {
	      data = {};
	      warn(
	        'data functions should return an object:\n' +
	        'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
	        vm
	      );
	    }
	    // proxy data on instance
	    var keys = Object.keys(data);
	    var props = vm.$options.props;
	    var methods = vm.$options.methods;
	    var i = keys.length;
	    while (i--) {
	      var key = keys[i];
	      {
	        if (methods && hasOwn(methods, key)) {
	          warn(
	            ("Method \"" + key + "\" has already been defined as a data property."),
	            vm
	          );
	        }
	      }
	      if (props && hasOwn(props, key)) {
	        warn(
	          "The data property \"" + key + "\" is already declared as a prop. " +
	          "Use prop default value instead.",
	          vm
	        );
	      } else if (!isReserved(key)) {
	        proxy(vm, "_data", key);
	      }
	    }
	    // observe data
	    observe(data, true /* asRootData */);
	  }

	  function getData (data, vm) {
	    // #7573 disable dep collection when invoking data getters
	    pushTarget();
	    try {
	      return data.call(vm, vm)
	    } catch (e) {
	      handleError(e, vm, "data()");
	      return {}
	    } finally {
	      popTarget();
	    }
	  }

	  var computedWatcherOptions = { lazy: true };

	  function initComputed (vm, computed) {
	    // $flow-disable-line
	    var watchers = vm._computedWatchers = Object.create(null);
	    // computed properties are just getters during SSR
	    var isSSR = isServerRendering();

	    for (var key in computed) {
	      var userDef = computed[key];
	      var getter = typeof userDef === 'function' ? userDef : userDef.get;
	      if (getter == null) {
	        warn(
	          ("Getter is missing for computed property \"" + key + "\"."),
	          vm
	        );
	      }

	      if (!isSSR) {
	        // create internal watcher for the computed property.
	        watchers[key] = new Watcher(
	          vm,
	          getter || noop,
	          noop,
	          computedWatcherOptions
	        );
	      }

	      // component-defined computed properties are already defined on the
	      // component prototype. We only need to define computed properties defined
	      // at instantiation here.
	      if (!(key in vm)) {
	        defineComputed(vm, key, userDef);
	      } else {
	        if (key in vm.$data) {
	          warn(("The computed property \"" + key + "\" is already defined in data."), vm);
	        } else if (vm.$options.props && key in vm.$options.props) {
	          warn(("The computed property \"" + key + "\" is already defined as a prop."), vm);
	        }
	      }
	    }
	  }

	  function defineComputed (
	    target,
	    key,
	    userDef
	  ) {
	    var shouldCache = !isServerRendering();
	    if (typeof userDef === 'function') {
	      sharedPropertyDefinition.get = shouldCache
	        ? createComputedGetter(key)
	        : createGetterInvoker(userDef);
	      sharedPropertyDefinition.set = noop;
	    } else {
	      sharedPropertyDefinition.get = userDef.get
	        ? shouldCache && userDef.cache !== false
	          ? createComputedGetter(key)
	          : createGetterInvoker(userDef.get)
	        : noop;
	      sharedPropertyDefinition.set = userDef.set || noop;
	    }
	    if (sharedPropertyDefinition.set === noop) {
	      sharedPropertyDefinition.set = function () {
	        warn(
	          ("Computed property \"" + key + "\" was assigned to but it has no setter."),
	          this
	        );
	      };
	    }
	    Object.defineProperty(target, key, sharedPropertyDefinition);
	  }

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

	  function createGetterInvoker(fn) {
	    return function computedGetter () {
	      return fn.call(this, this)
	    }
	  }

	  function initMethods (vm, methods) {
	    var props = vm.$options.props;
	    for (var key in methods) {
	      {
	        if (typeof methods[key] !== 'function') {
	          warn(
	            "Method \"" + key + "\" has type \"" + (typeof methods[key]) + "\" in the component definition. " +
	            "Did you reference the function correctly?",
	            vm
	          );
	        }
	        if (props && hasOwn(props, key)) {
	          warn(
	            ("Method \"" + key + "\" has already been defined as a prop."),
	            vm
	          );
	        }
	        if ((key in vm) && isReserved(key)) {
	          warn(
	            "Method \"" + key + "\" conflicts with an existing Vue instance method. " +
	            "Avoid defining component methods that start with _ or $."
	          );
	        }
	      }
	      vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm);
	    }
	  }

	  function initWatch (vm, watch) {
	    for (var key in watch) {
	      var handler = watch[key];
	      if (Array.isArray(handler)) {
	        for (var i = 0; i < handler.length; i++) {
	          createWatcher(vm, key, handler[i]);
	        }
	      } else {
	        createWatcher(vm, key, handler);
	      }
	    }
	  }

	  function createWatcher (
	    vm,
	    expOrFn,
	    handler,
	    options
	  ) {
	    if (isPlainObject(handler)) {
	      options = handler;
	      handler = handler.handler;
	    }
	    if (typeof handler === 'string') {
	      handler = vm[handler];
	    }
	    return vm.$watch(expOrFn, handler, options)
	  }

	  function stateMixin (Vue) {
	    // flow somehow has problems with directly declared definition object
	    // when using Object.defineProperty, so we have to procedurally build up
	    // the object here.
	    var dataDef = {};
	    dataDef.get = function () { return this._data };
	    var propsDef = {};
	    propsDef.get = function () { return this._props };
	    {
	      dataDef.set = function () {
	        warn(
	          'Avoid replacing instance root $data. ' +
	          'Use nested data properties instead.',
	          this
	        );
	      };
	      propsDef.set = function () {
	        warn("$props is readonly.", this);
	      };
	    }
	    Object.defineProperty(Vue.prototype, '$data', dataDef);
	    Object.defineProperty(Vue.prototype, '$props', propsDef);

	    Vue.prototype.$set = set;
	    Vue.prototype.$delete = del;

	    Vue.prototype.$watch = function (
	      expOrFn,
	      cb,
	      options
	    ) {
	      var vm = this;
	      if (isPlainObject(cb)) {
	        return createWatcher(vm, expOrFn, cb, options)
	      }
	      options = options || {};
	      options.user = true;
	      var watcher = new Watcher(vm, expOrFn, cb, options);
	      if (options.immediate) {
	        try {
	          cb.call(vm, watcher.value);
	        } catch (error) {
	          handleError(error, vm, ("callback for immediate watcher \"" + (watcher.expression) + "\""));
	        }
	      }
	      return function unwatchFn () {
	        watcher.teardown();
	      }
	    };
	  }

	  /*  */

	  var uid$3 = 0;

	  function initMixin (Vue) {
	    Vue.prototype._init = function (options) {
	      var vm = this;
	      // a uid
	      vm._uid = uid$3++;

	      var startTag, endTag;
	      /* istanbul ignore if */
	      if (config.performance && mark) {
	        startTag = "vue-perf-start:" + (vm._uid);
	        endTag = "vue-perf-end:" + (vm._uid);
	        mark(startTag);
	      }

	      // a flag to avoid this being observed
	      vm._isVue = true;
	      // merge options
	      if (options && options._isComponent) {
	        // optimize internal component instantiation
	        // since dynamic options merging is pretty slow, and none of the
	        // internal component options needs special treatment.
	        initInternalComponent(vm, options);
	      } else {
	        vm.$options = mergeOptions(
	          resolveConstructorOptions(vm.constructor),
	          options || {},
	          vm
	        );
	      }
	      /* istanbul ignore else */
	      {
	        initProxy(vm);
	      }
	      // expose real self
	      vm._self = vm;
	      initLifecycle(vm);
	      initEvents(vm);
	      initRender(vm);
	      callHook(vm, 'beforeCreate');
	      initInjections(vm); // resolve injections before data/props
	      initState(vm);
	      initProvide(vm); // resolve provide after data/props
	      callHook(vm, 'created');

	      /* istanbul ignore if */
	      if (config.performance && mark) {
	        vm._name = formatComponentName(vm, false);
	        mark(endTag);
	        measure(("vue " + (vm._name) + " init"), startTag, endTag);
	      }

	      if (vm.$options.el) {
	        vm.$mount(vm.$options.el);
	      }
	    };
	  }

	  function initInternalComponent (vm, options) {
	    var opts = vm.$options = Object.create(vm.constructor.options);
	    // doing this because it's faster than dynamic enumeration.
	    var parentVnode = options._parentVnode;
	    opts.parent = options.parent;
	    opts._parentVnode = parentVnode;

	    var vnodeComponentOptions = parentVnode.componentOptions;
	    opts.propsData = vnodeComponentOptions.propsData;
	    opts._parentListeners = vnodeComponentOptions.listeners;
	    opts._renderChildren = vnodeComponentOptions.children;
	    opts._componentTag = vnodeComponentOptions.tag;

	    if (options.render) {
	      opts.render = options.render;
	      opts.staticRenderFns = options.staticRenderFns;
	    }
	  }

	  function resolveConstructorOptions (Ctor) {
	    var options = Ctor.options;
	    if (Ctor.super) {
	      var superOptions = resolveConstructorOptions(Ctor.super);
	      var cachedSuperOptions = Ctor.superOptions;
	      if (superOptions !== cachedSuperOptions) {
	        // super option changed,
	        // need to resolve new options.
	        Ctor.superOptions = superOptions;
	        // check if there are any late-modified/attached options (#4976)
	        var modifiedOptions = resolveModifiedOptions(Ctor);
	        // update base extend options
	        if (modifiedOptions) {
	          extend(Ctor.extendOptions, modifiedOptions);
	        }
	        options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions);
	        if (options.name) {
	          options.components[options.name] = Ctor;
	        }
	      }
	    }
	    return options
	  }

	  function resolveModifiedOptions (Ctor) {
	    var modified;
	    var latest = Ctor.options;
	    var sealed = Ctor.sealedOptions;
	    for (var key in latest) {
	      if (latest[key] !== sealed[key]) {
	        if (!modified) { modified = {}; }
	        modified[key] = latest[key];
	      }
	    }
	    return modified
	  }

	  function Vue (options) {
	    if (!(this instanceof Vue)
	    ) {
	      warn('Vue is a constructor and should be called with the `new` keyword');
	    }
	    this._init(options);
	  }

	  initMixin(Vue);
	  stateMixin(Vue);
	  eventsMixin(Vue);
	  lifecycleMixin(Vue);
	  renderMixin(Vue);

	  /*  */

	  function initUse (Vue) {
	    Vue.use = function (plugin) {
	      var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
	      if (installedPlugins.indexOf(plugin) > -1) {
	        return this
	      }

	      // additional parameters
	      var args = toArray(arguments, 1);
	      args.unshift(this);
	      if (typeof plugin.install === 'function') {
	        plugin.install.apply(plugin, args);
	      } else if (typeof plugin === 'function') {
	        plugin.apply(null, args);
	      }
	      installedPlugins.push(plugin);
	      return this
	    };
	  }

	  /*  */

	  function initMixin$1 (Vue) {
	    Vue.mixin = function (mixin) {
	      this.options = mergeOptions(this.options, mixin);
	      return this
	    };
	  }

	  /*  */

	  function initExtend (Vue) {
	    /**
	     * Each instance constructor, including Vue, has a unique
	     * cid. This enables us to create wrapped "child
	     * constructors" for prototypal inheritance and cache them.
	     */
	    Vue.cid = 0;
	    var cid = 1;

	    /**
	     * Class inheritance
	     */
	    Vue.extend = function (extendOptions) {
	      extendOptions = extendOptions || {};
	      var Super = this;
	      var SuperId = Super.cid;
	      var cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {});
	      if (cachedCtors[SuperId]) {
	        return cachedCtors[SuperId]
	      }

	      var name = extendOptions.name || Super.options.name;
	      if (name) {
	        validateComponentName(name);
	      }

	      var Sub = function VueComponent (options) {
	        this._init(options);
	      };
	      Sub.prototype = Object.create(Super.prototype);
	      Sub.prototype.constructor = Sub;
	      Sub.cid = cid++;
	      Sub.options = mergeOptions(
	        Super.options,
	        extendOptions
	      );
	      Sub['super'] = Super;

	      // For props and computed properties, we define the proxy getters on
	      // the Vue instances at extension time, on the extended prototype. This
	      // avoids Object.defineProperty calls for each instance created.
	      if (Sub.options.props) {
	        initProps$1(Sub);
	      }
	      if (Sub.options.computed) {
	        initComputed$1(Sub);
	      }

	      // allow further extension/mixin/plugin usage
	      Sub.extend = Super.extend;
	      Sub.mixin = Super.mixin;
	      Sub.use = Super.use;

	      // create asset registers, so extended classes
	      // can have their private assets too.
	      ASSET_TYPES.forEach(function (type) {
	        Sub[type] = Super[type];
	      });
	      // enable recursive self-lookup
	      if (name) {
	        Sub.options.components[name] = Sub;
	      }

	      // keep a reference to the super options at extension time.
	      // later at instantiation we can check if Super's options have
	      // been updated.
	      Sub.superOptions = Super.options;
	      Sub.extendOptions = extendOptions;
	      Sub.sealedOptions = extend({}, Sub.options);

	      // cache constructor
	      cachedCtors[SuperId] = Sub;
	      return Sub
	    };
	  }

	  function initProps$1 (Comp) {
	    var props = Comp.options.props;
	    for (var key in props) {
	      proxy(Comp.prototype, "_props", key);
	    }
	  }

	  function initComputed$1 (Comp) {
	    var computed = Comp.options.computed;
	    for (var key in computed) {
	      defineComputed(Comp.prototype, key, computed[key]);
	    }
	  }

	  /*  */

	  function initAssetRegisters (Vue) {
	    /**
	     * Create asset registration methods.
	     */
	    ASSET_TYPES.forEach(function (type) {
	      Vue[type] = function (
	        id,
	        definition
	      ) {
	        if (!definition) {
	          return this.options[type + 's'][id]
	        } else {
	          /* istanbul ignore if */
	          if (type === 'component') {
	            validateComponentName(id);
	          }
	          if (type === 'component' && isPlainObject(definition)) {
	            definition.name = definition.name || id;
	            definition = this.options._base.extend(definition);
	          }
	          if (type === 'directive' && typeof definition === 'function') {
	            definition = { bind: definition, update: definition };
	          }
	          this.options[type + 's'][id] = definition;
	          return definition
	        }
	      };
	    });
	  }

	  /*  */



	  function getComponentName (opts) {
	    return opts && (opts.Ctor.options.name || opts.tag)
	  }

	  function matches (pattern, name) {
	    if (Array.isArray(pattern)) {
	      return pattern.indexOf(name) > -1
	    } else if (typeof pattern === 'string') {
	      return pattern.split(',').indexOf(name) > -1
	    } else if (isRegExp(pattern)) {
	      return pattern.test(name)
	    }
	    /* istanbul ignore next */
	    return false
	  }

	  function pruneCache (keepAliveInstance, filter) {
	    var cache = keepAliveInstance.cache;
	    var keys = keepAliveInstance.keys;
	    var _vnode = keepAliveInstance._vnode;
	    for (var key in cache) {
	      var cachedNode = cache[key];
	      if (cachedNode) {
	        var name = getComponentName(cachedNode.componentOptions);
	        if (name && !filter(name)) {
	          pruneCacheEntry(cache, key, keys, _vnode);
	        }
	      }
	    }
	  }

	  function pruneCacheEntry (
	    cache,
	    key,
	    keys,
	    current
	  ) {
	    var cached$$1 = cache[key];
	    if (cached$$1 && (!current || cached$$1.tag !== current.tag)) {
	      cached$$1.componentInstance.$destroy();
	    }
	    cache[key] = null;
	    remove(keys, key);
	  }

	  var patternTypes = [String, RegExp, Array];

	  var KeepAlive = {
	    name: 'keep-alive',
	    abstract: true,

	    props: {
	      include: patternTypes,
	      exclude: patternTypes,
	      max: [String, Number]
	    },

	    created: function created () {
	      this.cache = Object.create(null);
	      this.keys = [];
	    },

	    destroyed: function destroyed () {
	      for (var key in this.cache) {
	        pruneCacheEntry(this.cache, key, this.keys);
	      }
	    },

	    mounted: function mounted () {
	      var this$1 = this;

	      this.$watch('include', function (val) {
	        pruneCache(this$1, function (name) { return matches(val, name); });
	      });
	      this.$watch('exclude', function (val) {
	        pruneCache(this$1, function (name) { return !matches(val, name); });
	      });
	    },

	    render: function render () {
	      var slot = this.$slots.default;
	      var vnode = getFirstComponentChild(slot);
	      var componentOptions = vnode && vnode.componentOptions;
	      if (componentOptions) {
	        // check pattern
	        var name = getComponentName(componentOptions);
	        var ref = this;
	        var include = ref.include;
	        var exclude = ref.exclude;
	        if (
	          // not included
	          (include && (!name || !matches(include, name))) ||
	          // excluded
	          (exclude && name && matches(exclude, name))
	        ) {
	          return vnode
	        }

	        var ref$1 = this;
	        var cache = ref$1.cache;
	        var keys = ref$1.keys;
	        var key = vnode.key == null
	          // same constructor may get registered as different local components
	          // so cid alone is not enough (#3269)
	          ? componentOptions.Ctor.cid + (componentOptions.tag ? ("::" + (componentOptions.tag)) : '')
	          : vnode.key;
	        if (cache[key]) {
	          vnode.componentInstance = cache[key].componentInstance;
	          // make current key freshest
	          remove(keys, key);
	          keys.push(key);
	        } else {
	          cache[key] = vnode;
	          keys.push(key);
	          // prune oldest entry
	          if (this.max && keys.length > parseInt(this.max)) {
	            pruneCacheEntry(cache, keys[0], keys, this._vnode);
	          }
	        }

	        vnode.data.keepAlive = true;
	      }
	      return vnode || (slot && slot[0])
	    }
	  };

	  var builtInComponents = {
	    KeepAlive: KeepAlive
	  };

	  /*  */

	  function initGlobalAPI (Vue) {
	    // config
	    var configDef = {};
	    configDef.get = function () { return config; };
	    {
	      configDef.set = function () {
	        warn(
	          'Do not replace the Vue.config object, set individual fields instead.'
	        );
	      };
	    }
	    Object.defineProperty(Vue, 'config', configDef);

	    // exposed util methods.
	    // NOTE: these are not considered part of the public API - avoid relying on
	    // them unless you are aware of the risk.
	    Vue.util = {
	      warn: warn,
	      extend: extend,
	      mergeOptions: mergeOptions,
	      defineReactive: defineReactive$$1
	    };

	    Vue.set = set;
	    Vue.delete = del;
	    Vue.nextTick = nextTick;

	    // 2.6 explicit observable API
	    Vue.observable = function (obj) {
	      observe(obj);
	      return obj
	    };

	    Vue.options = Object.create(null);
	    ASSET_TYPES.forEach(function (type) {
	      Vue.options[type + 's'] = Object.create(null);
	    });

	    // this is used to identify the "base" constructor to extend all plain-object
	    // components with in Weex's multi-instance scenarios.
	    Vue.options._base = Vue;

	    extend(Vue.options.components, builtInComponents);

	    initUse(Vue);
	    initMixin$1(Vue);
	    initExtend(Vue);
	    initAssetRegisters(Vue);
	  }

	  initGlobalAPI(Vue);

	  Object.defineProperty(Vue.prototype, '$isServer', {
	    get: isServerRendering
	  });

	  Object.defineProperty(Vue.prototype, '$ssrContext', {
	    get: function get () {
	      /* istanbul ignore next */
	      return this.$vnode && this.$vnode.ssrContext
	    }
	  });

	  // expose FunctionalRenderContext for ssr runtime helper installation
	  Object.defineProperty(Vue, 'FunctionalRenderContext', {
	    value: FunctionalRenderContext
	  });

	  Vue.version = '2.6.12';

	  /*  */

	  // these are reserved for web because they are directly compiled away
	  // during template compilation
	  var isReservedAttr = makeMap('style,class');

	  // attributes that should be using props for binding
	  var acceptValue = makeMap('input,textarea,option,select,progress');
	  var mustUseProp = function (tag, type, attr) {
	    return (
	      (attr === 'value' && acceptValue(tag)) && type !== 'button' ||
	      (attr === 'selected' && tag === 'option') ||
	      (attr === 'checked' && tag === 'input') ||
	      (attr === 'muted' && tag === 'video')
	    )
	  };

	  var isEnumeratedAttr = makeMap('contenteditable,draggable,spellcheck');

	  var isValidContentEditableValue = makeMap('events,caret,typing,plaintext-only');

	  var convertEnumeratedValue = function (key, value) {
	    return isFalsyAttrValue(value) || value === 'false'
	      ? 'false'
	      // allow arbitrary string value for contenteditable
	      : key === 'contenteditable' && isValidContentEditableValue(value)
	        ? value
	        : 'true'
	  };

	  var isBooleanAttr = makeMap(
	    'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' +
	    'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' +
	    'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' +
	    'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' +
	    'required,reversed,scoped,seamless,selected,sortable,translate,' +
	    'truespeed,typemustmatch,visible'
	  );

	  var xlinkNS = 'http://www.w3.org/1999/xlink';

	  var isXlink = function (name) {
	    return name.charAt(5) === ':' && name.slice(0, 5) === 'xlink'
	  };

	  var getXlinkProp = function (name) {
	    return isXlink(name) ? name.slice(6, name.length) : ''
	  };

	  var isFalsyAttrValue = function (val) {
	    return val == null || val === false
	  };

	  /*  */

	  function genClassForVnode (vnode) {
	    var data = vnode.data;
	    var parentNode = vnode;
	    var childNode = vnode;
	    while (isDef(childNode.componentInstance)) {
	      childNode = childNode.componentInstance._vnode;
	      if (childNode && childNode.data) {
	        data = mergeClassData(childNode.data, data);
	      }
	    }
	    while (isDef(parentNode = parentNode.parent)) {
	      if (parentNode && parentNode.data) {
	        data = mergeClassData(data, parentNode.data);
	      }
	    }
	    return renderClass(data.staticClass, data.class)
	  }

	  function mergeClassData (child, parent) {
	    return {
	      staticClass: concat(child.staticClass, parent.staticClass),
	      class: isDef(child.class)
	        ? [child.class, parent.class]
	        : parent.class
	    }
	  }

	  function renderClass (
	    staticClass,
	    dynamicClass
	  ) {
	    if (isDef(staticClass) || isDef(dynamicClass)) {
	      return concat(staticClass, stringifyClass(dynamicClass))
	    }
	    /* istanbul ignore next */
	    return ''
	  }

	  function concat (a, b) {
	    return a ? b ? (a + ' ' + b) : a : (b || '')
	  }

	  function stringifyClass (value) {
	    if (Array.isArray(value)) {
	      return stringifyArray(value)
	    }
	    if (isObject(value)) {
	      return stringifyObject(value)
	    }
	    if (typeof value === 'string') {
	      return value
	    }
	    /* istanbul ignore next */
	    return ''
	  }

	  function stringifyArray (value) {
	    var res = '';
	    var stringified;
	    for (var i = 0, l = value.length; i < l; i++) {
	      if (isDef(stringified = stringifyClass(value[i])) && stringified !== '') {
	        if (res) { res += ' '; }
	        res += stringified;
	      }
	    }
	    return res
	  }

	  function stringifyObject (value) {
	    var res = '';
	    for (var key in value) {
	      if (value[key]) {
	        if (res) { res += ' '; }
	        res += key;
	      }
	    }
	    return res
	  }

	  /*  */

	  var namespaceMap = {
	    svg: 'http://www.w3.org/2000/svg',
	    math: 'http://www.w3.org/1998/Math/MathML'
	  };

	  var isHTMLTag = makeMap(
	    'html,body,base,head,link,meta,style,title,' +
	    'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
	    'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
	    'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
	    's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
	    'embed,object,param,source,canvas,script,noscript,del,ins,' +
	    'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
	    'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
	    'output,progress,select,textarea,' +
	    'details,dialog,menu,menuitem,summary,' +
	    'content,element,shadow,template,blockquote,iframe,tfoot'
	  );

	  // this map is intentionally selective, only covering SVG elements that may
	  // contain child elements.
	  var isSVG = makeMap(
	    'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +
	    'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +
	    'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',
	    true
	  );

	  var isPreTag = function (tag) { return tag === 'pre'; };

	  var isReservedTag = function (tag) {
	    return isHTMLTag(tag) || isSVG(tag)
	  };

	  function getTagNamespace (tag) {
	    if (isSVG(tag)) {
	      return 'svg'
	    }
	    // basic support for MathML
	    // note it doesn't support other MathML elements being component roots
	    if (tag === 'math') {
	      return 'math'
	    }
	  }

	  var unknownElementCache = Object.create(null);
	  function isUnknownElement (tag) {
	    /* istanbul ignore if */
	    if (!inBrowser) {
	      return true
	    }
	    if (isReservedTag(tag)) {
	      return false
	    }
	    tag = tag.toLowerCase();
	    /* istanbul ignore if */
	    if (unknownElementCache[tag] != null) {
	      return unknownElementCache[tag]
	    }
	    var el = document.createElement(tag);
	    if (tag.indexOf('-') > -1) {
	      // http://stackoverflow.com/a/28210364/1070244
	      return (unknownElementCache[tag] = (
	        el.constructor === window.HTMLUnknownElement ||
	        el.constructor === window.HTMLElement
	      ))
	    } else {
	      return (unknownElementCache[tag] = /HTMLUnknownElement/.test(el.toString()))
	    }
	  }

	  var isTextInputType = makeMap('text,number,password,search,email,tel,url');

	  /*  */

	  /**
	   * Query an element selector if it's not an element already.
	   */
	  function query (el) {
	    if (typeof el === 'string') {
	      var selected = document.querySelector(el);
	      if (!selected) {
	        warn(
	          'Cannot find element: ' + el
	        );
	        return document.createElement('div')
	      }
	      return selected
	    } else {
	      return el
	    }
	  }

	  /*  */

	  function createElement$1 (tagName, vnode) {
	    var elm = document.createElement(tagName);
	    if (tagName !== 'select') {
	      return elm
	    }
	    // false or null will remove the attribute but undefined will not
	    if (vnode.data && vnode.data.attrs && vnode.data.attrs.multiple !== undefined) {
	      elm.setAttribute('multiple', 'multiple');
	    }
	    return elm
	  }

	  function createElementNS (namespace, tagName) {
	    return document.createElementNS(namespaceMap[namespace], tagName)
	  }

	  function createTextNode (text) {
	    return document.createTextNode(text)
	  }

	  function createComment (text) {
	    return document.createComment(text)
	  }

	  function insertBefore (parentNode, newNode, referenceNode) {
	    parentNode.insertBefore(newNode, referenceNode);
	  }

	  function removeChild (node, child) {
	    node.removeChild(child);
	  }

	  function appendChild (node, child) {
	    node.appendChild(child);
	  }

	  function parentNode (node) {
	    return node.parentNode
	  }

	  function nextSibling (node) {
	    return node.nextSibling
	  }

	  function tagName (node) {
	    return node.tagName
	  }

	  function setTextContent (node, text) {
	    node.textContent = text;
	  }

	  function setStyleScope (node, scopeId) {
	    node.setAttribute(scopeId, '');
	  }

	  var nodeOps = /*#__PURE__*/Object.freeze({
	    createElement: createElement$1,
	    createElementNS: createElementNS,
	    createTextNode: createTextNode,
	    createComment: createComment,
	    insertBefore: insertBefore,
	    removeChild: removeChild,
	    appendChild: appendChild,
	    parentNode: parentNode,
	    nextSibling: nextSibling,
	    tagName: tagName,
	    setTextContent: setTextContent,
	    setStyleScope: setStyleScope
	  });

	  /*  */

	  var ref = {
	    create: function create (_, vnode) {
	      registerRef(vnode);
	    },
	    update: function update (oldVnode, vnode) {
	      if (oldVnode.data.ref !== vnode.data.ref) {
	        registerRef(oldVnode, true);
	        registerRef(vnode);
	      }
	    },
	    destroy: function destroy (vnode) {
	      registerRef(vnode, true);
	    }
	  };

	  function registerRef (vnode, isRemoval) {
	    var key = vnode.data.ref;
	    if (!isDef(key)) { return }

	    var vm = vnode.context;
	    var ref = vnode.componentInstance || vnode.elm;
	    var refs = vm.$refs;
	    if (isRemoval) {
	      if (Array.isArray(refs[key])) {
	        remove(refs[key], ref);
	      } else if (refs[key] === ref) {
	        refs[key] = undefined;
	      }
	    } else {
	      if (vnode.data.refInFor) {
	        if (!Array.isArray(refs[key])) {
	          refs[key] = [ref];
	        } else if (refs[key].indexOf(ref) < 0) {
	          // $flow-disable-line
	          refs[key].push(ref);
	        }
	      } else {
	        refs[key] = ref;
	      }
	    }
	  }

	  /**
	   * Virtual DOM patching algorithm based on Snabbdom by
	   * Simon Friis Vindum (@paldepind)
	   * Licensed under the MIT License
	   * https://github.com/paldepind/snabbdom/blob/master/LICENSE
	   *
	   * modified by Evan You (@yyx990803)
	   *
	   * Not type-checking this because this file is perf-critical and the cost
	   * of making flow understand it is not worth it.
	   */

	  var emptyNode = new VNode('', {}, []);

	  var hooks = ['create', 'activate', 'update', 'remove', 'destroy'];

	  function sameVnode (a, b) {
	    return (
	      a.key === b.key && (
	        (
	          a.tag === b.tag &&
	          a.isComment === b.isComment &&
	          isDef(a.data) === isDef(b.data) &&
	          sameInputType(a, b)
	        ) || (
	          isTrue(a.isAsyncPlaceholder) &&
	          a.asyncFactory === b.asyncFactory &&
	          isUndef(b.asyncFactory.error)
	        )
	      )
	    )
	  }

	  function sameInputType (a, b) {
	    if (a.tag !== 'input') { return true }
	    var i;
	    var typeA = isDef(i = a.data) && isDef(i = i.attrs) && i.type;
	    var typeB = isDef(i = b.data) && isDef(i = i.attrs) && i.type;
	    return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)
	  }

	  function createKeyToOldIdx (children, beginIdx, endIdx) {
	    var i, key;
	    var map = {};
	    for (i = beginIdx; i <= endIdx; ++i) {
	      key = children[i].key;
	      if (isDef(key)) { map[key] = i; }
	    }
	    return map
	  }

	  function createPatchFunction (backend) {
	    var i, j;
	    var cbs = {};

	    var modules = backend.modules;
	    var nodeOps = backend.nodeOps;

	    for (i = 0; i < hooks.length; ++i) {
	      cbs[hooks[i]] = [];
	      for (j = 0; j < modules.length; ++j) {
	        if (isDef(modules[j][hooks[i]])) {
	          cbs[hooks[i]].push(modules[j][hooks[i]]);
	        }
	      }
	    }

	    function emptyNodeAt (elm) {
	      return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
	    }

	    function createRmCb (childElm, listeners) {
	      function remove$$1 () {
	        if (--remove$$1.listeners === 0) {
	          removeNode(childElm);
	        }
	      }
	      remove$$1.listeners = listeners;
	      return remove$$1
	    }

	    function removeNode (el) {
	      var parent = nodeOps.parentNode(el);
	      // element may have already been removed due to v-html / v-text
	      if (isDef(parent)) {
	        nodeOps.removeChild(parent, el);
	      }
	    }

	    function isUnknownElement$$1 (vnode, inVPre) {
	      return (
	        !inVPre &&
	        !vnode.ns &&
	        !(
	          config.ignoredElements.length &&
	          config.ignoredElements.some(function (ignore) {
	            return isRegExp(ignore)
	              ? ignore.test(vnode.tag)
	              : ignore === vnode.tag
	          })
	        ) &&
	        config.isUnknownElement(vnode.tag)
	      )
	    }

	    var creatingElmInVPre = 0;

	    function createElm (
	      vnode,
	      insertedVnodeQueue,
	      parentElm,
	      refElm,
	      nested,
	      ownerArray,
	      index
	    ) {
	      if (isDef(vnode.elm) && isDef(ownerArray)) {
	        // This vnode was used in a previous render!
	        // now it's used as a new node, overwriting its elm would cause
	        // potential patch errors down the road when it's used as an insertion
	        // reference node. Instead, we clone the node on-demand before creating
	        // associated DOM element for it.
	        vnode = ownerArray[index] = cloneVNode(vnode);
	      }

	      vnode.isRootInsert = !nested; // for transition enter check
	      if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
	        return
	      }

	      var data = vnode.data;
	      var children = vnode.children;
	      var tag = vnode.tag;
	      if (isDef(tag)) {
	        {
	          if (data && data.pre) {
	            creatingElmInVPre++;
	          }
	          if (isUnknownElement$$1(vnode, creatingElmInVPre)) {
	            warn(
	              'Unknown custom element: <' + tag + '> - did you ' +
	              'register the component correctly? For recursive components, ' +
	              'make sure to provide the "name" option.',
	              vnode.context
	            );
	          }
	        }

	        vnode.elm = vnode.ns
	          ? nodeOps.createElementNS(vnode.ns, tag)
	          : nodeOps.createElement(tag, vnode);
	        setScope(vnode);

	        /* istanbul ignore if */
	        {
	          createChildren(vnode, children, insertedVnodeQueue);
	          if (isDef(data)) {
	            invokeCreateHooks(vnode, insertedVnodeQueue);
	          }
	          insert(parentElm, vnode.elm, refElm);
	        }

	        if (data && data.pre) {
	          creatingElmInVPre--;
	        }
	      } else if (isTrue(vnode.isComment)) {
	        vnode.elm = nodeOps.createComment(vnode.text);
	        insert(parentElm, vnode.elm, refElm);
	      } else {
	        vnode.elm = nodeOps.createTextNode(vnode.text);
	        insert(parentElm, vnode.elm, refElm);
	      }
	    }

	    function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
	      var i = vnode.data;
	      if (isDef(i)) {
	        var isReactivated = isDef(vnode.componentInstance) && i.keepAlive;
	        if (isDef(i = i.hook) && isDef(i = i.init)) {
	          i(vnode, false /* hydrating */);
	        }
	        // after calling the init hook, if the vnode is a child component
	        // it should've created a child instance and mounted it. the child
	        // component also has set the placeholder vnode's elm.
	        // in that case we can just return the element and be done.
	        if (isDef(vnode.componentInstance)) {
	          initComponent(vnode, insertedVnodeQueue);
	          insert(parentElm, vnode.elm, refElm);
	          if (isTrue(isReactivated)) {
	            reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm);
	          }
	          return true
	        }
	      }
	    }

	    function initComponent (vnode, insertedVnodeQueue) {
	      if (isDef(vnode.data.pendingInsert)) {
	        insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert);
	        vnode.data.pendingInsert = null;
	      }
	      vnode.elm = vnode.componentInstance.$el;
	      if (isPatchable(vnode)) {
	        invokeCreateHooks(vnode, insertedVnodeQueue);
	        setScope(vnode);
	      } else {
	        // empty component root.
	        // skip all element-related modules except for ref (#3455)
	        registerRef(vnode);
	        // make sure to invoke the insert hook
	        insertedVnodeQueue.push(vnode);
	      }
	    }

	    function reactivateComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
	      var i;
	      // hack for #4339: a reactivated component with inner transition
	      // does not trigger because the inner node's created hooks are not called
	      // again. It's not ideal to involve module-specific logic in here but
	      // there doesn't seem to be a better way to do it.
	      var innerNode = vnode;
	      while (innerNode.componentInstance) {
	        innerNode = innerNode.componentInstance._vnode;
	        if (isDef(i = innerNode.data) && isDef(i = i.transition)) {
	          for (i = 0; i < cbs.activate.length; ++i) {
	            cbs.activate[i](emptyNode, innerNode);
	          }
	          insertedVnodeQueue.push(innerNode);
	          break
	        }
	      }
	      // unlike a newly created component,
	      // a reactivated keep-alive component doesn't insert itself
	      insert(parentElm, vnode.elm, refElm);
	    }

	    function insert (parent, elm, ref$$1) {
	      if (isDef(parent)) {
	        if (isDef(ref$$1)) {
	          if (nodeOps.parentNode(ref$$1) === parent) {
	            nodeOps.insertBefore(parent, elm, ref$$1);
	          }
	        } else {
	          nodeOps.appendChild(parent, elm);
	        }
	      }
	    }

	    function createChildren (vnode, children, insertedVnodeQueue) {
	      if (Array.isArray(children)) {
	        {
	          checkDuplicateKeys(children);
	        }
	        for (var i = 0; i < children.length; ++i) {
	          createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i);
	        }
	      } else if (isPrimitive(vnode.text)) {
	        nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)));
	      }
	    }

	    function isPatchable (vnode) {
	      while (vnode.componentInstance) {
	        vnode = vnode.componentInstance._vnode;
	      }
	      return isDef(vnode.tag)
	    }

	    function invokeCreateHooks (vnode, insertedVnodeQueue) {
	      for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {
	        cbs.create[i$1](emptyNode, vnode);
	      }
	      i = vnode.data.hook; // Reuse variable
	      if (isDef(i)) {
	        if (isDef(i.create)) { i.create(emptyNode, vnode); }
	        if (isDef(i.insert)) { insertedVnodeQueue.push(vnode); }
	      }
	    }

	    // set scope id attribute for scoped CSS.
	    // this is implemented as a special case to avoid the overhead
	    // of going through the normal attribute patching process.
	    function setScope (vnode) {
	      var i;
	      if (isDef(i = vnode.fnScopeId)) {
	        nodeOps.setStyleScope(vnode.elm, i);
	      } else {
	        var ancestor = vnode;
	        while (ancestor) {
	          if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) {
	            nodeOps.setStyleScope(vnode.elm, i);
	          }
	          ancestor = ancestor.parent;
	        }
	      }
	      // for slot content they should also get the scopeId from the host instance.
	      if (isDef(i = activeInstance) &&
	        i !== vnode.context &&
	        i !== vnode.fnContext &&
	        isDef(i = i.$options._scopeId)
	      ) {
	        nodeOps.setStyleScope(vnode.elm, i);
	      }
	    }

	    function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {
	      for (; startIdx <= endIdx; ++startIdx) {
	        createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm, false, vnodes, startIdx);
	      }
	    }

	    function invokeDestroyHook (vnode) {
	      var i, j;
	      var data = vnode.data;
	      if (isDef(data)) {
	        if (isDef(i = data.hook) && isDef(i = i.destroy)) { i(vnode); }
	        for (i = 0; i < cbs.destroy.length; ++i) { cbs.destroy[i](vnode); }
	      }
	      if (isDef(i = vnode.children)) {
	        for (j = 0; j < vnode.children.length; ++j) {
	          invokeDestroyHook(vnode.children[j]);
	        }
	      }
	    }

	    function removeVnodes (vnodes, startIdx, endIdx) {
	      for (; startIdx <= endIdx; ++startIdx) {
	        var ch = vnodes[startIdx];
	        if (isDef(ch)) {
	          if (isDef(ch.tag)) {
	            removeAndInvokeRemoveHook(ch);
	            invokeDestroyHook(ch);
	          } else { // Text node
	            removeNode(ch.elm);
	          }
	        }
	      }
	    }

	    function removeAndInvokeRemoveHook (vnode, rm) {
	      if (isDef(rm) || isDef(vnode.data)) {
	        var i;
	        var listeners = cbs.remove.length + 1;
	        if (isDef(rm)) {
	          // we have a recursively passed down rm callback
	          // increase the listeners count
	          rm.listeners += listeners;
	        } else {
	          // directly removing
	          rm = createRmCb(vnode.elm, listeners);
	        }
	        // recursively invoke hooks on child component root node
	        if (isDef(i = vnode.componentInstance) && isDef(i = i._vnode) && isDef(i.data)) {
	          removeAndInvokeRemoveHook(i, rm);
	        }
	        for (i = 0; i < cbs.remove.length; ++i) {
	          cbs.remove[i](vnode, rm);
	        }
	        if (isDef(i = vnode.data.hook) && isDef(i = i.remove)) {
	          i(vnode, rm);
	        } else {
	          rm();
	        }
	      } else {
	        removeNode(vnode.elm);
	      }
	    }

	    function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
	      var oldStartIdx = 0;
	      var newStartIdx = 0;
	      var oldEndIdx = oldCh.length - 1;
	      var oldStartVnode = oldCh[0];
	      var oldEndVnode = oldCh[oldEndIdx];
	      var newEndIdx = newCh.length - 1;
	      var newStartVnode = newCh[0];
	      var newEndVnode = newCh[newEndIdx];
	      var oldKeyToIdx, idxInOld, vnodeToMove, refElm;

	      // removeOnly is a special flag used only by <transition-group>
	      // to ensure removed elements stay in correct relative positions
	      // during leaving transitions
	      var canMove = !removeOnly;

	      {
	        checkDuplicateKeys(newCh);
	      }

	      while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
	        if (isUndef(oldStartVnode)) {
	          oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
	        } else if (isUndef(oldEndVnode)) {
	          oldEndVnode = oldCh[--oldEndIdx];
	        } else if (sameVnode(oldStartVnode, newStartVnode)) {
	          patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
	          oldStartVnode = oldCh[++oldStartIdx];
	          newStartVnode = newCh[++newStartIdx];
	        } else if (sameVnode(oldEndVnode, newEndVnode)) {
	          patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
	          oldEndVnode = oldCh[--oldEndIdx];
	          newEndVnode = newCh[--newEndIdx];
	        } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
	          patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
	          canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));
	          oldStartVnode = oldCh[++oldStartIdx];
	          newEndVnode = newCh[--newEndIdx];
	        } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
	          patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
	          canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
	          oldEndVnode = oldCh[--oldEndIdx];
	          newStartVnode = newCh[++newStartIdx];
	        } else {
	          if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); }
	          idxInOld = isDef(newStartVnode.key)
	            ? oldKeyToIdx[newStartVnode.key]
	            : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx);
	          if (isUndef(idxInOld)) { // New element
	            createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
	          } else {
	            vnodeToMove = oldCh[idxInOld];
	            if (sameVnode(vnodeToMove, newStartVnode)) {
	              patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
	              oldCh[idxInOld] = undefined;
	              canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);
	            } else {
	              // same key but different element. treat as new element
	              createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
	            }
	          }
	          newStartVnode = newCh[++newStartIdx];
	        }
	      }
	      if (oldStartIdx > oldEndIdx) {
	        refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
	        addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
	      } else if (newStartIdx > newEndIdx) {
	        removeVnodes(oldCh, oldStartIdx, oldEndIdx);
	      }
	    }

	    function checkDuplicateKeys (children) {
	      var seenKeys = {};
	      for (var i = 0; i < children.length; i++) {
	        var vnode = children[i];
	        var key = vnode.key;
	        if (isDef(key)) {
	          if (seenKeys[key]) {
	            warn(
	              ("Duplicate keys detected: '" + key + "'. This may cause an update error."),
	              vnode.context
	            );
	          } else {
	            seenKeys[key] = true;
	          }
	        }
	      }
	    }

	    function findIdxInOld (node, oldCh, start, end) {
	      for (var i = start; i < end; i++) {
	        var c = oldCh[i];
	        if (isDef(c) && sameVnode(node, c)) { return i }
	      }
	    }

	    function patchVnode (
	      oldVnode,
	      vnode,
	      insertedVnodeQueue,
	      ownerArray,
	      index,
	      removeOnly
	    ) {
	      if (oldVnode === vnode) {
	        return
	      }

	      if (isDef(vnode.elm) && isDef(ownerArray)) {
	        // clone reused vnode
	        vnode = ownerArray[index] = cloneVNode(vnode);
	      }

	      var elm = vnode.elm = oldVnode.elm;

	      if (isTrue(oldVnode.isAsyncPlaceholder)) {
	        if (isDef(vnode.asyncFactory.resolved)) {
	          hydrate(oldVnode.elm, vnode, insertedVnodeQueue);
	        } else {
	          vnode.isAsyncPlaceholder = true;
	        }
	        return
	      }

	      // reuse element for static trees.
	      // note we only do this if the vnode is cloned -
	      // if the new node is not cloned it means the render functions have been
	      // reset by the hot-reload-api and we need to do a proper re-render.
	      if (isTrue(vnode.isStatic) &&
	        isTrue(oldVnode.isStatic) &&
	        vnode.key === oldVnode.key &&
	        (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
	      ) {
	        vnode.componentInstance = oldVnode.componentInstance;
	        return
	      }

	      var i;
	      var data = vnode.data;
	      if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
	        i(oldVnode, vnode);
	      }

	      var oldCh = oldVnode.children;
	      var ch = vnode.children;
	      if (isDef(data) && isPatchable(vnode)) {
	        for (i = 0; i < cbs.update.length; ++i) { cbs.update[i](oldVnode, vnode); }
	        if (isDef(i = data.hook) && isDef(i = i.update)) { i(oldVnode, vnode); }
	      }
	      if (isUndef(vnode.text)) {
	        if (isDef(oldCh) && isDef(ch)) {
	          if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }
	        } else if (isDef(ch)) {
	          {
	            checkDuplicateKeys(ch);
	          }
	          if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }
	          addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
	        } else if (isDef(oldCh)) {
	          removeVnodes(oldCh, 0, oldCh.length - 1);
	        } else if (isDef(oldVnode.text)) {
	          nodeOps.setTextContent(elm, '');
	        }
	      } else if (oldVnode.text !== vnode.text) {
	        nodeOps.setTextContent(elm, vnode.text);
	      }
	      if (isDef(data)) {
	        if (isDef(i = data.hook) && isDef(i = i.postpatch)) { i(oldVnode, vnode); }
	      }
	    }

	    function invokeInsertHook (vnode, queue, initial) {
	      // delay insert hooks for component root nodes, invoke them after the
	      // element is really inserted
	      if (isTrue(initial) && isDef(vnode.parent)) {
	        vnode.parent.data.pendingInsert = queue;
	      } else {
	        for (var i = 0; i < queue.length; ++i) {
	          queue[i].data.hook.insert(queue[i]);
	        }
	      }
	    }

	    var hydrationBailed = false;
	    // list of modules that can skip create hook during hydration because they
	    // are already rendered on the client or has no need for initialization
	    // Note: style is excluded because it relies on initial clone for future
	    // deep updates (#7063).
	    var isRenderedModule = makeMap('attrs,class,staticClass,staticStyle,key');

	    // Note: this is a browser-only function so we can assume elms are DOM nodes.
	    function hydrate (elm, vnode, insertedVnodeQueue, inVPre) {
	      var i;
	      var tag = vnode.tag;
	      var data = vnode.data;
	      var children = vnode.children;
	      inVPre = inVPre || (data && data.pre);
	      vnode.elm = elm;

	      if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {
	        vnode.isAsyncPlaceholder = true;
	        return true
	      }
	      // assert node match
	      {
	        if (!assertNodeMatch(elm, vnode, inVPre)) {
	          return false
	        }
	      }
	      if (isDef(data)) {
	        if (isDef(i = data.hook) && isDef(i = i.init)) { i(vnode, true /* hydrating */); }
	        if (isDef(i = vnode.componentInstance)) {
	          // child component. it should have hydrated its own tree.
	          initComponent(vnode, insertedVnodeQueue);
	          return true
	        }
	      }
	      if (isDef(tag)) {
	        if (isDef(children)) {
	          // empty element, allow client to pick up and populate children
	          if (!elm.hasChildNodes()) {
	            createChildren(vnode, children, insertedVnodeQueue);
	          } else {
	            // v-html and domProps: innerHTML
	            if (isDef(i = data) && isDef(i = i.domProps) && isDef(i = i.innerHTML)) {
	              if (i !== elm.innerHTML) {
	                /* istanbul ignore if */
	                if (typeof console !== 'undefined' &&
	                  !hydrationBailed
	                ) {
	                  hydrationBailed = true;
	                  console.warn('Parent: ', elm);
	                  console.warn('server innerHTML: ', i);
	                  console.warn('client innerHTML: ', elm.innerHTML);
	                }
	                return false
	              }
	            } else {
	              // iterate and compare children lists
	              var childrenMatch = true;
	              var childNode = elm.firstChild;
	              for (var i$1 = 0; i$1 < children.length; i$1++) {
	                if (!childNode || !hydrate(childNode, children[i$1], insertedVnodeQueue, inVPre)) {
	                  childrenMatch = false;
	                  break
	                }
	                childNode = childNode.nextSibling;
	              }
	              // if childNode is not null, it means the actual childNodes list is
	              // longer than the virtual children list.
	              if (!childrenMatch || childNode) {
	                /* istanbul ignore if */
	                if (typeof console !== 'undefined' &&
	                  !hydrationBailed
	                ) {
	                  hydrationBailed = true;
	                  console.warn('Parent: ', elm);
	                  console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children);
	                }
	                return false
	              }
	            }
	          }
	        }
	        if (isDef(data)) {
	          var fullInvoke = false;
	          for (var key in data) {
	            if (!isRenderedModule(key)) {
	              fullInvoke = true;
	              invokeCreateHooks(vnode, insertedVnodeQueue);
	              break
	            }
	          }
	          if (!fullInvoke && data['class']) {
	            // ensure collecting deps for deep class bindings for future updates
	            traverse(data['class']);
	          }
	        }
	      } else if (elm.data !== vnode.text) {
	        elm.data = vnode.text;
	      }
	      return true
	    }

	    function assertNodeMatch (node, vnode, inVPre) {
	      if (isDef(vnode.tag)) {
	        return vnode.tag.indexOf('vue-component') === 0 || (
	          !isUnknownElement$$1(vnode, inVPre) &&
	          vnode.tag.toLowerCase() === (node.tagName && node.tagName.toLowerCase())
	        )
	      } else {
	        return node.nodeType === (vnode.isComment ? 8 : 3)
	      }
	    }

	    return function patch (oldVnode, vnode, hydrating, removeOnly) {
	      if (isUndef(vnode)) {
	        if (isDef(oldVnode)) { invokeDestroyHook(oldVnode); }
	        return
	      }

	      var isInitialPatch = false;
	      var insertedVnodeQueue = [];

	      if (isUndef(oldVnode)) {
	        // empty mount (likely as component), create new root element
	        isInitialPatch = true;
	        createElm(vnode, insertedVnodeQueue);
	      } else {
	        var isRealElement = isDef(oldVnode.nodeType);
	        if (!isRealElement && sameVnode(oldVnode, vnode)) {
	          // patch existing root node
	          patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly);
	        } else {
	          if (isRealElement) {
	            // mounting to a real element
	            // check if this is server-rendered content and if we can perform
	            // a successful hydration.
	            if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
	              oldVnode.removeAttribute(SSR_ATTR);
	              hydrating = true;
	            }
	            if (isTrue(hydrating)) {
	              if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
	                invokeInsertHook(vnode, insertedVnodeQueue, true);
	                return oldVnode
	              } else {
	                warn(
	                  'The client-side rendered virtual DOM tree is not matching ' +
	                  'server-rendered content. This is likely caused by incorrect ' +
	                  'HTML markup, for example nesting block-level elements inside ' +
	                  '<p>, or missing <tbody>. Bailing hydration and performing ' +
	                  'full client-side render.'
	                );
	              }
	            }
	            // either not server-rendered, or hydration failed.
	            // create an empty node and replace it
	            oldVnode = emptyNodeAt(oldVnode);
	          }

	          // replacing existing element
	          var oldElm = oldVnode.elm;
	          var parentElm = nodeOps.parentNode(oldElm);

	          // create new node
	          createElm(
	            vnode,
	            insertedVnodeQueue,
	            // extremely rare edge case: do not insert if old element is in a
	            // leaving transition. Only happens when combining transition +
	            // keep-alive + HOCs. (#4590)
	            oldElm._leaveCb ? null : parentElm,
	            nodeOps.nextSibling(oldElm)
	          );

	          // update parent placeholder node element, recursively
	          if (isDef(vnode.parent)) {
	            var ancestor = vnode.parent;
	            var patchable = isPatchable(vnode);
	            while (ancestor) {
	              for (var i = 0; i < cbs.destroy.length; ++i) {
	                cbs.destroy[i](ancestor);
	              }
	              ancestor.elm = vnode.elm;
	              if (patchable) {
	                for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {
	                  cbs.create[i$1](emptyNode, ancestor);
	                }
	                // #6513
	                // invoke insert hooks that may have been merged by create hooks.
	                // e.g. for directives that uses the "inserted" hook.
	                var insert = ancestor.data.hook.insert;
	                if (insert.merged) {
	                  // start at index 1 to avoid re-invoking component mounted hook
	                  for (var i$2 = 1; i$2 < insert.fns.length; i$2++) {
	                    insert.fns[i$2]();
	                  }
	                }
	              } else {
	                registerRef(ancestor);
	              }
	              ancestor = ancestor.parent;
	            }
	          }

	          // destroy old node
	          if (isDef(parentElm)) {
	            removeVnodes([oldVnode], 0, 0);
	          } else if (isDef(oldVnode.tag)) {
	            invokeDestroyHook(oldVnode);
	          }
	        }
	      }

	      invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch);
	      return vnode.elm
	    }
	  }

	  /*  */

	  var directives = {
	    create: updateDirectives,
	    update: updateDirectives,
	    destroy: function unbindDirectives (vnode) {
	      updateDirectives(vnode, emptyNode);
	    }
	  };

	  function updateDirectives (oldVnode, vnode) {
	    if (oldVnode.data.directives || vnode.data.directives) {
	      _update(oldVnode, vnode);
	    }
	  }

	  function _update (oldVnode, vnode) {
	    var isCreate = oldVnode === emptyNode;
	    var isDestroy = vnode === emptyNode;
	    var oldDirs = normalizeDirectives$1(oldVnode.data.directives, oldVnode.context);
	    var newDirs = normalizeDirectives$1(vnode.data.directives, vnode.context);

	    var dirsWithInsert = [];
	    var dirsWithPostpatch = [];

	    var key, oldDir, dir;
	    for (key in newDirs) {
	      oldDir = oldDirs[key];
	      dir = newDirs[key];
	      if (!oldDir) {
	        // new directive, bind
	        callHook$1(dir, 'bind', vnode, oldVnode);
	        if (dir.def && dir.def.inserted) {
	          dirsWithInsert.push(dir);
	        }
	      } else {
	        // existing directive, update
	        dir.oldValue = oldDir.value;
	        dir.oldArg = oldDir.arg;
	        callHook$1(dir, 'update', vnode, oldVnode);
	        if (dir.def && dir.def.componentUpdated) {
	          dirsWithPostpatch.push(dir);
	        }
	      }
	    }

	    if (dirsWithInsert.length) {
	      var callInsert = function () {
	        for (var i = 0; i < dirsWithInsert.length; i++) {
	          callHook$1(dirsWithInsert[i], 'inserted', vnode, oldVnode);
	        }
	      };
	      if (isCreate) {
	        mergeVNodeHook(vnode, 'insert', callInsert);
	      } else {
	        callInsert();
	      }
	    }

	    if (dirsWithPostpatch.length) {
	      mergeVNodeHook(vnode, 'postpatch', function () {
	        for (var i = 0; i < dirsWithPostpatch.length; i++) {
	          callHook$1(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode);
	        }
	      });
	    }

	    if (!isCreate) {
	      for (key in oldDirs) {
	        if (!newDirs[key]) {
	          // no longer present, unbind
	          callHook$1(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy);
	        }
	      }
	    }
	  }

	  var emptyModifiers = Object.create(null);

	  function normalizeDirectives$1 (
	    dirs,
	    vm
	  ) {
	    var res = Object.create(null);
	    if (!dirs) {
	      // $flow-disable-line
	      return res
	    }
	    var i, dir;
	    for (i = 0; i < dirs.length; i++) {
	      dir = dirs[i];
	      if (!dir.modifiers) {
	        // $flow-disable-line
	        dir.modifiers = emptyModifiers;
	      }
	      res[getRawDirName(dir)] = dir;
	      dir.def = resolveAsset(vm.$options, 'directives', dir.name, true);
	    }
	    // $flow-disable-line
	    return res
	  }

	  function getRawDirName (dir) {
	    return dir.rawName || ((dir.name) + "." + (Object.keys(dir.modifiers || {}).join('.')))
	  }

	  function callHook$1 (dir, hook, vnode, oldVnode, isDestroy) {
	    var fn = dir.def && dir.def[hook];
	    if (fn) {
	      try {
	        fn(vnode.elm, dir, vnode, oldVnode, isDestroy);
	      } catch (e) {
	        handleError(e, vnode.context, ("directive " + (dir.name) + " " + hook + " hook"));
	      }
	    }
	  }

	  var baseModules = [
	    ref,
	    directives
	  ];

	  /*  */

	  function updateAttrs (oldVnode, vnode) {
	    var opts = vnode.componentOptions;
	    if (isDef(opts) && opts.Ctor.options.inheritAttrs === false) {
	      return
	    }
	    if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) {
	      return
	    }
	    var key, cur, old;
	    var elm = vnode.elm;
	    var oldAttrs = oldVnode.data.attrs || {};
	    var attrs = vnode.data.attrs || {};
	    // clone observed objects, as the user probably wants to mutate it
	    if (isDef(attrs.__ob__)) {
	      attrs = vnode.data.attrs = extend({}, attrs);
	    }

	    for (key in attrs) {
	      cur = attrs[key];
	      old = oldAttrs[key];
	      if (old !== cur) {
	        setAttr(elm, key, cur);
	      }
	    }
	    // #4391: in IE9, setting type can reset value for input[type=radio]
	    // #6666: IE/Edge forces progress value down to 1 before setting a max
	    /* istanbul ignore if */
	    if ((isIE || isEdge) && attrs.value !== oldAttrs.value) {
	      setAttr(elm, 'value', attrs.value);
	    }
	    for (key in oldAttrs) {
	      if (isUndef(attrs[key])) {
	        if (isXlink(key)) {
	          elm.removeAttributeNS(xlinkNS, getXlinkProp(key));
	        } else if (!isEnumeratedAttr(key)) {
	          elm.removeAttribute(key);
	        }
	      }
	    }
	  }

	  function setAttr (el, key, value) {
	    if (el.tagName.indexOf('-') > -1) {
	      baseSetAttr(el, key, value);
	    } else if (isBooleanAttr(key)) {
	      // set attribute for blank value
	      // e.g. <option disabled>Select one</option>
	      if (isFalsyAttrValue(value)) {
	        el.removeAttribute(key);
	      } else {
	        // technically allowfullscreen is a boolean attribute for <iframe>,
	        // but Flash expects a value of "true" when used on <embed> tag
	        value = key === 'allowfullscreen' && el.tagName === 'EMBED'
	          ? 'true'
	          : key;
	        el.setAttribute(key, value);
	      }
	    } else if (isEnumeratedAttr(key)) {
	      el.setAttribute(key, convertEnumeratedValue(key, value));
	    } else if (isXlink(key)) {
	      if (isFalsyAttrValue(value)) {
	        el.removeAttributeNS(xlinkNS, getXlinkProp(key));
	      } else {
	        el.setAttributeNS(xlinkNS, key, value);
	      }
	    } else {
	      baseSetAttr(el, key, value);
	    }
	  }

	  function baseSetAttr (el, key, value) {
	    if (isFalsyAttrValue(value)) {
	      el.removeAttribute(key);
	    } else {
	      // #7138: IE10 & 11 fires input event when setting placeholder on
	      // <textarea>... block the first input event and remove the blocker
	      // immediately.
	      /* istanbul ignore if */
	      if (
	        isIE && !isIE9 &&
	        el.tagName === 'TEXTAREA' &&
	        key === 'placeholder' && value !== '' && !el.__ieph
	      ) {
	        var blocker = function (e) {
	          e.stopImmediatePropagation();
	          el.removeEventListener('input', blocker);
	        };
	        el.addEventListener('input', blocker);
	        // $flow-disable-line
	        el.__ieph = true; /* IE placeholder patched */
	      }
	      el.setAttribute(key, value);
	    }
	  }

	  var attrs = {
	    create: updateAttrs,
	    update: updateAttrs
	  };

	  /*  */

	  function updateClass (oldVnode, vnode) {
	    var el = vnode.elm;
	    var data = vnode.data;
	    var oldData = oldVnode.data;
	    if (
	      isUndef(data.staticClass) &&
	      isUndef(data.class) && (
	        isUndef(oldData) || (
	          isUndef(oldData.staticClass) &&
	          isUndef(oldData.class)
	        )
	      )
	    ) {
	      return
	    }

	    var cls = genClassForVnode(vnode);

	    // handle transition classes
	    var transitionClass = el._transitionClasses;
	    if (isDef(transitionClass)) {
	      cls = concat(cls, stringifyClass(transitionClass));
	    }

	    // set the class
	    if (cls !== el._prevClass) {
	      el.setAttribute('class', cls);
	      el._prevClass = cls;
	    }
	  }

	  var klass = {
	    create: updateClass,
	    update: updateClass
	  };

	  /*  */

	  var validDivisionCharRE = /[\w).+\-_$\]]/;

	  function parseFilters (exp) {
	    var inSingle = false;
	    var inDouble = false;
	    var inTemplateString = false;
	    var inRegex = false;
	    var curly = 0;
	    var square = 0;
	    var paren = 0;
	    var lastFilterIndex = 0;
	    var c, prev, i, expression, filters;

	    for (i = 0; i < exp.length; i++) {
	      prev = c;
	      c = exp.charCodeAt(i);
	      if (inSingle) {
	        if (c === 0x27 && prev !== 0x5C) { inSingle = false; }
	      } else if (inDouble) {
	        if (c === 0x22 && prev !== 0x5C) { inDouble = false; }
	      } else if (inTemplateString) {
	        if (c === 0x60 && prev !== 0x5C) { inTemplateString = false; }
	      } else if (inRegex) {
	        if (c === 0x2f && prev !== 0x5C) { inRegex = false; }
	      } else if (
	        c === 0x7C && // pipe
	        exp.charCodeAt(i + 1) !== 0x7C &&
	        exp.charCodeAt(i - 1) !== 0x7C &&
	        !curly && !square && !paren
	      ) {
	        if (expression === undefined) {
	          // first filter, end of expression
	          lastFilterIndex = i + 1;
	          expression = exp.slice(0, i).trim();
	        } else {
	          pushFilter();
	        }
	      } else {
	        switch (c) {
	          case 0x22: inDouble = true; break         // "
	          case 0x27: inSingle = true; break         // '
	          case 0x60: inTemplateString = true; break // `
	          case 0x28: paren++; break                 // (
	          case 0x29: paren--; break                 // )
	          case 0x5B: square++; break                // [
	          case 0x5D: square--; break                // ]
	          case 0x7B: curly++; break                 // {
	          case 0x7D: curly--; break                 // }
	        }
	        if (c === 0x2f) { // /
	          var j = i - 1;
	          var p = (void 0);
	          // find first non-whitespace prev char
	          for (; j >= 0; j--) {
	            p = exp.charAt(j);
	            if (p !== ' ') { break }
	          }
	          if (!p || !validDivisionCharRE.test(p)) {
	            inRegex = true;
	          }
	        }
	      }
	    }

	    if (expression === undefined) {
	      expression = exp.slice(0, i).trim();
	    } else if (lastFilterIndex !== 0) {
	      pushFilter();
	    }

	    function pushFilter () {
	      (filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim());
	      lastFilterIndex = i + 1;
	    }

	    if (filters) {
	      for (i = 0; i < filters.length; i++) {
	        expression = wrapFilter(expression, filters[i]);
	      }
	    }

	    return expression
	  }

	  function wrapFilter (exp, filter) {
	    var i = filter.indexOf('(');
	    if (i < 0) {
	      // _f: resolveFilter
	      return ("_f(\"" + filter + "\")(" + exp + ")")
	    } else {
	      var name = filter.slice(0, i);
	      var args = filter.slice(i + 1);
	      return ("_f(\"" + name + "\")(" + exp + (args !== ')' ? ',' + args : args))
	    }
	  }

	  /*  */



	  /* eslint-disable no-unused-vars */
	  function baseWarn (msg, range) {
	    console.error(("[Vue compiler]: " + msg));
	  }
	  /* eslint-enable no-unused-vars */

	  function pluckModuleFunction (
	    modules,
	    key
	  ) {
	    return modules
	      ? modules.map(function (m) { return m[key]; }).filter(function (_) { return _; })
	      : []
	  }

	  function addProp (el, name, value, range, dynamic) {
	    (el.props || (el.props = [])).push(rangeSetItem({ name: name, value: value, dynamic: dynamic }, range));
	    el.plain = false;
	  }

	  function addAttr (el, name, value, range, dynamic) {
	    var attrs = dynamic
	      ? (el.dynamicAttrs || (el.dynamicAttrs = []))
	      : (el.attrs || (el.attrs = []));
	    attrs.push(rangeSetItem({ name: name, value: value, dynamic: dynamic }, range));
	    el.plain = false;
	  }

	  // add a raw attr (use this in preTransforms)
	  function addRawAttr (el, name, value, range) {
	    el.attrsMap[name] = value;
	    el.attrsList.push(rangeSetItem({ name: name, value: value }, range));
	  }

	  function addDirective (
	    el,
	    name,
	    rawName,
	    value,
	    arg,
	    isDynamicArg,
	    modifiers,
	    range
	  ) {
	    (el.directives || (el.directives = [])).push(rangeSetItem({
	      name: name,
	      rawName: rawName,
	      value: value,
	      arg: arg,
	      isDynamicArg: isDynamicArg,
	      modifiers: modifiers
	    }, range));
	    el.plain = false;
	  }

	  function prependModifierMarker (symbol, name, dynamic) {
	    return dynamic
	      ? ("_p(" + name + ",\"" + symbol + "\")")
	      : symbol + name // mark the event as captured
	  }

	  function addHandler (
	    el,
	    name,
	    value,
	    modifiers,
	    important,
	    warn,
	    range,
	    dynamic
	  ) {
	    modifiers = modifiers || emptyObject;
	    // warn prevent and passive modifier
	    /* istanbul ignore if */
	    if (
	      warn &&
	      modifiers.prevent && modifiers.passive
	    ) {
	      warn(
	        'passive and prevent can\'t be used together. ' +
	        'Passive handler can\'t prevent default event.',
	        range
	      );
	    }

	    // normalize click.right and click.middle since they don't actually fire
	    // this is technically browser-specific, but at least for now browsers are
	    // the only target envs that have right/middle clicks.
	    if (modifiers.right) {
	      if (dynamic) {
	        name = "(" + name + ")==='click'?'contextmenu':(" + name + ")";
	      } else if (name === 'click') {
	        name = 'contextmenu';
	        delete modifiers.right;
	      }
	    } else if (modifiers.middle) {
	      if (dynamic) {
	        name = "(" + name + ")==='click'?'mouseup':(" + name + ")";
	      } else if (name === 'click') {
	        name = 'mouseup';
	      }
	    }

	    // check capture modifier
	    if (modifiers.capture) {
	      delete modifiers.capture;
	      name = prependModifierMarker('!', name, dynamic);
	    }
	    if (modifiers.once) {
	      delete modifiers.once;
	      name = prependModifierMarker('~', name, dynamic);
	    }
	    /* istanbul ignore if */
	    if (modifiers.passive) {
	      delete modifiers.passive;
	      name = prependModifierMarker('&', name, dynamic);
	    }

	    var events;
	    if (modifiers.native) {
	      delete modifiers.native;
	      events = el.nativeEvents || (el.nativeEvents = {});
	    } else {
	      events = el.events || (el.events = {});
	    }

	    var newHandler = rangeSetItem({ value: value.trim(), dynamic: dynamic }, range);
	    if (modifiers !== emptyObject) {
	      newHandler.modifiers = modifiers;
	    }

	    var handlers = events[name];
	    /* istanbul ignore if */
	    if (Array.isArray(handlers)) {
	      important ? handlers.unshift(newHandler) : handlers.push(newHandler);
	    } else if (handlers) {
	      events[name] = important ? [newHandler, handlers] : [handlers, newHandler];
	    } else {
	      events[name] = newHandler;
	    }

	    el.plain = false;
	  }

	  function getRawBindingAttr (
	    el,
	    name
	  ) {
	    return el.rawAttrsMap[':' + name] ||
	      el.rawAttrsMap['v-bind:' + name] ||
	      el.rawAttrsMap[name]
	  }

	  function getBindingAttr (
	    el,
	    name,
	    getStatic
	  ) {
	    var dynamicValue =
	      getAndRemoveAttr(el, ':' + name) ||
	      getAndRemoveAttr(el, 'v-bind:' + name);
	    if (dynamicValue != null) {
	      return parseFilters(dynamicValue)
	    } else if (getStatic !== false) {
	      var staticValue = getAndRemoveAttr(el, name);
	      if (staticValue != null) {
	        return JSON.stringify(staticValue)
	      }
	    }
	  }

	  // note: this only removes the attr from the Array (attrsList) so that it
	  // doesn't get processed by processAttrs.
	  // By default it does NOT remove it from the map (attrsMap) because the map is
	  // needed during codegen.
	  function getAndRemoveAttr (
	    el,
	    name,
	    removeFromMap
	  ) {
	    var val;
	    if ((val = el.attrsMap[name]) != null) {
	      var list = el.attrsList;
	      for (var i = 0, l = list.length; i < l; i++) {
	        if (list[i].name === name) {
	          list.splice(i, 1);
	          break
	        }
	      }
	    }
	    if (removeFromMap) {
	      delete el.attrsMap[name];
	    }
	    return val
	  }

	  function getAndRemoveAttrByRegex (
	    el,
	    name
	  ) {
	    var list = el.attrsList;
	    for (var i = 0, l = list.length; i < l; i++) {
	      var attr = list[i];
	      if (name.test(attr.name)) {
	        list.splice(i, 1);
	        return attr
	      }
	    }
	  }

	  function rangeSetItem (
	    item,
	    range
	  ) {
	    if (range) {
	      if (range.start != null) {
	        item.start = range.start;
	      }
	      if (range.end != null) {
	        item.end = range.end;
	      }
	    }
	    return item
	  }

	  /*  */

	  /**
	   * Cross-platform code generation for component v-model
	   */
	  function genComponentModel (
	    el,
	    value,
	    modifiers
	  ) {
	    var ref = modifiers || {};
	    var number = ref.number;
	    var trim = ref.trim;

	    var baseValueExpression = '$$v';
	    var valueExpression = baseValueExpression;
	    if (trim) {
	      valueExpression =
	        "(typeof " + baseValueExpression + " === 'string'" +
	        "? " + baseValueExpression + ".trim()" +
	        ": " + baseValueExpression + ")";
	    }
	    if (number) {
	      valueExpression = "_n(" + valueExpression + ")";
	    }
	    var assignment = genAssignmentCode(value, valueExpression);

	    el.model = {
	      value: ("(" + value + ")"),
	      expression: JSON.stringify(value),
	      callback: ("function (" + baseValueExpression + ") {" + assignment + "}")
	    };
	  }

	  /**
	   * Cross-platform codegen helper for generating v-model value assignment code.
	   */
	  function genAssignmentCode (
	    value,
	    assignment
	  ) {
	    var res = parseModel(value);
	    if (res.key === null) {
	      return (value + "=" + assignment)
	    } else {
	      return ("$set(" + (res.exp) + ", " + (res.key) + ", " + assignment + ")")
	    }
	  }

	  /**
	   * Parse a v-model expression into a base path and a final key segment.
	   * Handles both dot-path and possible square brackets.
	   *
	   * Possible cases:
	   *
	   * - test
	   * - test[key]
	   * - test[test1[key]]
	   * - test["a"][key]
	   * - xxx.test[a[a].test1[key]]
	   * - test.xxx.a["asa"][test1[key]]
	   *
	   */

	  var len, str, chr, index$1, expressionPos, expressionEndPos;



	  function parseModel (val) {
	    // Fix https://github.com/vuejs/vue/pull/7730
	    // allow v-model="obj.val " (trailing whitespace)
	    val = val.trim();
	    len = val.length;

	    if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {
	      index$1 = val.lastIndexOf('.');
	      if (index$1 > -1) {
	        return {
	          exp: val.slice(0, index$1),
	          key: '"' + val.slice(index$1 + 1) + '"'
	        }
	      } else {
	        return {
	          exp: val,
	          key: null
	        }
	      }
	    }

	    str = val;
	    index$1 = expressionPos = expressionEndPos = 0;

	    while (!eof()) {
	      chr = next();
	      /* istanbul ignore if */
	      if (isStringStart(chr)) {
	        parseString(chr);
	      } else if (chr === 0x5B) {
	        parseBracket(chr);
	      }
	    }

	    return {
	      exp: val.slice(0, expressionPos),
	      key: val.slice(expressionPos + 1, expressionEndPos)
	    }
	  }

	  function next () {
	    return str.charCodeAt(++index$1)
	  }

	  function eof () {
	    return index$1 >= len
	  }

	  function isStringStart (chr) {
	    return chr === 0x22 || chr === 0x27
	  }

	  function parseBracket (chr) {
	    var inBracket = 1;
	    expressionPos = index$1;
	    while (!eof()) {
	      chr = next();
	      if (isStringStart(chr)) {
	        parseString(chr);
	        continue
	      }
	      if (chr === 0x5B) { inBracket++; }
	      if (chr === 0x5D) { inBracket--; }
	      if (inBracket === 0) {
	        expressionEndPos = index$1;
	        break
	      }
	    }
	  }

	  function parseString (chr) {
	    var stringQuote = chr;
	    while (!eof()) {
	      chr = next();
	      if (chr === stringQuote) {
	        break
	      }
	    }
	  }

	  /*  */

	  var warn$1;

	  // in some cases, the event used has to be determined at runtime
	  // so we used some reserved tokens during compile.
	  var RANGE_TOKEN = '__r';
	  var CHECKBOX_RADIO_TOKEN = '__c';

	  function model (
	    el,
	    dir,
	    _warn
	  ) {
	    warn$1 = _warn;
	    var value = dir.value;
	    var modifiers = dir.modifiers;
	    var tag = el.tag;
	    var type = el.attrsMap.type;

	    {
	      // inputs with type="file" are read only and setting the input's
	      // value will throw an error.
	      if (tag === 'input' && type === 'file') {
	        warn$1(
	          "<" + (el.tag) + " v-model=\"" + value + "\" type=\"file\">:\n" +
	          "File inputs are read only. Use a v-on:change listener instead.",
	          el.rawAttrsMap['v-model']
	        );
	      }
	    }

	    if (el.component) {
	      genComponentModel(el, value, modifiers);
	      // component v-model doesn't need extra runtime
	      return false
	    } else if (tag === 'select') {
	      genSelect(el, value, modifiers);
	    } else if (tag === 'input' && type === 'checkbox') {
	      genCheckboxModel(el, value, modifiers);
	    } else if (tag === 'input' && type === 'radio') {
	      genRadioModel(el, value, modifiers);
	    } else if (tag === 'input' || tag === 'textarea') {
	      genDefaultModel(el, value, modifiers);
	    } else if (!config.isReservedTag(tag)) {
	      genComponentModel(el, value, modifiers);
	      // component v-model doesn't need extra runtime
	      return false
	    } else {
	      warn$1(
	        "<" + (el.tag) + " v-model=\"" + value + "\">: " +
	        "v-model is not supported on this element type. " +
	        'If you are working with contenteditable, it\'s recommended to ' +
	        'wrap a library dedicated for that purpose inside a custom component.',
	        el.rawAttrsMap['v-model']
	      );
	    }

	    // ensure runtime directive metadata
	    return true
	  }

	  function genCheckboxModel (
	    el,
	    value,
	    modifiers
	  ) {
	    var number = modifiers && modifiers.number;
	    var valueBinding = getBindingAttr(el, 'value') || 'null';
	    var trueValueBinding = getBindingAttr(el, 'true-value') || 'true';
	    var falseValueBinding = getBindingAttr(el, 'false-value') || 'false';
	    addProp(el, 'checked',
	      "Array.isArray(" + value + ")" +
	      "?_i(" + value + "," + valueBinding + ")>-1" + (
	        trueValueBinding === 'true'
	          ? (":(" + value + ")")
	          : (":_q(" + value + "," + trueValueBinding + ")")
	      )
	    );
	    addHandler(el, 'change',
	      "var $$a=" + value + "," +
	          '$$el=$event.target,' +
	          "$$c=$$el.checked?(" + trueValueBinding + "):(" + falseValueBinding + ");" +
	      'if(Array.isArray($$a)){' +
	        "var $$v=" + (number ? '_n(' + valueBinding + ')' : valueBinding) + "," +
	            '$$i=_i($$a,$$v);' +
	        "if($$el.checked){$$i<0&&(" + (genAssignmentCode(value, '$$a.concat([$$v])')) + ")}" +
	        "else{$$i>-1&&(" + (genAssignmentCode(value, '$$a.slice(0,$$i).concat($$a.slice($$i+1))')) + ")}" +
	      "}else{" + (genAssignmentCode(value, '$$c')) + "}",
	      null, true
	    );
	  }

	  function genRadioModel (
	    el,
	    value,
	    modifiers
	  ) {
	    var number = modifiers && modifiers.number;
	    var valueBinding = getBindingAttr(el, 'value') || 'null';
	    valueBinding = number ? ("_n(" + valueBinding + ")") : valueBinding;
	    addProp(el, 'checked', ("_q(" + value + "," + valueBinding + ")"));
	    addHandler(el, 'change', genAssignmentCode(value, valueBinding), null, true);
	  }

	  function genSelect (
	    el,
	    value,
	    modifiers
	  ) {
	    var number = modifiers && modifiers.number;
	    var selectedVal = "Array.prototype.filter" +
	      ".call($event.target.options,function(o){return o.selected})" +
	      ".map(function(o){var val = \"_value\" in o ? o._value : o.value;" +
	      "return " + (number ? '_n(val)' : 'val') + "})";

	    var assignment = '$event.target.multiple ? $$selectedVal : $$selectedVal[0]';
	    var code = "var $$selectedVal = " + selectedVal + ";";
	    code = code + " " + (genAssignmentCode(value, assignment));
	    addHandler(el, 'change', code, null, true);
	  }

	  function genDefaultModel (
	    el,
	    value,
	    modifiers
	  ) {
	    var type = el.attrsMap.type;

	    // warn if v-bind:value conflicts with v-model
	    // except for inputs with v-bind:type
	    {
	      var value$1 = el.attrsMap['v-bind:value'] || el.attrsMap[':value'];
	      var typeBinding = el.attrsMap['v-bind:type'] || el.attrsMap[':type'];
	      if (value$1 && !typeBinding) {
	        var binding = el.attrsMap['v-bind:value'] ? 'v-bind:value' : ':value';
	        warn$1(
	          binding + "=\"" + value$1 + "\" conflicts with v-model on the same element " +
	          'because the latter already expands to a value binding internally',
	          el.rawAttrsMap[binding]
	        );
	      }
	    }

	    var ref = modifiers || {};
	    var lazy = ref.lazy;
	    var number = ref.number;
	    var trim = ref.trim;
	    var needCompositionGuard = !lazy && type !== 'range';
	    var event = lazy
	      ? 'change'
	      : type === 'range'
	        ? RANGE_TOKEN
	        : 'input';

	    var valueExpression = '$event.target.value';
	    if (trim) {
	      valueExpression = "$event.target.value.trim()";
	    }
	    if (number) {
	      valueExpression = "_n(" + valueExpression + ")";
	    }

	    var code = genAssignmentCode(value, valueExpression);
	    if (needCompositionGuard) {
	      code = "if($event.target.composing)return;" + code;
	    }

	    addProp(el, 'value', ("(" + value + ")"));
	    addHandler(el, event, code, null, true);
	    if (trim || number) {
	      addHandler(el, 'blur', '$forceUpdate()');
	    }
	  }

	  /*  */

	  // normalize v-model event tokens that can only be determined at runtime.
	  // it's important to place the event as the first in the array because
	  // the whole point is ensuring the v-model callback gets called before
	  // user-attached handlers.
	  function normalizeEvents (on) {
	    /* istanbul ignore if */
	    if (isDef(on[RANGE_TOKEN])) {
	      // IE input[type=range] only supports `change` event
	      var event = isIE ? 'change' : 'input';
	      on[event] = [].concat(on[RANGE_TOKEN], on[event] || []);
	      delete on[RANGE_TOKEN];
	    }
	    // This was originally intended to fix #4521 but no longer necessary
	    // after 2.5. Keeping it for backwards compat with generated code from < 2.4
	    /* istanbul ignore if */
	    if (isDef(on[CHECKBOX_RADIO_TOKEN])) {
	      on.change = [].concat(on[CHECKBOX_RADIO_TOKEN], on.change || []);
	      delete on[CHECKBOX_RADIO_TOKEN];
	    }
	  }

	  var target$1;

	  function createOnceHandler$1 (event, handler, capture) {
	    var _target = target$1; // save current target element in closure
	    return function onceHandler () {
	      var res = handler.apply(null, arguments);
	      if (res !== null) {
	        remove$2(event, onceHandler, capture, _target);
	      }
	    }
	  }

	  // #9446: Firefox <= 53 (in particular, ESR 52) has incorrect Event.timeStamp
	  // implementation and does not fire microtasks in between event propagation, so
	  // safe to exclude.
	  var useMicrotaskFix = isUsingMicroTask && !(isFF && Number(isFF[1]) <= 53);

	  function add$1 (
	    name,
	    handler,
	    capture,
	    passive
	  ) {
	    // async edge case #6566: inner click event triggers patch, event handler
	    // attached to outer element during patch, and triggered again. This
	    // happens because browsers fire microtask ticks between event propagation.
	    // the solution is simple: we save the timestamp when a handler is attached,
	    // and the handler would only fire if the event passed to it was fired
	    // AFTER it was attached.
	    if (useMicrotaskFix) {
	      var attachedTimestamp = currentFlushTimestamp;
	      var original = handler;
	      handler = original._wrapper = function (e) {
	        if (
	          // no bubbling, should always fire.
	          // this is just a safety net in case event.timeStamp is unreliable in
	          // certain weird environments...
	          e.target === e.currentTarget ||
	          // event is fired after handler attachment
	          e.timeStamp >= attachedTimestamp ||
	          // bail for environments that have buggy event.timeStamp implementations
	          // #9462 iOS 9 bug: event.timeStamp is 0 after history.pushState
	          // #9681 QtWebEngine event.timeStamp is negative value
	          e.timeStamp <= 0 ||
	          // #9448 bail if event is fired in another document in a multi-page
	          // electron/nw.js app, since event.timeStamp will be using a different
	          // starting reference
	          e.target.ownerDocument !== document
	        ) {
	          return original.apply(this, arguments)
	        }
	      };
	    }
	    target$1.addEventListener(
	      name,
	      handler,
	      supportsPassive
	        ? { capture: capture, passive: passive }
	        : capture
	    );
	  }

	  function remove$2 (
	    name,
	    handler,
	    capture,
	    _target
	  ) {
	    (_target || target$1).removeEventListener(
	      name,
	      handler._wrapper || handler,
	      capture
	    );
	  }

	  function updateDOMListeners (oldVnode, vnode) {
	    if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) {
	      return
	    }
	    var on = vnode.data.on || {};
	    var oldOn = oldVnode.data.on || {};
	    target$1 = vnode.elm;
	    normalizeEvents(on);
	    updateListeners(on, oldOn, add$1, remove$2, createOnceHandler$1, vnode.context);
	    target$1 = undefined;
	  }

	  var events = {
	    create: updateDOMListeners,
	    update: updateDOMListeners
	  };

	  /*  */

	  var svgContainer;

	  function updateDOMProps (oldVnode, vnode) {
	    if (isUndef(oldVnode.data.domProps) && isUndef(vnode.data.domProps)) {
	      return
	    }
	    var key, cur;
	    var elm = vnode.elm;
	    var oldProps = oldVnode.data.domProps || {};
	    var props = vnode.data.domProps || {};
	    // clone observed objects, as the user probably wants to mutate it
	    if (isDef(props.__ob__)) {
	      props = vnode.data.domProps = extend({}, props);
	    }

	    for (key in oldProps) {
	      if (!(key in props)) {
	        elm[key] = '';
	      }
	    }

	    for (key in props) {
	      cur = props[key];
	      // ignore children if the node has textContent or innerHTML,
	      // as these will throw away existing DOM nodes and cause removal errors
	      // on subsequent patches (#3360)
	      if (key === 'textContent' || key === 'innerHTML') {
	        if (vnode.children) { vnode.children.length = 0; }
	        if (cur === oldProps[key]) { continue }
	        // #6601 work around Chrome version <= 55 bug where single textNode
	        // replaced by innerHTML/textContent retains its parentNode property
	        if (elm.childNodes.length === 1) {
	          elm.removeChild(elm.childNodes[0]);
	        }
	      }

	      if (key === 'value' && elm.tagName !== 'PROGRESS') {
	        // store value as _value as well since
	        // non-string values will be stringified
	        elm._value = cur;
	        // avoid resetting cursor position when value is the same
	        var strCur = isUndef(cur) ? '' : String(cur);
	        if (shouldUpdateValue(elm, strCur)) {
	          elm.value = strCur;
	        }
	      } else if (key === 'innerHTML' && isSVG(elm.tagName) && isUndef(elm.innerHTML)) {
	        // IE doesn't support innerHTML for SVG elements
	        svgContainer = svgContainer || document.createElement('div');
	        svgContainer.innerHTML = "<svg>" + cur + "</svg>";
	        var svg = svgContainer.firstChild;
	        while (elm.firstChild) {
	          elm.removeChild(elm.firstChild);
	        }
	        while (svg.firstChild) {
	          elm.appendChild(svg.firstChild);
	        }
	      } else if (
	        // skip the update if old and new VDOM state is the same.
	        // `value` is handled separately because the DOM value may be temporarily
	        // out of sync with VDOM state due to focus, composition and modifiers.
	        // This  #4521 by skipping the unnecessary `checked` update.
	        cur !== oldProps[key]
	      ) {
	        // some property updates can throw
	        // e.g. `value` on <progress> w/ non-finite value
	        try {
	          elm[key] = cur;
	        } catch (e) {}
	      }
	    }
	  }

	  // check platforms/web/util/attrs.js acceptValue


	  function shouldUpdateValue (elm, checkVal) {
	    return (!elm.composing && (
	      elm.tagName === 'OPTION' ||
	      isNotInFocusAndDirty(elm, checkVal) ||
	      isDirtyWithModifiers(elm, checkVal)
	    ))
	  }

	  function isNotInFocusAndDirty (elm, checkVal) {
	    // return true when textbox (.number and .trim) loses focus and its value is
	    // not equal to the updated value
	    var notInFocus = true;
	    // #6157
	    // work around IE bug when accessing document.activeElement in an iframe
	    try { notInFocus = document.activeElement !== elm; } catch (e) {}
	    return notInFocus && elm.value !== checkVal
	  }

	  function isDirtyWithModifiers (elm, newVal) {
	    var value = elm.value;
	    var modifiers = elm._vModifiers; // injected by v-model runtime
	    if (isDef(modifiers)) {
	      if (modifiers.number) {
	        return toNumber(value) !== toNumber(newVal)
	      }
	      if (modifiers.trim) {
	        return value.trim() !== newVal.trim()
	      }
	    }
	    return value !== newVal
	  }

	  var domProps = {
	    create: updateDOMProps,
	    update: updateDOMProps
	  };

	  /*  */

	  var parseStyleText = cached(function (cssText) {
	    var res = {};
	    var listDelimiter = /;(?![^(]*\))/g;
	    var propertyDelimiter = /:(.+)/;
	    cssText.split(listDelimiter).forEach(function (item) {
	      if (item) {
	        var tmp = item.split(propertyDelimiter);
	        tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim());
	      }
	    });
	    return res
	  });

	  // merge static and dynamic style data on the same vnode
	  function normalizeStyleData (data) {
	    var style = normalizeStyleBinding(data.style);
	    // static style is pre-processed into an object during compilation
	    // and is always a fresh object, so it's safe to merge into it
	    return data.staticStyle
	      ? extend(data.staticStyle, style)
	      : style
	  }

	  // normalize possible array / string values into Object
	  function normalizeStyleBinding (bindingStyle) {
	    if (Array.isArray(bindingStyle)) {
	      return toObject(bindingStyle)
	    }
	    if (typeof bindingStyle === 'string') {
	      return parseStyleText(bindingStyle)
	    }
	    return bindingStyle
	  }

	  /**
	   * parent component style should be after child's
	   * so that parent component's style could override it
	   */
	  function getStyle (vnode, checkChild) {
	    var res = {};
	    var styleData;

	    if (checkChild) {
	      var childNode = vnode;
	      while (childNode.componentInstance) {
	        childNode = childNode.componentInstance._vnode;
	        if (
	          childNode && childNode.data &&
	          (styleData = normalizeStyleData(childNode.data))
	        ) {
	          extend(res, styleData);
	        }
	      }
	    }

	    if ((styleData = normalizeStyleData(vnode.data))) {
	      extend(res, styleData);
	    }

	    var parentNode = vnode;
	    while ((parentNode = parentNode.parent)) {
	      if (parentNode.data && (styleData = normalizeStyleData(parentNode.data))) {
	        extend(res, styleData);
	      }
	    }
	    return res
	  }

	  /*  */

	  var cssVarRE = /^--/;
	  var importantRE = /\s*!important$/;
	  var setProp = function (el, name, val) {
	    /* istanbul ignore if */
	    if (cssVarRE.test(name)) {
	      el.style.setProperty(name, val);
	    } else if (importantRE.test(val)) {
	      el.style.setProperty(hyphenate(name), val.replace(importantRE, ''), 'important');
	    } else {
	      var normalizedName = normalize(name);
	      if (Array.isArray(val)) {
	        // Support values array created by autoprefixer, e.g.
	        // {display: ["-webkit-box", "-ms-flexbox", "flex"]}
	        // Set them one by one, and the browser will only set those it can recognize
	        for (var i = 0, len = val.length; i < len; i++) {
	          el.style[normalizedName] = val[i];
	        }
	      } else {
	        el.style[normalizedName] = val;
	      }
	    }
	  };

	  var vendorNames = ['Webkit', 'Moz', 'ms'];

	  var emptyStyle;
	  var normalize = cached(function (prop) {
	    emptyStyle = emptyStyle || document.createElement('div').style;
	    prop = camelize(prop);
	    if (prop !== 'filter' && (prop in emptyStyle)) {
	      return prop
	    }
	    var capName = prop.charAt(0).toUpperCase() + prop.slice(1);
	    for (var i = 0; i < vendorNames.length; i++) {
	      var name = vendorNames[i] + capName;
	      if (name in emptyStyle) {
	        return name
	      }
	    }
	  });

	  function updateStyle (oldVnode, vnode) {
	    var data = vnode.data;
	    var oldData = oldVnode.data;

	    if (isUndef(data.staticStyle) && isUndef(data.style) &&
	      isUndef(oldData.staticStyle) && isUndef(oldData.style)
	    ) {
	      return
	    }

	    var cur, name;
	    var el = vnode.elm;
	    var oldStaticStyle = oldData.staticStyle;
	    var oldStyleBinding = oldData.normalizedStyle || oldData.style || {};

	    // if static style exists, stylebinding already merged into it when doing normalizeStyleData
	    var oldStyle = oldStaticStyle || oldStyleBinding;

	    var style = normalizeStyleBinding(vnode.data.style) || {};

	    // store normalized style under a different key for next diff
	    // make sure to clone it if it's reactive, since the user likely wants
	    // to mutate it.
	    vnode.data.normalizedStyle = isDef(style.__ob__)
	      ? extend({}, style)
	      : style;

	    var newStyle = getStyle(vnode, true);

	    for (name in oldStyle) {
	      if (isUndef(newStyle[name])) {
	        setProp(el, name, '');
	      }
	    }
	    for (name in newStyle) {
	      cur = newStyle[name];
	      if (cur !== oldStyle[name]) {
	        // ie9 setting to null has no effect, must use empty string
	        setProp(el, name, cur == null ? '' : cur);
	      }
	    }
	  }

	  var style = {
	    create: updateStyle,
	    update: updateStyle
	  };

	  /*  */

	  var whitespaceRE = /\s+/;

	  /**
	   * Add class with compatibility for SVG since classList is not supported on
	   * SVG elements in IE
	   */
	  function addClass (el, cls) {
	    /* istanbul ignore if */
	    if (!cls || !(cls = cls.trim())) {
	      return
	    }

	    /* istanbul ignore else */
	    if (el.classList) {
	      if (cls.indexOf(' ') > -1) {
	        cls.split(whitespaceRE).forEach(function (c) { return el.classList.add(c); });
	      } else {
	        el.classList.add(cls);
	      }
	    } else {
	      var cur = " " + (el.getAttribute('class') || '') + " ";
	      if (cur.indexOf(' ' + cls + ' ') < 0) {
	        el.setAttribute('class', (cur + cls).trim());
	      }
	    }
	  }

	  /**
	   * Remove class with compatibility for SVG since classList is not supported on
	   * SVG elements in IE
	   */
	  function removeClass (el, cls) {
	    /* istanbul ignore if */
	    if (!cls || !(cls = cls.trim())) {
	      return
	    }

	    /* istanbul ignore else */
	    if (el.classList) {
	      if (cls.indexOf(' ') > -1) {
	        cls.split(whitespaceRE).forEach(function (c) { return el.classList.remove(c); });
	      } else {
	        el.classList.remove(cls);
	      }
	      if (!el.classList.length) {
	        el.removeAttribute('class');
	      }
	    } else {
	      var cur = " " + (el.getAttribute('class') || '') + " ";
	      var tar = ' ' + cls + ' ';
	      while (cur.indexOf(tar) >= 0) {
	        cur = cur.replace(tar, ' ');
	      }
	      cur = cur.trim();
	      if (cur) {
	        el.setAttribute('class', cur);
	      } else {
	        el.removeAttribute('class');
	      }
	    }
	  }

	  /*  */

	  function resolveTransition (def$$1) {
	    if (!def$$1) {
	      return
	    }
	    /* istanbul ignore else */
	    if (typeof def$$1 === 'object') {
	      var res = {};
	      if (def$$1.css !== false) {
	        extend(res, autoCssTransition(def$$1.name || 'v'));
	      }
	      extend(res, def$$1);
	      return res
	    } else if (typeof def$$1 === 'string') {
	      return autoCssTransition(def$$1)
	    }
	  }

	  var autoCssTransition = cached(function (name) {
	    return {
	      enterClass: (name + "-enter"),
	      enterToClass: (name + "-enter-to"),
	      enterActiveClass: (name + "-enter-active"),
	      leaveClass: (name + "-leave"),
	      leaveToClass: (name + "-leave-to"),
	      leaveActiveClass: (name + "-leave-active")
	    }
	  });

	  var hasTransition = inBrowser && !isIE9;
	  var TRANSITION = 'transition';
	  var ANIMATION = 'animation';

	  // Transition property/event sniffing
	  var transitionProp = 'transition';
	  var transitionEndEvent = 'transitionend';
	  var animationProp = 'animation';
	  var animationEndEvent = 'animationend';
	  if (hasTransition) {
	    /* istanbul ignore if */
	    if (window.ontransitionend === undefined &&
	      window.onwebkittransitionend !== undefined
	    ) {
	      transitionProp = 'WebkitTransition';
	      transitionEndEvent = 'webkitTransitionEnd';
	    }
	    if (window.onanimationend === undefined &&
	      window.onwebkitanimationend !== undefined
	    ) {
	      animationProp = 'WebkitAnimation';
	      animationEndEvent = 'webkitAnimationEnd';
	    }
	  }

	  // binding to window is necessary to make hot reload work in IE in strict mode
	  var raf = inBrowser
	    ? window.requestAnimationFrame
	      ? window.requestAnimationFrame.bind(window)
	      : setTimeout
	    : /* istanbul ignore next */ function (fn) { return fn(); };

	  function nextFrame (fn) {
	    raf(function () {
	      raf(fn);
	    });
	  }

	  function addTransitionClass (el, cls) {
	    var transitionClasses = el._transitionClasses || (el._transitionClasses = []);
	    if (transitionClasses.indexOf(cls) < 0) {
	      transitionClasses.push(cls);
	      addClass(el, cls);
	    }
	  }

	  function removeTransitionClass (el, cls) {
	    if (el._transitionClasses) {
	      remove(el._transitionClasses, cls);
	    }
	    removeClass(el, cls);
	  }

	  function whenTransitionEnds (
	    el,
	    expectedType,
	    cb
	  ) {
	    var ref = getTransitionInfo(el, expectedType);
	    var type = ref.type;
	    var timeout = ref.timeout;
	    var propCount = ref.propCount;
	    if (!type) { return cb() }
	    var event = type === TRANSITION ? transitionEndEvent : animationEndEvent;
	    var ended = 0;
	    var end = function () {
	      el.removeEventListener(event, onEnd);
	      cb();
	    };
	    var onEnd = function (e) {
	      if (e.target === el) {
	        if (++ended >= propCount) {
	          end();
	        }
	      }
	    };
	    setTimeout(function () {
	      if (ended < propCount) {
	        end();
	      }
	    }, timeout + 1);
	    el.addEventListener(event, onEnd);
	  }

	  var transformRE = /\b(transform|all)(,|$)/;

	  function getTransitionInfo (el, expectedType) {
	    var styles = window.getComputedStyle(el);
	    // JSDOM may return undefined for transition properties
	    var transitionDelays = (styles[transitionProp + 'Delay'] || '').split(', ');
	    var transitionDurations = (styles[transitionProp + 'Duration'] || '').split(', ');
	    var transitionTimeout = getTimeout(transitionDelays, transitionDurations);
	    var animationDelays = (styles[animationProp + 'Delay'] || '').split(', ');
	    var animationDurations = (styles[animationProp + 'Duration'] || '').split(', ');
	    var animationTimeout = getTimeout(animationDelays, animationDurations);

	    var type;
	    var timeout = 0;
	    var propCount = 0;
	    /* istanbul ignore if */
	    if (expectedType === TRANSITION) {
	      if (transitionTimeout > 0) {
	        type = TRANSITION;
	        timeout = transitionTimeout;
	        propCount = transitionDurations.length;
	      }
	    } else if (expectedType === ANIMATION) {
	      if (animationTimeout > 0) {
	        type = ANIMATION;
	        timeout = animationTimeout;
	        propCount = animationDurations.length;
	      }
	    } else {
	      timeout = Math.max(transitionTimeout, animationTimeout);
	      type = timeout > 0
	        ? transitionTimeout > animationTimeout
	          ? TRANSITION
	          : ANIMATION
	        : null;
	      propCount = type
	        ? type === TRANSITION
	          ? transitionDurations.length
	          : animationDurations.length
	        : 0;
	    }
	    var hasTransform =
	      type === TRANSITION &&
	      transformRE.test(styles[transitionProp + 'Property']);
	    return {
	      type: type,
	      timeout: timeout,
	      propCount: propCount,
	      hasTransform: hasTransform
	    }
	  }

	  function getTimeout (delays, durations) {
	    /* istanbul ignore next */
	    while (delays.length < durations.length) {
	      delays = delays.concat(delays);
	    }

	    return Math.max.apply(null, durations.map(function (d, i) {
	      return toMs(d) + toMs(delays[i])
	    }))
	  }

	  // Old versions of Chromium (below 61.0.3163.100) formats floating pointer numbers
	  // in a locale-dependent way, using a comma instead of a dot.
	  // If comma is not replaced with a dot, the input will be rounded down (i.e. acting
	  // as a floor function) causing unexpected behaviors
	  function toMs (s) {
	    return Number(s.slice(0, -1).replace(',', '.')) * 1000
	  }

	  /*  */

	  function enter (vnode, toggleDisplay) {
	    var el = vnode.elm;

	    // call leave callback now
	    if (isDef(el._leaveCb)) {
	      el._leaveCb.cancelled = true;
	      el._leaveCb();
	    }

	    var data = resolveTransition(vnode.data.transition);
	    if (isUndef(data)) {
	      return
	    }

	    /* istanbul ignore if */
	    if (isDef(el._enterCb) || el.nodeType !== 1) {
	      return
	    }

	    var css = data.css;
	    var type = data.type;
	    var enterClass = data.enterClass;
	    var enterToClass = data.enterToClass;
	    var enterActiveClass = data.enterActiveClass;
	    var appearClass = data.appearClass;
	    var appearToClass = data.appearToClass;
	    var appearActiveClass = data.appearActiveClass;
	    var beforeEnter = data.beforeEnter;
	    var enter = data.enter;
	    var afterEnter = data.afterEnter;
	    var enterCancelled = data.enterCancelled;
	    var beforeAppear = data.beforeAppear;
	    var appear = data.appear;
	    var afterAppear = data.afterAppear;
	    var appearCancelled = data.appearCancelled;
	    var duration = data.duration;

	    // activeInstance will always be the <transition> component managing this
	    // transition. One edge case to check is when the <transition> is placed
	    // as the root node of a child component. In that case we need to check
	    // <transition>'s parent for appear check.
	    var context = activeInstance;
	    var transitionNode = activeInstance.$vnode;
	    while (transitionNode && transitionNode.parent) {
	      context = transitionNode.context;
	      transitionNode = transitionNode.parent;
	    }

	    var isAppear = !context._isMounted || !vnode.isRootInsert;

	    if (isAppear && !appear && appear !== '') {
	      return
	    }

	    var startClass = isAppear && appearClass
	      ? appearClass
	      : enterClass;
	    var activeClass = isAppear && appearActiveClass
	      ? appearActiveClass
	      : enterActiveClass;
	    var toClass = isAppear && appearToClass
	      ? appearToClass
	      : enterToClass;

	    var beforeEnterHook = isAppear
	      ? (beforeAppear || beforeEnter)
	      : beforeEnter;
	    var enterHook = isAppear
	      ? (typeof appear === 'function' ? appear : enter)
	      : enter;
	    var afterEnterHook = isAppear
	      ? (afterAppear || afterEnter)
	      : afterEnter;
	    var enterCancelledHook = isAppear
	      ? (appearCancelled || enterCancelled)
	      : enterCancelled;

	    var explicitEnterDuration = toNumber(
	      isObject(duration)
	        ? duration.enter
	        : duration
	    );

	    if (explicitEnterDuration != null) {
	      checkDuration(explicitEnterDuration, 'enter', vnode);
	    }

	    var expectsCSS = css !== false && !isIE9;
	    var userWantsControl = getHookArgumentsLength(enterHook);

	    var cb = el._enterCb = once(function () {
	      if (expectsCSS) {
	        removeTransitionClass(el, toClass);
	        removeTransitionClass(el, activeClass);
	      }
	      if (cb.cancelled) {
	        if (expectsCSS) {
	          removeTransitionClass(el, startClass);
	        }
	        enterCancelledHook && enterCancelledHook(el);
	      } else {
	        afterEnterHook && afterEnterHook(el);
	      }
	      el._enterCb = null;
	    });

	    if (!vnode.data.show) {
	      // remove pending leave element on enter by injecting an insert hook
	      mergeVNodeHook(vnode, 'insert', function () {
	        var parent = el.parentNode;
	        var pendingNode = parent && parent._pending && parent._pending[vnode.key];
	        if (pendingNode &&
	          pendingNode.tag === vnode.tag &&
	          pendingNode.elm._leaveCb
	        ) {
	          pendingNode.elm._leaveCb();
	        }
	        enterHook && enterHook(el, cb);
	      });
	    }

	    // start enter transition
	    beforeEnterHook && beforeEnterHook(el);
	    if (expectsCSS) {
	      addTransitionClass(el, startClass);
	      addTransitionClass(el, activeClass);
	      nextFrame(function () {
	        removeTransitionClass(el, startClass);
	        if (!cb.cancelled) {
	          addTransitionClass(el, toClass);
	          if (!userWantsControl) {
	            if (isValidDuration(explicitEnterDuration)) {
	              setTimeout(cb, explicitEnterDuration);
	            } else {
	              whenTransitionEnds(el, type, cb);
	            }
	          }
	        }
	      });
	    }

	    if (vnode.data.show) {
	      toggleDisplay && toggleDisplay();
	      enterHook && enterHook(el, cb);
	    }

	    if (!expectsCSS && !userWantsControl) {
	      cb();
	    }
	  }

	  function leave (vnode, rm) {
	    var el = vnode.elm;

	    // call enter callback now
	    if (isDef(el._enterCb)) {
	      el._enterCb.cancelled = true;
	      el._enterCb();
	    }

	    var data = resolveTransition(vnode.data.transition);
	    if (isUndef(data) || el.nodeType !== 1) {
	      return rm()
	    }

	    /* istanbul ignore if */
	    if (isDef(el._leaveCb)) {
	      return
	    }

	    var css = data.css;
	    var type = data.type;
	    var leaveClass = data.leaveClass;
	    var leaveToClass = data.leaveToClass;
	    var leaveActiveClass = data.leaveActiveClass;
	    var beforeLeave = data.beforeLeave;
	    var leave = data.leave;
	    var afterLeave = data.afterLeave;
	    var leaveCancelled = data.leaveCancelled;
	    var delayLeave = data.delayLeave;
	    var duration = data.duration;

	    var expectsCSS = css !== false && !isIE9;
	    var userWantsControl = getHookArgumentsLength(leave);

	    var explicitLeaveDuration = toNumber(
	      isObject(duration)
	        ? duration.leave
	        : duration
	    );

	    if (isDef(explicitLeaveDuration)) {
	      checkDuration(explicitLeaveDuration, 'leave', vnode);
	    }

	    var cb = el._leaveCb = once(function () {
	      if (el.parentNode && el.parentNode._pending) {
	        el.parentNode._pending[vnode.key] = null;
	      }
	      if (expectsCSS) {
	        removeTransitionClass(el, leaveToClass);
	        removeTransitionClass(el, leaveActiveClass);
	      }
	      if (cb.cancelled) {
	        if (expectsCSS) {
	          removeTransitionClass(el, leaveClass);
	        }
	        leaveCancelled && leaveCancelled(el);
	      } else {
	        rm();
	        afterLeave && afterLeave(el);
	      }
	      el._leaveCb = null;
	    });

	    if (delayLeave) {
	      delayLeave(performLeave);
	    } else {
	      performLeave();
	    }

	    function performLeave () {
	      // the delayed leave may have already been cancelled
	      if (cb.cancelled) {
	        return
	      }
	      // record leaving element
	      if (!vnode.data.show && el.parentNode) {
	        (el.parentNode._pending || (el.parentNode._pending = {}))[(vnode.key)] = vnode;
	      }
	      beforeLeave && beforeLeave(el);
	      if (expectsCSS) {
	        addTransitionClass(el, leaveClass);
	        addTransitionClass(el, leaveActiveClass);
	        nextFrame(function () {
	          removeTransitionClass(el, leaveClass);
	          if (!cb.cancelled) {
	            addTransitionClass(el, leaveToClass);
	            if (!userWantsControl) {
	              if (isValidDuration(explicitLeaveDuration)) {
	                setTimeout(cb, explicitLeaveDuration);
	              } else {
	                whenTransitionEnds(el, type, cb);
	              }
	            }
	          }
	        });
	      }
	      leave && leave(el, cb);
	      if (!expectsCSS && !userWantsControl) {
	        cb();
	      }
	    }
	  }

	  // only used in dev mode
	  function checkDuration (val, name, vnode) {
	    if (typeof val !== 'number') {
	      warn(
	        "<transition> explicit " + name + " duration is not a valid number - " +
	        "got " + (JSON.stringify(val)) + ".",
	        vnode.context
	      );
	    } else if (isNaN(val)) {
	      warn(
	        "<transition> explicit " + name + " duration is NaN - " +
	        'the duration expression might be incorrect.',
	        vnode.context
	      );
	    }
	  }

	  function isValidDuration (val) {
	    return typeof val === 'number' && !isNaN(val)
	  }

	  /**
	   * Normalize a transition hook's argument length. The hook may be:
	   * - a merged hook (invoker) with the original in .fns
	   * - a wrapped component method (check ._length)
	   * - a plain function (.length)
	   */
	  function getHookArgumentsLength (fn) {
	    if (isUndef(fn)) {
	      return false
	    }
	    var invokerFns = fn.fns;
	    if (isDef(invokerFns)) {
	      // invoker
	      return getHookArgumentsLength(
	        Array.isArray(invokerFns)
	          ? invokerFns[0]
	          : invokerFns
	      )
	    } else {
	      return (fn._length || fn.length) > 1
	    }
	  }

	  function _enter (_, vnode) {
	    if (vnode.data.show !== true) {
	      enter(vnode);
	    }
	  }

	  var transition = inBrowser ? {
	    create: _enter,
	    activate: _enter,
	    remove: function remove$$1 (vnode, rm) {
	      /* istanbul ignore else */
	      if (vnode.data.show !== true) {
	        leave(vnode, rm);
	      } else {
	        rm();
	      }
	    }
	  } : {};

	  var platformModules = [
	    attrs,
	    klass,
	    events,
	    domProps,
	    style,
	    transition
	  ];

	  /*  */

	  // the directive module should be applied last, after all
	  // built-in modules have been applied.
	  var modules = platformModules.concat(baseModules);

	  var patch = createPatchFunction({ nodeOps: nodeOps, modules: modules });

	  /**
	   * Not type checking this file because flow doesn't like attaching
	   * properties to Elements.
	   */

	  /* istanbul ignore if */
	  if (isIE9) {
	    // http://www.matts411.com/post/internet-explorer-9-oninput/
	    document.addEventListener('selectionchange', function () {
	      var el = document.activeElement;
	      if (el && el.vmodel) {
	        trigger(el, 'input');
	      }
	    });
	  }

	  var directive = {
	    inserted: function inserted (el, binding, vnode, oldVnode) {
	      if (vnode.tag === 'select') {
	        // #6903
	        if (oldVnode.elm && !oldVnode.elm._vOptions) {
	          mergeVNodeHook(vnode, 'postpatch', function () {
	            directive.componentUpdated(el, binding, vnode);
	          });
	        } else {
	          setSelected(el, binding, vnode.context);
	        }
	        el._vOptions = [].map.call(el.options, getValue);
	      } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
	        el._vModifiers = binding.modifiers;
	        if (!binding.modifiers.lazy) {
	          el.addEventListener('compositionstart', onCompositionStart);
	          el.addEventListener('compositionend', onCompositionEnd);
	          // Safari < 10.2 & UIWebView doesn't fire compositionend when
	          // switching focus before confirming composition choice
	          // this also fixes the issue where some browsers e.g. iOS Chrome
	          // fires "change" instead of "input" on autocomplete.
	          el.addEventListener('change', onCompositionEnd);
	          /* istanbul ignore if */
	          if (isIE9) {
	            el.vmodel = true;
	          }
	        }
	      }
	    },

	    componentUpdated: function componentUpdated (el, binding, vnode) {
	      if (vnode.tag === 'select') {
	        setSelected(el, binding, vnode.context);
	        // in case the options rendered by v-for have changed,
	        // it's possible that the value is out-of-sync with the rendered options.
	        // detect such cases and filter out values that no longer has a matching
	        // option in the DOM.
	        var prevOptions = el._vOptions;
	        var curOptions = el._vOptions = [].map.call(el.options, getValue);
	        if (curOptions.some(function (o, i) { return !looseEqual(o, prevOptions[i]); })) {
	          // trigger change event if
	          // no matching option found for at least one value
	          var needReset = el.multiple
	            ? binding.value.some(function (v) { return hasNoMatchingOption(v, curOptions); })
	            : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions);
	          if (needReset) {
	            trigger(el, 'change');
	          }
	        }
	      }
	    }
	  };

	  function setSelected (el, binding, vm) {
	    actuallySetSelected(el, binding, vm);
	    /* istanbul ignore if */
	    if (isIE || isEdge) {
	      setTimeout(function () {
	        actuallySetSelected(el, binding, vm);
	      }, 0);
	    }
	  }

	  function actuallySetSelected (el, binding, vm) {
	    var value = binding.value;
	    var isMultiple = el.multiple;
	    if (isMultiple && !Array.isArray(value)) {
	      warn(
	        "<select multiple v-model=\"" + (binding.expression) + "\"> " +
	        "expects an Array value for its binding, but got " + (Object.prototype.toString.call(value).slice(8, -1)),
	        vm
	      );
	      return
	    }
	    var selected, option;
	    for (var i = 0, l = el.options.length; i < l; i++) {
	      option = el.options[i];
	      if (isMultiple) {
	        selected = looseIndexOf(value, getValue(option)) > -1;
	        if (option.selected !== selected) {
	          option.selected = selected;
	        }
	      } else {
	        if (looseEqual(getValue(option), value)) {
	          if (el.selectedIndex !== i) {
	            el.selectedIndex = i;
	          }
	          return
	        }
	      }
	    }
	    if (!isMultiple) {
	      el.selectedIndex = -1;
	    }
	  }

	  function hasNoMatchingOption (value, options) {
	    return options.every(function (o) { return !looseEqual(o, value); })
	  }

	  function getValue (option) {
	    return '_value' in option
	      ? option._value
	      : option.value
	  }

	  function onCompositionStart (e) {
	    e.target.composing = true;
	  }

	  function onCompositionEnd (e) {
	    // prevent triggering an input event for no reason
	    if (!e.target.composing) { return }
	    e.target.composing = false;
	    trigger(e.target, 'input');
	  }

	  function trigger (el, type) {
	    var e = document.createEvent('HTMLEvents');
	    e.initEvent(type, true, true);
	    el.dispatchEvent(e);
	  }

	  /*  */

	  // recursively search for possible transition defined inside the component root
	  function locateNode (vnode) {
	    return vnode.componentInstance && (!vnode.data || !vnode.data.transition)
	      ? locateNode(vnode.componentInstance._vnode)
	      : vnode
	  }

	  var show = {
	    bind: function bind (el, ref, vnode) {
	      var value = ref.value;

	      vnode = locateNode(vnode);
	      var transition$$1 = vnode.data && vnode.data.transition;
	      var originalDisplay = el.__vOriginalDisplay =
	        el.style.display === 'none' ? '' : el.style.display;
	      if (value && transition$$1) {
	        vnode.data.show = true;
	        enter(vnode, function () {
	          el.style.display = originalDisplay;
	        });
	      } else {
	        el.style.display = value ? originalDisplay : 'none';
	      }
	    },

	    update: function update (el, ref, vnode) {
	      var value = ref.value;
	      var oldValue = ref.oldValue;

	      /* istanbul ignore if */
	      if (!value === !oldValue) { return }
	      vnode = locateNode(vnode);
	      var transition$$1 = vnode.data && vnode.data.transition;
	      if (transition$$1) {
	        vnode.data.show = true;
	        if (value) {
	          enter(vnode, function () {
	            el.style.display = el.__vOriginalDisplay;
	          });
	        } else {
	          leave(vnode, function () {
	            el.style.display = 'none';
	          });
	        }
	      } else {
	        el.style.display = value ? el.__vOriginalDisplay : 'none';
	      }
	    },

	    unbind: function unbind (
	      el,
	      binding,
	      vnode,
	      oldVnode,
	      isDestroy
	    ) {
	      if (!isDestroy) {
	        el.style.display = el.__vOriginalDisplay;
	      }
	    }
	  };

	  var platformDirectives = {
	    model: directive,
	    show: show
	  };

	  /*  */

	  var transitionProps = {
	    name: String,
	    appear: Boolean,
	    css: Boolean,
	    mode: String,
	    type: String,
	    enterClass: String,
	    leaveClass: String,
	    enterToClass: String,
	    leaveToClass: String,
	    enterActiveClass: String,
	    leaveActiveClass: String,
	    appearClass: String,
	    appearActiveClass: String,
	    appearToClass: String,
	    duration: [Number, String, Object]
	  };

	  // in case the child is also an abstract component, e.g. <keep-alive>
	  // we want to recursively retrieve the real component to be rendered
	  function getRealChild (vnode) {
	    var compOptions = vnode && vnode.componentOptions;
	    if (compOptions && compOptions.Ctor.options.abstract) {
	      return getRealChild(getFirstComponentChild(compOptions.children))
	    } else {
	      return vnode
	    }
	  }

	  function extractTransitionData (comp) {
	    var data = {};
	    var options = comp.$options;
	    // props
	    for (var key in options.propsData) {
	      data[key] = comp[key];
	    }
	    // events.
	    // extract listeners and pass them directly to the transition methods
	    var listeners = options._parentListeners;
	    for (var key$1 in listeners) {
	      data[camelize(key$1)] = listeners[key$1];
	    }
	    return data
	  }

	  function placeholder (h, rawChild) {
	    if (/\d-keep-alive$/.test(rawChild.tag)) {
	      return h('keep-alive', {
	        props: rawChild.componentOptions.propsData
	      })
	    }
	  }

	  function hasParentTransition (vnode) {
	    while ((vnode = vnode.parent)) {
	      if (vnode.data.transition) {
	        return true
	      }
	    }
	  }

	  function isSameChild (child, oldChild) {
	    return oldChild.key === child.key && oldChild.tag === child.tag
	  }

	  var isNotTextNode = function (c) { return c.tag || isAsyncPlaceholder(c); };

	  var isVShowDirective = function (d) { return d.name === 'show'; };

	  var Transition = {
	    name: 'transition',
	    props: transitionProps,
	    abstract: true,

	    render: function render (h) {
	      var this$1 = this;

	      var children = this.$slots.default;
	      if (!children) {
	        return
	      }

	      // filter out text nodes (possible whitespaces)
	      children = children.filter(isNotTextNode);
	      /* istanbul ignore if */
	      if (!children.length) {
	        return
	      }

	      // warn multiple elements
	      if (children.length > 1) {
	        warn(
	          '<transition> can only be used on a single element. Use ' +
	          '<transition-group> for lists.',
	          this.$parent
	        );
	      }

	      var mode = this.mode;

	      // warn invalid mode
	      if (mode && mode !== 'in-out' && mode !== 'out-in'
	      ) {
	        warn(
	          'invalid <transition> mode: ' + mode,
	          this.$parent
	        );
	      }

	      var rawChild = children[0];

	      // if this is a component root node and the component's
	      // parent container node also has transition, skip.
	      if (hasParentTransition(this.$vnode)) {
	        return rawChild
	      }

	      // apply transition data to child
	      // use getRealChild() to ignore abstract components e.g. keep-alive
	      var child = getRealChild(rawChild);
	      /* istanbul ignore if */
	      if (!child) {
	        return rawChild
	      }

	      if (this._leaving) {
	        return placeholder(h, rawChild)
	      }

	      // ensure a key that is unique to the vnode type and to this transition
	      // component instance. This key will be used to remove pending leaving nodes
	      // during entering.
	      var id = "__transition-" + (this._uid) + "-";
	      child.key = child.key == null
	        ? child.isComment
	          ? id + 'comment'
	          : id + child.tag
	        : isPrimitive(child.key)
	          ? (String(child.key).indexOf(id) === 0 ? child.key : id + child.key)
	          : child.key;

	      var data = (child.data || (child.data = {})).transition = extractTransitionData(this);
	      var oldRawChild = this._vnode;
	      var oldChild = getRealChild(oldRawChild);

	      // mark v-show
	      // so that the transition module can hand over the control to the directive
	      if (child.data.directives && child.data.directives.some(isVShowDirective)) {
	        child.data.show = true;
	      }

	      if (
	        oldChild &&
	        oldChild.data &&
	        !isSameChild(child, oldChild) &&
	        !isAsyncPlaceholder(oldChild) &&
	        // #6687 component root is a comment node
	        !(oldChild.componentInstance && oldChild.componentInstance._vnode.isComment)
	      ) {
	        // replace old child transition data with fresh one
	        // important for dynamic transitions!
	        var oldData = oldChild.data.transition = extend({}, data);
	        // handle transition mode
	        if (mode === 'out-in') {
	          // return placeholder node and queue update when leave finishes
	          this._leaving = true;
	          mergeVNodeHook(oldData, 'afterLeave', function () {
	            this$1._leaving = false;
	            this$1.$forceUpdate();
	          });
	          return placeholder(h, rawChild)
	        } else if (mode === 'in-out') {
	          if (isAsyncPlaceholder(child)) {
	            return oldRawChild
	          }
	          var delayedLeave;
	          var performLeave = function () { delayedLeave(); };
	          mergeVNodeHook(data, 'afterEnter', performLeave);
	          mergeVNodeHook(data, 'enterCancelled', performLeave);
	          mergeVNodeHook(oldData, 'delayLeave', function (leave) { delayedLeave = leave; });
	        }
	      }

	      return rawChild
	    }
	  };

	  /*  */

	  var props = extend({
	    tag: String,
	    moveClass: String
	  }, transitionProps);

	  delete props.mode;

	  var TransitionGroup = {
	    props: props,

	    beforeMount: function beforeMount () {
	      var this$1 = this;

	      var update = this._update;
	      this._update = function (vnode, hydrating) {
	        var restoreActiveInstance = setActiveInstance(this$1);
	        // force removing pass
	        this$1.__patch__(
	          this$1._vnode,
	          this$1.kept,
	          false, // hydrating
	          true // removeOnly (!important, avoids unnecessary moves)
	        );
	        this$1._vnode = this$1.kept;
	        restoreActiveInstance();
	        update.call(this$1, vnode, hydrating);
	      };
	    },

	    render: function render (h) {
	      var tag = this.tag || this.$vnode.data.tag || 'span';
	      var map = Object.create(null);
	      var prevChildren = this.prevChildren = this.children;
	      var rawChildren = this.$slots.default || [];
	      var children = this.children = [];
	      var transitionData = extractTransitionData(this);

	      for (var i = 0; i < rawChildren.length; i++) {
	        var c = rawChildren[i];
	        if (c.tag) {
	          if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
	            children.push(c);
	            map[c.key] = c
	            ;(c.data || (c.data = {})).transition = transitionData;
	          } else {
	            var opts = c.componentOptions;
	            var name = opts ? (opts.Ctor.options.name || opts.tag || '') : c.tag;
	            warn(("<transition-group> children must be keyed: <" + name + ">"));
	          }
	        }
	      }

	      if (prevChildren) {
	        var kept = [];
	        var removed = [];
	        for (var i$1 = 0; i$1 < prevChildren.length; i$1++) {
	          var c$1 = prevChildren[i$1];
	          c$1.data.transition = transitionData;
	          c$1.data.pos = c$1.elm.getBoundingClientRect();
	          if (map[c$1.key]) {
	            kept.push(c$1);
	          } else {
	            removed.push(c$1);
	          }
	        }
	        this.kept = h(tag, null, kept);
	        this.removed = removed;
	      }

	      return h(tag, null, children)
	    },

	    updated: function updated () {
	      var children = this.prevChildren;
	      var moveClass = this.moveClass || ((this.name || 'v') + '-move');
	      if (!children.length || !this.hasMove(children[0].elm, moveClass)) {
	        return
	      }

	      // we divide the work into three loops to avoid mixing DOM reads and writes
	      // in each iteration - which helps prevent layout thrashing.
	      children.forEach(callPendingCbs);
	      children.forEach(recordPosition);
	      children.forEach(applyTranslation);

	      // force reflow to put everything in position
	      // assign to this to avoid being removed in tree-shaking
	      // $flow-disable-line
	      this._reflow = document.body.offsetHeight;

	      children.forEach(function (c) {
	        if (c.data.moved) {
	          var el = c.elm;
	          var s = el.style;
	          addTransitionClass(el, moveClass);
	          s.transform = s.WebkitTransform = s.transitionDuration = '';
	          el.addEventListener(transitionEndEvent, el._moveCb = function cb (e) {
	            if (e && e.target !== el) {
	              return
	            }
	            if (!e || /transform$/.test(e.propertyName)) {
	              el.removeEventListener(transitionEndEvent, cb);
	              el._moveCb = null;
	              removeTransitionClass(el, moveClass);
	            }
	          });
	        }
	      });
	    },

	    methods: {
	      hasMove: function hasMove (el, moveClass) {
	        /* istanbul ignore if */
	        if (!hasTransition) {
	          return false
	        }
	        /* istanbul ignore if */
	        if (this._hasMove) {
	          return this._hasMove
	        }
	        // Detect whether an element with the move class applied has
	        // CSS transitions. Since the element may be inside an entering
	        // transition at this very moment, we make a clone of it and remove
	        // all other transition classes applied to ensure only the move class
	        // is applied.
	        var clone = el.cloneNode();
	        if (el._transitionClasses) {
	          el._transitionClasses.forEach(function (cls) { removeClass(clone, cls); });
	        }
	        addClass(clone, moveClass);
	        clone.style.display = 'none';
	        this.$el.appendChild(clone);
	        var info = getTransitionInfo(clone);
	        this.$el.removeChild(clone);
	        return (this._hasMove = info.hasTransform)
	      }
	    }
	  };

	  function callPendingCbs (c) {
	    /* istanbul ignore if */
	    if (c.elm._moveCb) {
	      c.elm._moveCb();
	    }
	    /* istanbul ignore if */
	    if (c.elm._enterCb) {
	      c.elm._enterCb();
	    }
	  }

	  function recordPosition (c) {
	    c.data.newPos = c.elm.getBoundingClientRect();
	  }

	  function applyTranslation (c) {
	    var oldPos = c.data.pos;
	    var newPos = c.data.newPos;
	    var dx = oldPos.left - newPos.left;
	    var dy = oldPos.top - newPos.top;
	    if (dx || dy) {
	      c.data.moved = true;
	      var s = c.elm.style;
	      s.transform = s.WebkitTransform = "translate(" + dx + "px," + dy + "px)";
	      s.transitionDuration = '0s';
	    }
	  }

	  var platformComponents = {
	    Transition: Transition,
	    TransitionGroup: TransitionGroup
	  };

	  /*  */

	  // install platform specific utils
	  Vue.config.mustUseProp = mustUseProp;
	  Vue.config.isReservedTag = isReservedTag;
	  Vue.config.isReservedAttr = isReservedAttr;
	  Vue.config.getTagNamespace = getTagNamespace;
	  Vue.config.isUnknownElement = isUnknownElement;

	  // install platform runtime directives & components
	  extend(Vue.options.directives, platformDirectives);
	  extend(Vue.options.components, platformComponents);

	  // install platform patch function
	  Vue.prototype.__patch__ = inBrowser ? patch : noop;

	  // public mount method
	  Vue.prototype.$mount = function (
	    el,
	    hydrating
	  ) {
	    el = el && inBrowser ? query(el) : undefined;
	    return mountComponent(this, el, hydrating)
	  };

	  // devtools global hook
	  /* istanbul ignore next */
	  if (inBrowser) {
	    setTimeout(function () {
	      if (config.devtools) {
	        if (devtools) {
	          devtools.emit('init', Vue);
	        } else {
	          console[console.info ? 'info' : 'log'](
	            'Download the Vue Devtools extension for a better development experience:\n' +
	            'https://github.com/vuejs/vue-devtools'
	          );
	        }
	      }
	      if (config.productionTip !== false &&
	        typeof console !== 'undefined'
	      ) {
	        console[console.info ? 'info' : 'log'](
	          "You are running Vue in development mode.\n" +
	          "Make sure to turn on production mode when deploying for production.\n" +
	          "See more tips at https://vuejs.org/guide/deployment.html"
	        );
	      }
	    }, 0);
	  }

	  /*  */

	  var defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g;
	  var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g;

	  var buildRegex = cached(function (delimiters) {
	    var open = delimiters[0].replace(regexEscapeRE, '\\$&');
	    var close = delimiters[1].replace(regexEscapeRE, '\\$&');
	    return new RegExp(open + '((?:.|\\n)+?)' + close, 'g')
	  });



	  function parseText (
	    text,
	    delimiters
	  ) {
	    var tagRE = delimiters ? buildRegex(delimiters) : defaultTagRE;
	    if (!tagRE.test(text)) {
	      return
	    }
	    var tokens = [];
	    var rawTokens = [];
	    var lastIndex = tagRE.lastIndex = 0;
	    var match, index, tokenValue;
	    while ((match = tagRE.exec(text))) {
	      index = match.index;
	      // push text token
	      if (index > lastIndex) {
	        rawTokens.push(tokenValue = text.slice(lastIndex, index));
	        tokens.push(JSON.stringify(tokenValue));
	      }
	      // tag token
	      var exp = parseFilters(match[1].trim());
	      tokens.push(("_s(" + exp + ")"));
	      rawTokens.push({ '@binding': exp });
	      lastIndex = index + match[0].length;
	    }
	    if (lastIndex < text.length) {
	      rawTokens.push(tokenValue = text.slice(lastIndex));
	      tokens.push(JSON.stringify(tokenValue));
	    }
	    return {
	      expression: tokens.join('+'),
	      tokens: rawTokens
	    }
	  }

	  /*  */

	  function transformNode (el, options) {
	    var warn = options.warn || baseWarn;
	    var staticClass = getAndRemoveAttr(el, 'class');
	    if (staticClass) {
	      var res = parseText(staticClass, options.delimiters);
	      if (res) {
	        warn(
	          "class=\"" + staticClass + "\": " +
	          'Interpolation inside attributes has been removed. ' +
	          'Use v-bind or the colon shorthand instead. For example, ' +
	          'instead of <div class="{{ val }}">, use <div :class="val">.',
	          el.rawAttrsMap['class']
	        );
	      }
	    }
	    if (staticClass) {
	      el.staticClass = JSON.stringify(staticClass);
	    }
	    var classBinding = getBindingAttr(el, 'class', false /* getStatic */);
	    if (classBinding) {
	      el.classBinding = classBinding;
	    }
	  }

	  function genData (el) {
	    var data = '';
	    if (el.staticClass) {
	      data += "staticClass:" + (el.staticClass) + ",";
	    }
	    if (el.classBinding) {
	      data += "class:" + (el.classBinding) + ",";
	    }
	    return data
	  }

	  var klass$1 = {
	    staticKeys: ['staticClass'],
	    transformNode: transformNode,
	    genData: genData
	  };

	  /*  */

	  function transformNode$1 (el, options) {
	    var warn = options.warn || baseWarn;
	    var staticStyle = getAndRemoveAttr(el, 'style');
	    if (staticStyle) {
	      /* istanbul ignore if */
	      {
	        var res = parseText(staticStyle, options.delimiters);
	        if (res) {
	          warn(
	            "style=\"" + staticStyle + "\": " +
	            'Interpolation inside attributes has been removed. ' +
	            'Use v-bind or the colon shorthand instead. For example, ' +
	            'instead of <div style="{{ val }}">, use <div :style="val">.',
	            el.rawAttrsMap['style']
	          );
	        }
	      }
	      el.staticStyle = JSON.stringify(parseStyleText(staticStyle));
	    }

	    var styleBinding = getBindingAttr(el, 'style', false /* getStatic */);
	    if (styleBinding) {
	      el.styleBinding = styleBinding;
	    }
	  }

	  function genData$1 (el) {
	    var data = '';
	    if (el.staticStyle) {
	      data += "staticStyle:" + (el.staticStyle) + ",";
	    }
	    if (el.styleBinding) {
	      data += "style:(" + (el.styleBinding) + "),";
	    }
	    return data
	  }

	  var style$1 = {
	    staticKeys: ['staticStyle'],
	    transformNode: transformNode$1,
	    genData: genData$1
	  };

	  /*  */

	  var decoder;

	  var he = {
	    decode: function decode (html) {
	      decoder = decoder || document.createElement('div');
	      decoder.innerHTML = html;
	      return decoder.textContent
	    }
	  };

	  /*  */

	  var isUnaryTag = makeMap(
	    'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
	    'link,meta,param,source,track,wbr'
	  );

	  // Elements that you can, intentionally, leave open
	  // (and which close themselves)
	  var canBeLeftOpenTag = makeMap(
	    'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'
	  );

	  // HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3
	  // Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
	  var isNonPhrasingTag = makeMap(
	    'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
	    'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
	    'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
	    'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
	    'title,tr,track'
	  );

	  /**
	   * Not type-checking this file because it's mostly vendor code.
	   */

	  // Regular Expressions for parsing tags and attributes
	  var attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
	  var dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
	  var ncname = "[a-zA-Z_][\\-\\.0-9_a-zA-Z" + (unicodeRegExp.source) + "]*";
	  var qnameCapture = "((?:" + ncname + "\\:)?" + ncname + ")";
	  var startTagOpen = new RegExp(("^<" + qnameCapture));
	  var startTagClose = /^\s*(\/?)>/;
	  var endTag = new RegExp(("^<\\/" + qnameCapture + "[^>]*>"));
	  var doctype = /^<!DOCTYPE [^>]+>/i;
	  // #7298: escape - to avoid being passed as HTML comment when inlined in page
	  var comment = /^<!\--/;
	  var conditionalComment = /^<!\[/;

	  // Special Elements (can contain anything)
	  var isPlainTextElement = makeMap('script,style,textarea', true);
	  var reCache = {};

	  var decodingMap = {
	    '&lt;': '<',
	    '&gt;': '>',
	    '&quot;': '"',
	    '&amp;': '&',
	    '&#10;': '\n',
	    '&#9;': '\t',
	    '&#39;': "'"
	  };
	  var encodedAttr = /&(?:lt|gt|quot|amp|#39);/g;
	  var encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#39|#10|#9);/g;

	  // #5992
	  var isIgnoreNewlineTag = makeMap('pre,textarea', true);
	  var shouldIgnoreFirstNewline = function (tag, html) { return tag && isIgnoreNewlineTag(tag) && html[0] === '\n'; };

	  function decodeAttr (value, shouldDecodeNewlines) {
	    var re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr;
	    return value.replace(re, function (match) { return decodingMap[match]; })
	  }

	  function parseHTML (html, options) {
	    var stack = [];
	    var expectHTML = options.expectHTML;
	    var isUnaryTag$$1 = options.isUnaryTag || no;
	    var canBeLeftOpenTag$$1 = options.canBeLeftOpenTag || no;
	    var index = 0;
	    var last, lastTag;
	    while (html) {
	      last = html;
	      // Make sure we're not in a plaintext content element like script/style
	      if (!lastTag || !isPlainTextElement(lastTag)) {
	        var textEnd = html.indexOf('<');
	        if (textEnd === 0) {
	          // Comment:
	          if (comment.test(html)) {
	            var commentEnd = html.indexOf('-->');

	            if (commentEnd >= 0) {
	              if (options.shouldKeepComment) {
	                options.comment(html.substring(4, commentEnd), index, index + commentEnd + 3);
	              }
	              advance(commentEnd + 3);
	              continue
	            }
	          }

	          // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
	          if (conditionalComment.test(html)) {
	            var conditionalEnd = html.indexOf(']>');

	            if (conditionalEnd >= 0) {
	              advance(conditionalEnd + 2);
	              continue
	            }
	          }

	          // Doctype:
	          var doctypeMatch = html.match(doctype);
	          if (doctypeMatch) {
	            advance(doctypeMatch[0].length);
	            continue
	          }

	          // End tag:
	          var endTagMatch = html.match(endTag);
	          if (endTagMatch) {
	            var curIndex = index;
	            advance(endTagMatch[0].length);
	            parseEndTag(endTagMatch[1], curIndex, index);
	            continue
	          }

	          // Start tag:
	          var startTagMatch = parseStartTag();
	          if (startTagMatch) {
	            handleStartTag(startTagMatch);
	            if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) {
	              advance(1);
	            }
	            continue
	          }
	        }

	        var text = (void 0), rest = (void 0), next = (void 0);
	        if (textEnd >= 0) {
	          rest = html.slice(textEnd);
	          while (
	            !endTag.test(rest) &&
	            !startTagOpen.test(rest) &&
	            !comment.test(rest) &&
	            !conditionalComment.test(rest)
	          ) {
	            // < in plain text, be forgiving and treat it as text
	            next = rest.indexOf('<', 1);
	            if (next < 0) { break }
	            textEnd += next;
	            rest = html.slice(textEnd);
	          }
	          text = html.substring(0, textEnd);
	        }

	        if (textEnd < 0) {
	          text = html;
	        }

	        if (text) {
	          advance(text.length);
	        }

	        if (options.chars && text) {
	          options.chars(text, index - text.length, index);
	        }
	      } else {
	        var endTagLength = 0;
	        var stackedTag = lastTag.toLowerCase();
	        var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(</' + stackedTag + '[^>]*>)', 'i'));
	        var rest$1 = html.replace(reStackedTag, function (all, text, endTag) {
	          endTagLength = endTag.length;
	          if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') {
	            text = text
	              .replace(/<!\--([\s\S]*?)-->/g, '$1') // #7298
	              .replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1');
	          }
	          if (shouldIgnoreFirstNewline(stackedTag, text)) {
	            text = text.slice(1);
	          }
	          if (options.chars) {
	            options.chars(text);
	          }
	          return ''
	        });
	        index += html.length - rest$1.length;
	        html = rest$1;
	        parseEndTag(stackedTag, index - endTagLength, index);
	      }

	      if (html === last) {
	        options.chars && options.chars(html);
	        if (!stack.length && options.warn) {
	          options.warn(("Mal-formatted tag at end of template: \"" + html + "\""), { start: index + html.length });
	        }
	        break
	      }
	    }

	    // Clean up any remaining tags
	    parseEndTag();

	    function advance (n) {
	      index += n;
	      html = html.substring(n);
	    }

	    function parseStartTag () {
	      var start = html.match(startTagOpen);
	      if (start) {
	        var match = {
	          tagName: start[1],
	          attrs: [],
	          start: index
	        };
	        advance(start[0].length);
	        var end, attr;
	        while (!(end = html.match(startTagClose)) && (attr = html.match(dynamicArgAttribute) || html.match(attribute))) {
	          attr.start = index;
	          advance(attr[0].length);
	          attr.end = index;
	          match.attrs.push(attr);
	        }
	        if (end) {
	          match.unarySlash = end[1];
	          advance(end[0].length);
	          match.end = index;
	          return match
	        }
	      }
	    }

	    function handleStartTag (match) {
	      var tagName = match.tagName;
	      var unarySlash = match.unarySlash;

	      if (expectHTML) {
	        if (lastTag === 'p' && isNonPhrasingTag(tagName)) {
	          parseEndTag(lastTag);
	        }
	        if (canBeLeftOpenTag$$1(tagName) && lastTag === tagName) {
	          parseEndTag(tagName);
	        }
	      }

	      var unary = isUnaryTag$$1(tagName) || !!unarySlash;

	      var l = match.attrs.length;
	      var attrs = new Array(l);
	      for (var i = 0; i < l; i++) {
	        var args = match.attrs[i];
	        var value = args[3] || args[4] || args[5] || '';
	        var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href'
	          ? options.shouldDecodeNewlinesForHref
	          : options.shouldDecodeNewlines;
	        attrs[i] = {
	          name: args[1],
	          value: decodeAttr(value, shouldDecodeNewlines)
	        };
	        if (options.outputSourceRange) {
	          attrs[i].start = args.start + args[0].match(/^\s*/).length;
	          attrs[i].end = args.end;
	        }
	      }

	      if (!unary) {
	        stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs, start: match.start, end: match.end });
	        lastTag = tagName;
	      }

	      if (options.start) {
	        options.start(tagName, attrs, unary, match.start, match.end);
	      }
	    }

	    function parseEndTag (tagName, start, end) {
	      var pos, lowerCasedTagName;
	      if (start == null) { start = index; }
	      if (end == null) { end = index; }

	      // Find the closest opened tag of the same type
	      if (tagName) {
	        lowerCasedTagName = tagName.toLowerCase();
	        for (pos = stack.length - 1; pos >= 0; pos--) {
	          if (stack[pos].lowerCasedTag === lowerCasedTagName) {
	            break
	          }
	        }
	      } else {
	        // If no tag name is provided, clean shop
	        pos = 0;
	      }

	      if (pos >= 0) {
	        // Close all the open elements, up the stack
	        for (var i = stack.length - 1; i >= pos; i--) {
	          if (i > pos || !tagName &&
	            options.warn
	          ) {
	            options.warn(
	              ("tag <" + (stack[i].tag) + "> has no matching end tag."),
	              { start: stack[i].start, end: stack[i].end }
	            );
	          }
	          if (options.end) {
	            options.end(stack[i].tag, start, end);
	          }
	        }

	        // Remove the open elements from the stack
	        stack.length = pos;
	        lastTag = pos && stack[pos - 1].tag;
	      } else if (lowerCasedTagName === 'br') {
	        if (options.start) {
	          options.start(tagName, [], true, start, end);
	        }
	      } else if (lowerCasedTagName === 'p') {
	        if (options.start) {
	          options.start(tagName, [], false, start, end);
	        }
	        if (options.end) {
	          options.end(tagName, start, end);
	        }
	      }
	    }
	  }

	  /*  */

	  var onRE = /^@|^v-on:/;
	  var dirRE = /^v-|^@|^:|^#/;
	  var forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
	  var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
	  var stripParensRE = /^\(|\)$/g;
	  var dynamicArgRE = /^\[.*\]$/;

	  var argRE = /:(.*)$/;
	  var bindRE = /^:|^\.|^v-bind:/;
	  var modifierRE = /\.[^.\]]+(?=[^\]]*$)/g;

	  var slotRE = /^v-slot(:|$)|^#/;

	  var lineBreakRE = /[\r\n]/;
	  var whitespaceRE$1 = /\s+/g;

	  var invalidAttributeRE = /[\s"'<>\/=]/;

	  var decodeHTMLCached = cached(he.decode);

	  var emptySlotScopeToken = "_empty_";

	  // configurable state
	  var warn$2;
	  var delimiters;
	  var transforms;
	  var preTransforms;
	  var postTransforms;
	  var platformIsPreTag;
	  var platformMustUseProp;
	  var platformGetTagNamespace;
	  var maybeComponent;

	  function createASTElement (
	    tag,
	    attrs,
	    parent
	  ) {
	    return {
	      type: 1,
	      tag: tag,
	      attrsList: attrs,
	      attrsMap: makeAttrsMap(attrs),
	      rawAttrsMap: {},
	      parent: parent,
	      children: []
	    }
	  }

	  /**
	   * Convert HTML string to AST.
	   */
	  function parse (
	    template,
	    options
	  ) {
	    warn$2 = options.warn || baseWarn;

	    platformIsPreTag = options.isPreTag || no;
	    platformMustUseProp = options.mustUseProp || no;
	    platformGetTagNamespace = options.getTagNamespace || no;
	    var isReservedTag = options.isReservedTag || no;
	    maybeComponent = function (el) { return !!el.component || !isReservedTag(el.tag); };

	    transforms = pluckModuleFunction(options.modules, 'transformNode');
	    preTransforms = pluckModuleFunction(options.modules, 'preTransformNode');
	    postTransforms = pluckModuleFunction(options.modules, 'postTransformNode');

	    delimiters = options.delimiters;

	    var stack = [];
	    var preserveWhitespace = options.preserveWhitespace !== false;
	    var whitespaceOption = options.whitespace;
	    var root;
	    var currentParent;
	    var inVPre = false;
	    var inPre = false;
	    var warned = false;

	    function warnOnce (msg, range) {
	      if (!warned) {
	        warned = true;
	        warn$2(msg, range);
	      }
	    }

	    function closeElement (element) {
	      trimEndingWhitespace(element);
	      if (!inVPre && !element.processed) {
	        element = processElement(element, options);
	      }
	      // tree management
	      if (!stack.length && element !== root) {
	        // allow root elements with v-if, v-else-if and v-else
	        if (root.if && (element.elseif || element.else)) {
	          {
	            checkRootConstraints(element);
	          }
	          addIfCondition(root, {
	            exp: element.elseif,
	            block: element
	          });
	        } else {
	          warnOnce(
	            "Component template should contain exactly one root element. " +
	            "If you are using v-if on multiple elements, " +
	            "use v-else-if to chain them instead.",
	            { start: element.start }
	          );
	        }
	      }
	      if (currentParent && !element.forbidden) {
	        if (element.elseif || element.else) {
	          processIfConditions(element, currentParent);
	        } else {
	          if (element.slotScope) {
	            // scoped slot
	            // keep it in the children list so that v-else(-if) conditions can
	            // find it as the prev node.
	            var name = element.slotTarget || '"default"'
	            ;(currentParent.scopedSlots || (currentParent.scopedSlots = {}))[name] = element;
	          }
	          currentParent.children.push(element);
	          element.parent = currentParent;
	        }
	      }

	      // final children cleanup
	      // filter out scoped slots
	      element.children = element.children.filter(function (c) { return !(c).slotScope; });
	      // remove trailing whitespace node again
	      trimEndingWhitespace(element);

	      // check pre state
	      if (element.pre) {
	        inVPre = false;
	      }
	      if (platformIsPreTag(element.tag)) {
	        inPre = false;
	      }
	      // apply post-transforms
	      for (var i = 0; i < postTransforms.length; i++) {
	        postTransforms[i](element, options);
	      }
	    }

	    function trimEndingWhitespace (el) {
	      // remove trailing whitespace node
	      if (!inPre) {
	        var lastNode;
	        while (
	          (lastNode = el.children[el.children.length - 1]) &&
	          lastNode.type === 3 &&
	          lastNode.text === ' '
	        ) {
	          el.children.pop();
	        }
	      }
	    }

	    function checkRootConstraints (el) {
	      if (el.tag === 'slot' || el.tag === 'template') {
	        warnOnce(
	          "Cannot use <" + (el.tag) + "> as component root element because it may " +
	          'contain multiple nodes.',
	          { start: el.start }
	        );
	      }
	      if (el.attrsMap.hasOwnProperty('v-for')) {
	        warnOnce(
	          'Cannot use v-for on stateful component root element because ' +
	          'it renders multiple elements.',
	          el.rawAttrsMap['v-for']
	        );
	      }
	    }

	    parseHTML(template, {
	      warn: warn$2,
	      expectHTML: options.expectHTML,
	      isUnaryTag: options.isUnaryTag,
	      canBeLeftOpenTag: options.canBeLeftOpenTag,
	      shouldDecodeNewlines: options.shouldDecodeNewlines,
	      shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
	      shouldKeepComment: options.comments,
	      outputSourceRange: options.outputSourceRange,
	      start: function start (tag, attrs, unary, start$1, end) {
	        // check namespace.
	        // inherit parent ns if there is one
	        var ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag);

	        // handle IE svg bug
	        /* istanbul ignore if */
	        if (isIE && ns === 'svg') {
	          attrs = guardIESVGBug(attrs);
	        }

	        var element = createASTElement(tag, attrs, currentParent);
	        if (ns) {
	          element.ns = ns;
	        }

	        {
	          if (options.outputSourceRange) {
	            element.start = start$1;
	            element.end = end;
	            element.rawAttrsMap = element.attrsList.reduce(function (cumulated, attr) {
	              cumulated[attr.name] = attr;
	              return cumulated
	            }, {});
	          }
	          attrs.forEach(function (attr) {
	            if (invalidAttributeRE.test(attr.name)) {
	              warn$2(
	                "Invalid dynamic argument expression: attribute names cannot contain " +
	                "spaces, quotes, <, >, / or =.",
	                {
	                  start: attr.start + attr.name.indexOf("["),
	                  end: attr.start + attr.name.length
	                }
	              );
	            }
	          });
	        }

	        if (isForbiddenTag(element) && !isServerRendering()) {
	          element.forbidden = true;
	          warn$2(
	            'Templates should only be responsible for mapping the state to the ' +
	            'UI. Avoid placing tags with side-effects in your templates, such as ' +
	            "<" + tag + ">" + ', as they will not be parsed.',
	            { start: element.start }
	          );
	        }

	        // apply pre-transforms
	        for (var i = 0; i < preTransforms.length; i++) {
	          element = preTransforms[i](element, options) || element;
	        }

	        if (!inVPre) {
	          processPre(element);
	          if (element.pre) {
	            inVPre = true;
	          }
	        }
	        if (platformIsPreTag(element.tag)) {
	          inPre = true;
	        }
	        if (inVPre) {
	          processRawAttrs(element);
	        } else if (!element.processed) {
	          // structural directives
	          processFor(element);
	          processIf(element);
	          processOnce(element);
	        }

	        if (!root) {
	          root = element;
	          {
	            checkRootConstraints(root);
	          }
	        }

	        if (!unary) {
	          currentParent = element;
	          stack.push(element);
	        } else {
	          closeElement(element);
	        }
	      },

	      end: function end (tag, start, end$1) {
	        var element = stack[stack.length - 1];
	        // pop stack
	        stack.length -= 1;
	        currentParent = stack[stack.length - 1];
	        if (options.outputSourceRange) {
	          element.end = end$1;
	        }
	        closeElement(element);
	      },

	      chars: function chars (text, start, end) {
	        if (!currentParent) {
	          {
	            if (text === template) {
	              warnOnce(
	                'Component template requires a root element, rather than just text.',
	                { start: start }
	              );
	            } else if ((text = text.trim())) {
	              warnOnce(
	                ("text \"" + text + "\" outside root element will be ignored."),
	                { start: start }
	              );
	            }
	          }
	          return
	        }
	        // IE textarea placeholder bug
	        /* istanbul ignore if */
	        if (isIE &&
	          currentParent.tag === 'textarea' &&
	          currentParent.attrsMap.placeholder === text
	        ) {
	          return
	        }
	        var children = currentParent.children;
	        if (inPre || text.trim()) {
	          text = isTextTag(currentParent) ? text : decodeHTMLCached(text);
	        } else if (!children.length) {
	          // remove the whitespace-only node right after an opening tag
	          text = '';
	        } else if (whitespaceOption) {
	          if (whitespaceOption === 'condense') {
	            // in condense mode, remove the whitespace node if it contains
	            // line break, otherwise condense to a single space
	            text = lineBreakRE.test(text) ? '' : ' ';
	          } else {
	            text = ' ';
	          }
	        } else {
	          text = preserveWhitespace ? ' ' : '';
	        }
	        if (text) {
	          if (!inPre && whitespaceOption === 'condense') {
	            // condense consecutive whitespaces into single space
	            text = text.replace(whitespaceRE$1, ' ');
	          }
	          var res;
	          var child;
	          if (!inVPre && text !== ' ' && (res = parseText(text, delimiters))) {
	            child = {
	              type: 2,
	              expression: res.expression,
	              tokens: res.tokens,
	              text: text
	            };
	          } else if (text !== ' ' || !children.length || children[children.length - 1].text !== ' ') {
	            child = {
	              type: 3,
	              text: text
	            };
	          }
	          if (child) {
	            if (options.outputSourceRange) {
	              child.start = start;
	              child.end = end;
	            }
	            children.push(child);
	          }
	        }
	      },
	      comment: function comment (text, start, end) {
	        // adding anything as a sibling to the root node is forbidden
	        // comments should still be allowed, but ignored
	        if (currentParent) {
	          var child = {
	            type: 3,
	            text: text,
	            isComment: true
	          };
	          if (options.outputSourceRange) {
	            child.start = start;
	            child.end = end;
	          }
	          currentParent.children.push(child);
	        }
	      }
	    });
	    return root
	  }

	  function processPre (el) {
	    if (getAndRemoveAttr(el, 'v-pre') != null) {
	      el.pre = true;
	    }
	  }

	  function processRawAttrs (el) {
	    var list = el.attrsList;
	    var len = list.length;
	    if (len) {
	      var attrs = el.attrs = new Array(len);
	      for (var i = 0; i < len; i++) {
	        attrs[i] = {
	          name: list[i].name,
	          value: JSON.stringify(list[i].value)
	        };
	        if (list[i].start != null) {
	          attrs[i].start = list[i].start;
	          attrs[i].end = list[i].end;
	        }
	      }
	    } else if (!el.pre) {
	      // non root node in pre blocks with no attributes
	      el.plain = true;
	    }
	  }

	  function processElement (
	    element,
	    options
	  ) {
	    processKey(element);

	    // determine whether this is a plain element after
	    // removing structural attributes
	    element.plain = (
	      !element.key &&
	      !element.scopedSlots &&
	      !element.attrsList.length
	    );

	    processRef(element);
	    processSlotContent(element);
	    processSlotOutlet(element);
	    processComponent(element);
	    for (var i = 0; i < transforms.length; i++) {
	      element = transforms[i](element, options) || element;
	    }
	    processAttrs(element);
	    return element
	  }

	  function processKey (el) {
	    var exp = getBindingAttr(el, 'key');
	    if (exp) {
	      {
	        if (el.tag === 'template') {
	          warn$2(
	            "<template> cannot be keyed. Place the key on real elements instead.",
	            getRawBindingAttr(el, 'key')
	          );
	        }
	        if (el.for) {
	          var iterator = el.iterator2 || el.iterator1;
	          var parent = el.parent;
	          if (iterator && iterator === exp && parent && parent.tag === 'transition-group') {
	            warn$2(
	              "Do not use v-for index as key on <transition-group> children, " +
	              "this is the same as not using keys.",
	              getRawBindingAttr(el, 'key'),
	              true /* tip */
	            );
	          }
	        }
	      }
	      el.key = exp;
	    }
	  }

	  function processRef (el) {
	    var ref = getBindingAttr(el, 'ref');
	    if (ref) {
	      el.ref = ref;
	      el.refInFor = checkInFor(el);
	    }
	  }

	  function processFor (el) {
	    var exp;
	    if ((exp = getAndRemoveAttr(el, 'v-for'))) {
	      var res = parseFor(exp);
	      if (res) {
	        extend(el, res);
	      } else {
	        warn$2(
	          ("Invalid v-for expression: " + exp),
	          el.rawAttrsMap['v-for']
	        );
	      }
	    }
	  }



	  function parseFor (exp) {
	    var inMatch = exp.match(forAliasRE);
	    if (!inMatch) { return }
	    var res = {};
	    res.for = inMatch[2].trim();
	    var alias = inMatch[1].trim().replace(stripParensRE, '');
	    var iteratorMatch = alias.match(forIteratorRE);
	    if (iteratorMatch) {
	      res.alias = alias.replace(forIteratorRE, '').trim();
	      res.iterator1 = iteratorMatch[1].trim();
	      if (iteratorMatch[2]) {
	        res.iterator2 = iteratorMatch[2].trim();
	      }
	    } else {
	      res.alias = alias;
	    }
	    return res
	  }

	  function processIf (el) {
	    var exp = getAndRemoveAttr(el, 'v-if');
	    if (exp) {
	      el.if = exp;
	      addIfCondition(el, {
	        exp: exp,
	        block: el
	      });
	    } else {
	      if (getAndRemoveAttr(el, 'v-else') != null) {
	        el.else = true;
	      }
	      var elseif = getAndRemoveAttr(el, 'v-else-if');
	      if (elseif) {
	        el.elseif = elseif;
	      }
	    }
	  }

	  function processIfConditions (el, parent) {
	    var prev = findPrevElement(parent.children);
	    if (prev && prev.if) {
	      addIfCondition(prev, {
	        exp: el.elseif,
	        block: el
	      });
	    } else {
	      warn$2(
	        "v-" + (el.elseif ? ('else-if="' + el.elseif + '"') : 'else') + " " +
	        "used on element <" + (el.tag) + "> without corresponding v-if.",
	        el.rawAttrsMap[el.elseif ? 'v-else-if' : 'v-else']
	      );
	    }
	  }

	  function findPrevElement (children) {
	    var i = children.length;
	    while (i--) {
	      if (children[i].type === 1) {
	        return children[i]
	      } else {
	        if (children[i].text !== ' ') {
	          warn$2(
	            "text \"" + (children[i].text.trim()) + "\" between v-if and v-else(-if) " +
	            "will be ignored.",
	            children[i]
	          );
	        }
	        children.pop();
	      }
	    }
	  }

	  function addIfCondition (el, condition) {
	    if (!el.ifConditions) {
	      el.ifConditions = [];
	    }
	    el.ifConditions.push(condition);
	  }

	  function processOnce (el) {
	    var once$$1 = getAndRemoveAttr(el, 'v-once');
	    if (once$$1 != null) {
	      el.once = true;
	    }
	  }

	  // handle content being passed to a component as slot,
	  // e.g. <template slot="xxx">, <div slot-scope="xxx">
	  function processSlotContent (el) {
	    var slotScope;
	    if (el.tag === 'template') {
	      slotScope = getAndRemoveAttr(el, 'scope');
	      /* istanbul ignore if */
	      if (slotScope) {
	        warn$2(
	          "the \"scope\" attribute for scoped slots have been deprecated and " +
	          "replaced by \"slot-scope\" since 2.5. The new \"slot-scope\" attribute " +
	          "can also be used on plain elements in addition to <template> to " +
	          "denote scoped slots.",
	          el.rawAttrsMap['scope'],
	          true
	        );
	      }
	      el.slotScope = slotScope || getAndRemoveAttr(el, 'slot-scope');
	    } else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) {
	      /* istanbul ignore if */
	      if (el.attrsMap['v-for']) {
	        warn$2(
	          "Ambiguous combined usage of slot-scope and v-for on <" + (el.tag) + "> " +
	          "(v-for takes higher priority). Use a wrapper <template> for the " +
	          "scoped slot to make it clearer.",
	          el.rawAttrsMap['slot-scope'],
	          true
	        );
	      }
	      el.slotScope = slotScope;
	    }

	    // slot="xxx"
	    var slotTarget = getBindingAttr(el, 'slot');
	    if (slotTarget) {
	      el.slotTarget = slotTarget === '""' ? '"default"' : slotTarget;
	      el.slotTargetDynamic = !!(el.attrsMap[':slot'] || el.attrsMap['v-bind:slot']);
	      // preserve slot as an attribute for native shadow DOM compat
	      // only for non-scoped slots.
	      if (el.tag !== 'template' && !el.slotScope) {
	        addAttr(el, 'slot', slotTarget, getRawBindingAttr(el, 'slot'));
	      }
	    }

	    // 2.6 v-slot syntax
	    {
	      if (el.tag === 'template') {
	        // v-slot on <template>
	        var slotBinding = getAndRemoveAttrByRegex(el, slotRE);
	        if (slotBinding) {
	          {
	            if (el.slotTarget || el.slotScope) {
	              warn$2(
	                "Unexpected mixed usage of different slot syntaxes.",
	                el
	              );
	            }
	            if (el.parent && !maybeComponent(el.parent)) {
	              warn$2(
	                "<template v-slot> can only appear at the root level inside " +
	                "the receiving component",
	                el
	              );
	            }
	          }
	          var ref = getSlotName(slotBinding);
	          var name = ref.name;
	          var dynamic = ref.dynamic;
	          el.slotTarget = name;
	          el.slotTargetDynamic = dynamic;
	          el.slotScope = slotBinding.value || emptySlotScopeToken; // force it into a scoped slot for perf
	        }
	      } else {
	        // v-slot on component, denotes default slot
	        var slotBinding$1 = getAndRemoveAttrByRegex(el, slotRE);
	        if (slotBinding$1) {
	          {
	            if (!maybeComponent(el)) {
	              warn$2(
	                "v-slot can only be used on components or <template>.",
	                slotBinding$1
	              );
	            }
	            if (el.slotScope || el.slotTarget) {
	              warn$2(
	                "Unexpected mixed usage of different slot syntaxes.",
	                el
	              );
	            }
	            if (el.scopedSlots) {
	              warn$2(
	                "To avoid scope ambiguity, the default slot should also use " +
	                "<template> syntax when there are other named slots.",
	                slotBinding$1
	              );
	            }
	          }
	          // add the component's children to its default slot
	          var slots = el.scopedSlots || (el.scopedSlots = {});
	          var ref$1 = getSlotName(slotBinding$1);
	          var name$1 = ref$1.name;
	          var dynamic$1 = ref$1.dynamic;
	          var slotContainer = slots[name$1] = createASTElement('template', [], el);
	          slotContainer.slotTarget = name$1;
	          slotContainer.slotTargetDynamic = dynamic$1;
	          slotContainer.children = el.children.filter(function (c) {
	            if (!c.slotScope) {
	              c.parent = slotContainer;
	              return true
	            }
	          });
	          slotContainer.slotScope = slotBinding$1.value || emptySlotScopeToken;
	          // remove children as they are returned from scopedSlots now
	          el.children = [];
	          // mark el non-plain so data gets generated
	          el.plain = false;
	        }
	      }
	    }
	  }

	  function getSlotName (binding) {
	    var name = binding.name.replace(slotRE, '');
	    if (!name) {
	      if (binding.name[0] !== '#') {
	        name = 'default';
	      } else {
	        warn$2(
	          "v-slot shorthand syntax requires a slot name.",
	          binding
	        );
	      }
	    }
	    return dynamicArgRE.test(name)
	      // dynamic [name]
	      ? { name: name.slice(1, -1), dynamic: true }
	      // static name
	      : { name: ("\"" + name + "\""), dynamic: false }
	  }

	  // handle <slot/> outlets
	  function processSlotOutlet (el) {
	    if (el.tag === 'slot') {
	      el.slotName = getBindingAttr(el, 'name');
	      if (el.key) {
	        warn$2(
	          "`key` does not work on <slot> because slots are abstract outlets " +
	          "and can possibly expand into multiple elements. " +
	          "Use the key on a wrapping element instead.",
	          getRawBindingAttr(el, 'key')
	        );
	      }
	    }
	  }

	  function processComponent (el) {
	    var binding;
	    if ((binding = getBindingAttr(el, 'is'))) {
	      el.component = binding;
	    }
	    if (getAndRemoveAttr(el, 'inline-template') != null) {
	      el.inlineTemplate = true;
	    }
	  }

	  function processAttrs (el) {
	    var list = el.attrsList;
	    var i, l, name, rawName, value, modifiers, syncGen, isDynamic;
	    for (i = 0, l = list.length; i < l; i++) {
	      name = rawName = list[i].name;
	      value = list[i].value;
	      if (dirRE.test(name)) {
	        // mark element as dynamic
	        el.hasBindings = true;
	        // modifiers
	        modifiers = parseModifiers(name.replace(dirRE, ''));
	        // support .foo shorthand syntax for the .prop modifier
	        if (modifiers) {
	          name = name.replace(modifierRE, '');
	        }
	        if (bindRE.test(name)) { // v-bind
	          name = name.replace(bindRE, '');
	          value = parseFilters(value);
	          isDynamic = dynamicArgRE.test(name);
	          if (isDynamic) {
	            name = name.slice(1, -1);
	          }
	          if (
	            value.trim().length === 0
	          ) {
	            warn$2(
	              ("The value for a v-bind expression cannot be empty. Found in \"v-bind:" + name + "\"")
	            );
	          }
	          if (modifiers) {
	            if (modifiers.prop && !isDynamic) {
	              name = camelize(name);
	              if (name === 'innerHtml') { name = 'innerHTML'; }
	            }
	            if (modifiers.camel && !isDynamic) {
	              name = camelize(name);
	            }
	            if (modifiers.sync) {
	              syncGen = genAssignmentCode(value, "$event");
	              if (!isDynamic) {
	                addHandler(
	                  el,
	                  ("update:" + (camelize(name))),
	                  syncGen,
	                  null,
	                  false,
	                  warn$2,
	                  list[i]
	                );
	                if (hyphenate(name) !== camelize(name)) {
	                  addHandler(
	                    el,
	                    ("update:" + (hyphenate(name))),
	                    syncGen,
	                    null,
	                    false,
	                    warn$2,
	                    list[i]
	                  );
	                }
	              } else {
	                // handler w/ dynamic event name
	                addHandler(
	                  el,
	                  ("\"update:\"+(" + name + ")"),
	                  syncGen,
	                  null,
	                  false,
	                  warn$2,
	                  list[i],
	                  true // dynamic
	                );
	              }
	            }
	          }
	          if ((modifiers && modifiers.prop) || (
	            !el.component && platformMustUseProp(el.tag, el.attrsMap.type, name)
	          )) {
	            addProp(el, name, value, list[i], isDynamic);
	          } else {
	            addAttr(el, name, value, list[i], isDynamic);
	          }
	        } else if (onRE.test(name)) { // v-on
	          name = name.replace(onRE, '');
	          isDynamic = dynamicArgRE.test(name);
	          if (isDynamic) {
	            name = name.slice(1, -1);
	          }
	          addHandler(el, name, value, modifiers, false, warn$2, list[i], isDynamic);
	        } else { // normal directives
	          name = name.replace(dirRE, '');
	          // parse arg
	          var argMatch = name.match(argRE);
	          var arg = argMatch && argMatch[1];
	          isDynamic = false;
	          if (arg) {
	            name = name.slice(0, -(arg.length + 1));
	            if (dynamicArgRE.test(arg)) {
	              arg = arg.slice(1, -1);
	              isDynamic = true;
	            }
	          }
	          addDirective(el, name, rawName, value, arg, isDynamic, modifiers, list[i]);
	          if (name === 'model') {
	            checkForAliasModel(el, value);
	          }
	        }
	      } else {
	        // literal attribute
	        {
	          var res = parseText(value, delimiters);
	          if (res) {
	            warn$2(
	              name + "=\"" + value + "\": " +
	              'Interpolation inside attributes has been removed. ' +
	              'Use v-bind or the colon shorthand instead. For example, ' +
	              'instead of <div id="{{ val }}">, use <div :id="val">.',
	              list[i]
	            );
	          }
	        }
	        addAttr(el, name, JSON.stringify(value), list[i]);
	        // #6887 firefox doesn't update muted state if set via attribute
	        // even immediately after element creation
	        if (!el.component &&
	            name === 'muted' &&
	            platformMustUseProp(el.tag, el.attrsMap.type, name)) {
	          addProp(el, name, 'true', list[i]);
	        }
	      }
	    }
	  }

	  function checkInFor (el) {
	    var parent = el;
	    while (parent) {
	      if (parent.for !== undefined) {
	        return true
	      }
	      parent = parent.parent;
	    }
	    return false
	  }

	  function parseModifiers (name) {
	    var match = name.match(modifierRE);
	    if (match) {
	      var ret = {};
	      match.forEach(function (m) { ret[m.slice(1)] = true; });
	      return ret
	    }
	  }

	  function makeAttrsMap (attrs) {
	    var map = {};
	    for (var i = 0, l = attrs.length; i < l; i++) {
	      if (
	        map[attrs[i].name] && !isIE && !isEdge
	      ) {
	        warn$2('duplicate attribute: ' + attrs[i].name, attrs[i]);
	      }
	      map[attrs[i].name] = attrs[i].value;
	    }
	    return map
	  }

	  // for script (e.g. type="x/template") or style, do not decode content
	  function isTextTag (el) {
	    return el.tag === 'script' || el.tag === 'style'
	  }

	  function isForbiddenTag (el) {
	    return (
	      el.tag === 'style' ||
	      (el.tag === 'script' && (
	        !el.attrsMap.type ||
	        el.attrsMap.type === 'text/javascript'
	      ))
	    )
	  }

	  var ieNSBug = /^xmlns:NS\d+/;
	  var ieNSPrefix = /^NS\d+:/;

	  /* istanbul ignore next */
	  function guardIESVGBug (attrs) {
	    var res = [];
	    for (var i = 0; i < attrs.length; i++) {
	      var attr = attrs[i];
	      if (!ieNSBug.test(attr.name)) {
	        attr.name = attr.name.replace(ieNSPrefix, '');
	        res.push(attr);
	      }
	    }
	    return res
	  }

	  function checkForAliasModel (el, value) {
	    var _el = el;
	    while (_el) {
	      if (_el.for && _el.alias === value) {
	        warn$2(
	          "<" + (el.tag) + " v-model=\"" + value + "\">: " +
	          "You are binding v-model directly to a v-for iteration alias. " +
	          "This will not be able to modify the v-for source array because " +
	          "writing to the alias is like modifying a function local variable. " +
	          "Consider using an array of objects and use v-model on an object property instead.",
	          el.rawAttrsMap['v-model']
	        );
	      }
	      _el = _el.parent;
	    }
	  }

	  /*  */

	  function preTransformNode (el, options) {
	    if (el.tag === 'input') {
	      var map = el.attrsMap;
	      if (!map['v-model']) {
	        return
	      }

	      var typeBinding;
	      if (map[':type'] || map['v-bind:type']) {
	        typeBinding = getBindingAttr(el, 'type');
	      }
	      if (!map.type && !typeBinding && map['v-bind']) {
	        typeBinding = "(" + (map['v-bind']) + ").type";
	      }

	      if (typeBinding) {
	        var ifCondition = getAndRemoveAttr(el, 'v-if', true);
	        var ifConditionExtra = ifCondition ? ("&&(" + ifCondition + ")") : "";
	        var hasElse = getAndRemoveAttr(el, 'v-else', true) != null;
	        var elseIfCondition = getAndRemoveAttr(el, 'v-else-if', true);
	        // 1. checkbox
	        var branch0 = cloneASTElement(el);
	        // process for on the main node
	        processFor(branch0);
	        addRawAttr(branch0, 'type', 'checkbox');
	        processElement(branch0, options);
	        branch0.processed = true; // prevent it from double-processed
	        branch0.if = "(" + typeBinding + ")==='checkbox'" + ifConditionExtra;
	        addIfCondition(branch0, {
	          exp: branch0.if,
	          block: branch0
	        });
	        // 2. add radio else-if condition
	        var branch1 = cloneASTElement(el);
	        getAndRemoveAttr(branch1, 'v-for', true);
	        addRawAttr(branch1, 'type', 'radio');
	        processElement(branch1, options);
	        addIfCondition(branch0, {
	          exp: "(" + typeBinding + ")==='radio'" + ifConditionExtra,
	          block: branch1
	        });
	        // 3. other
	        var branch2 = cloneASTElement(el);
	        getAndRemoveAttr(branch2, 'v-for', true);
	        addRawAttr(branch2, ':type', typeBinding);
	        processElement(branch2, options);
	        addIfCondition(branch0, {
	          exp: ifCondition,
	          block: branch2
	        });

	        if (hasElse) {
	          branch0.else = true;
	        } else if (elseIfCondition) {
	          branch0.elseif = elseIfCondition;
	        }

	        return branch0
	      }
	    }
	  }

	  function cloneASTElement (el) {
	    return createASTElement(el.tag, el.attrsList.slice(), el.parent)
	  }

	  var model$1 = {
	    preTransformNode: preTransformNode
	  };

	  var modules$1 = [
	    klass$1,
	    style$1,
	    model$1
	  ];

	  /*  */

	  function text (el, dir) {
	    if (dir.value) {
	      addProp(el, 'textContent', ("_s(" + (dir.value) + ")"), dir);
	    }
	  }

	  /*  */

	  function html (el, dir) {
	    if (dir.value) {
	      addProp(el, 'innerHTML', ("_s(" + (dir.value) + ")"), dir);
	    }
	  }

	  var directives$1 = {
	    model: model,
	    text: text,
	    html: html
	  };

	  /*  */

	  var baseOptions = {
	    expectHTML: true,
	    modules: modules$1,
	    directives: directives$1,
	    isPreTag: isPreTag,
	    isUnaryTag: isUnaryTag,
	    mustUseProp: mustUseProp,
	    canBeLeftOpenTag: canBeLeftOpenTag,
	    isReservedTag: isReservedTag,
	    getTagNamespace: getTagNamespace,
	    staticKeys: genStaticKeys(modules$1)
	  };

	  /*  */

	  var isStaticKey;
	  var isPlatformReservedTag;

	  var genStaticKeysCached = cached(genStaticKeys$1);

	  /**
	   * Goal of the optimizer: walk the generated template AST tree
	   * and detect sub-trees that are purely static, i.e. parts of
	   * the DOM that never needs to change.
	   *
	   * Once we detect these sub-trees, we can:
	   *
	   * 1. Hoist them into constants, so that we no longer need to
	   *    create fresh nodes for them on each re-render;
	   * 2. Completely skip them in the patching process.
	   */
	  function optimize (root, options) {
	    if (!root) { return }
	    isStaticKey = genStaticKeysCached(options.staticKeys || '');
	    isPlatformReservedTag = options.isReservedTag || no;
	    // first pass: mark all non-static nodes.
	    markStatic$1(root);
	    // second pass: mark static roots.
	    markStaticRoots(root, false);
	  }

	  function genStaticKeys$1 (keys) {
	    return makeMap(
	      'type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap' +
	      (keys ? ',' + keys : '')
	    )
	  }

	  function markStatic$1 (node) {
	    node.static = isStatic(node);
	    if (node.type === 1) {
	      // do not make component slot content static. this avoids
	      // 1. components not able to mutate slot nodes
	      // 2. static slot content fails for hot-reloading
	      if (
	        !isPlatformReservedTag(node.tag) &&
	        node.tag !== 'slot' &&
	        node.attrsMap['inline-template'] == null
	      ) {
	        return
	      }
	      for (var i = 0, l = node.children.length; i < l; i++) {
	        var child = node.children[i];
	        markStatic$1(child);
	        if (!child.static) {
	          node.static = false;
	        }
	      }
	      if (node.ifConditions) {
	        for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) {
	          var block = node.ifConditions[i$1].block;
	          markStatic$1(block);
	          if (!block.static) {
	            node.static = false;
	          }
	        }
	      }
	    }
	  }

	  function markStaticRoots (node, isInFor) {
	    if (node.type === 1) {
	      if (node.static || node.once) {
	        node.staticInFor = isInFor;
	      }
	      // For a node to qualify as a static root, it should have children that
	      // are not just static text. Otherwise the cost of hoisting out will
	      // outweigh the benefits and it's better off to just always render it fresh.
	      if (node.static && node.children.length && !(
	        node.children.length === 1 &&
	        node.children[0].type === 3
	      )) {
	        node.staticRoot = true;
	        return
	      } else {
	        node.staticRoot = false;
	      }
	      if (node.children) {
	        for (var i = 0, l = node.children.length; i < l; i++) {
	          markStaticRoots(node.children[i], isInFor || !!node.for);
	        }
	      }
	      if (node.ifConditions) {
	        for (var i$1 = 1, l$1 = node.ifConditions.length; i$1 < l$1; i$1++) {
	          markStaticRoots(node.ifConditions[i$1].block, isInFor);
	        }
	      }
	    }
	  }

	  function isStatic (node) {
	    if (node.type === 2) { // expression
	      return false
	    }
	    if (node.type === 3) { // text
	      return true
	    }
	    return !!(node.pre || (
	      !node.hasBindings && // no dynamic bindings
	      !node.if && !node.for && // not v-if or v-for or v-else
	      !isBuiltInTag(node.tag) && // not a built-in
	      isPlatformReservedTag(node.tag) && // not a component
	      !isDirectChildOfTemplateFor(node) &&
	      Object.keys(node).every(isStaticKey)
	    ))
	  }

	  function isDirectChildOfTemplateFor (node) {
	    while (node.parent) {
	      node = node.parent;
	      if (node.tag !== 'template') {
	        return false
	      }
	      if (node.for) {
	        return true
	      }
	    }
	    return false
	  }

	  /*  */

	  var fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/;
	  var fnInvokeRE = /\([^)]*?\);*$/;
	  var simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/;

	  // KeyboardEvent.keyCode aliases
	  var keyCodes = {
	    esc: 27,
	    tab: 9,
	    enter: 13,
	    space: 32,
	    up: 38,
	    left: 37,
	    right: 39,
	    down: 40,
	    'delete': [8, 46]
	  };

	  // KeyboardEvent.key aliases
	  var keyNames = {
	    // #7880: IE11 and Edge use `Esc` for Escape key name.
	    esc: ['Esc', 'Escape'],
	    tab: 'Tab',
	    enter: 'Enter',
	    // #9112: IE11 uses `Spacebar` for Space key name.
	    space: [' ', 'Spacebar'],
	    // #7806: IE11 uses key names without `Arrow` prefix for arrow keys.
	    up: ['Up', 'ArrowUp'],
	    left: ['Left', 'ArrowLeft'],
	    right: ['Right', 'ArrowRight'],
	    down: ['Down', 'ArrowDown'],
	    // #9112: IE11 uses `Del` for Delete key name.
	    'delete': ['Backspace', 'Delete', 'Del']
	  };

	  // #4868: modifiers that prevent the execution of the listener
	  // need to explicitly return null so that we can determine whether to remove
	  // the listener for .once
	  var genGuard = function (condition) { return ("if(" + condition + ")return null;"); };

	  var modifierCode = {
	    stop: '$event.stopPropagation();',
	    prevent: '$event.preventDefault();',
	    self: genGuard("$event.target !== $event.currentTarget"),
	    ctrl: genGuard("!$event.ctrlKey"),
	    shift: genGuard("!$event.shiftKey"),
	    alt: genGuard("!$event.altKey"),
	    meta: genGuard("!$event.metaKey"),
	    left: genGuard("'button' in $event && $event.button !== 0"),
	    middle: genGuard("'button' in $event && $event.button !== 1"),
	    right: genGuard("'button' in $event && $event.button !== 2")
	  };

	  function genHandlers (
	    events,
	    isNative
	  ) {
	    var prefix = isNative ? 'nativeOn:' : 'on:';
	    var staticHandlers = "";
	    var dynamicHandlers = "";
	    for (var name in events) {
	      var handlerCode = genHandler(events[name]);
	      if (events[name] && events[name].dynamic) {
	        dynamicHandlers += name + "," + handlerCode + ",";
	      } else {
	        staticHandlers += "\"" + name + "\":" + handlerCode + ",";
	      }
	    }
	    staticHandlers = "{" + (staticHandlers.slice(0, -1)) + "}";
	    if (dynamicHandlers) {
	      return prefix + "_d(" + staticHandlers + ",[" + (dynamicHandlers.slice(0, -1)) + "])"
	    } else {
	      return prefix + staticHandlers
	    }
	  }

	  function genHandler (handler) {
	    if (!handler) {
	      return 'function(){}'
	    }

	    if (Array.isArray(handler)) {
	      return ("[" + (handler.map(function (handler) { return genHandler(handler); }).join(',')) + "]")
	    }

	    var isMethodPath = simplePathRE.test(handler.value);
	    var isFunctionExpression = fnExpRE.test(handler.value);
	    var isFunctionInvocation = simplePathRE.test(handler.value.replace(fnInvokeRE, ''));

	    if (!handler.modifiers) {
	      if (isMethodPath || isFunctionExpression) {
	        return handler.value
	      }
	      return ("function($event){" + (isFunctionInvocation ? ("return " + (handler.value)) : handler.value) + "}") // inline statement
	    } else {
	      var code = '';
	      var genModifierCode = '';
	      var keys = [];
	      for (var key in handler.modifiers) {
	        if (modifierCode[key]) {
	          genModifierCode += modifierCode[key];
	          // left/right
	          if (keyCodes[key]) {
	            keys.push(key);
	          }
	        } else if (key === 'exact') {
	          var modifiers = (handler.modifiers);
	          genModifierCode += genGuard(
	            ['ctrl', 'shift', 'alt', 'meta']
	              .filter(function (keyModifier) { return !modifiers[keyModifier]; })
	              .map(function (keyModifier) { return ("$event." + keyModifier + "Key"); })
	              .join('||')
	          );
	        } else {
	          keys.push(key);
	        }
	      }
	      if (keys.length) {
	        code += genKeyFilter(keys);
	      }
	      // Make sure modifiers like prevent and stop get executed after key filtering
	      if (genModifierCode) {
	        code += genModifierCode;
	      }
	      var handlerCode = isMethodPath
	        ? ("return " + (handler.value) + "($event)")
	        : isFunctionExpression
	          ? ("return (" + (handler.value) + ")($event)")
	          : isFunctionInvocation
	            ? ("return " + (handler.value))
	            : handler.value;
	      return ("function($event){" + code + handlerCode + "}")
	    }
	  }

	  function genKeyFilter (keys) {
	    return (
	      // make sure the key filters only apply to KeyboardEvents
	      // #9441: can't use 'keyCode' in $event because Chrome autofill fires fake
	      // key events that do not have keyCode property...
	      "if(!$event.type.indexOf('key')&&" +
	      (keys.map(genFilterCode).join('&&')) + ")return null;"
	    )
	  }

	  function genFilterCode (key) {
	    var keyVal = parseInt(key, 10);
	    if (keyVal) {
	      return ("$event.keyCode!==" + keyVal)
	    }
	    var keyCode = keyCodes[key];
	    var keyName = keyNames[key];
	    return (
	      "_k($event.keyCode," +
	      (JSON.stringify(key)) + "," +
	      (JSON.stringify(keyCode)) + "," +
	      "$event.key," +
	      "" + (JSON.stringify(keyName)) +
	      ")"
	    )
	  }

	  /*  */

	  function on (el, dir) {
	    if (dir.modifiers) {
	      warn("v-on without argument does not support modifiers.");
	    }
	    el.wrapListeners = function (code) { return ("_g(" + code + "," + (dir.value) + ")"); };
	  }

	  /*  */

	  function bind$1 (el, dir) {
	    el.wrapData = function (code) {
	      return ("_b(" + code + ",'" + (el.tag) + "'," + (dir.value) + "," + (dir.modifiers && dir.modifiers.prop ? 'true' : 'false') + (dir.modifiers && dir.modifiers.sync ? ',true' : '') + ")")
	    };
	  }

	  /*  */

	  var baseDirectives = {
	    on: on,
	    bind: bind$1,
	    cloak: noop
	  };

	  /*  */





	  var CodegenState = function CodegenState (options) {
	    this.options = options;
	    this.warn = options.warn || baseWarn;
	    this.transforms = pluckModuleFunction(options.modules, 'transformCode');
	    this.dataGenFns = pluckModuleFunction(options.modules, 'genData');
	    this.directives = extend(extend({}, baseDirectives), options.directives);
	    var isReservedTag = options.isReservedTag || no;
	    this.maybeComponent = function (el) { return !!el.component || !isReservedTag(el.tag); };
	    this.onceId = 0;
	    this.staticRenderFns = [];
	    this.pre = false;
	  };



	  function generate (
	    ast,
	    options
	  ) {
	    var state = new CodegenState(options);
	    var code = ast ? genElement(ast, state) : '_c("div")';
	    return {
	      render: ("with(this){return " + code + "}"),
	      staticRenderFns: state.staticRenderFns
	    }
	  }

	  function genElement (el, state) {
	    if (el.parent) {
	      el.pre = el.pre || el.parent.pre;
	    }

	    if (el.staticRoot && !el.staticProcessed) {
	      return genStatic(el, state)
	    } else if (el.once && !el.onceProcessed) {
	      return genOnce(el, state)
	    } else if (el.for && !el.forProcessed) {
	      return genFor(el, state)
	    } else if (el.if && !el.ifProcessed) {
	      return genIf(el, state)
	    } else if (el.tag === 'template' && !el.slotTarget && !state.pre) {
	      return genChildren(el, state) || 'void 0'
	    } else if (el.tag === 'slot') {
	      return genSlot(el, state)
	    } else {
	      // component or element
	      var code;
	      if (el.component) {
	        code = genComponent(el.component, el, state);
	      } else {
	        var data;
	        if (!el.plain || (el.pre && state.maybeComponent(el))) {
	          data = genData$2(el, state);
	        }

	        var children = el.inlineTemplate ? null : genChildren(el, state, true);
	        code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";
	      }
	      // module transforms
	      for (var i = 0; i < state.transforms.length; i++) {
	        code = state.transforms[i](el, code);
	      }
	      return code
	    }
	  }

	  // hoist static sub-trees out
	  function genStatic (el, state) {
	    el.staticProcessed = true;
	    // Some elements (templates) need to behave differently inside of a v-pre
	    // node.  All pre nodes are static roots, so we can use this as a location to
	    // wrap a state change and reset it upon exiting the pre node.
	    var originalPreState = state.pre;
	    if (el.pre) {
	      state.pre = el.pre;
	    }
	    state.staticRenderFns.push(("with(this){return " + (genElement(el, state)) + "}"));
	    state.pre = originalPreState;
	    return ("_m(" + (state.staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + ")")
	  }

	  // v-once
	  function genOnce (el, state) {
	    el.onceProcessed = true;
	    if (el.if && !el.ifProcessed) {
	      return genIf(el, state)
	    } else if (el.staticInFor) {
	      var key = '';
	      var parent = el.parent;
	      while (parent) {
	        if (parent.for) {
	          key = parent.key;
	          break
	        }
	        parent = parent.parent;
	      }
	      if (!key) {
	        state.warn(
	          "v-once can only be used inside v-for that is keyed. ",
	          el.rawAttrsMap['v-once']
	        );
	        return genElement(el, state)
	      }
	      return ("_o(" + (genElement(el, state)) + "," + (state.onceId++) + "," + key + ")")
	    } else {
	      return genStatic(el, state)
	    }
	  }

	  function genIf (
	    el,
	    state,
	    altGen,
	    altEmpty
	  ) {
	    el.ifProcessed = true; // avoid recursion
	    return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)
	  }

	  function genIfConditions (
	    conditions,
	    state,
	    altGen,
	    altEmpty
	  ) {
	    if (!conditions.length) {
	      return altEmpty || '_e()'
	    }

	    var condition = conditions.shift();
	    if (condition.exp) {
	      return ("(" + (condition.exp) + ")?" + (genTernaryExp(condition.block)) + ":" + (genIfConditions(conditions, state, altGen, altEmpty)))
	    } else {
	      return ("" + (genTernaryExp(condition.block)))
	    }

	    // v-if with v-once should generate code like (a)?_m(0):_m(1)
	    function genTernaryExp (el) {
	      return altGen
	        ? altGen(el, state)
	        : el.once
	          ? genOnce(el, state)
	          : genElement(el, state)
	    }
	  }

	  function genFor (
	    el,
	    state,
	    altGen,
	    altHelper
	  ) {
	    var exp = el.for;
	    var alias = el.alias;
	    var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : '';
	    var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : '';

	    if (state.maybeComponent(el) &&
	      el.tag !== 'slot' &&
	      el.tag !== 'template' &&
	      !el.key
	    ) {
	      state.warn(
	        "<" + (el.tag) + " v-for=\"" + alias + " in " + exp + "\">: component lists rendered with " +
	        "v-for should have explicit keys. " +
	        "See https://vuejs.org/guide/list.html#key for more info.",
	        el.rawAttrsMap['v-for'],
	        true /* tip */
	      );
	    }

	    el.forProcessed = true; // avoid recursion
	    return (altHelper || '_l') + "((" + exp + ")," +
	      "function(" + alias + iterator1 + iterator2 + "){" +
	        "return " + ((altGen || genElement)(el, state)) +
	      '})'
	  }

	  function genData$2 (el, state) {
	    var data = '{';

	    // directives first.
	    // directives may mutate the el's other properties before they are generated.
	    var dirs = genDirectives(el, state);
	    if (dirs) { data += dirs + ','; }

	    // key
	    if (el.key) {
	      data += "key:" + (el.key) + ",";
	    }
	    // ref
	    if (el.ref) {
	      data += "ref:" + (el.ref) + ",";
	    }
	    if (el.refInFor) {
	      data += "refInFor:true,";
	    }
	    // pre
	    if (el.pre) {
	      data += "pre:true,";
	    }
	    // record original tag name for components using "is" attribute
	    if (el.component) {
	      data += "tag:\"" + (el.tag) + "\",";
	    }
	    // module data generation functions
	    for (var i = 0; i < state.dataGenFns.length; i++) {
	      data += state.dataGenFns[i](el);
	    }
	    // attributes
	    if (el.attrs) {
	      data += "attrs:" + (genProps(el.attrs)) + ",";
	    }
	    // DOM props
	    if (el.props) {
	      data += "domProps:" + (genProps(el.props)) + ",";
	    }
	    // event handlers
	    if (el.events) {
	      data += (genHandlers(el.events, false)) + ",";
	    }
	    if (el.nativeEvents) {
	      data += (genHandlers(el.nativeEvents, true)) + ",";
	    }
	    // slot target
	    // only for non-scoped slots
	    if (el.slotTarget && !el.slotScope) {
	      data += "slot:" + (el.slotTarget) + ",";
	    }
	    // scoped slots
	    if (el.scopedSlots) {
	      data += (genScopedSlots(el, el.scopedSlots, state)) + ",";
	    }
	    // component v-model
	    if (el.model) {
	      data += "model:{value:" + (el.model.value) + ",callback:" + (el.model.callback) + ",expression:" + (el.model.expression) + "},";
	    }
	    // inline-template
	    if (el.inlineTemplate) {
	      var inlineTemplate = genInlineTemplate(el, state);
	      if (inlineTemplate) {
	        data += inlineTemplate + ",";
	      }
	    }
	    data = data.replace(/,$/, '') + '}';
	    // v-bind dynamic argument wrap
	    // v-bind with dynamic arguments must be applied using the same v-bind object
	    // merge helper so that class/style/mustUseProp attrs are handled correctly.
	    if (el.dynamicAttrs) {
	      data = "_b(" + data + ",\"" + (el.tag) + "\"," + (genProps(el.dynamicAttrs)) + ")";
	    }
	    // v-bind data wrap
	    if (el.wrapData) {
	      data = el.wrapData(data);
	    }
	    // v-on data wrap
	    if (el.wrapListeners) {
	      data = el.wrapListeners(data);
	    }
	    return data
	  }

	  function genDirectives (el, state) {
	    var dirs = el.directives;
	    if (!dirs) { return }
	    var res = 'directives:[';
	    var hasRuntime = false;
	    var i, l, dir, needRuntime;
	    for (i = 0, l = dirs.length; i < l; i++) {
	      dir = dirs[i];
	      needRuntime = true;
	      var gen = state.directives[dir.name];
	      if (gen) {
	        // compile-time directive that manipulates AST.
	        // returns true if it also needs a runtime counterpart.
	        needRuntime = !!gen(el, dir, state.warn);
	      }
	      if (needRuntime) {
	        hasRuntime = true;
	        res += "{name:\"" + (dir.name) + "\",rawName:\"" + (dir.rawName) + "\"" + (dir.value ? (",value:(" + (dir.value) + "),expression:" + (JSON.stringify(dir.value))) : '') + (dir.arg ? (",arg:" + (dir.isDynamicArg ? dir.arg : ("\"" + (dir.arg) + "\""))) : '') + (dir.modifiers ? (",modifiers:" + (JSON.stringify(dir.modifiers))) : '') + "},";
	      }
	    }
	    if (hasRuntime) {
	      return res.slice(0, -1) + ']'
	    }
	  }

	  function genInlineTemplate (el, state) {
	    var ast = el.children[0];
	    if (el.children.length !== 1 || ast.type !== 1) {
	      state.warn(
	        'Inline-template components must have exactly one child element.',
	        { start: el.start }
	      );
	    }
	    if (ast && ast.type === 1) {
	      var inlineRenderFns = generate(ast, state.options);
	      return ("inlineTemplate:{render:function(){" + (inlineRenderFns.render) + "},staticRenderFns:[" + (inlineRenderFns.staticRenderFns.map(function (code) { return ("function(){" + code + "}"); }).join(',')) + "]}")
	    }
	  }

	  function genScopedSlots (
	    el,
	    slots,
	    state
	  ) {
	    // by default scoped slots are considered "stable", this allows child
	    // components with only scoped slots to skip forced updates from parent.
	    // but in some cases we have to bail-out of this optimization
	    // for example if the slot contains dynamic names, has v-if or v-for on them...
	    var needsForceUpdate = el.for || Object.keys(slots).some(function (key) {
	      var slot = slots[key];
	      return (
	        slot.slotTargetDynamic ||
	        slot.if ||
	        slot.for ||
	        containsSlotChild(slot) // is passing down slot from parent which may be dynamic
	      )
	    });

	    // #9534: if a component with scoped slots is inside a conditional branch,
	    // it's possible for the same component to be reused but with different
	    // compiled slot content. To avoid that, we generate a unique key based on
	    // the generated code of all the slot contents.
	    var needsKey = !!el.if;

	    // OR when it is inside another scoped slot or v-for (the reactivity may be
	    // disconnected due to the intermediate scope variable)
	    // #9438, #9506
	    // TODO: this can be further optimized by properly analyzing in-scope bindings
	    // and skip force updating ones that do not actually use scope variables.
	    if (!needsForceUpdate) {
	      var parent = el.parent;
	      while (parent) {
	        if (
	          (parent.slotScope && parent.slotScope !== emptySlotScopeToken) ||
	          parent.for
	        ) {
	          needsForceUpdate = true;
	          break
	        }
	        if (parent.if) {
	          needsKey = true;
	        }
	        parent = parent.parent;
	      }
	    }

	    var generatedSlots = Object.keys(slots)
	      .map(function (key) { return genScopedSlot(slots[key], state); })
	      .join(',');

	    return ("scopedSlots:_u([" + generatedSlots + "]" + (needsForceUpdate ? ",null,true" : "") + (!needsForceUpdate && needsKey ? (",null,false," + (hash(generatedSlots))) : "") + ")")
	  }

	  function hash(str) {
	    var hash = 5381;
	    var i = str.length;
	    while(i) {
	      hash = (hash * 33) ^ str.charCodeAt(--i);
	    }
	    return hash >>> 0
	  }

	  function containsSlotChild (el) {
	    if (el.type === 1) {
	      if (el.tag === 'slot') {
	        return true
	      }
	      return el.children.some(containsSlotChild)
	    }
	    return false
	  }

	  function genScopedSlot (
	    el,
	    state
	  ) {
	    var isLegacySyntax = el.attrsMap['slot-scope'];
	    if (el.if && !el.ifProcessed && !isLegacySyntax) {
	      return genIf(el, state, genScopedSlot, "null")
	    }
	    if (el.for && !el.forProcessed) {
	      return genFor(el, state, genScopedSlot)
	    }
	    var slotScope = el.slotScope === emptySlotScopeToken
	      ? ""
	      : String(el.slotScope);
	    var fn = "function(" + slotScope + "){" +
	      "return " + (el.tag === 'template'
	        ? el.if && isLegacySyntax
	          ? ("(" + (el.if) + ")?" + (genChildren(el, state) || 'undefined') + ":undefined")
	          : genChildren(el, state) || 'undefined'
	        : genElement(el, state)) + "}";
	    // reverse proxy v-slot without scope on this.$slots
	    var reverseProxy = slotScope ? "" : ",proxy:true";
	    return ("{key:" + (el.slotTarget || "\"default\"") + ",fn:" + fn + reverseProxy + "}")
	  }

	  function genChildren (
	    el,
	    state,
	    checkSkip,
	    altGenElement,
	    altGenNode
	  ) {
	    var children = el.children;
	    if (children.length) {
	      var el$1 = children[0];
	      // optimize single v-for
	      if (children.length === 1 &&
	        el$1.for &&
	        el$1.tag !== 'template' &&
	        el$1.tag !== 'slot'
	      ) {
	        var normalizationType = checkSkip
	          ? state.maybeComponent(el$1) ? ",1" : ",0"
	          : "";
	        return ("" + ((altGenElement || genElement)(el$1, state)) + normalizationType)
	      }
	      var normalizationType$1 = checkSkip
	        ? getNormalizationType(children, state.maybeComponent)
	        : 0;
	      var gen = altGenNode || genNode;
	      return ("[" + (children.map(function (c) { return gen(c, state); }).join(',')) + "]" + (normalizationType$1 ? ("," + normalizationType$1) : ''))
	    }
	  }

	  // determine the normalization needed for the children array.
	  // 0: no normalization needed
	  // 1: simple normalization needed (possible 1-level deep nested array)
	  // 2: full normalization needed
	  function getNormalizationType (
	    children,
	    maybeComponent
	  ) {
	    var res = 0;
	    for (var i = 0; i < children.length; i++) {
	      var el = children[i];
	      if (el.type !== 1) {
	        continue
	      }
	      if (needsNormalization(el) ||
	          (el.ifConditions && el.ifConditions.some(function (c) { return needsNormalization(c.block); }))) {
	        res = 2;
	        break
	      }
	      if (maybeComponent(el) ||
	          (el.ifConditions && el.ifConditions.some(function (c) { return maybeComponent(c.block); }))) {
	        res = 1;
	      }
	    }
	    return res
	  }

	  function needsNormalization (el) {
	    return el.for !== undefined || el.tag === 'template' || el.tag === 'slot'
	  }

	  function genNode (node, state) {
	    if (node.type === 1) {
	      return genElement(node, state)
	    } else if (node.type === 3 && node.isComment) {
	      return genComment(node)
	    } else {
	      return genText(node)
	    }
	  }

	  function genText (text) {
	    return ("_v(" + (text.type === 2
	      ? text.expression // no need for () because already wrapped in _s()
	      : transformSpecialNewlines(JSON.stringify(text.text))) + ")")
	  }

	  function genComment (comment) {
	    return ("_e(" + (JSON.stringify(comment.text)) + ")")
	  }

	  function genSlot (el, state) {
	    var slotName = el.slotName || '"default"';
	    var children = genChildren(el, state);
	    var res = "_t(" + slotName + (children ? ("," + children) : '');
	    var attrs = el.attrs || el.dynamicAttrs
	      ? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(function (attr) { return ({
	          // slot props are camelized
	          name: camelize(attr.name),
	          value: attr.value,
	          dynamic: attr.dynamic
	        }); }))
	      : null;
	    var bind$$1 = el.attrsMap['v-bind'];
	    if ((attrs || bind$$1) && !children) {
	      res += ",null";
	    }
	    if (attrs) {
	      res += "," + attrs;
	    }
	    if (bind$$1) {
	      res += (attrs ? '' : ',null') + "," + bind$$1;
	    }
	    return res + ')'
	  }

	  // componentName is el.component, take it as argument to shun flow's pessimistic refinement
	  function genComponent (
	    componentName,
	    el,
	    state
	  ) {
	    var children = el.inlineTemplate ? null : genChildren(el, state, true);
	    return ("_c(" + componentName + "," + (genData$2(el, state)) + (children ? ("," + children) : '') + ")")
	  }

	  function genProps (props) {
	    var staticProps = "";
	    var dynamicProps = "";
	    for (var i = 0; i < props.length; i++) {
	      var prop = props[i];
	      var value = transformSpecialNewlines(prop.value);
	      if (prop.dynamic) {
	        dynamicProps += (prop.name) + "," + value + ",";
	      } else {
	        staticProps += "\"" + (prop.name) + "\":" + value + ",";
	      }
	    }
	    staticProps = "{" + (staticProps.slice(0, -1)) + "}";
	    if (dynamicProps) {
	      return ("_d(" + staticProps + ",[" + (dynamicProps.slice(0, -1)) + "])")
	    } else {
	      return staticProps
	    }
	  }

	  // #3895, #4268
	  function transformSpecialNewlines (text) {
	    return text
	      .replace(/\u2028/g, '\\u2028')
	      .replace(/\u2029/g, '\\u2029')
	  }

	  /*  */



	  // these keywords should not appear inside expressions, but operators like
	  // typeof, instanceof and in are allowed
	  var prohibitedKeywordRE = new RegExp('\\b' + (
	    'do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +
	    'super,throw,while,yield,delete,export,import,return,switch,default,' +
	    'extends,finally,continue,debugger,function,arguments'
	  ).split(',').join('\\b|\\b') + '\\b');

	  // these unary operators should not be used as property/method names
	  var unaryOperatorsRE = new RegExp('\\b' + (
	    'delete,typeof,void'
	  ).split(',').join('\\s*\\([^\\)]*\\)|\\b') + '\\s*\\([^\\)]*\\)');

	  // strip strings in expressions
	  var stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g;

	  // detect problematic expressions in a template
	  function detectErrors (ast, warn) {
	    if (ast) {
	      checkNode(ast, warn);
	    }
	  }

	  function checkNode (node, warn) {
	    if (node.type === 1) {
	      for (var name in node.attrsMap) {
	        if (dirRE.test(name)) {
	          var value = node.attrsMap[name];
	          if (value) {
	            var range = node.rawAttrsMap[name];
	            if (name === 'v-for') {
	              checkFor(node, ("v-for=\"" + value + "\""), warn, range);
	            } else if (name === 'v-slot' || name[0] === '#') {
	              checkFunctionParameterExpression(value, (name + "=\"" + value + "\""), warn, range);
	            } else if (onRE.test(name)) {
	              checkEvent(value, (name + "=\"" + value + "\""), warn, range);
	            } else {
	              checkExpression(value, (name + "=\"" + value + "\""), warn, range);
	            }
	          }
	        }
	      }
	      if (node.children) {
	        for (var i = 0; i < node.children.length; i++) {
	          checkNode(node.children[i], warn);
	        }
	      }
	    } else if (node.type === 2) {
	      checkExpression(node.expression, node.text, warn, node);
	    }
	  }

	  function checkEvent (exp, text, warn, range) {
	    var stripped = exp.replace(stripStringRE, '');
	    var keywordMatch = stripped.match(unaryOperatorsRE);
	    if (keywordMatch && stripped.charAt(keywordMatch.index - 1) !== '$') {
	      warn(
	        "avoid using JavaScript unary operator as property name: " +
	        "\"" + (keywordMatch[0]) + "\" in expression " + (text.trim()),
	        range
	      );
	    }
	    checkExpression(exp, text, warn, range);
	  }

	  function checkFor (node, text, warn, range) {
	    checkExpression(node.for || '', text, warn, range);
	    checkIdentifier(node.alias, 'v-for alias', text, warn, range);
	    checkIdentifier(node.iterator1, 'v-for iterator', text, warn, range);
	    checkIdentifier(node.iterator2, 'v-for iterator', text, warn, range);
	  }

	  function checkIdentifier (
	    ident,
	    type,
	    text,
	    warn,
	    range
	  ) {
	    if (typeof ident === 'string') {
	      try {
	        new Function(("var " + ident + "=_"));
	      } catch (e) {
	        warn(("invalid " + type + " \"" + ident + "\" in expression: " + (text.trim())), range);
	      }
	    }
	  }

	  function checkExpression (exp, text, warn, range) {
	    try {
	      new Function(("return " + exp));
	    } catch (e) {
	      var keywordMatch = exp.replace(stripStringRE, '').match(prohibitedKeywordRE);
	      if (keywordMatch) {
	        warn(
	          "avoid using JavaScript keyword as property name: " +
	          "\"" + (keywordMatch[0]) + "\"\n  Raw expression: " + (text.trim()),
	          range
	        );
	      } else {
	        warn(
	          "invalid expression: " + (e.message) + " in\n\n" +
	          "    " + exp + "\n\n" +
	          "  Raw expression: " + (text.trim()) + "\n",
	          range
	        );
	      }
	    }
	  }

	  function checkFunctionParameterExpression (exp, text, warn, range) {
	    try {
	      new Function(exp, '');
	    } catch (e) {
	      warn(
	        "invalid function parameter expression: " + (e.message) + " in\n\n" +
	        "    " + exp + "\n\n" +
	        "  Raw expression: " + (text.trim()) + "\n",
	        range
	      );
	    }
	  }

	  /*  */

	  var range = 2;

	  function generateCodeFrame (
	    source,
	    start,
	    end
	  ) {
	    if ( start === void 0 ) start = 0;
	    if ( end === void 0 ) end = source.length;

	    var lines = source.split(/\r?\n/);
	    var count = 0;
	    var res = [];
	    for (var i = 0; i < lines.length; i++) {
	      count += lines[i].length + 1;
	      if (count >= start) {
	        for (var j = i - range; j <= i + range || end > count; j++) {
	          if (j < 0 || j >= lines.length) { continue }
	          res.push(("" + (j + 1) + (repeat$1(" ", 3 - String(j + 1).length)) + "|  " + (lines[j])));
	          var lineLength = lines[j].length;
	          if (j === i) {
	            // push underline
	            var pad = start - (count - lineLength) + 1;
	            var length = end > count ? lineLength - pad : end - start;
	            res.push("   |  " + repeat$1(" ", pad) + repeat$1("^", length));
	          } else if (j > i) {
	            if (end > count) {
	              var length$1 = Math.min(end - count, lineLength);
	              res.push("   |  " + repeat$1("^", length$1));
	            }
	            count += lineLength + 1;
	          }
	        }
	        break
	      }
	    }
	    return res.join('\n')
	  }

	  function repeat$1 (str, n) {
	    var result = '';
	    if (n > 0) {
	      while (true) { // eslint-disable-line
	        if (n & 1) { result += str; }
	        n >>>= 1;
	        if (n <= 0) { break }
	        str += str;
	      }
	    }
	    return result
	  }

	  /*  */



	  function createFunction (code, errors) {
	    try {
	      return new Function(code)
	    } catch (err) {
	      errors.push({ err: err, code: code });
	      return noop
	    }
	  }

	  function createCompileToFunctionFn (compile) {
	    var cache = Object.create(null);

	    return function compileToFunctions (
	      template,
	      options,
	      vm
	    ) {
	      options = extend({}, options);
	      var warn$$1 = options.warn || warn;
	      delete options.warn;

	      /* istanbul ignore if */
	      {
	        // detect possible CSP restriction
	        try {
	          new Function('return 1');
	        } catch (e) {
	          if (e.toString().match(/unsafe-eval|CSP/)) {
	            warn$$1(
	              'It seems you are using the standalone build of Vue.js in an ' +
	              'environment with Content Security Policy that prohibits unsafe-eval. ' +
	              'The template compiler cannot work in this environment. Consider ' +
	              'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
	              'templates into render functions.'
	            );
	          }
	        }
	      }

	      // check cache
	      var key = options.delimiters
	        ? String(options.delimiters) + template
	        : template;
	      if (cache[key]) {
	        return cache[key]
	      }

	      // compile
	      var compiled = compile(template, options);

	      // check compilation errors/tips
	      {
	        if (compiled.errors && compiled.errors.length) {
	          if (options.outputSourceRange) {
	            compiled.errors.forEach(function (e) {
	              warn$$1(
	                "Error compiling template:\n\n" + (e.msg) + "\n\n" +
	                generateCodeFrame(template, e.start, e.end),
	                vm
	              );
	            });
	          } else {
	            warn$$1(
	              "Error compiling template:\n\n" + template + "\n\n" +
	              compiled.errors.map(function (e) { return ("- " + e); }).join('\n') + '\n',
	              vm
	            );
	          }
	        }
	        if (compiled.tips && compiled.tips.length) {
	          if (options.outputSourceRange) {
	            compiled.tips.forEach(function (e) { return tip(e.msg, vm); });
	          } else {
	            compiled.tips.forEach(function (msg) { return tip(msg, vm); });
	          }
	        }
	      }

	      // turn code into functions
	      var res = {};
	      var fnGenErrors = [];
	      res.render = createFunction(compiled.render, fnGenErrors);
	      res.staticRenderFns = compiled.staticRenderFns.map(function (code) {
	        return createFunction(code, fnGenErrors)
	      });

	      // check function generation errors.
	      // this should only happen if there is a bug in the compiler itself.
	      // mostly for codegen development use
	      /* istanbul ignore if */
	      {
	        if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
	          warn$$1(
	            "Failed to generate render function:\n\n" +
	            fnGenErrors.map(function (ref) {
	              var err = ref.err;
	              var code = ref.code;

	              return ((err.toString()) + " in\n\n" + code + "\n");
	          }).join('\n'),
	            vm
	          );
	        }
	      }

	      return (cache[key] = res)
	    }
	  }

	  /*  */

	  function createCompilerCreator (baseCompile) {
	    return function createCompiler (baseOptions) {
	      function compile (
	        template,
	        options
	      ) {
	        var finalOptions = Object.create(baseOptions);
	        var errors = [];
	        var tips = [];

	        var warn = function (msg, range, tip) {
	          (tip ? tips : errors).push(msg);
	        };

	        if (options) {
	          if (options.outputSourceRange) {
	            // $flow-disable-line
	            var leadingSpaceLength = template.match(/^\s*/)[0].length;

	            warn = function (msg, range, tip) {
	              var data = { msg: msg };
	              if (range) {
	                if (range.start != null) {
	                  data.start = range.start + leadingSpaceLength;
	                }
	                if (range.end != null) {
	                  data.end = range.end + leadingSpaceLength;
	                }
	              }
	              (tip ? tips : errors).push(data);
	            };
	          }
	          // merge custom modules
	          if (options.modules) {
	            finalOptions.modules =
	              (baseOptions.modules || []).concat(options.modules);
	          }
	          // merge custom directives
	          if (options.directives) {
	            finalOptions.directives = extend(
	              Object.create(baseOptions.directives || null),
	              options.directives
	            );
	          }
	          // copy other options
	          for (var key in options) {
	            if (key !== 'modules' && key !== 'directives') {
	              finalOptions[key] = options[key];
	            }
	          }
	        }

	        finalOptions.warn = warn;

	        var compiled = baseCompile(template.trim(), finalOptions);
	        {
	          detectErrors(compiled.ast, warn);
	        }
	        compiled.errors = errors;
	        compiled.tips = tips;
	        return compiled
	      }

	      return {
	        compile: compile,
	        compileToFunctions: createCompileToFunctionFn(compile)
	      }
	    }
	  }

	  /*  */

	  // `createCompilerCreator` allows creating compilers that use alternative
	  // parser/optimizer/codegen, e.g the SSR optimizing compiler.
	  // Here we just export a default compiler using the default parts.
	  var createCompiler = createCompilerCreator(function baseCompile (
	    template,
	    options
	  ) {
	    var ast = parse(template.trim(), options);
	    if (options.optimize !== false) {
	      optimize(ast, options);
	    }
	    var code = generate(ast, options);
	    return {
	      ast: ast,
	      render: code.render,
	      staticRenderFns: code.staticRenderFns
	    }
	  });

	  /*  */

	  var ref$1 = createCompiler(baseOptions);
	  var compileToFunctions = ref$1.compileToFunctions;

	  /*  */

	  // check whether current browser encodes a char inside attribute values
	  var div;
	  function getShouldDecode (href) {
	    div = div || document.createElement('div');
	    div.innerHTML = href ? "<a href=\"\n\"/>" : "<div a=\"\n\"/>";
	    return div.innerHTML.indexOf('&#10;') > 0
	  }

	  // #3663: IE encodes newlines inside attribute values while other browsers don't
	  var shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false;
	  // #6828: chrome encodes content in a[href]
	  var shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false;

	  /*  */

	  var idToTemplate = cached(function (id) {
	    var el = query(id);
	    return el && el.innerHTML
	  });

	  var mount = Vue.prototype.$mount;
	  Vue.prototype.$mount = function (
	    el,
	    hydrating
	  ) {
	    el = el && query(el);

	    /* istanbul ignore if */
	    if (el === document.body || el === document.documentElement) {
	      warn(
	        "Do not mount Vue to <html> or <body> - mount to normal elements instead."
	      );
	      return this
	    }

	    var options = this.$options;
	    // resolve template/el and convert to render function
	    if (!options.render) {
	      var template = options.template;
	      if (template) {
	        if (typeof template === 'string') {
	          if (template.charAt(0) === '#') {
	            template = idToTemplate(template);
	            /* istanbul ignore if */
	            if (!template) {
	              warn(
	                ("Template element not found or is empty: " + (options.template)),
	                this
	              );
	            }
	          }
	        } else if (template.nodeType) {
	          template = template.innerHTML;
	        } else {
	          {
	            warn('invalid template option:' + template, this);
	          }
	          return this
	        }
	      } else if (el) {
	        template = getOuterHTML(el);
	      }
	      if (template) {
	        /* istanbul ignore if */
	        if (config.performance && mark) {
	          mark('compile');
	        }

	        var ref = compileToFunctions(template, {
	          outputSourceRange: "development" !== 'production',
	          shouldDecodeNewlines: shouldDecodeNewlines,
	          shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
	          delimiters: options.delimiters,
	          comments: options.comments
	        }, this);
	        var render = ref.render;
	        var staticRenderFns = ref.staticRenderFns;
	        options.render = render;
	        options.staticRenderFns = staticRenderFns;

	        /* istanbul ignore if */
	        if (config.performance && mark) {
	          mark('compile end');
	          measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
	        }
	      }
	    }
	    return mount.call(this, el, hydrating)
	  };

	  /**
	   * Get outerHTML of elements, taking care
	   * of SVG elements in IE as well.
	   */
	  function getOuterHTML (el) {
	    if (el.outerHTML) {
	      return el.outerHTML
	    } else {
	      var container = document.createElement('div');
	      container.appendChild(el.cloneNode(true));
	      return container.innerHTML
	    }
	  }

	  Vue.compile = compileToFunctions;

	  return Vue;

	}));
	});

	var Vue$1 = unwrapExports(vue);

	var vueModaltor = createCommonjsModule(function (module, exports) {
	!function(root,factory){module.exports=factory();}("undefined"!=typeof self?self:commonjsGlobal,function(){return function(modules){function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={i:moduleId,l:!1,exports:{}};return modules[moduleId].call(module.exports,module,module.exports,__webpack_require__),module.l=!0,module.exports}var installedModules={};return __webpack_require__.m=modules,__webpack_require__.c=installedModules,__webpack_require__.d=function(exports,name,getter){__webpack_require__.o(exports,name)||Object.defineProperty(exports,name,{configurable:!1,enumerable:!0,get:getter});},__webpack_require__.n=function(module){var getter=module&&module.__esModule?function(){return module.default}:function(){return module};return __webpack_require__.d(getter,"a",getter),getter},__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)},__webpack_require__.p="",__webpack_require__(__webpack_require__.s=0)}([function(module,exports,__webpack_require__){Object.defineProperty(exports,"__esModule",{value:!0});var _vueModaltor=__webpack_require__(1),_vueModaltor2=function(obj){return obj&&obj.__esModule?obj:{default:obj}}(_vueModaltor),modalTor={install:function(Vue,options){Vue.component("vue-modaltor",_vueModaltor2.default);}};exports.default=modalTor,"undefined"!=typeof window&&window.Vue&&window.Vue.use(modalTor);},function(module,exports,__webpack_require__){__webpack_require__(2);var Component=__webpack_require__(7)(__webpack_require__(8),__webpack_require__(9),null,null);Component.options.__file="e:\\fakor\\modaltor\\src\\vue-modaltor.vue",Component.esModule&&Object.keys(Component.esModule).some(function(key){return "default"!==key&&"__esModule"!==key})&&console.error("named exports are not supported in *.vue files."),Component.options.functional&&console.error("[vue-loader] vue-modaltor.vue: functional components are not supported with templates, they should use render functions."),module.exports=Component.exports;},function(module,exports,__webpack_require__){var content=__webpack_require__(3);"string"==typeof content&&(content=[[module.i,content,""]]),content.locals&&(module.exports=content.locals);__webpack_require__(5)("b6523272",content,!1);},function(module,exports,__webpack_require__){exports=module.exports=__webpack_require__(4)(),exports.push([module.i,"\n.modal-vue-wrapper.modal-fade {\n  opacity: 0.1;\n  visibility: hidden;\n}\n.modal-vue-wrapper.modal-scale {\n  -webkit-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  -o-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n.modal-vue-wrapper {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100vw;\n  height: 100vh;\n  font-size: 14px;\n  -webkit-font-smoothing: antialiased;\n  z-index: 99;\n  -webkit-transform: translate3D(0, 0, 0);\n  -ms-transform: translate3D(0, 0, 0);\n  -o-transform: translate3D(0, 0, 0);\n  transform: translate3D(0, 0, 0);\n  transition: all 0.2s cubic-bezier(0.52, 0.02, 0.19, 1.02);\n}\n.modal-vue-wrapper .modal-vue-overlay {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100vw;\n  height: 100vh;\n  z-index: 9001;\n  font-size: 14px;\n  -webkit-font-smoothing: antialiased;\n  z-index: 999;\n}\n.modal-vue-wrapper .modal-vue-panel.modal-fade {\n  transform: scale(1) translate(0, -50%);\n}\n.modal-vue-wrapper .modal-vue-panel.modal-rotate {\n  transform: rotate(45deg) translate(0, -50%);\n}\n.modal-vue-wrapper .modal-vue-panel.modal-slide-right {\n  transform: translate(100px, -50%);\n}\n.modal-vue-wrapper .modal-vue-panel.modal-slide-left {\n  transform: translate(-100px, -50%);\n}\n.modal-vue-wrapper .modal-vue-panel.modal-slide-top {\n  transform: translate(0, -100%);\n}\n.modal-vue-wrapper .modal-vue-panel.modal-slide-bottom {\n  transform: translate(0, 100%);\n}\n.modal-vue-wrapper .modal-vue-panel {\n  z-index: 99999999999;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n  background: #fff;\n  box-shadow: 0px 8px 46px rgba(0, 0, 0, 0.08), 0px 2px 6px rgba(0, 0, 0, 0.03);\n  position: absolute;\n  max-height: 100vh;\n  overflow-y: auto;\n  border-radius: 2px;\n  top: 50%;\n  left: 0;\n  right: 0;\n  margin: 0 auto;\n  opacity: 0;\n  transition-property: transform, opacity, width ;\n  transition-duration: 0.3s;\n  /* // 0.3s;  */\n  transition-delay: 0.05s;\n  transition-timing-function: cubic-bezier(0.52, 0.02, 0.19, 1.02);\n}\n.modal-vue-wrapper .modal-vue-panel::-webkit-scrollbar-track {\n  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);\n  background-color: #F5F5F5;\n}\n.modal-vue-wrapper .modal-vue-panel::-webkit-scrollbar {\n  width: 6px;\n  height: 5px;\n  background-color: #F5F5F5;\n}\n.modal-vue-wrapper .modal-vue-panel::-webkit-scrollbar-thumb {\n  background-color: #41b9d2;\n}\n.modal-vue-wrapper .modal-vue-panel .modal-vue-actions {\n  position: absolute;\n  top: 12px;\n  right: 12px;\n}\n.modal-vue-wrapper .modal-vue-panel .modal-vue-actions .modal-vue-action-close {\n  display: inline-block;\n  cursor: pointer;\n  color: #222C38;\n  text-align: center;\n  width: 42px;\n  height: 42px;\n  line-height: 42px;\n  border-radius: 50%;\n}\n.modal-vue-wrapper .modal-vue-panel .modal-vue-content {\n  display: flex;\n  align-items: center;\n  padding-left: 15px;\n  padding-right: 15px;\n  padding-top: 24px;\n  padding-bottom: 24px;\n  line-height: 1.5;\n}\n.modal-vue-wrapper .modal-vue-panel .modal-vue-content .modal-vue-content-panel {\n  display: block;\n  text-align: justify;\n  font-size: 16px;\n  padding-top: 5px;\n  padding-bottom: 10px;\n  flex-grow: 1;\n}\n.modal-vue-wrapper .modal-vue-show {\n  transform: translate(0, -50%) !important;\n  opacity: 1 !important;\n}\n.modal-vue-wrapper-show,\n.modal-vue-wrapper-show.modal-fade,\n.modal-vue-wrapper-show.modal-scale {\n  visibility: visible;\n  opacity: 1;\n  -webkit-transform: translate3D(0, 0, 0);\n  -ms-transform: translate3D(0, 0, 0);\n  -o-transform: translate3D(0, 0, 0);\n  transform: translate3D(0, 0, 0);\n}\n.img-mode img {\n  box-shadow: 0px 8px 46px rgba(0, 0, 0, 0.08), 0px 2px 6px rgba(0, 0, 0, 0.03);\n  width: auto;\n  height: auto;\n  max-width: 100%;\n  max-height: 100%;\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  margin: auto;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  z-index: 9999;\n}\n.modal-vue-actions-parent:before,\n.modal-vue-actions-parent:after {\n  content: '';\n  display: block;\n  width: 2px;\n  height: 30px;\n  position: absolute;\n  right: 30px;\n  top: 15px;\n  cursor: pointer;\n  z-index: 99;\n  background: #000;\n  border-radius: 100%;\n}\n.modal-vue-actions-parent:before {\n  transform: rotate(-45deg);\n}\n.modal-vue-actions-parent:after {\n  transform: rotate(45deg);\n}\n.modal-vue-actions-parent .modal-vue-action-close {\n  display: inline-block;\n  cursor: pointer;\n  color: #222C38;\n  text-align: center;\n  width: 42px;\n  height: 42px;\n  line-height: 42px;\n  border-radius: 50%;\n}\n",""]);},function(module,exports){module.exports=function(){var list=[];return list.toString=function(){for(var result=[],i=0;i<this.length;i++){var item=this[i];item[2]?result.push("@media "+item[2]+"{"+item[1]+"}"):result.push(item[1]);}return result.join("")},list.i=function(modules,mediaQuery){"string"==typeof modules&&(modules=[[null,modules,""]]);for(var alreadyImportedModules={},i=0;i<this.length;i++){var id=this[i][0];"number"==typeof id&&(alreadyImportedModules[id]=!0);}for(i=0;i<modules.length;i++){var item=modules[i];"number"==typeof item[0]&&alreadyImportedModules[item[0]]||(mediaQuery&&!item[2]?item[2]=mediaQuery:mediaQuery&&(item[2]="("+item[2]+") and ("+mediaQuery+")"),list.push(item));}},list};},function(module,exports,__webpack_require__){function addStylesToDom(styles){for(var i=0;i<styles.length;i++){var item=styles[i],domStyle=stylesInDom[item.id];if(domStyle){domStyle.refs++;for(var j=0;j<domStyle.parts.length;j++)domStyle.parts[j](item.parts[j]);for(;j<item.parts.length;j++)domStyle.parts.push(addStyle(item.parts[j]));domStyle.parts.length>item.parts.length&&(domStyle.parts.length=item.parts.length);}else {for(var parts=[],j=0;j<item.parts.length;j++)parts.push(addStyle(item.parts[j]));stylesInDom[item.id]={id:item.id,refs:1,parts:parts};}}}function createStyleElement(){var styleElement=document.createElement("style");return styleElement.type="text/css",head.appendChild(styleElement),styleElement}function addStyle(obj){var update,remove,styleElement=document.querySelector('style[data-vue-ssr-id~="'+obj.id+'"]');if(styleElement){if(isProduction)return noop;styleElement.parentNode.removeChild(styleElement);}if(isOldIE){var styleIndex=singletonCounter++;styleElement=singletonElement||(singletonElement=createStyleElement()),update=applyToSingletonTag.bind(null,styleElement,styleIndex,!1),remove=applyToSingletonTag.bind(null,styleElement,styleIndex,!0);}else styleElement=createStyleElement(),update=applyToTag.bind(null,styleElement),remove=function(){styleElement.parentNode.removeChild(styleElement);};return update(obj),function(newObj){if(newObj){if(newObj.css===obj.css&&newObj.media===obj.media&&newObj.sourceMap===obj.sourceMap)return;update(obj=newObj);}else remove();}}function applyToSingletonTag(styleElement,index,remove,obj){var css=remove?"":obj.css;if(styleElement.styleSheet)styleElement.styleSheet.cssText=replaceText(index,css);else {var cssNode=document.createTextNode(css),childNodes=styleElement.childNodes;childNodes[index]&&styleElement.removeChild(childNodes[index]),childNodes.length?styleElement.insertBefore(cssNode,childNodes[index]):styleElement.appendChild(cssNode);}}function applyToTag(styleElement,obj){var css=obj.css,media=obj.media,sourceMap=obj.sourceMap;if(media&&styleElement.setAttribute("media",media),sourceMap&&(css+="\n/*# sourceURL="+sourceMap.sources[0]+" */",css+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))))+" */"),styleElement.styleSheet)styleElement.styleSheet.cssText=css;else {for(;styleElement.firstChild;)styleElement.removeChild(styleElement.firstChild);styleElement.appendChild(document.createTextNode(css));}}var hasDocument="undefined"!=typeof document;if("undefined"!=typeof DEBUG&&DEBUG&&!hasDocument)throw new Error("vue-style-loader cannot be used in a non-browser environment. Use { target: 'node' } in your Webpack config to indicate a server-rendering environment.");var listToStyles=__webpack_require__(6),stylesInDom={},head=hasDocument&&(document.head||document.getElementsByTagName("head")[0]),singletonElement=null,singletonCounter=0,isProduction=!1,noop=function(){},isOldIE="undefined"!=typeof navigator&&/msie [6-9]\b/.test(navigator.userAgent.toLowerCase());module.exports=function(parentId,list,_isProduction){isProduction=_isProduction;var styles=listToStyles(parentId,list);return addStylesToDom(styles),function(newList){for(var mayRemove=[],i=0;i<styles.length;i++){var item=styles[i],domStyle=stylesInDom[item.id];domStyle.refs--,mayRemove.push(domStyle);}newList?(styles=listToStyles(parentId,newList),addStylesToDom(styles)):styles=[];for(var i=0;i<mayRemove.length;i++){var domStyle=mayRemove[i];if(0===domStyle.refs){for(var j=0;j<domStyle.parts.length;j++)domStyle.parts[j]();delete stylesInDom[domStyle.id];}}}};var replaceText=function(){var textStore=[];return function(index,replacement){return textStore[index]=replacement,textStore.filter(Boolean).join("\n")}}();},function(module,exports){module.exports=function(parentId,list){for(var styles=[],newStyles={},i=0;i<list.length;i++){var item=list[i],id=item[0],css=item[1],media=item[2],sourceMap=item[3],part={id:parentId+":"+i,css:css,media:media,sourceMap:sourceMap};newStyles[id]?newStyles[id].parts.push(part):styles.push(newStyles[id]={id:id,parts:[part]});}return styles};},function(module,exports){module.exports=function(rawScriptExports,compiledTemplate,scopeId,cssModules){var esModule,scriptExports=rawScriptExports=rawScriptExports||{},type=typeof rawScriptExports.default;"object"!==type&&"function"!==type||(esModule=rawScriptExports,scriptExports=rawScriptExports.default);var options="function"==typeof scriptExports?scriptExports.options:scriptExports;if(compiledTemplate&&(options.render=compiledTemplate.render,options.staticRenderFns=compiledTemplate.staticRenderFns),scopeId&&(options._scopeId=scopeId),cssModules){var computed=Object.create(options.computed||null);Object.keys(cssModules).forEach(function(key){var module=cssModules[key];computed[key]=function(){return module};}),options.computed=computed;}return {esModule:esModule,exports:scriptExports,options:options}};},function(module,exports,__webpack_require__){Object.defineProperty(exports,"__esModule",{value:!0}),exports.default={name:"modal-vue-perfect",props:{visible:{type:Boolean,required:!1,default:!1},resizeWidth:{type:Object},animationPanel:{type:String,required:!1,default:"modal-fade"},bgOverlay:{type:String,required:!1,default:"rgba(255, 255, 255, 0.57)"},bgPanel:{type:String,required:!1,default:"#fff"},animationParent:{type:String,required:!1,default:"modal-fade"},imgMode:{type:Boolean,required:!1,default:!1},defaultWidth:{type:String,required:!1,default:"80%"},closeScroll:{type:Boolean,required:!1,default:!0}},data:function(){return {width:this.defaultWidth||"80%",open:!1,isOpen:!1,backups:{body:{height:null,overflow:null,paddingRight:null}}}},watch:{visible:function(val){var _this=this;val?(this.isOpen=!0,setTimeout(function(){return _this.open=!0},30),this.closeScroll&&this._lockBody()):(this.closeScroll&&this._unlockBody(),this.open=!1,setTimeout(function(){return _this.isOpen=!1},300));}},beforeDestroy:function(){window.removeEventListener("resize",this.getWindowWidth),window.removeEventListener("resize",this.getWindowHeight);},destroyed:function(){var _this2=this;this.open&&(this.closeScroll&&this._unlockBody(),this.open=!1,setTimeout(function(){return _this2.isOpen=!1},300));},mounted:function(){this.$nextTick(function(){window.addEventListener("resize",this.getWindowWidth),window.addEventListener("resize",this.getWindowHeight),this.getWindowWidth(),this.getWindowHeight();});},methods:{getWindowHeight:function(event){this.windowHeight=document.documentElement.clientHeight;},getWindowWidth:function(event){var _this3=this;if(this.resizeWidth&&Object.keys(this.resizeWidth).length>0){this.windowWidth=document.documentElement.clientWidth;var filter=Object.keys(this.resizeWidth).find(function(f){return f>=_this3.windowWidth});this.width=filter?this.resizeWidth[filter]:this.defaultWidth;}},_lockBody:function(){this.backups.body.height=document.body.style.height,this.backups.body.overflow=document.body.style.overflow,document.body.style.paddingRight="15px",document.body.style.height="100%",document.body.style.overflow="hidden";},_unlockBody:function(){document.body.style.height=this.backups.body.height,document.body.style.overflow=this.backups.body.overflow,document.body.style.paddingRight=this.backups.body.paddingRight;}}};},function(module,exports,__webpack_require__){module.exports={render:function(){var _vm=this,_h=_vm.$createElement,_c=_vm._self._c||_h;return _c("div",{staticClass:"div"},[_c("div",{directives:[{name:"show",rawName:"v-show",value:_vm.isOpen,expression:"isOpen"}],staticClass:"modal-vue-wrapper",class:[_vm.animationParent,{"modal-vue-wrapper-show":_vm.open}]},[_c("div",{class:["modal-vue-overlay",{"modal-vue-actions-parent":_vm.imgMode}],style:{backgroundColor:_vm.bgOverlay},on:{click:function($event){_vm.$emit("hide");}}}),_vm._v(" "),_vm.imgMode?_c("div",{staticClass:"img-mode"},[_vm._t("default")],2):_vm._e(),_vm._v(" "),_vm.imgMode?_vm._e():_c("div",{class:["modal-vue-panel",_vm.animationPanel,{"modal-vue-show":_vm.open}],style:{width:_vm.width,backgroundColor:_vm.bgPanel}},[_c("div",{staticClass:"modal-vue-content"},[_vm.imgMode?_vm._e():_c("div",{class:{"modal-vue-actions":!_vm.imgMode}},[_c("div",{staticClass:"modal-vue-action-close",on:{click:function($event){_vm.$emit("hide");}}},[_c("svg",{attrs:{xmlns:"http://www.w3.org/2000/svg",width:"24",height:"24",viewBox:"0 0 24 24"}},[_c("path",{attrs:{d:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z",fill:"#292c34"}})])])]),_vm._v(" "),_c("div",{staticClass:"modal-vue-content-panel"},[_vm._t("default")],2)])])])])},staticRenderFns:[]},module.exports.render._withStripped=!0;}])});
	});

	var VueModalTor = unwrapExports(vueModaltor);

	/**!
	 * @fileOverview Kickass library to create and place poppers near their reference elements.
	 * @version 1.14.3
	 * @license
	 * Copyright (c) 2016 Federico Zivolo and contributors
	 *
	 * Permission is hereby granted, free of charge, to any person obtaining a copy
	 * of this software and associated documentation files (the "Software"), to deal
	 * in the Software without restriction, including without limitation the rights
	 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	 * copies of the Software, and to permit persons to whom the Software is
	 * furnished to do so, subject to the following conditions:
	 *
	 * The above copyright notice and this permission notice shall be included in all
	 * copies or substantial portions of the Software.
	 *
	 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
	 * SOFTWARE.
	 */
	var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';

	var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
	var timeoutDuration = 0;
	for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
	  if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
	    timeoutDuration = 1;
	    break;
	  }
	}

	function microtaskDebounce(fn) {
	  var called = false;
	  return function () {
	    if (called) {
	      return;
	    }
	    called = true;
	    window.Promise.resolve().then(function () {
	      called = false;
	      fn();
	    });
	  };
	}

	function taskDebounce(fn) {
	  var scheduled = false;
	  return function () {
	    if (!scheduled) {
	      scheduled = true;
	      setTimeout(function () {
	        scheduled = false;
	        fn();
	      }, timeoutDuration);
	    }
	  };
	}

	var supportsMicroTasks = isBrowser && window.Promise;

	/**
	* Create a debounced version of a method, that's asynchronously deferred
	* but called in the minimum time possible.
	*
	* @method
	* @memberof Popper.Utils
	* @argument {Function} fn
	* @returns {Function}
	*/
	var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;

	/**
	 * Check if the given variable is a function
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Any} functionToCheck - variable to check
	 * @returns {Boolean} answer to: is a function?
	 */
	function isFunction(functionToCheck) {
	  var getType = {};
	  return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
	}

	/**
	 * Get CSS computed property of the given element
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Eement} element
	 * @argument {String} property
	 */
	function getStyleComputedProperty(element, property) {
	  if (element.nodeType !== 1) {
	    return [];
	  }
	  // NOTE: 1 DOM access here
	  var css = getComputedStyle(element, null);
	  return property ? css[property] : css;
	}

	/**
	 * Returns the parentNode or the host of the element
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element
	 * @returns {Element} parent
	 */
	function getParentNode(element) {
	  if (element.nodeName === 'HTML') {
	    return element;
	  }
	  return element.parentNode || element.host;
	}

	/**
	 * Returns the scrolling parent of the given element
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element
	 * @returns {Element} scroll parent
	 */
	function getScrollParent(element) {
	  // Return body, `getScroll` will take care to get the correct `scrollTop` from it
	  if (!element) {
	    return document.body;
	  }

	  switch (element.nodeName) {
	    case 'HTML':
	    case 'BODY':
	      return element.ownerDocument.body;
	    case '#document':
	      return element.body;
	  }

	  // Firefox want us to check `-x` and `-y` variations as well

	  var _getStyleComputedProp = getStyleComputedProperty(element),
	      overflow = _getStyleComputedProp.overflow,
	      overflowX = _getStyleComputedProp.overflowX,
	      overflowY = _getStyleComputedProp.overflowY;

	  if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
	    return element;
	  }

	  return getScrollParent(getParentNode(element));
	}

	var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);
	var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);

	/**
	 * Determines if the browser is Internet Explorer
	 * @method
	 * @memberof Popper.Utils
	 * @param {Number} version to check
	 * @returns {Boolean} isIE
	 */
	function isIE(version) {
	  if (version === 11) {
	    return isIE11;
	  }
	  if (version === 10) {
	    return isIE10;
	  }
	  return isIE11 || isIE10;
	}

	/**
	 * Returns the offset parent of the given element
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element
	 * @returns {Element} offset parent
	 */
	function getOffsetParent(element) {
	  if (!element) {
	    return document.documentElement;
	  }

	  var noOffsetParent = isIE(10) ? document.body : null;

	  // NOTE: 1 DOM access here
	  var offsetParent = element.offsetParent;
	  // Skip hidden elements which don't have an offsetParent
	  while (offsetParent === noOffsetParent && element.nextElementSibling) {
	    offsetParent = (element = element.nextElementSibling).offsetParent;
	  }

	  var nodeName = offsetParent && offsetParent.nodeName;

	  if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
	    return element ? element.ownerDocument.documentElement : document.documentElement;
	  }

	  // .offsetParent will return the closest TD or TABLE in case
	  // no offsetParent is present, I hate this job...
	  if (['TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
	    return getOffsetParent(offsetParent);
	  }

	  return offsetParent;
	}

	function isOffsetContainer(element) {
	  var nodeName = element.nodeName;

	  if (nodeName === 'BODY') {
	    return false;
	  }
	  return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
	}

	/**
	 * Finds the root node (document, shadowDOM root) of the given element
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} node
	 * @returns {Element} root node
	 */
	function getRoot(node) {
	  if (node.parentNode !== null) {
	    return getRoot(node.parentNode);
	  }

	  return node;
	}

	/**
	 * Finds the offset parent common to the two provided nodes
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element1
	 * @argument {Element} element2
	 * @returns {Element} common offset parent
	 */
	function findCommonOffsetParent(element1, element2) {
	  // This check is needed to avoid errors in case one of the elements isn't defined for any reason
	  if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
	    return document.documentElement;
	  }

	  // Here we make sure to give as "start" the element that comes first in the DOM
	  var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
	  var start = order ? element1 : element2;
	  var end = order ? element2 : element1;

	  // Get common ancestor container
	  var range = document.createRange();
	  range.setStart(start, 0);
	  range.setEnd(end, 0);
	  var commonAncestorContainer = range.commonAncestorContainer;

	  // Both nodes are inside #document

	  if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
	    if (isOffsetContainer(commonAncestorContainer)) {
	      return commonAncestorContainer;
	    }

	    return getOffsetParent(commonAncestorContainer);
	  }

	  // one of the nodes is inside shadowDOM, find which one
	  var element1root = getRoot(element1);
	  if (element1root.host) {
	    return findCommonOffsetParent(element1root.host, element2);
	  } else {
	    return findCommonOffsetParent(element1, getRoot(element2).host);
	  }
	}

	/**
	 * Gets the scroll value of the given element in the given side (top and left)
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element
	 * @argument {String} side `top` or `left`
	 * @returns {number} amount of scrolled pixels
	 */
	function getScroll(element) {
	  var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';

	  var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
	  var nodeName = element.nodeName;

	  if (nodeName === 'BODY' || nodeName === 'HTML') {
	    var html = element.ownerDocument.documentElement;
	    var scrollingElement = element.ownerDocument.scrollingElement || html;
	    return scrollingElement[upperSide];
	  }

	  return element[upperSide];
	}

	/*
	 * Sum or subtract the element scroll values (left and top) from a given rect object
	 * @method
	 * @memberof Popper.Utils
	 * @param {Object} rect - Rect object you want to change
	 * @param {HTMLElement} element - The element from the function reads the scroll values
	 * @param {Boolean} subtract - set to true if you want to subtract the scroll values
	 * @return {Object} rect - The modifier rect object
	 */
	function includeScroll(rect, element) {
	  var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

	  var scrollTop = getScroll(element, 'top');
	  var scrollLeft = getScroll(element, 'left');
	  var modifier = subtract ? -1 : 1;
	  rect.top += scrollTop * modifier;
	  rect.bottom += scrollTop * modifier;
	  rect.left += scrollLeft * modifier;
	  rect.right += scrollLeft * modifier;
	  return rect;
	}

	/*
	 * Helper to detect borders of a given element
	 * @method
	 * @memberof Popper.Utils
	 * @param {CSSStyleDeclaration} styles
	 * Result of `getStyleComputedProperty` on the given element
	 * @param {String} axis - `x` or `y`
	 * @return {number} borders - The borders size of the given axis
	 */

	function getBordersSize(styles, axis) {
	  var sideA = axis === 'x' ? 'Left' : 'Top';
	  var sideB = sideA === 'Left' ? 'Right' : 'Bottom';

	  return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);
	}

	function getSize(axis, body, html, computedStyle) {
	  return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? html['offset' + axis] + computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')] + computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')] : 0);
	}

	function getWindowSizes() {
	  var body = document.body;
	  var html = document.documentElement;
	  var computedStyle = isIE(10) && getComputedStyle(html);

	  return {
	    height: getSize('Height', body, html, computedStyle),
	    width: getSize('Width', body, html, computedStyle)
	  };
	}

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

	var createClass = 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);
	    }
	  }

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





	var defineProperty = function (obj, key, value) {
	  if (key in obj) {
	    Object.defineProperty(obj, key, {
	      value: value,
	      enumerable: true,
	      configurable: true,
	      writable: true
	    });
	  } else {
	    obj[key] = value;
	  }

	  return obj;
	};

	var _extends = Object.assign || function (target) {
	  for (var i = 1; i < arguments.length; i++) {
	    var source = arguments[i];

	    for (var key in source) {
	      if (Object.prototype.hasOwnProperty.call(source, key)) {
	        target[key] = source[key];
	      }
	    }
	  }

	  return target;
	};

	/**
	 * Given element offsets, generate an output similar to getBoundingClientRect
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Object} offsets
	 * @returns {Object} ClientRect like output
	 */
	function getClientRect(offsets) {
	  return _extends({}, offsets, {
	    right: offsets.left + offsets.width,
	    bottom: offsets.top + offsets.height
	  });
	}

	/**
	 * Get bounding client rect of given element
	 * @method
	 * @memberof Popper.Utils
	 * @param {HTMLElement} element
	 * @return {Object} client rect
	 */
	function getBoundingClientRect(element) {
	  var rect = {};

	  // IE10 10 FIX: Please, don't ask, the element isn't
	  // considered in DOM in some circumstances...
	  // This isn't reproducible in IE10 compatibility mode of IE11
	  try {
	    if (isIE(10)) {
	      rect = element.getBoundingClientRect();
	      var scrollTop = getScroll(element, 'top');
	      var scrollLeft = getScroll(element, 'left');
	      rect.top += scrollTop;
	      rect.left += scrollLeft;
	      rect.bottom += scrollTop;
	      rect.right += scrollLeft;
	    } else {
	      rect = element.getBoundingClientRect();
	    }
	  } catch (e) {}

	  var result = {
	    left: rect.left,
	    top: rect.top,
	    width: rect.right - rect.left,
	    height: rect.bottom - rect.top
	  };

	  // subtract scrollbar size from sizes
	  var sizes = element.nodeName === 'HTML' ? getWindowSizes() : {};
	  var width = sizes.width || element.clientWidth || result.right - result.left;
	  var height = sizes.height || element.clientHeight || result.bottom - result.top;

	  var horizScrollbar = element.offsetWidth - width;
	  var vertScrollbar = element.offsetHeight - height;

	  // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
	  // we make this check conditional for performance reasons
	  if (horizScrollbar || vertScrollbar) {
	    var styles = getStyleComputedProperty(element);
	    horizScrollbar -= getBordersSize(styles, 'x');
	    vertScrollbar -= getBordersSize(styles, 'y');

	    result.width -= horizScrollbar;
	    result.height -= vertScrollbar;
	  }

	  return getClientRect(result);
	}

	function getOffsetRectRelativeToArbitraryNode(children, parent) {
	  var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

	  var isIE10 = isIE(10);
	  var isHTML = parent.nodeName === 'HTML';
	  var childrenRect = getBoundingClientRect(children);
	  var parentRect = getBoundingClientRect(parent);
	  var scrollParent = getScrollParent(children);

	  var styles = getStyleComputedProperty(parent);
	  var borderTopWidth = parseFloat(styles.borderTopWidth, 10);
	  var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);

	  // In cases where the parent is fixed, we must ignore negative scroll in offset calc
	  if (fixedPosition && parent.nodeName === 'HTML') {
	    parentRect.top = Math.max(parentRect.top, 0);
	    parentRect.left = Math.max(parentRect.left, 0);
	  }
	  var offsets = getClientRect({
	    top: childrenRect.top - parentRect.top - borderTopWidth,
	    left: childrenRect.left - parentRect.left - borderLeftWidth,
	    width: childrenRect.width,
	    height: childrenRect.height
	  });
	  offsets.marginTop = 0;
	  offsets.marginLeft = 0;

	  // Subtract margins of documentElement in case it's being used as parent
	  // we do this only on HTML because it's the only element that behaves
	  // differently when margins are applied to it. The margins are included in
	  // the box of the documentElement, in the other cases not.
	  if (!isIE10 && isHTML) {
	    var marginTop = parseFloat(styles.marginTop, 10);
	    var marginLeft = parseFloat(styles.marginLeft, 10);

	    offsets.top -= borderTopWidth - marginTop;
	    offsets.bottom -= borderTopWidth - marginTop;
	    offsets.left -= borderLeftWidth - marginLeft;
	    offsets.right -= borderLeftWidth - marginLeft;

	    // Attach marginTop and marginLeft because in some circumstances we may need them
	    offsets.marginTop = marginTop;
	    offsets.marginLeft = marginLeft;
	  }

	  if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
	    offsets = includeScroll(offsets, parent);
	  }

	  return offsets;
	}

	function getViewportOffsetRectRelativeToArtbitraryNode(element) {
	  var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

	  var html = element.ownerDocument.documentElement;
	  var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
	  var width = Math.max(html.clientWidth, window.innerWidth || 0);
	  var height = Math.max(html.clientHeight, window.innerHeight || 0);

	  var scrollTop = !excludeScroll ? getScroll(html) : 0;
	  var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;

	  var offset = {
	    top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
	    left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
	    width: width,
	    height: height
	  };

	  return getClientRect(offset);
	}

	/**
	 * Check if the given element is fixed or is inside a fixed parent
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element
	 * @argument {Element} customContainer
	 * @returns {Boolean} answer to "isFixed?"
	 */
	function isFixed(element) {
	  var nodeName = element.nodeName;
	  if (nodeName === 'BODY' || nodeName === 'HTML') {
	    return false;
	  }
	  if (getStyleComputedProperty(element, 'position') === 'fixed') {
	    return true;
	  }
	  return isFixed(getParentNode(element));
	}

	/**
	 * Finds the first parent of an element that has a transformed property defined
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element
	 * @returns {Element} first transformed parent or documentElement
	 */

	function getFixedPositionOffsetParent(element) {
	  // This check is needed to avoid errors in case one of the elements isn't defined for any reason
	  if (!element || !element.parentElement || isIE()) {
	    return document.documentElement;
	  }
	  var el = element.parentElement;
	  while (el && getStyleComputedProperty(el, 'transform') === 'none') {
	    el = el.parentElement;
	  }
	  return el || document.documentElement;
	}

	/**
	 * Computed the boundaries limits and return them
	 * @method
	 * @memberof Popper.Utils
	 * @param {HTMLElement} popper
	 * @param {HTMLElement} reference
	 * @param {number} padding
	 * @param {HTMLElement} boundariesElement - Element used to define the boundaries
	 * @param {Boolean} fixedPosition - Is in fixed position mode
	 * @returns {Object} Coordinates of the boundaries
	 */
	function getBoundaries(popper, reference, padding, boundariesElement) {
	  var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;

	  // NOTE: 1 DOM access here

	  var boundaries = { top: 0, left: 0 };
	  var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);

	  // Handle viewport case
	  if (boundariesElement === 'viewport') {
	    boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);
	  } else {
	    // Handle other cases based on DOM element used as boundaries
	    var boundariesNode = void 0;
	    if (boundariesElement === 'scrollParent') {
	      boundariesNode = getScrollParent(getParentNode(reference));
	      if (boundariesNode.nodeName === 'BODY') {
	        boundariesNode = popper.ownerDocument.documentElement;
	      }
	    } else if (boundariesElement === 'window') {
	      boundariesNode = popper.ownerDocument.documentElement;
	    } else {
	      boundariesNode = boundariesElement;
	    }

	    var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);

	    // In case of HTML, we need a different computation
	    if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
	      var _getWindowSizes = getWindowSizes(),
	          height = _getWindowSizes.height,
	          width = _getWindowSizes.width;

	      boundaries.top += offsets.top - offsets.marginTop;
	      boundaries.bottom = height + offsets.top;
	      boundaries.left += offsets.left - offsets.marginLeft;
	      boundaries.right = width + offsets.left;
	    } else {
	      // for all the other DOM elements, this one is good
	      boundaries = offsets;
	    }
	  }

	  // Add paddings
	  boundaries.left += padding;
	  boundaries.top += padding;
	  boundaries.right -= padding;
	  boundaries.bottom -= padding;

	  return boundaries;
	}

	function getArea(_ref) {
	  var width = _ref.width,
	      height = _ref.height;

	  return width * height;
	}

	/**
	 * Utility used to transform the `auto` placement to the placement with more
	 * available space.
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Object} data - The data object generated by update method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
	  var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;

	  if (placement.indexOf('auto') === -1) {
	    return placement;
	  }

	  var boundaries = getBoundaries(popper, reference, padding, boundariesElement);

	  var rects = {
	    top: {
	      width: boundaries.width,
	      height: refRect.top - boundaries.top
	    },
	    right: {
	      width: boundaries.right - refRect.right,
	      height: boundaries.height
	    },
	    bottom: {
	      width: boundaries.width,
	      height: boundaries.bottom - refRect.bottom
	    },
	    left: {
	      width: refRect.left - boundaries.left,
	      height: boundaries.height
	    }
	  };

	  var sortedAreas = Object.keys(rects).map(function (key) {
	    return _extends({
	      key: key
	    }, rects[key], {
	      area: getArea(rects[key])
	    });
	  }).sort(function (a, b) {
	    return b.area - a.area;
	  });

	  var filteredAreas = sortedAreas.filter(function (_ref2) {
	    var width = _ref2.width,
	        height = _ref2.height;
	    return width >= popper.clientWidth && height >= popper.clientHeight;
	  });

	  var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;

	  var variation = placement.split('-')[1];

	  return computedPlacement + (variation ? '-' + variation : '');
	}

	/**
	 * Get offsets to the reference element
	 * @method
	 * @memberof Popper.Utils
	 * @param {Object} state
	 * @param {Element} popper - the popper element
	 * @param {Element} reference - the reference element (the popper will be relative to this)
	 * @param {Element} fixedPosition - is in fixed position mode
	 * @returns {Object} An object containing the offsets which will be applied to the popper
	 */
	function getReferenceOffsets(state, popper, reference) {
	  var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;

	  var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);
	  return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);
	}

	/**
	 * Get the outer sizes of the given element (offset size + margins)
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element
	 * @returns {Object} object containing width and height properties
	 */
	function getOuterSizes(element) {
	  var styles = getComputedStyle(element);
	  var x = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
	  var y = parseFloat(styles.marginLeft) + parseFloat(styles.marginRight);
	  var result = {
	    width: element.offsetWidth + y,
	    height: element.offsetHeight + x
	  };
	  return result;
	}

	/**
	 * Get the opposite placement of the given one
	 * @method
	 * @memberof Popper.Utils
	 * @argument {String} placement
	 * @returns {String} flipped placement
	 */
	function getOppositePlacement(placement) {
	  var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
	  return placement.replace(/left|right|bottom|top/g, function (matched) {
	    return hash[matched];
	  });
	}

	/**
	 * Get offsets to the popper
	 * @method
	 * @memberof Popper.Utils
	 * @param {Object} position - CSS position the Popper will get applied
	 * @param {HTMLElement} popper - the popper element
	 * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
	 * @param {String} placement - one of the valid placement options
	 * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
	 */
	function getPopperOffsets(popper, referenceOffsets, placement) {
	  placement = placement.split('-')[0];

	  // Get popper node sizes
	  var popperRect = getOuterSizes(popper);

	  // Add position, width and height to our offsets object
	  var popperOffsets = {
	    width: popperRect.width,
	    height: popperRect.height
	  };

	  // depending by the popper placement we have to compute its offsets slightly differently
	  var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
	  var mainSide = isHoriz ? 'top' : 'left';
	  var secondarySide = isHoriz ? 'left' : 'top';
	  var measurement = isHoriz ? 'height' : 'width';
	  var secondaryMeasurement = !isHoriz ? 'height' : 'width';

	  popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
	  if (placement === secondarySide) {
	    popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
	  } else {
	    popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
	  }

	  return popperOffsets;
	}

	/**
	 * Mimics the `find` method of Array
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Array} arr
	 * @argument prop
	 * @argument value
	 * @returns index or -1
	 */
	function find(arr, check) {
	  // use native find if supported
	  if (Array.prototype.find) {
	    return arr.find(check);
	  }

	  // use `filter` to obtain the same behavior of `find`
	  return arr.filter(check)[0];
	}

	/**
	 * Return the index of the matching object
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Array} arr
	 * @argument prop
	 * @argument value
	 * @returns index or -1
	 */
	function findIndex(arr, prop, value) {
	  // use native findIndex if supported
	  if (Array.prototype.findIndex) {
	    return arr.findIndex(function (cur) {
	      return cur[prop] === value;
	    });
	  }

	  // use `find` + `indexOf` if `findIndex` isn't supported
	  var match = find(arr, function (obj) {
	    return obj[prop] === value;
	  });
	  return arr.indexOf(match);
	}

	/**
	 * Loop trough the list of modifiers and run them in order,
	 * each of them will then edit the data object.
	 * @method
	 * @memberof Popper.Utils
	 * @param {dataObject} data
	 * @param {Array} modifiers
	 * @param {String} ends - Optional modifier name used as stopper
	 * @returns {dataObject}
	 */
	function runModifiers(modifiers, data, ends) {
	  var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));

	  modifiersToRun.forEach(function (modifier) {
	    if (modifier['function']) {
	      // eslint-disable-line dot-notation
	      console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
	    }
	    var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
	    if (modifier.enabled && isFunction(fn)) {
	      // Add properties to offsets to make them a complete clientRect object
	      // we do this before each modifier to make sure the previous one doesn't
	      // mess with these values
	      data.offsets.popper = getClientRect(data.offsets.popper);
	      data.offsets.reference = getClientRect(data.offsets.reference);

	      data = fn(data, modifier);
	    }
	  });

	  return data;
	}

	/**
	 * Updates the position of the popper, computing the new offsets and applying
	 * the new style.<br />
	 * Prefer `scheduleUpdate` over `update` because of performance reasons.
	 * @method
	 * @memberof Popper
	 */
	function update() {
	  // if popper is destroyed, don't perform any further update
	  if (this.state.isDestroyed) {
	    return;
	  }

	  var data = {
	    instance: this,
	    styles: {},
	    arrowStyles: {},
	    attributes: {},
	    flipped: false,
	    offsets: {}
	  };

	  // compute reference element offsets
	  data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);

	  // compute auto placement, store placement inside the data object,
	  // modifiers will be able to edit `placement` if needed
	  // and refer to originalPlacement to know the original value
	  data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);

	  // store the computed placement inside `originalPlacement`
	  data.originalPlacement = data.placement;

	  data.positionFixed = this.options.positionFixed;

	  // compute the popper offsets
	  data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);

	  data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';

	  // run the modifiers
	  data = runModifiers(this.modifiers, data);

	  // the first `update` will call `onCreate` callback
	  // the other ones will call `onUpdate` callback
	  if (!this.state.isCreated) {
	    this.state.isCreated = true;
	    this.options.onCreate(data);
	  } else {
	    this.options.onUpdate(data);
	  }
	}

	/**
	 * Helper used to know if the given modifier is enabled.
	 * @method
	 * @memberof Popper.Utils
	 * @returns {Boolean}
	 */
	function isModifierEnabled(modifiers, modifierName) {
	  return modifiers.some(function (_ref) {
	    var name = _ref.name,
	        enabled = _ref.enabled;
	    return enabled && name === modifierName;
	  });
	}

	/**
	 * Get the prefixed supported property name
	 * @method
	 * @memberof Popper.Utils
	 * @argument {String} property (camelCase)
	 * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
	 */
	function getSupportedPropertyName(property) {
	  var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
	  var upperProp = property.charAt(0).toUpperCase() + property.slice(1);

	  for (var i = 0; i < prefixes.length; i++) {
	    var prefix = prefixes[i];
	    var toCheck = prefix ? '' + prefix + upperProp : property;
	    if (typeof document.body.style[toCheck] !== 'undefined') {
	      return toCheck;
	    }
	  }
	  return null;
	}

	/**
	 * Destroy the popper
	 * @method
	 * @memberof Popper
	 */
	function destroy() {
	  this.state.isDestroyed = true;

	  // touch DOM only if `applyStyle` modifier is enabled
	  if (isModifierEnabled(this.modifiers, 'applyStyle')) {
	    this.popper.removeAttribute('x-placement');
	    this.popper.style.position = '';
	    this.popper.style.top = '';
	    this.popper.style.left = '';
	    this.popper.style.right = '';
	    this.popper.style.bottom = '';
	    this.popper.style.willChange = '';
	    this.popper.style[getSupportedPropertyName('transform')] = '';
	  }

	  this.disableEventListeners();

	  // remove the popper if user explicity asked for the deletion on destroy
	  // do not use `remove` because IE11 doesn't support it
	  if (this.options.removeOnDestroy) {
	    this.popper.parentNode.removeChild(this.popper);
	  }
	  return this;
	}

	/**
	 * Get the window associated with the element
	 * @argument {Element} element
	 * @returns {Window}
	 */
	function getWindow(element) {
	  var ownerDocument = element.ownerDocument;
	  return ownerDocument ? ownerDocument.defaultView : window;
	}

	function attachToScrollParents(scrollParent, event, callback, scrollParents) {
	  var isBody = scrollParent.nodeName === 'BODY';
	  var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
	  target.addEventListener(event, callback, { passive: true });

	  if (!isBody) {
	    attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
	  }
	  scrollParents.push(target);
	}

	/**
	 * Setup needed event listeners used to update the popper position
	 * @method
	 * @memberof Popper.Utils
	 * @private
	 */
	function setupEventListeners(reference, options, state, updateBound) {
	  // Resize event listener on window
	  state.updateBound = updateBound;
	  getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });

	  // Scroll event listener on scroll parents
	  var scrollElement = getScrollParent(reference);
	  attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
	  state.scrollElement = scrollElement;
	  state.eventsEnabled = true;

	  return state;
	}

	/**
	 * It will add resize/scroll events and start recalculating
	 * position of the popper element when they are triggered.
	 * @method
	 * @memberof Popper
	 */
	function enableEventListeners() {
	  if (!this.state.eventsEnabled) {
	    this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
	  }
	}

	/**
	 * Remove event listeners used to update the popper position
	 * @method
	 * @memberof Popper.Utils
	 * @private
	 */
	function removeEventListeners(reference, state) {
	  // Remove resize event listener on window
	  getWindow(reference).removeEventListener('resize', state.updateBound);

	  // Remove scroll event listener on scroll parents
	  state.scrollParents.forEach(function (target) {
	    target.removeEventListener('scroll', state.updateBound);
	  });

	  // Reset state
	  state.updateBound = null;
	  state.scrollParents = [];
	  state.scrollElement = null;
	  state.eventsEnabled = false;
	  return state;
	}

	/**
	 * It will remove resize/scroll events and won't recalculate popper position
	 * when they are triggered. It also won't trigger onUpdate callback anymore,
	 * unless you call `update` method manually.
	 * @method
	 * @memberof Popper
	 */
	function disableEventListeners() {
	  if (this.state.eventsEnabled) {
	    cancelAnimationFrame(this.scheduleUpdate);
	    this.state = removeEventListeners(this.reference, this.state);
	  }
	}

	/**
	 * Tells if a given input is a number
	 * @method
	 * @memberof Popper.Utils
	 * @param {*} input to check
	 * @return {Boolean}
	 */
	function isNumeric(n) {
	  return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
	}

	/**
	 * Set the style to the given popper
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element - Element to apply the style to
	 * @argument {Object} styles
	 * Object with a list of properties and values which will be applied to the element
	 */
	function setStyles(element, styles) {
	  Object.keys(styles).forEach(function (prop) {
	    var unit = '';
	    // add unit if the value is numeric and is one of the following
	    if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
	      unit = 'px';
	    }
	    element.style[prop] = styles[prop] + unit;
	  });
	}

	/**
	 * Set the attributes to the given popper
	 * @method
	 * @memberof Popper.Utils
	 * @argument {Element} element - Element to apply the attributes to
	 * @argument {Object} styles
	 * Object with a list of properties and values which will be applied to the element
	 */
	function setAttributes(element, attributes) {
	  Object.keys(attributes).forEach(function (prop) {
	    var value = attributes[prop];
	    if (value !== false) {
	      element.setAttribute(prop, attributes[prop]);
	    } else {
	      element.removeAttribute(prop);
	    }
	  });
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by `update` method
	 * @argument {Object} data.styles - List of style properties - values to apply to popper element
	 * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The same data object
	 */
	function applyStyle(data) {
	  // any property present in `data.styles` will be applied to the popper,
	  // in this way we can make the 3rd party modifiers add custom styles to it
	  // Be aware, modifiers could override the properties defined in the previous
	  // lines of this modifier!
	  setStyles(data.instance.popper, data.styles);

	  // any property present in `data.attributes` will be applied to the popper,
	  // they will be set as HTML attributes of the element
	  setAttributes(data.instance.popper, data.attributes);

	  // if arrowElement is defined and arrowStyles has some properties
	  if (data.arrowElement && Object.keys(data.arrowStyles).length) {
	    setStyles(data.arrowElement, data.arrowStyles);
	  }

	  return data;
	}

	/**
	 * Set the x-placement attribute before everything else because it could be used
	 * to add margins to the popper margins needs to be calculated to get the
	 * correct popper offsets.
	 * @method
	 * @memberof Popper.modifiers
	 * @param {HTMLElement} reference - The reference element used to position the popper
	 * @param {HTMLElement} popper - The HTML element used as popper
	 * @param {Object} options - Popper.js options
	 */
	function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
	  // compute reference element offsets
	  var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);

	  // compute auto placement, store placement inside the data object,
	  // modifiers will be able to edit `placement` if needed
	  // and refer to originalPlacement to know the original value
	  var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);

	  popper.setAttribute('x-placement', placement);

	  // Apply `position` to popper before anything else because
	  // without the position applied we can't guarantee correct computations
	  setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });

	  return options;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by `update` method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function computeStyle(data, options) {
	  var x = options.x,
	      y = options.y;
	  var popper = data.offsets.popper;

	  // Remove this legacy support in Popper.js v2

	  var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
	    return modifier.name === 'applyStyle';
	  }).gpuAcceleration;
	  if (legacyGpuAccelerationOption !== undefined) {
	    console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');
	  }
	  var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;

	  var offsetParent = getOffsetParent(data.instance.popper);
	  var offsetParentRect = getBoundingClientRect(offsetParent);

	  // Styles
	  var styles = {
	    position: popper.position
	  };

	  // Avoid blurry text by using full pixel integers.
	  // For pixel-perfect positioning, top/bottom prefers rounded
	  // values, while left/right prefers floored values.
	  var offsets = {
	    left: Math.floor(popper.left),
	    top: Math.round(popper.top),
	    bottom: Math.round(popper.bottom),
	    right: Math.floor(popper.right)
	  };

	  var sideA = x === 'bottom' ? 'top' : 'bottom';
	  var sideB = y === 'right' ? 'left' : 'right';

	  // if gpuAcceleration is set to `true` and transform is supported,
	  //  we use `translate3d` to apply the position to the popper we
	  // automatically use the supported prefixed version if needed
	  var prefixedProperty = getSupportedPropertyName('transform');

	  // now, let's make a step back and look at this code closely (wtf?)
	  // If the content of the popper grows once it's been positioned, it
	  // may happen that the popper gets misplaced because of the new content
	  // overflowing its reference element
	  // To avoid this problem, we provide two options (x and y), which allow
	  // the consumer to define the offset origin.
	  // If we position a popper on top of a reference element, we can set
	  // `x` to `top` to make the popper grow towards its top instead of
	  // its bottom.
	  var left = void 0,
	      top = void 0;
	  if (sideA === 'bottom') {
	    top = -offsetParentRect.height + offsets.bottom;
	  } else {
	    top = offsets.top;
	  }
	  if (sideB === 'right') {
	    left = -offsetParentRect.width + offsets.right;
	  } else {
	    left = offsets.left;
	  }
	  if (gpuAcceleration && prefixedProperty) {
	    styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
	    styles[sideA] = 0;
	    styles[sideB] = 0;
	    styles.willChange = 'transform';
	  } else {
	    // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties
	    var invertTop = sideA === 'bottom' ? -1 : 1;
	    var invertLeft = sideB === 'right' ? -1 : 1;
	    styles[sideA] = top * invertTop;
	    styles[sideB] = left * invertLeft;
	    styles.willChange = sideA + ', ' + sideB;
	  }

	  // Attributes
	  var attributes = {
	    'x-placement': data.placement
	  };

	  // Update `data` attributes, styles and arrowStyles
	  data.attributes = _extends({}, attributes, data.attributes);
	  data.styles = _extends({}, styles, data.styles);
	  data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);

	  return data;
	}

	/**
	 * Helper used to know if the given modifier depends from another one.<br />
	 * It checks if the needed modifier is listed and enabled.
	 * @method
	 * @memberof Popper.Utils
	 * @param {Array} modifiers - list of modifiers
	 * @param {String} requestingName - name of requesting modifier
	 * @param {String} requestedName - name of requested modifier
	 * @returns {Boolean}
	 */
	function isModifierRequired(modifiers, requestingName, requestedName) {
	  var requesting = find(modifiers, function (_ref) {
	    var name = _ref.name;
	    return name === requestingName;
	  });

	  var isRequired = !!requesting && modifiers.some(function (modifier) {
	    return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
	  });

	  if (!isRequired) {
	    var _requesting = '`' + requestingName + '`';
	    var requested = '`' + requestedName + '`';
	    console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
	  }
	  return isRequired;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by update method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function arrow(data, options) {
	  var _data$offsets$arrow;

	  // arrow depends on keepTogether in order to work
	  if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
	    return data;
	  }

	  var arrowElement = options.element;

	  // if arrowElement is a string, suppose it's a CSS selector
	  if (typeof arrowElement === 'string') {
	    arrowElement = data.instance.popper.querySelector(arrowElement);

	    // if arrowElement is not found, don't run the modifier
	    if (!arrowElement) {
	      return data;
	    }
	  } else {
	    // if the arrowElement isn't a query selector we must check that the
	    // provided DOM node is child of its popper node
	    if (!data.instance.popper.contains(arrowElement)) {
	      console.warn('WARNING: `arrow.element` must be child of its popper element!');
	      return data;
	    }
	  }

	  var placement = data.placement.split('-')[0];
	  var _data$offsets = data.offsets,
	      popper = _data$offsets.popper,
	      reference = _data$offsets.reference;

	  var isVertical = ['left', 'right'].indexOf(placement) !== -1;

	  var len = isVertical ? 'height' : 'width';
	  var sideCapitalized = isVertical ? 'Top' : 'Left';
	  var side = sideCapitalized.toLowerCase();
	  var altSide = isVertical ? 'left' : 'top';
	  var opSide = isVertical ? 'bottom' : 'right';
	  var arrowElementSize = getOuterSizes(arrowElement)[len];

	  //
	  // extends keepTogether behavior making sure the popper and its
	  // reference have enough pixels in conjuction
	  //

	  // top/left side
	  if (reference[opSide] - arrowElementSize < popper[side]) {
	    data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
	  }
	  // bottom/right side
	  if (reference[side] + arrowElementSize > popper[opSide]) {
	    data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
	  }
	  data.offsets.popper = getClientRect(data.offsets.popper);

	  // compute center of the popper
	  var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;

	  // Compute the sideValue using the updated popper offsets
	  // take popper margin in account because we don't have this info available
	  var css = getStyleComputedProperty(data.instance.popper);
	  var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);
	  var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);
	  var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;

	  // prevent arrowElement from being placed not contiguously to its popper
	  sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);

	  data.arrowElement = arrowElement;
	  data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);

	  return data;
	}

	/**
	 * Get the opposite placement variation of the given one
	 * @method
	 * @memberof Popper.Utils
	 * @argument {String} placement variation
	 * @returns {String} flipped placement variation
	 */
	function getOppositeVariation(variation) {
	  if (variation === 'end') {
	    return 'start';
	  } else if (variation === 'start') {
	    return 'end';
	  }
	  return variation;
	}

	/**
	 * List of accepted placements to use as values of the `placement` option.<br />
	 * Valid placements are:
	 * - `auto`
	 * - `top`
	 * - `right`
	 * - `bottom`
	 * - `left`
	 *
	 * Each placement can have a variation from this list:
	 * - `-start`
	 * - `-end`
	 *
	 * Variations are interpreted easily if you think of them as the left to right
	 * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
	 * is right.<br />
	 * Vertically (`left` and `right`), `start` is top and `end` is bottom.
	 *
	 * Some valid examples are:
	 * - `top-end` (on top of reference, right aligned)
	 * - `right-start` (on right of reference, top aligned)
	 * - `bottom` (on bottom, centered)
	 * - `auto-right` (on the side with more space available, alignment depends by placement)
	 *
	 * @static
	 * @type {Array}
	 * @enum {String}
	 * @readonly
	 * @method placements
	 * @memberof Popper
	 */
	var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];

	// Get rid of `auto` `auto-start` and `auto-end`
	var validPlacements = placements.slice(3);

	/**
	 * Given an initial placement, returns all the subsequent placements
	 * clockwise (or counter-clockwise).
	 *
	 * @method
	 * @memberof Popper.Utils
	 * @argument {String} placement - A valid placement (it accepts variations)
	 * @argument {Boolean} counter - Set to true to walk the placements counterclockwise
	 * @returns {Array} placements including their variations
	 */
	function clockwise(placement) {
	  var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

	  var index = validPlacements.indexOf(placement);
	  var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));
	  return counter ? arr.reverse() : arr;
	}

	var BEHAVIORS = {
	  FLIP: 'flip',
	  CLOCKWISE: 'clockwise',
	  COUNTERCLOCKWISE: 'counterclockwise'
	};

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by update method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function flip(data, options) {
	  // if `inner` modifier is enabled, we can't use the `flip` modifier
	  if (isModifierEnabled(data.instance.modifiers, 'inner')) {
	    return data;
	  }

	  if (data.flipped && data.placement === data.originalPlacement) {
	    // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
	    return data;
	  }

	  var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);

	  var placement = data.placement.split('-')[0];
	  var placementOpposite = getOppositePlacement(placement);
	  var variation = data.placement.split('-')[1] || '';

	  var flipOrder = [];

	  switch (options.behavior) {
	    case BEHAVIORS.FLIP:
	      flipOrder = [placement, placementOpposite];
	      break;
	    case BEHAVIORS.CLOCKWISE:
	      flipOrder = clockwise(placement);
	      break;
	    case BEHAVIORS.COUNTERCLOCKWISE:
	      flipOrder = clockwise(placement, true);
	      break;
	    default:
	      flipOrder = options.behavior;
	  }

	  flipOrder.forEach(function (step, index) {
	    if (placement !== step || flipOrder.length === index + 1) {
	      return data;
	    }

	    placement = data.placement.split('-')[0];
	    placementOpposite = getOppositePlacement(placement);

	    var popperOffsets = data.offsets.popper;
	    var refOffsets = data.offsets.reference;

	    // using floor because the reference offsets may contain decimals we are not going to consider here
	    var floor = Math.floor;
	    var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);

	    var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
	    var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
	    var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
	    var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);

	    var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;

	    // flip the variation if required
	    var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
	    var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);

	    if (overlapsRef || overflowsBoundaries || flippedVariation) {
	      // this boolean to detect any flip loop
	      data.flipped = true;

	      if (overlapsRef || overflowsBoundaries) {
	        placement = flipOrder[index + 1];
	      }

	      if (flippedVariation) {
	        variation = getOppositeVariation(variation);
	      }

	      data.placement = placement + (variation ? '-' + variation : '');

	      // this object contains `position`, we want to preserve it along with
	      // any additional property we may add in the future
	      data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));

	      data = runModifiers(data.instance.modifiers, data, 'flip');
	    }
	  });
	  return data;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by update method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function keepTogether(data) {
	  var _data$offsets = data.offsets,
	      popper = _data$offsets.popper,
	      reference = _data$offsets.reference;

	  var placement = data.placement.split('-')[0];
	  var floor = Math.floor;
	  var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
	  var side = isVertical ? 'right' : 'bottom';
	  var opSide = isVertical ? 'left' : 'top';
	  var measurement = isVertical ? 'width' : 'height';

	  if (popper[side] < floor(reference[opSide])) {
	    data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
	  }
	  if (popper[opSide] > floor(reference[side])) {
	    data.offsets.popper[opSide] = floor(reference[side]);
	  }

	  return data;
	}

	/**
	 * Converts a string containing value + unit into a px value number
	 * @function
	 * @memberof {modifiers~offset}
	 * @private
	 * @argument {String} str - Value + unit string
	 * @argument {String} measurement - `height` or `width`
	 * @argument {Object} popperOffsets
	 * @argument {Object} referenceOffsets
	 * @returns {Number|String}
	 * Value in pixels, or original string if no values were extracted
	 */
	function toValue(str, measurement, popperOffsets, referenceOffsets) {
	  // separate value from unit
	  var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);
	  var value = +split[1];
	  var unit = split[2];

	  // If it's not a number it's an operator, I guess
	  if (!value) {
	    return str;
	  }

	  if (unit.indexOf('%') === 0) {
	    var element = void 0;
	    switch (unit) {
	      case '%p':
	        element = popperOffsets;
	        break;
	      case '%':
	      case '%r':
	      default:
	        element = referenceOffsets;
	    }

	    var rect = getClientRect(element);
	    return rect[measurement] / 100 * value;
	  } else if (unit === 'vh' || unit === 'vw') {
	    // if is a vh or vw, we calculate the size based on the viewport
	    var size = void 0;
	    if (unit === 'vh') {
	      size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
	    } else {
	      size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
	    }
	    return size / 100 * value;
	  } else {
	    // if is an explicit pixel unit, we get rid of the unit and keep the value
	    // if is an implicit unit, it's px, and we return just the value
	    return value;
	  }
	}

	/**
	 * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
	 * @function
	 * @memberof {modifiers~offset}
	 * @private
	 * @argument {String} offset
	 * @argument {Object} popperOffsets
	 * @argument {Object} referenceOffsets
	 * @argument {String} basePlacement
	 * @returns {Array} a two cells array with x and y offsets in numbers
	 */
	function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
	  var offsets = [0, 0];

	  // Use height if placement is left or right and index is 0 otherwise use width
	  // in this way the first offset will use an axis and the second one
	  // will use the other one
	  var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;

	  // Split the offset string to obtain a list of values and operands
	  // The regex addresses values with the plus or minus sign in front (+10, -20, etc)
	  var fragments = offset.split(/(\+|\-)/).map(function (frag) {
	    return frag.trim();
	  });

	  // Detect if the offset string contains a pair of values or a single one
	  // they could be separated by comma or space
	  var divider = fragments.indexOf(find(fragments, function (frag) {
	    return frag.search(/,|\s/) !== -1;
	  }));

	  if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
	    console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
	  }

	  // If divider is found, we divide the list of values and operands to divide
	  // them by ofset X and Y.
	  var splitRegex = /\s*,\s*|\s+/;
	  var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];

	  // Convert the values with units to absolute pixels to allow our computations
	  ops = ops.map(function (op, index) {
	    // Most of the units rely on the orientation of the popper
	    var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
	    var mergeWithPrevious = false;
	    return op
	    // This aggregates any `+` or `-` sign that aren't considered operators
	    // e.g.: 10 + +5 => [10, +, +5]
	    .reduce(function (a, b) {
	      if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
	        a[a.length - 1] = b;
	        mergeWithPrevious = true;
	        return a;
	      } else if (mergeWithPrevious) {
	        a[a.length - 1] += b;
	        mergeWithPrevious = false;
	        return a;
	      } else {
	        return a.concat(b);
	      }
	    }, [])
	    // Here we convert the string values into number values (in px)
	    .map(function (str) {
	      return toValue(str, measurement, popperOffsets, referenceOffsets);
	    });
	  });

	  // Loop trough the offsets arrays and execute the operations
	  ops.forEach(function (op, index) {
	    op.forEach(function (frag, index2) {
	      if (isNumeric(frag)) {
	        offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
	      }
	    });
	  });
	  return offsets;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by update method
	 * @argument {Object} options - Modifiers configuration and options
	 * @argument {Number|String} options.offset=0
	 * The offset value as described in the modifier description
	 * @returns {Object} The data object, properly modified
	 */
	function offset(data, _ref) {
	  var offset = _ref.offset;
	  var placement = data.placement,
	      _data$offsets = data.offsets,
	      popper = _data$offsets.popper,
	      reference = _data$offsets.reference;

	  var basePlacement = placement.split('-')[0];

	  var offsets = void 0;
	  if (isNumeric(+offset)) {
	    offsets = [+offset, 0];
	  } else {
	    offsets = parseOffset(offset, popper, reference, basePlacement);
	  }

	  if (basePlacement === 'left') {
	    popper.top += offsets[0];
	    popper.left -= offsets[1];
	  } else if (basePlacement === 'right') {
	    popper.top += offsets[0];
	    popper.left += offsets[1];
	  } else if (basePlacement === 'top') {
	    popper.left += offsets[0];
	    popper.top -= offsets[1];
	  } else if (basePlacement === 'bottom') {
	    popper.left += offsets[0];
	    popper.top += offsets[1];
	  }

	  data.popper = popper;
	  return data;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by `update` method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function preventOverflow(data, options) {
	  var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);

	  // If offsetParent is the reference element, we really want to
	  // go one step up and use the next offsetParent as reference to
	  // avoid to make this modifier completely useless and look like broken
	  if (data.instance.reference === boundariesElement) {
	    boundariesElement = getOffsetParent(boundariesElement);
	  }

	  // NOTE: DOM access here
	  // resets the popper's position so that the document size can be calculated excluding
	  // the size of the popper element itself
	  var transformProp = getSupportedPropertyName('transform');
	  var popperStyles = data.instance.popper.style; // assignment to help minification
	  var top = popperStyles.top,
	      left = popperStyles.left,
	      transform = popperStyles[transformProp];

	  popperStyles.top = '';
	  popperStyles.left = '';
	  popperStyles[transformProp] = '';

	  var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);

	  // NOTE: DOM access here
	  // restores the original style properties after the offsets have been computed
	  popperStyles.top = top;
	  popperStyles.left = left;
	  popperStyles[transformProp] = transform;

	  options.boundaries = boundaries;

	  var order = options.priority;
	  var popper = data.offsets.popper;

	  var check = {
	    primary: function primary(placement) {
	      var value = popper[placement];
	      if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
	        value = Math.max(popper[placement], boundaries[placement]);
	      }
	      return defineProperty({}, placement, value);
	    },
	    secondary: function secondary(placement) {
	      var mainSide = placement === 'right' ? 'left' : 'top';
	      var value = popper[mainSide];
	      if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
	        value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
	      }
	      return defineProperty({}, mainSide, value);
	    }
	  };

	  order.forEach(function (placement) {
	    var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
	    popper = _extends({}, popper, check[side](placement));
	  });

	  data.offsets.popper = popper;

	  return data;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by `update` method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function shift(data) {
	  var placement = data.placement;
	  var basePlacement = placement.split('-')[0];
	  var shiftvariation = placement.split('-')[1];

	  // if shift shiftvariation is specified, run the modifier
	  if (shiftvariation) {
	    var _data$offsets = data.offsets,
	        reference = _data$offsets.reference,
	        popper = _data$offsets.popper;

	    var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
	    var side = isVertical ? 'left' : 'top';
	    var measurement = isVertical ? 'width' : 'height';

	    var shiftOffsets = {
	      start: defineProperty({}, side, reference[side]),
	      end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
	    };

	    data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
	  }

	  return data;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by update method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function hide(data) {
	  if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
	    return data;
	  }

	  var refRect = data.offsets.reference;
	  var bound = find(data.instance.modifiers, function (modifier) {
	    return modifier.name === 'preventOverflow';
	  }).boundaries;

	  if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
	    // Avoid unnecessary DOM access if visibility hasn't changed
	    if (data.hide === true) {
	      return data;
	    }

	    data.hide = true;
	    data.attributes['x-out-of-boundaries'] = '';
	  } else {
	    // Avoid unnecessary DOM access if visibility hasn't changed
	    if (data.hide === false) {
	      return data;
	    }

	    data.hide = false;
	    data.attributes['x-out-of-boundaries'] = false;
	  }

	  return data;
	}

	/**
	 * @function
	 * @memberof Modifiers
	 * @argument {Object} data - The data object generated by `update` method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {Object} The data object, properly modified
	 */
	function inner(data) {
	  var placement = data.placement;
	  var basePlacement = placement.split('-')[0];
	  var _data$offsets = data.offsets,
	      popper = _data$offsets.popper,
	      reference = _data$offsets.reference;

	  var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;

	  var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;

	  popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);

	  data.placement = getOppositePlacement(placement);
	  data.offsets.popper = getClientRect(popper);

	  return data;
	}

	/**
	 * Modifier function, each modifier can have a function of this type assigned
	 * to its `fn` property.<br />
	 * These functions will be called on each update, this means that you must
	 * make sure they are performant enough to avoid performance bottlenecks.
	 *
	 * @function ModifierFn
	 * @argument {dataObject} data - The data object generated by `update` method
	 * @argument {Object} options - Modifiers configuration and options
	 * @returns {dataObject} The data object, properly modified
	 */

	/**
	 * Modifiers are plugins used to alter the behavior of your poppers.<br />
	 * Popper.js uses a set of 9 modifiers to provide all the basic functionalities
	 * needed by the library.
	 *
	 * Usually you don't want to override the `order`, `fn` and `onLoad` props.
	 * All the other properties are configurations that could be tweaked.
	 * @namespace modifiers
	 */
	var modifiers = {
	  /**
	   * Modifier used to shift the popper on the start or end of its reference
	   * element.<br />
	   * It will read the variation of the `placement` property.<br />
	   * It can be one either `-end` or `-start`.
	   * @memberof modifiers
	   * @inner
	   */
	  shift: {
	    /** @prop {number} order=100 - Index used to define the order of execution */
	    order: 100,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: shift
	  },

	  /**
	   * The `offset` modifier can shift your popper on both its axis.
	   *
	   * It accepts the following units:
	   * - `px` or unitless, interpreted as pixels
	   * - `%` or `%r`, percentage relative to the length of the reference element
	   * - `%p`, percentage relative to the length of the popper element
	   * - `vw`, CSS viewport width unit
	   * - `vh`, CSS viewport height unit
	   *
	   * For length is intended the main axis relative to the placement of the popper.<br />
	   * This means that if the placement is `top` or `bottom`, the length will be the
	   * `width`. In case of `left` or `right`, it will be the height.
	   *
	   * You can provide a single value (as `Number` or `String`), or a pair of values
	   * as `String` divided by a comma or one (or more) white spaces.<br />
	   * The latter is a deprecated method because it leads to confusion and will be
	   * removed in v2.<br />
	   * Additionally, it accepts additions and subtractions between different units.
	   * Note that multiplications and divisions aren't supported.
	   *
	   * Valid examples are:
	   * ```
	   * 10
	   * '10%'
	   * '10, 10'
	   * '10%, 10'
	   * '10 + 10%'
	   * '10 - 5vh + 3%'
	   * '-10px + 5vh, 5px - 6%'
	   * ```
	   * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
	   * > with their reference element, unfortunately, you will have to disable the `flip` modifier.
	   * > More on this [reading this issue](https://github.com/FezVrasta/popper.js/issues/373)
	   *
	   * @memberof modifiers
	   * @inner
	   */
	  offset: {
	    /** @prop {number} order=200 - Index used to define the order of execution */
	    order: 200,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: offset,
	    /** @prop {Number|String} offset=0
	     * The offset value as described in the modifier description
	     */
	    offset: 0
	  },

	  /**
	   * Modifier used to prevent the popper from being positioned outside the boundary.
	   *
	   * An scenario exists where the reference itself is not within the boundaries.<br />
	   * We can say it has "escaped the boundaries" — or just "escaped".<br />
	   * In this case we need to decide whether the popper should either:
	   *
	   * - detach from the reference and remain "trapped" in the boundaries, or
	   * - if it should ignore the boundary and "escape with its reference"
	   *
	   * When `escapeWithReference` is set to`true` and reference is completely
	   * outside its boundaries, the popper will overflow (or completely leave)
	   * the boundaries in order to remain attached to the edge of the reference.
	   *
	   * @memberof modifiers
	   * @inner
	   */
	  preventOverflow: {
	    /** @prop {number} order=300 - Index used to define the order of execution */
	    order: 300,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: preventOverflow,
	    /**
	     * @prop {Array} [priority=['left','right','top','bottom']]
	     * Popper will try to prevent overflow following these priorities by default,
	     * then, it could overflow on the left and on top of the `boundariesElement`
	     */
	    priority: ['left', 'right', 'top', 'bottom'],
	    /**
	     * @prop {number} padding=5
	     * Amount of pixel used to define a minimum distance between the boundaries
	     * and the popper this makes sure the popper has always a little padding
	     * between the edges of its container
	     */
	    padding: 5,
	    /**
	     * @prop {String|HTMLElement} boundariesElement='scrollParent'
	     * Boundaries used by the modifier, can be `scrollParent`, `window`,
	     * `viewport` or any DOM element.
	     */
	    boundariesElement: 'scrollParent'
	  },

	  /**
	   * Modifier used to make sure the reference and its popper stay near eachothers
	   * without leaving any gap between the two. Expecially useful when the arrow is
	   * enabled and you want to assure it to point to its reference element.
	   * It cares only about the first axis, you can still have poppers with margin
	   * between the popper and its reference element.
	   * @memberof modifiers
	   * @inner
	   */
	  keepTogether: {
	    /** @prop {number} order=400 - Index used to define the order of execution */
	    order: 400,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: keepTogether
	  },

	  /**
	   * This modifier is used to move the `arrowElement` of the popper to make
	   * sure it is positioned between the reference element and its popper element.
	   * It will read the outer size of the `arrowElement` node to detect how many
	   * pixels of conjuction are needed.
	   *
	   * It has no effect if no `arrowElement` is provided.
	   * @memberof modifiers
	   * @inner
	   */
	  arrow: {
	    /** @prop {number} order=500 - Index used to define the order of execution */
	    order: 500,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: arrow,
	    /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */
	    element: '[x-arrow]'
	  },

	  /**
	   * Modifier used to flip the popper's placement when it starts to overlap its
	   * reference element.
	   *
	   * Requires the `preventOverflow` modifier before it in order to work.
	   *
	   * **NOTE:** this modifier will interrupt the current update cycle and will
	   * restart it if it detects the need to flip the placement.
	   * @memberof modifiers
	   * @inner
	   */
	  flip: {
	    /** @prop {number} order=600 - Index used to define the order of execution */
	    order: 600,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: flip,
	    /**
	     * @prop {String|Array} behavior='flip'
	     * The behavior used to change the popper's placement. It can be one of
	     * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
	     * placements (with optional variations).
	     */
	    behavior: 'flip',
	    /**
	     * @prop {number} padding=5
	     * The popper will flip if it hits the edges of the `boundariesElement`
	     */
	    padding: 5,
	    /**
	     * @prop {String|HTMLElement} boundariesElement='viewport'
	     * The element which will define the boundaries of the popper position,
	     * the popper will never be placed outside of the defined boundaries
	     * (except if keepTogether is enabled)
	     */
	    boundariesElement: 'viewport'
	  },

	  /**
	   * Modifier used to make the popper flow toward the inner of the reference element.
	   * By default, when this modifier is disabled, the popper will be placed outside
	   * the reference element.
	   * @memberof modifiers
	   * @inner
	   */
	  inner: {
	    /** @prop {number} order=700 - Index used to define the order of execution */
	    order: 700,
	    /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */
	    enabled: false,
	    /** @prop {ModifierFn} */
	    fn: inner
	  },

	  /**
	   * Modifier used to hide the popper when its reference element is outside of the
	   * popper boundaries. It will set a `x-out-of-boundaries` attribute which can
	   * be used to hide with a CSS selector the popper when its reference is
	   * out of boundaries.
	   *
	   * Requires the `preventOverflow` modifier before it in order to work.
	   * @memberof modifiers
	   * @inner
	   */
	  hide: {
	    /** @prop {number} order=800 - Index used to define the order of execution */
	    order: 800,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: hide
	  },

	  /**
	   * Computes the style that will be applied to the popper element to gets
	   * properly positioned.
	   *
	   * Note that this modifier will not touch the DOM, it just prepares the styles
	   * so that `applyStyle` modifier can apply it. This separation is useful
	   * in case you need to replace `applyStyle` with a custom implementation.
	   *
	   * This modifier has `850` as `order` value to maintain backward compatibility
	   * with previous versions of Popper.js. Expect the modifiers ordering method
	   * to change in future major versions of the library.
	   *
	   * @memberof modifiers
	   * @inner
	   */
	  computeStyle: {
	    /** @prop {number} order=850 - Index used to define the order of execution */
	    order: 850,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: computeStyle,
	    /**
	     * @prop {Boolean} gpuAcceleration=true
	     * If true, it uses the CSS 3d transformation to position the popper.
	     * Otherwise, it will use the `top` and `left` properties.
	     */
	    gpuAcceleration: true,
	    /**
	     * @prop {string} [x='bottom']
	     * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
	     * Change this if your popper should grow in a direction different from `bottom`
	     */
	    x: 'bottom',
	    /**
	     * @prop {string} [x='left']
	     * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
	     * Change this if your popper should grow in a direction different from `right`
	     */
	    y: 'right'
	  },

	  /**
	   * Applies the computed styles to the popper element.
	   *
	   * All the DOM manipulations are limited to this modifier. This is useful in case
	   * you want to integrate Popper.js inside a framework or view library and you
	   * want to delegate all the DOM manipulations to it.
	   *
	   * Note that if you disable this modifier, you must make sure the popper element
	   * has its position set to `absolute` before Popper.js can do its work!
	   *
	   * Just disable this modifier and define you own to achieve the desired effect.
	   *
	   * @memberof modifiers
	   * @inner
	   */
	  applyStyle: {
	    /** @prop {number} order=900 - Index used to define the order of execution */
	    order: 900,
	    /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
	    enabled: true,
	    /** @prop {ModifierFn} */
	    fn: applyStyle,
	    /** @prop {Function} */
	    onLoad: applyStyleOnLoad,
	    /**
	     * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
	     * @prop {Boolean} gpuAcceleration=true
	     * If true, it uses the CSS 3d transformation to position the popper.
	     * Otherwise, it will use the `top` and `left` properties.
	     */
	    gpuAcceleration: undefined
	  }
	};

	/**
	 * The `dataObject` is an object containing all the informations used by Popper.js
	 * this object get passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
	 * @name dataObject
	 * @property {Object} data.instance The Popper.js instance
	 * @property {String} data.placement Placement applied to popper
	 * @property {String} data.originalPlacement Placement originally defined on init
	 * @property {Boolean} data.flipped True if popper has been flipped by flip modifier
	 * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper.
	 * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
	 * @property {Object} data.styles Any CSS property defined here will be applied to the popper, it expects the JavaScript nomenclature (eg. `marginBottom`)
	 * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow, it expects the JavaScript nomenclature (eg. `marginBottom`)
	 * @property {Object} data.boundaries Offsets of the popper boundaries
	 * @property {Object} data.offsets The measurements of popper, reference and arrow elements.
	 * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
	 * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
	 * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
	 */

	/**
	 * Default options provided to Popper.js constructor.<br />
	 * These can be overriden using the `options` argument of Popper.js.<br />
	 * To override an option, simply pass as 3rd argument an object with the same
	 * structure of this object, example:
	 * ```
	 * new Popper(ref, pop, {
	 *   modifiers: {
	 *     preventOverflow: { enabled: false }
	 *   }
	 * })
	 * ```
	 * @type {Object}
	 * @static
	 * @memberof Popper
	 */
	var Defaults = {
	  /**
	   * Popper's placement
	   * @prop {Popper.placements} placement='bottom'
	   */
	  placement: 'bottom',

	  /**
	   * Set this to true if you want popper to position it self in 'fixed' mode
	   * @prop {Boolean} positionFixed=false
	   */
	  positionFixed: false,

	  /**
	   * Whether events (resize, scroll) are initially enabled
	   * @prop {Boolean} eventsEnabled=true
	   */
	  eventsEnabled: true,

	  /**
	   * Set to true if you want to automatically remove the popper when
	   * you call the `destroy` method.
	   * @prop {Boolean} removeOnDestroy=false
	   */
	  removeOnDestroy: false,

	  /**
	   * Callback called when the popper is created.<br />
	   * By default, is set to no-op.<br />
	   * Access Popper.js instance with `data.instance`.
	   * @prop {onCreate}
	   */
	  onCreate: function onCreate() {},

	  /**
	   * Callback called when the popper is updated, this callback is not called
	   * on the initialization/creation of the popper, but only on subsequent
	   * updates.<br />
	   * By default, is set to no-op.<br />
	   * Access Popper.js instance with `data.instance`.
	   * @prop {onUpdate}
	   */
	  onUpdate: function onUpdate() {},

	  /**
	   * List of modifiers used to modify the offsets before they are applied to the popper.
	   * They provide most of the functionalities of Popper.js
	   * @prop {modifiers}
	   */
	  modifiers: modifiers
	};

	/**
	 * @callback onCreate
	 * @param {dataObject} data
	 */

	/**
	 * @callback onUpdate
	 * @param {dataObject} data
	 */

	// Utils
	// Methods
	var Popper = function () {
	  /**
	   * Create a new Popper.js instance
	   * @class Popper
	   * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper
	   * @param {HTMLElement} popper - The HTML element used as popper.
	   * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
	   * @return {Object} instance - The generated Popper.js instance
	   */
	  function Popper(reference, popper) {
	    var _this = this;

	    var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
	    classCallCheck(this, Popper);

	    this.scheduleUpdate = function () {
	      return requestAnimationFrame(_this.update);
	    };

	    // make update() debounced, so that it only runs at most once-per-tick
	    this.update = debounce(this.update.bind(this));

	    // with {} we create a new object with the options inside it
	    this.options = _extends({}, Popper.Defaults, options);

	    // init state
	    this.state = {
	      isDestroyed: false,
	      isCreated: false,
	      scrollParents: []
	    };

	    // get reference and popper elements (allow jQuery wrappers)
	    this.reference = reference && reference.jquery ? reference[0] : reference;
	    this.popper = popper && popper.jquery ? popper[0] : popper;

	    // Deep merge modifiers options
	    this.options.modifiers = {};
	    Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
	      _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
	    });

	    // Refactoring modifiers' list (Object => Array)
	    this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
	      return _extends({
	        name: name
	      }, _this.options.modifiers[name]);
	    })
	    // sort the modifiers by order
	    .sort(function (a, b) {
	      return a.order - b.order;
	    });

	    // modifiers have the ability to execute arbitrary code when Popper.js get inited
	    // such code is executed in the same order of its modifier
	    // they could add new properties to their options configuration
	    // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
	    this.modifiers.forEach(function (modifierOptions) {
	      if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
	        modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
	      }
	    });

	    // fire the first update to position the popper in the right place
	    this.update();

	    var eventsEnabled = this.options.eventsEnabled;
	    if (eventsEnabled) {
	      // setup event listeners, they will take care of update the position in specific situations
	      this.enableEventListeners();
	    }

	    this.state.eventsEnabled = eventsEnabled;
	  }

	  // We can't use class properties because they don't get listed in the
	  // class prototype and break stuff like Sinon stubs


	  createClass(Popper, [{
	    key: 'update',
	    value: function update$$1() {
	      return update.call(this);
	    }
	  }, {
	    key: 'destroy',
	    value: function destroy$$1() {
	      return destroy.call(this);
	    }
	  }, {
	    key: 'enableEventListeners',
	    value: function enableEventListeners$$1() {
	      return enableEventListeners.call(this);
	    }
	  }, {
	    key: 'disableEventListeners',
	    value: function disableEventListeners$$1() {
	      return disableEventListeners.call(this);
	    }

	    /**
	     * Schedule an update, it will run on the next UI update available
	     * @method scheduleUpdate
	     * @memberof Popper
	     */


	    /**
	     * Collection of utilities useful when writing custom modifiers.
	     * Starting from version 1.7, this method is available only if you
	     * include `popper-utils.js` before `popper.js`.
	     *
	     * **DEPRECATION**: This way to access PopperUtils is deprecated
	     * and will be removed in v2! Use the PopperUtils module directly instead.
	     * Due to the high instability of the methods contained in Utils, we can't
	     * guarantee them to follow semver. Use them at your own risk!
	     * @static
	     * @private
	     * @type {Object}
	     * @deprecated since version 1.8
	     * @member Utils
	     * @memberof Popper
	     */

	  }]);
	  return Popper;
	}();

	/**
	 * The `referenceObject` is an object that provides an interface compatible with Popper.js
	 * and lets you use it as replacement of a real DOM node.<br />
	 * You can use this method to position a popper relatively to a set of coordinates
	 * in case you don't have a DOM node to use as reference.
	 *
	 * ```
	 * new Popper(referenceObject, popperNode);
	 * ```
	 *
	 * NB: This feature isn't supported in Internet Explorer 10
	 * @name referenceObject
	 * @property {Function} data.getBoundingClientRect
	 * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
	 * @property {number} data.clientWidth
	 * An ES6 getter that will return the width of the virtual reference element.
	 * @property {number} data.clientHeight
	 * An ES6 getter that will return the height of the virtual reference element.
	 */


	Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
	Popper.placements = placements;
	Popper.Defaults = Defaults;

	var SVGAnimatedString = function SVGAnimatedString() {};
	if (typeof window !== 'undefined') {
		SVGAnimatedString = window.SVGAnimatedString;
	}

	function convertToArray(value) {
		if (typeof value === 'string') {
			value = value.split(' ');
		}
		return value;
	}

	/**
	 * Add classes to an element.
	 * This method checks to ensure that the classes don't already exist before adding them.
	 * It uses el.className rather than classList in order to be IE friendly.
	 * @param {object} el - The element to add the classes to.
	 * @param {classes} string - List of space separated classes to be added to the element.
	 */
	function addClasses(el, classes) {
		var newClasses = convertToArray(classes);
		var classList = void 0;
		if (el.className instanceof SVGAnimatedString) {
			classList = convertToArray(el.className.baseVal);
		} else {
			classList = convertToArray(el.className);
		}
		newClasses.forEach(function (newClass) {
			if (classList.indexOf(newClass) === -1) {
				classList.push(newClass);
			}
		});
		if (el instanceof SVGElement) {
			el.setAttribute('class', classList.join(' '));
		} else {
			el.className = classList.join(' ');
		}
	}

	/**
	 * Remove classes from an element.
	 * It uses el.className rather than classList in order to be IE friendly.
	 * @export
	 * @param {any} el The element to remove the classes from.
	 * @param {any} classes List of space separated classes to be removed from the element.
	 */
	function removeClasses(el, classes) {
		var newClasses = convertToArray(classes);
		var classList = void 0;
		if (el.className instanceof SVGAnimatedString) {
			classList = convertToArray(el.className.baseVal);
		} else {
			classList = convertToArray(el.className);
		}
		newClasses.forEach(function (newClass) {
			var index = classList.indexOf(newClass);
			if (index !== -1) {
				classList.splice(index, 1);
			}
		});
		if (el instanceof SVGElement) {
			el.setAttribute('class', classList.join(' '));
		} else {
			el.className = classList.join(' ');
		}
	}

	var supportsPassive = false;

	if (typeof window !== 'undefined') {
		supportsPassive = false;
		try {
			var opts = Object.defineProperty({}, 'passive', {
				get: function get() {
					supportsPassive = true;
				}
			});
			window.addEventListener('test', null, opts);
		} catch (e) {}
	}

	var _typeof = 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 classCallCheck$1 = function (instance, Constructor) {
	  if (!(instance instanceof Constructor)) {
	    throw new TypeError("Cannot call a class as a function");
	  }
	};

	var createClass$1 = 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);
	    }
	  }

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







	var _extends$1 = Object.assign || function (target) {
	  for (var i = 1; i < arguments.length; i++) {
	    var source = arguments[i];

	    for (var key in source) {
	      if (Object.prototype.hasOwnProperty.call(source, key)) {
	        target[key] = source[key];
	      }
	    }
	  }

	  return target;
	};

	/* Forked from https://github.com/FezVrasta/popper.js/blob/master/packages/tooltip/src/index.js */

	var DEFAULT_OPTIONS = {
		container: false,
		delay: 0,
		html: false,
		placement: 'top',
		title: '',
		template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
		trigger: 'hover focus',
		offset: 0
	};

	var openTooltips = [];

	var Tooltip = function () {
		/**
	  * Create a new Tooltip.js instance
	  * @class Tooltip
	  * @param {HTMLElement} reference - The DOM node used as reference of the tooltip (it can be a jQuery element).
	  * @param {Object} options
	  * @param {String} options.placement=bottom
	  *			Placement of the popper accepted values: `top(-start, -end), right(-start, -end), bottom(-start, -end),
	  *			left(-start, -end)`
	  * @param {HTMLElement|String|false} options.container=false - Append the tooltip to a specific element.
	  * @param {Number|Object} options.delay=0
	  *			Delay showing and hiding the tooltip (ms) - does not apply to manual trigger type.
	  *			If a number is supplied, delay is applied to both hide/show.
	  *			Object structure is: `{ show: 500, hide: 100 }`
	  * @param {Boolean} options.html=false - Insert HTML into the tooltip. If false, the content will inserted with `innerText`.
	  * @param {String|PlacementFunction} options.placement='top' - One of the allowed placements, or a function returning one of them.
	  * @param {String} [options.template='<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>']
	  *			Base HTML to used when creating the tooltip.
	  *			The tooltip's `title` will be injected into the `.tooltip-inner` or `.tooltip__inner`.
	  *			`.tooltip-arrow` or `.tooltip__arrow` will become the tooltip's arrow.
	  *			The outermost wrapper element should have the `.tooltip` class.
	  * @param {String|HTMLElement|TitleFunction} options.title='' - Default title value if `title` attribute isn't present.
	  * @param {String} [options.trigger='hover focus']
	  *			How tooltip is triggered - click, hover, focus, manual.
	  *			You may pass multiple triggers; separate them with a space. `manual` cannot be combined with any other trigger.
	  * @param {HTMLElement} options.boundariesElement
	  *			The element used as boundaries for the tooltip. For more information refer to Popper.js'
	  *			[boundariesElement docs](https://popper.js.org/popper-documentation.html)
	  * @param {Number|String} options.offset=0 - Offset of the tooltip relative to its reference. For more information refer to Popper.js'
	  *			[offset docs](https://popper.js.org/popper-documentation.html)
	  * @param {Object} options.popperOptions={} - Popper options, will be passed directly to popper instance. For more information refer to Popper.js'
	  *			[options docs](https://popper.js.org/popper-documentation.html)
	  * @return {Object} instance - The generated tooltip instance
	  */
		function Tooltip(reference, options) {
			classCallCheck$1(this, Tooltip);

			_initialiseProps.call(this);

			// apply user options over default ones
			options = _extends$1({}, DEFAULT_OPTIONS, options);

			reference.jquery && (reference = reference[0]);

			// cache reference and options
			this.reference = reference;
			this.options = options;

			// set initial state
			this._isOpen = false;

			this._init();
		}

		//
		// Public methods
		//

		/**
	  * Reveals an element's tooltip. This is considered a "manual" triggering of the tooltip.
	  * Tooltips with zero-length titles are never displayed.
	  * @method Tooltip#show
	  * @memberof Tooltip
	  */


		/**
	  * Hides an element’s tooltip. This is considered a “manual” triggering of the tooltip.
	  * @method Tooltip#hide
	  * @memberof Tooltip
	  */


		/**
	  * Hides and destroys an element’s tooltip.
	  * @method Tooltip#dispose
	  * @memberof Tooltip
	  */


		/**
	  * Toggles an element’s tooltip. This is considered a “manual” triggering of the tooltip.
	  * @method Tooltip#toggle
	  * @memberof Tooltip
	  */


		createClass$1(Tooltip, [{
			key: 'setClasses',
			value: function setClasses(classes) {
				this._classes = classes;
			}
		}, {
			key: 'setContent',
			value: function setContent(content) {
				this.options.title = content;
				if (this._tooltipNode) {
					this._setContent(content, this.options);
				}
			}
		}, {
			key: 'setOptions',
			value: function setOptions(options) {
				var classesUpdated = false;
				var classes = options && options.classes || directive.options.defaultClass;
				if (this._classes !== classes) {
					this.setClasses(classes);
					classesUpdated = true;
				}

				options = getOptions(options);

				var needPopperUpdate = false;
				var needRestart = false;

				if (this.options.offset !== options.offset || this.options.placement !== options.placement) {
					needPopperUpdate = true;
				}

				if (this.options.template !== options.template || this.options.trigger !== options.trigger || this.options.container !== options.container || classesUpdated) {
					needRestart = true;
				}

				for (var key in options) {
					this.options[key] = options[key];
				}

				if (this._tooltipNode) {
					if (needRestart) {
						var isOpen = this._isOpen;

						this.dispose();
						this._init();

						if (isOpen) {
							this.show();
						}
					} else if (needPopperUpdate) {
						this.popperInstance.update();
					}
				}
			}

			//
			// Private methods
			//

		}, {
			key: '_init',
			value: function _init() {
				// get events list
				var events = typeof this.options.trigger === 'string' ? this.options.trigger.split(' ').filter(function (trigger) {
					return ['click', 'hover', 'focus'].indexOf(trigger) !== -1;
				}) : [];
				this._isDisposed = false;
				this._enableDocumentTouch = events.indexOf('manual') === -1;

				// set event listeners
				this._setEventListeners(this.reference, events, this.options);
			}

			/**
	   * Creates a new tooltip node
	   * @memberof Tooltip
	   * @private
	   * @param {HTMLElement} reference
	   * @param {String} template
	   * @param {String|HTMLElement|TitleFunction} title
	   * @param {Boolean} allowHtml
	   * @return {HTMLelement} tooltipNode
	   */

		}, {
			key: '_create',
			value: function _create(reference, template) {
				// create tooltip element
				var tooltipGenerator = window.document.createElement('div');
				tooltipGenerator.innerHTML = template.trim();
				var tooltipNode = tooltipGenerator.childNodes[0];

				// add unique ID to our tooltip (needed for accessibility reasons)
				tooltipNode.id = 'tooltip_' + Math.random().toString(36).substr(2, 10);

				// Initially hide the tooltip
				// The attribute will be switched in a next frame so
				// CSS transitions can play
				tooltipNode.setAttribute('aria-hidden', 'true');

				if (this.options.autoHide && this.options.trigger.indexOf('hover') !== -1) {
					tooltipNode.addEventListener('mouseenter', this.hide);
					tooltipNode.addEventListener('click', this.hide);
				}

				// return the generated tooltip node
				return tooltipNode;
			}
		}, {
			key: '_setContent',
			value: function _setContent(content, options) {
				var _this = this;

				this.asyncContent = false;
				this._applyContent(content, options).then(function () {
					_this.popperInstance.update();
				});
			}
		}, {
			key: '_applyContent',
			value: function _applyContent(title, options) {
				var _this2 = this;

				return new Promise(function (resolve, reject) {
					var allowHtml = options.html;
					var rootNode = _this2._tooltipNode;
					if (!rootNode) return;
					var titleNode = rootNode.querySelector(_this2.options.innerSelector);
					if (title.nodeType === 1) {
						// if title is a node, append it only if allowHtml is true
						if (allowHtml) {
							while (titleNode.firstChild) {
								titleNode.removeChild(titleNode.firstChild);
							}
							titleNode.appendChild(title);
						}
					} else if (typeof title === 'function') {
						// if title is a function, call it and set innerText or innerHtml depending by `allowHtml` value
						var result = title();
						if (result && typeof result.then === 'function') {
							_this2.asyncContent = true;
							options.loadingClass && addClasses(rootNode, options.loadingClass);
							if (options.loadingContent) {
								_this2._applyContent(options.loadingContent, options);
							}
							result.then(function (asyncResult) {
								options.loadingClass && removeClasses(rootNode, options.loadingClass);
								return _this2._applyContent(asyncResult, options);
							}).then(resolve).catch(reject);
						} else {
							_this2._applyContent(result, options).then(resolve).catch(reject);
						}
						return;
					} else {
						// if it's just a simple text, set innerText or innerHtml depending by `allowHtml` value
						allowHtml ? titleNode.innerHTML = title : titleNode.innerText = title;
					}
					resolve();
				});
			}
		}, {
			key: '_show',
			value: function _show(reference, options) {
				if (options && typeof options.container === 'string') {
					var container = document.querySelector(options.container);
					if (!container) return;
				}

				clearTimeout(this._disposeTimer);

				options = Object.assign({}, options);
				delete options.offset;

				var updateClasses = true;
				if (this._tooltipNode) {
					addClasses(this._tooltipNode, this._classes);
					updateClasses = false;
				}

				var result = this._ensureShown(reference, options);

				if (updateClasses && this._tooltipNode) {
					addClasses(this._tooltipNode, this._classes);
				}

				addClasses(reference, ['v-tooltip-open']);

				return result;
			}
		}, {
			key: '_ensureShown',
			value: function _ensureShown(reference, options) {
				var _this3 = this;

				// don't show if it's already visible
				if (this._isOpen) {
					return this;
				}
				this._isOpen = true;

				openTooltips.push(this);

				// if the tooltipNode already exists, just show it
				if (this._tooltipNode) {
					this._tooltipNode.style.display = '';
					this._tooltipNode.setAttribute('aria-hidden', 'false');
					this.popperInstance.enableEventListeners();
					this.popperInstance.update();
					if (this.asyncContent) {
						this._setContent(options.title, options);
					}
					return this;
				}

				// get title
				var title = reference.getAttribute('title') || options.title;

				// don't show tooltip if no title is defined
				if (!title) {
					return this;
				}

				// create tooltip node
				var tooltipNode = this._create(reference, options.template);
				this._tooltipNode = tooltipNode;

				this._setContent(title, options);

				// Add `aria-describedby` to our reference element for accessibility reasons
				reference.setAttribute('aria-describedby', tooltipNode.id);

				// append tooltip to container
				var container = this._findContainer(options.container, reference);

				this._append(tooltipNode, container);

				var popperOptions = _extends$1({}, options.popperOptions, {
					placement: options.placement
				});

				popperOptions.modifiers = _extends$1({}, popperOptions.modifiers, {
					arrow: {
						element: this.options.arrowSelector
					}
				});

				if (options.boundariesElement) {
					popperOptions.modifiers.preventOverflow = {
						boundariesElement: options.boundariesElement
					};
				}

				this.popperInstance = new Popper(reference, tooltipNode, popperOptions);

				// Fix position
				requestAnimationFrame(function () {
					if (!_this3._isDisposed && _this3.popperInstance) {
						_this3.popperInstance.update();

						// Show the tooltip
						requestAnimationFrame(function () {
							if (!_this3._isDisposed) {
								_this3._isOpen && tooltipNode.setAttribute('aria-hidden', 'false');
							} else {
								_this3.dispose();
							}
						});
					} else {
						_this3.dispose();
					}
				});

				return this;
			}
		}, {
			key: '_noLongerOpen',
			value: function _noLongerOpen() {
				var index = openTooltips.indexOf(this);
				if (index !== -1) {
					openTooltips.splice(index, 1);
				}
			}
		}, {
			key: '_hide',
			value: function _hide() /* reference, options */{
				var _this4 = this;

				// don't hide if it's already hidden
				if (!this._isOpen) {
					return this;
				}

				this._isOpen = false;
				this._noLongerOpen();

				// hide tooltipNode
				this._tooltipNode.style.display = 'none';
				this._tooltipNode.setAttribute('aria-hidden', 'true');

				this.popperInstance.disableEventListeners();

				clearTimeout(this._disposeTimer);
				var disposeTime = directive.options.disposeTimeout;
				if (disposeTime !== null) {
					this._disposeTimer = setTimeout(function () {
						if (_this4._tooltipNode) {
							_this4._tooltipNode.removeEventListener('mouseenter', _this4.hide);
							_this4._tooltipNode.removeEventListener('click', _this4.hide);
							// Don't remove popper instance, just the HTML element
							_this4._tooltipNode.parentNode.removeChild(_this4._tooltipNode);
							_this4._tooltipNode = null;
						}
					}, disposeTime);
				}

				removeClasses(this.reference, ['v-tooltip-open']);

				return this;
			}
		}, {
			key: '_dispose',
			value: function _dispose() {
				var _this5 = this;

				this._isDisposed = true;

				// remove event listeners first to prevent any unexpected behaviour
				this._events.forEach(function (_ref) {
					var func = _ref.func,
					    event = _ref.event;

					_this5.reference.removeEventListener(event, func);
				});
				this._events = [];

				if (this._tooltipNode) {
					this._hide();

					this._tooltipNode.removeEventListener('mouseenter', this.hide);
					this._tooltipNode.removeEventListener('click', this.hide);

					// destroy instance
					this.popperInstance.destroy();

					// destroy tooltipNode if removeOnDestroy is not set, as popperInstance.destroy() already removes the element
					if (!this.popperInstance.options.removeOnDestroy) {
						this._tooltipNode.parentNode.removeChild(this._tooltipNode);
						this._tooltipNode = null;
					}
				} else {
					this._noLongerOpen();
				}
				return this;
			}
		}, {
			key: '_findContainer',
			value: function _findContainer(container, reference) {
				// if container is a query, get the relative element
				if (typeof container === 'string') {
					container = window.document.querySelector(container);
				} else if (container === false) {
					// if container is `false`, set it to reference parent
					container = reference.parentNode;
				}
				return container;
			}

			/**
	   * Append tooltip to container
	   * @memberof Tooltip
	   * @private
	   * @param {HTMLElement} tooltip
	   * @param {HTMLElement|String|false} container
	   */

		}, {
			key: '_append',
			value: function _append(tooltipNode, container) {
				container.appendChild(tooltipNode);
			}
		}, {
			key: '_setEventListeners',
			value: function _setEventListeners(reference, events, options) {
				var _this6 = this;

				var directEvents = [];
				var oppositeEvents = [];

				events.forEach(function (event) {
					switch (event) {
						case 'hover':
							directEvents.push('mouseenter');
							oppositeEvents.push('mouseleave');
							if (_this6.options.hideOnTargetClick) oppositeEvents.push('click');
							break;
						case 'focus':
							directEvents.push('focus');
							oppositeEvents.push('blur');
							if (_this6.options.hideOnTargetClick) oppositeEvents.push('click');
							break;
						case 'click':
							directEvents.push('click');
							oppositeEvents.push('click');
							break;
					}
				});

				// schedule show tooltip
				directEvents.forEach(function (event) {
					var func = function func(evt) {
						if (_this6._isOpen === true) {
							return;
						}
						evt.usedByTooltip = true;
						_this6._scheduleShow(reference, options.delay, options, evt);
					};
					_this6._events.push({ event: event, func: func });
					reference.addEventListener(event, func);
				});

				// schedule hide tooltip
				oppositeEvents.forEach(function (event) {
					var func = function func(evt) {
						if (evt.usedByTooltip === true) {
							return;
						}
						_this6._scheduleHide(reference, options.delay, options, evt);
					};
					_this6._events.push({ event: event, func: func });
					reference.addEventListener(event, func);
				});
			}
		}, {
			key: '_onDocumentTouch',
			value: function _onDocumentTouch(event) {
				if (this._enableDocumentTouch) {
					this._scheduleHide(this.reference, this.options.delay, this.options, event);
				}
			}
		}, {
			key: '_scheduleShow',
			value: function _scheduleShow(reference, delay, options /*, evt */) {
				var _this7 = this;

				// defaults to 0
				var computedDelay = delay && delay.show || delay || 0;
				clearTimeout(this._scheduleTimer);
				this._scheduleTimer = window.setTimeout(function () {
					return _this7._show(reference, options);
				}, computedDelay);
			}
		}, {
			key: '_scheduleHide',
			value: function _scheduleHide(reference, delay, options, evt) {
				var _this8 = this;

				// defaults to 0
				var computedDelay = delay && delay.hide || delay || 0;
				clearTimeout(this._scheduleTimer);
				this._scheduleTimer = window.setTimeout(function () {
					if (_this8._isOpen === false) {
						return;
					}
					if (!document.body.contains(_this8._tooltipNode)) {
						return;
					}

					// if we are hiding because of a mouseleave, we must check that the new
					// reference isn't the tooltip, because in this case we don't want to hide it
					if (evt.type === 'mouseleave') {
						var isSet = _this8._setTooltipNodeEvent(evt, reference, delay, options);

						// if we set the new event, don't hide the tooltip yet
						// the new event will take care to hide it if necessary
						if (isSet) {
							return;
						}
					}

					_this8._hide(reference, options);
				}, computedDelay);
			}
		}]);
		return Tooltip;
	}();

	// Hide tooltips on touch devices


	var _initialiseProps = function _initialiseProps() {
		var _this9 = this;

		this.show = function () {
			_this9._show(_this9.reference, _this9.options);
		};

		this.hide = function () {
			_this9._hide();
		};

		this.dispose = function () {
			_this9._dispose();
		};

		this.toggle = function () {
			if (_this9._isOpen) {
				return _this9.hide();
			} else {
				return _this9.show();
			}
		};

		this._events = [];

		this._setTooltipNodeEvent = function (evt, reference, delay, options) {
			var relatedreference = evt.relatedreference || evt.toElement || evt.relatedTarget;

			var callback = function callback(evt2) {
				var relatedreference2 = evt2.relatedreference || evt2.toElement || evt2.relatedTarget;

				// Remove event listener after call
				_this9._tooltipNode.removeEventListener(evt.type, callback);

				// If the new reference is not the reference element
				if (!reference.contains(relatedreference2)) {
					// Schedule to hide tooltip
					_this9._scheduleHide(reference, options.delay, options, evt2);
				}
			};

			if (_this9._tooltipNode.contains(relatedreference)) {
				// listen to mouseleave on the tooltip element to be able to hide the tooltip
				_this9._tooltipNode.addEventListener(evt.type, callback);
				return true;
			}

			return false;
		};
	};

	if (typeof document !== 'undefined') {
		document.addEventListener('touchstart', function (event) {
			for (var i = 0; i < openTooltips.length; i++) {
				openTooltips[i]._onDocumentTouch(event);
			}
		}, supportsPassive ? {
			passive: true,
			capture: true
		} : true);
	}

	/**
	 * Placement function, its context is the Tooltip instance.
	 * @memberof Tooltip
	 * @callback PlacementFunction
	 * @param {HTMLElement} tooltip - tooltip DOM node.
	 * @param {HTMLElement} reference - reference DOM node.
	 * @return {String} placement - One of the allowed placement options.
	 */

	/**
	 * Title function, its context is the Tooltip instance.
	 * @memberof Tooltip
	 * @callback TitleFunction
	 * @return {String} placement - The desired title.
	 */

	var state = {
		enabled: true
	};

	var positions = ['top', 'top-start', 'top-end', 'right', 'right-start', 'right-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end'];

	var defaultOptions = {
		// Default tooltip placement relative to target element
		defaultPlacement: 'top',
		// Default CSS classes applied to the tooltip element
		defaultClass: 'vue-tooltip-theme',
		// Default CSS classes applied to the target element of the tooltip
		defaultTargetClass: 'has-tooltip',
		// Is the content HTML by default?
		defaultHtml: true,
		// Default HTML template of the tooltip element
		// It must include `tooltip-arrow` & `tooltip-inner` CSS classes (can be configured, see below)
		// Change if the classes conflict with other libraries (for example bootstrap)
		defaultTemplate: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
		// Selector used to get the arrow element in the tooltip template
		defaultArrowSelector: '.tooltip-arrow, .tooltip__arrow',
		// Selector used to get the inner content element in the tooltip template
		defaultInnerSelector: '.tooltip-inner, .tooltip__inner',
		// Delay (ms)
		defaultDelay: 0,
		// Default events that trigger the tooltip
		defaultTrigger: 'hover focus',
		// Default position offset (px)
		defaultOffset: 0,
		// Default container where the tooltip will be appended
		defaultContainer: 'body',
		defaultBoundariesElement: undefined,
		defaultPopperOptions: {},
		// Class added when content is loading
		defaultLoadingClass: 'tooltip-loading',
		// Displayed when tooltip content is loading
		defaultLoadingContent: '...',
		// Hide on mouseover tooltip
		autoHide: true,
		// Close tooltip on click on tooltip target?
		defaultHideOnTargetClick: true,
		// Auto destroy tooltip DOM nodes (ms)
		disposeTimeout: 5000,
		// Options for popover
		popover: {
			defaultPlacement: 'bottom',
			// Use the `popoverClass` prop for theming
			defaultClass: 'vue-popover-theme',
			// Base class (change if conflicts with other libraries)
			defaultBaseClass: 'tooltip popover',
			// Wrapper class (contains arrow and inner)
			defaultWrapperClass: 'wrapper',
			// Inner content class
			defaultInnerClass: 'tooltip-inner popover-inner',
			// Arrow class
			defaultArrowClass: 'tooltip-arrow popover-arrow',
			defaultDelay: 0,
			defaultTrigger: 'click',
			defaultOffset: 0,
			defaultContainer: 'body',
			defaultBoundariesElement: undefined,
			defaultPopperOptions: {},
			// Hides if clicked outside of popover
			defaultAutoHide: true,
			// Update popper on content resize
			defaultHandleResize: true
		}
	};

	function getOptions(options) {
		var result = {
			placement: typeof options.placement !== 'undefined' ? options.placement : directive.options.defaultPlacement,
			delay: typeof options.delay !== 'undefined' ? options.delay : directive.options.defaultDelay,
			html: typeof options.html !== 'undefined' ? options.html : directive.options.defaultHtml,
			template: typeof options.template !== 'undefined' ? options.template : directive.options.defaultTemplate,
			arrowSelector: typeof options.arrowSelector !== 'undefined' ? options.arrowSelector : directive.options.defaultArrowSelector,
			innerSelector: typeof options.innerSelector !== 'undefined' ? options.innerSelector : directive.options.defaultInnerSelector,
			trigger: typeof options.trigger !== 'undefined' ? options.trigger : directive.options.defaultTrigger,
			offset: typeof options.offset !== 'undefined' ? options.offset : directive.options.defaultOffset,
			container: typeof options.container !== 'undefined' ? options.container : directive.options.defaultContainer,
			boundariesElement: typeof options.boundariesElement !== 'undefined' ? options.boundariesElement : directive.options.defaultBoundariesElement,
			autoHide: typeof options.autoHide !== 'undefined' ? options.autoHide : directive.options.autoHide,
			hideOnTargetClick: typeof options.hideOnTargetClick !== 'undefined' ? options.hideOnTargetClick : directive.options.defaultHideOnTargetClick,
			loadingClass: typeof options.loadingClass !== 'undefined' ? options.loadingClass : directive.options.defaultLoadingClass,
			loadingContent: typeof options.loadingContent !== 'undefined' ? options.loadingContent : directive.options.defaultLoadingContent,
			popperOptions: _extends$1({}, typeof options.popperOptions !== 'undefined' ? options.popperOptions : directive.options.defaultPopperOptions)
		};

		if (result.offset) {
			var typeofOffset = _typeof(result.offset);
			var offset = result.offset;

			// One value -> switch
			if (typeofOffset === 'number' || typeofOffset === 'string' && offset.indexOf(',') === -1) {
				offset = '0, ' + offset;
			}

			if (!result.popperOptions.modifiers) {
				result.popperOptions.modifiers = {};
			}
			result.popperOptions.modifiers.offset = {
				offset: offset
			};
		}

		if (result.trigger && result.trigger.indexOf('click') !== -1) {
			result.hideOnTargetClick = false;
		}

		return result;
	}

	function getPlacement(value, modifiers) {
		var placement = value.placement;
		for (var i = 0; i < positions.length; i++) {
			var pos = positions[i];
			if (modifiers[pos]) {
				placement = pos;
			}
		}
		return placement;
	}

	function getContent(value) {
		var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);
		if (type === 'string') {
			return value;
		} else if (value && type === 'object') {
			return value.content;
		} else {
			return false;
		}
	}

	function createTooltip(el, value) {
		var modifiers = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

		var content = getContent(value);
		var classes = typeof value.classes !== 'undefined' ? value.classes : directive.options.defaultClass;
		var opts = _extends$1({
			title: content
		}, getOptions(_extends$1({}, value, {
			placement: getPlacement(value, modifiers)
		})));
		var tooltip = el._tooltip = new Tooltip(el, opts);
		tooltip.setClasses(classes);
		tooltip._vueEl = el;

		// Class on target
		var targetClasses = typeof value.targetClasses !== 'undefined' ? value.targetClasses : directive.options.defaultTargetClass;
		el._tooltipTargetClasses = targetClasses;
		addClasses(el, targetClasses);

		return tooltip;
	}

	function destroyTooltip(el) {
		if (el._tooltip) {
			el._tooltip.dispose();
			delete el._tooltip;
			delete el._tooltipOldShow;
		}

		if (el._tooltipTargetClasses) {
			removeClasses(el, el._tooltipTargetClasses);
			delete el._tooltipTargetClasses;
		}
	}

	function bind(el, _ref) {
		var value = _ref.value,
		    oldValue = _ref.oldValue,
		    modifiers = _ref.modifiers;

		var content = getContent(value);
		if (!content || !state.enabled) {
			destroyTooltip(el);
		} else {
			var tooltip = void 0;
			if (el._tooltip) {
				tooltip = el._tooltip;
				// Content
				tooltip.setContent(content);
				// Options
				tooltip.setOptions(_extends$1({}, value, {
					placement: getPlacement(value, modifiers)
				}));
			} else {
				tooltip = createTooltip(el, value, modifiers);
			}

			// Manual show
			if (typeof value.show !== 'undefined' && value.show !== el._tooltipOldShow) {
				el._tooltipOldShow = value.show;
				value.show ? tooltip.show() : tooltip.hide();
			}
		}
	}

	var directive = {
		options: defaultOptions,
		bind: bind,
		update: bind,
		unbind: function unbind(el) {
			destroyTooltip(el);
		}
	};

	function addListeners(el) {
		el.addEventListener('click', onClick);
		el.addEventListener('touchstart', onTouchStart, supportsPassive ? {
			passive: true
		} : false);
	}

	function removeListeners(el) {
		el.removeEventListener('click', onClick);
		el.removeEventListener('touchstart', onTouchStart);
		el.removeEventListener('touchend', onTouchEnd);
		el.removeEventListener('touchcancel', onTouchCancel);
	}

	function onClick(event) {
		var el = event.currentTarget;
		event.closePopover = !el.$_vclosepopover_touch;
		event.closeAllPopover = el.$_closePopoverModifiers && !!el.$_closePopoverModifiers.all;
	}

	function onTouchStart(event) {
		if (event.changedTouches.length === 1) {
			var el = event.currentTarget;
			el.$_vclosepopover_touch = true;
			var touch = event.changedTouches[0];
			el.$_vclosepopover_touchPoint = touch;
			el.addEventListener('touchend', onTouchEnd);
			el.addEventListener('touchcancel', onTouchCancel);
		}
	}

	function onTouchEnd(event) {
		var el = event.currentTarget;
		el.$_vclosepopover_touch = false;
		if (event.changedTouches.length === 1) {
			var touch = event.changedTouches[0];
			var firstTouch = el.$_vclosepopover_touchPoint;
			event.closePopover = Math.abs(touch.screenY - firstTouch.screenY) < 20 && Math.abs(touch.screenX - firstTouch.screenX) < 20;
			event.closeAllPopover = el.$_closePopoverModifiers && !!el.$_closePopoverModifiers.all;
		}
	}

	function onTouchCancel(event) {
		var el = event.currentTarget;
		el.$_vclosepopover_touch = false;
	}

	var vclosepopover = {
		bind: function bind(el, _ref) {
			var value = _ref.value,
			    modifiers = _ref.modifiers;

			el.$_closePopoverModifiers = modifiers;
			if (typeof value === 'undefined' || value) {
				addListeners(el);
			}
		},
		update: function update(el, _ref2) {
			var value = _ref2.value,
			    oldValue = _ref2.oldValue,
			    modifiers = _ref2.modifiers;

			el.$_closePopoverModifiers = modifiers;
			if (value !== oldValue) {
				if (typeof value === 'undefined' || value) {
					addListeners(el);
				} else {
					removeListeners(el);
				}
			}
		},
		unbind: function unbind(el) {
			removeListeners(el);
		}
	};

	function getInternetExplorerVersion() {
		var ua = window.navigator.userAgent;

		var msie = ua.indexOf('MSIE ');
		if (msie > 0) {
			// IE 10 or older => return version number
			return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
		}

		var trident = ua.indexOf('Trident/');
		if (trident > 0) {
			// IE 11 => return version number
			var rv = ua.indexOf('rv:');
			return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
		}

		var edge = ua.indexOf('Edge/');
		if (edge > 0) {
			// Edge (IE 12+) => return version number
			return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
		}

		// other browser
		return -1;
	}

	var isIE$1 = void 0;

	function initCompat() {
		if (!initCompat.init) {
			initCompat.init = true;
			isIE$1 = getInternetExplorerVersion() !== -1;
		}
	}

	var ResizeObserver = { render: function render() {
			var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('div', { staticClass: "resize-observer", attrs: { "tabindex": "-1" } });
		}, staticRenderFns: [], _scopeId: 'data-v-b329ee4c',
		name: 'resize-observer',

		methods: {
			notify: function notify() {
				this.$emit('notify');
			},
			addResizeHandlers: function addResizeHandlers() {
				this._resizeObject.contentDocument.defaultView.addEventListener('resize', this.notify);
				if (this._w !== this.$el.offsetWidth || this._h !== this.$el.offsetHeight) {
					this.notify();
				}
			},
			removeResizeHandlers: function removeResizeHandlers() {
				if (this._resizeObject && this._resizeObject.onload) {
					if (!isIE$1 && this._resizeObject.contentDocument) {
						this._resizeObject.contentDocument.defaultView.removeEventListener('resize', this.notify);
					}
					delete this._resizeObject.onload;
				}
			}
		},

		mounted: function mounted() {
			var _this = this;

			initCompat();
			this.$nextTick(function () {
				_this._w = _this.$el.offsetWidth;
				_this._h = _this.$el.offsetHeight;
			});
			var object = document.createElement('object');
			this._resizeObject = object;
			object.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
			object.setAttribute('aria-hidden', 'true');
			object.setAttribute('tabindex', -1);
			object.onload = this.addResizeHandlers;
			object.type = 'text/html';
			if (isIE$1) {
				this.$el.appendChild(object);
			}
			object.data = 'about:blank';
			if (!isIE$1) {
				this.$el.appendChild(object);
			}
		},
		beforeDestroy: function beforeDestroy() {
			this.removeResizeHandlers();
		}
	};

	// Install the components
	function install$1(Vue) {
		Vue.component('resize-observer', ResizeObserver);
		/* -- Add more components here -- */
	}

	/* -- Plugin definition & Auto-install -- */
	/* You shouldn't have to modify the code below */

	// Plugin
	var plugin$2 = {
		// eslint-disable-next-line no-undef
		version: "0.4.4",
		install: install$1
	};

	// Auto-install
	var GlobalVue$1 = null;
	if (typeof window !== 'undefined') {
		GlobalVue$1 = window.Vue;
	} else if (typeof global !== 'undefined') {
		GlobalVue$1 = global.Vue;
	}
	if (GlobalVue$1) {
		GlobalVue$1.use(plugin$2);
	}

	function getDefault(key) {
		var value = directive.options.popover[key];
		if (typeof value === 'undefined') {
			return directive.options[key];
		}
		return value;
	}

	var isIOS = false;
	if (typeof window !== 'undefined' && typeof navigator !== 'undefined') {
		isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
	}

	var openPopovers = [];

	var Element = function Element() {};
	if (typeof window !== 'undefined') {
		Element = window.Element;
	}

	var Popover = { render: function render() {
			var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('div', { staticClass: "v-popover", class: _vm.cssClass }, [_c('span', { ref: "trigger", staticClass: "trigger", staticStyle: { "display": "inline-block" }, attrs: { "aria-describedby": _vm.popoverId, "tabindex": _vm.trigger.indexOf('focus') !== -1 ? 0 : -1 } }, [_vm._t("default")], 2), _vm._v(" "), _c('div', { ref: "popover", class: [_vm.popoverBaseClass, _vm.popoverClass, _vm.cssClass], style: {
					visibility: _vm.isOpen ? 'visible' : 'hidden'
				}, attrs: { "id": _vm.popoverId, "aria-hidden": _vm.isOpen ? 'false' : 'true' } }, [_c('div', { class: _vm.popoverWrapperClass }, [_c('div', { ref: "inner", class: _vm.popoverInnerClass, staticStyle: { "position": "relative" } }, [_c('div', [_vm._t("popover")], 2), _vm._v(" "), _vm.handleResize ? _c('ResizeObserver', { on: { "notify": _vm.$_handleResize } }) : _vm._e()], 1), _vm._v(" "), _c('div', { ref: "arrow", class: _vm.popoverArrowClass })])])]);
		}, staticRenderFns: [],
		name: 'VPopover',

		components: {
			ResizeObserver: ResizeObserver
		},

		props: {
			open: {
				type: Boolean,
				default: false
			},
			disabled: {
				type: Boolean,
				default: false
			},
			placement: {
				type: String,
				default: function _default() {
					return getDefault('defaultPlacement');
				}
			},
			delay: {
				type: [String, Number, Object],
				default: function _default() {
					return getDefault('defaultDelay');
				}
			},
			offset: {
				type: [String, Number],
				default: function _default() {
					return getDefault('defaultOffset');
				}
			},
			trigger: {
				type: String,
				default: function _default() {
					return getDefault('defaultTrigger');
				}
			},
			container: {
				type: [String, Object, Element, Boolean],
				default: function _default() {
					return getDefault('defaultContainer');
				}
			},
			boundariesElement: {
				type: [String, Element],
				default: function _default() {
					return getDefault('defaultBoundariesElement');
				}
			},
			popperOptions: {
				type: Object,
				default: function _default() {
					return getDefault('defaultPopperOptions');
				}
			},
			popoverClass: {
				type: [String, Array],
				default: function _default() {
					return getDefault('defaultClass');
				}
			},
			popoverBaseClass: {
				type: [String, Array],
				default: function _default() {
					return directive.options.popover.defaultBaseClass;
				}
			},
			popoverInnerClass: {
				type: [String, Array],
				default: function _default() {
					return directive.options.popover.defaultInnerClass;
				}
			},
			popoverWrapperClass: {
				type: [String, Array],
				default: function _default() {
					return directive.options.popover.defaultWrapperClass;
				}
			},
			popoverArrowClass: {
				type: [String, Array],
				default: function _default() {
					return directive.options.popover.defaultArrowClass;
				}
			},
			autoHide: {
				type: Boolean,
				default: function _default() {
					return directive.options.popover.defaultAutoHide;
				}
			},
			handleResize: {
				type: Boolean,
				default: function _default() {
					return directive.options.popover.defaultHandleResize;
				}
			},
			openGroup: {
				type: String,
				default: null
			}
		},

		data: function data() {
			return {
				isOpen: false,
				id: Math.random().toString(36).substr(2, 10)
			};
		},


		computed: {
			cssClass: function cssClass() {
				return {
					'open': this.isOpen
				};
			},
			popoverId: function popoverId() {
				return 'popover_' + this.id;
			}
		},

		watch: {
			open: function open(val) {
				if (val) {
					this.show();
				} else {
					this.hide();
				}
			},
			disabled: function disabled(val, oldVal) {
				if (val !== oldVal) {
					if (val) {
						this.hide();
					} else if (this.open) {
						this.show();
					}
				}
			},
			container: function container(val) {
				if (this.isOpen && this.popperInstance) {
					var popoverNode = this.$refs.popover;
					var reference = this.$refs.trigger;

					var container = this.$_findContainer(this.container, reference);
					if (!container) {
						console.warn('No container for popover', this);
						return;
					}

					container.appendChild(popoverNode);
					this.popperInstance.scheduleUpdate();
				}
			},
			trigger: function trigger(val) {
				this.$_removeEventListeners();
				this.$_addEventListeners();
			},
			placement: function placement(val) {
				var _this = this;

				this.$_updatePopper(function () {
					_this.popperInstance.options.placement = val;
				});
			},


			offset: '$_restartPopper',

			boundariesElement: '$_restartPopper',

			popperOptions: {
				handler: '$_restartPopper',
				deep: true
			}
		},

		created: function created() {
			this.$_isDisposed = false;
			this.$_mounted = false;
			this.$_events = [];
			this.$_preventOpen = false;
		},
		mounted: function mounted() {
			var popoverNode = this.$refs.popover;
			popoverNode.parentNode && popoverNode.parentNode.removeChild(popoverNode);

			this.$_init();

			if (this.open) {
				this.show();
			}
		},
		beforeDestroy: function beforeDestroy() {
			this.dispose();
		},


		methods: {
			show: function show() {
				var _this2 = this;

				var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
				    event = _ref.event,
				    _ref$skipDelay = _ref.skipDelay,
				    _ref$force = _ref.force,
				    force = _ref$force === undefined ? false : _ref$force;

				if (force || !this.disabled) {
					this.$_scheduleShow(event);
					this.$emit('show');
				}
				this.$emit('update:open', true);
				this.$_beingShowed = true;
				requestAnimationFrame(function () {
					_this2.$_beingShowed = false;
				});
			},
			hide: function hide() {
				var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
				    event = _ref2.event,
				    _ref2$skipDelay = _ref2.skipDelay;

				this.$_scheduleHide(event);

				this.$emit('hide');
				this.$emit('update:open', false);
			},
			dispose: function dispose() {
				this.$_isDisposed = true;
				this.$_removeEventListeners();
				this.hide({ skipDelay: true });
				if (this.popperInstance) {
					this.popperInstance.destroy();

					// destroy tooltipNode if removeOnDestroy is not set, as popperInstance.destroy() already removes the element
					if (!this.popperInstance.options.removeOnDestroy) {
						var popoverNode = this.$refs.popover;
						popoverNode.parentNode && popoverNode.parentNode.removeChild(popoverNode);
					}
				}
				this.$_mounted = false;
				this.popperInstance = null;
				this.isOpen = false;

				this.$emit('dispose');
			},
			$_init: function $_init() {
				if (this.trigger.indexOf('manual') === -1) {
					this.$_addEventListeners();
				}
			},
			$_show: function $_show() {
				var _this3 = this;

				var reference = this.$refs.trigger;
				var popoverNode = this.$refs.popover;

				clearTimeout(this.$_disposeTimer);

				// Already open
				if (this.isOpen) {
					return;
				}

				// Popper is already initialized
				if (this.popperInstance) {
					this.isOpen = true;
					this.popperInstance.enableEventListeners();
					this.popperInstance.scheduleUpdate();
				}

				if (!this.$_mounted) {
					var container = this.$_findContainer(this.container, reference);
					if (!container) {
						console.warn('No container for popover', this);
						return;
					}
					container.appendChild(popoverNode);
					this.$_mounted = true;
				}

				if (!this.popperInstance) {
					var popperOptions = _extends$1({}, this.popperOptions, {
						placement: this.placement
					});

					popperOptions.modifiers = _extends$1({}, popperOptions.modifiers, {
						arrow: _extends$1({}, popperOptions.modifiers && popperOptions.modifiers.arrow, {
							element: this.$refs.arrow
						})
					});

					if (this.offset) {
						var offset = this.$_getOffset();

						popperOptions.modifiers.offset = _extends$1({}, popperOptions.modifiers && popperOptions.modifiers.offset, {
							offset: offset
						});
					}

					if (this.boundariesElement) {
						popperOptions.modifiers.preventOverflow = _extends$1({}, popperOptions.modifiers && popperOptions.modifiers.preventOverflow, {
							boundariesElement: this.boundariesElement
						});
					}

					this.popperInstance = new Popper(reference, popoverNode, popperOptions);

					// Fix position
					requestAnimationFrame(function () {
						if (!_this3.$_isDisposed && _this3.popperInstance) {
							_this3.popperInstance.scheduleUpdate();

							// Show the tooltip
							requestAnimationFrame(function () {
								if (!_this3.$_isDisposed) {
									_this3.isOpen = true;
								} else {
									_this3.dispose();
								}
							});
						} else {
							_this3.dispose();
						}
					});
				}

				var openGroup = this.openGroup;
				if (openGroup) {
					var popover = void 0;
					for (var i = 0; i < openPopovers.length; i++) {
						popover = openPopovers[i];
						if (popover.openGroup !== openGroup) {
							popover.hide();
							popover.$emit('close-group');
						}
					}
				}

				openPopovers.push(this);

				this.$emit('apply-show');
			},
			$_hide: function $_hide() {
				var _this4 = this;

				// Already hidden
				if (!this.isOpen) {
					return;
				}

				var index = openPopovers.indexOf(this);
				if (index !== -1) {
					openPopovers.splice(index, 1);
				}

				this.isOpen = false;
				if (this.popperInstance) {
					this.popperInstance.disableEventListeners();
				}

				clearTimeout(this.$_disposeTimer);
				var disposeTime = directive.options.popover.disposeTimeout || directive.options.disposeTimeout;
				if (disposeTime !== null) {
					this.$_disposeTimer = setTimeout(function () {
						var popoverNode = _this4.$refs.popover;
						if (popoverNode) {
							// Don't remove popper instance, just the HTML element
							popoverNode.parentNode && popoverNode.parentNode.removeChild(popoverNode);
							_this4.$_mounted = false;
						}
					}, disposeTime);
				}

				this.$emit('apply-hide');
			},
			$_findContainer: function $_findContainer(container, reference) {
				// if container is a query, get the relative element
				if (typeof container === 'string') {
					container = window.document.querySelector(container);
				} else if (container === false) {
					// if container is `false`, set it to reference parent
					container = reference.parentNode;
				}
				return container;
			},
			$_getOffset: function $_getOffset() {
				var typeofOffset = _typeof(this.offset);
				var offset = this.offset;

				// One value -> switch
				if (typeofOffset === 'number' || typeofOffset === 'string' && offset.indexOf(',') === -1) {
					offset = '0, ' + offset;
				}

				return offset;
			},
			$_addEventListeners: function $_addEventListeners() {
				var _this5 = this;

				var reference = this.$refs.trigger;
				var directEvents = [];
				var oppositeEvents = [];

				var events = typeof this.trigger === 'string' ? this.trigger.split(' ').filter(function (trigger) {
					return ['click', 'hover', 'focus'].indexOf(trigger) !== -1;
				}) : [];

				events.forEach(function (event) {
					switch (event) {
						case 'hover':
							directEvents.push('mouseenter');
							oppositeEvents.push('mouseleave');
							break;
						case 'focus':
							directEvents.push('focus');
							oppositeEvents.push('blur');
							break;
						case 'click':
							directEvents.push('click');
							oppositeEvents.push('click');
							break;
					}
				});

				// schedule show tooltip
				directEvents.forEach(function (event) {
					var func = function func(event) {
						if (_this5.isOpen) {
							return;
						}
						event.usedByTooltip = true;
						!_this5.$_preventOpen && _this5.show({ event: event });
					};
					_this5.$_events.push({ event: event, func: func });
					reference.addEventListener(event, func);
				});

				// schedule hide tooltip
				oppositeEvents.forEach(function (event) {
					var func = function func(event) {
						if (event.usedByTooltip) {
							return;
						}
						_this5.hide({ event: event });
					};
					_this5.$_events.push({ event: event, func: func });
					reference.addEventListener(event, func);
				});
			},
			$_scheduleShow: function $_scheduleShow() {
				var skipDelay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

				clearTimeout(this.$_scheduleTimer);
				if (skipDelay) {
					this.$_show();
				} else {
					// defaults to 0
					var computedDelay = parseInt(this.delay && this.delay.show || this.delay || 0);
					this.$_scheduleTimer = setTimeout(this.$_show.bind(this), computedDelay);
				}
			},
			$_scheduleHide: function $_scheduleHide() {
				var _this6 = this;

				var event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
				var skipDelay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

				clearTimeout(this.$_scheduleTimer);
				if (skipDelay) {
					this.$_hide();
				} else {
					// defaults to 0
					var computedDelay = parseInt(this.delay && this.delay.hide || this.delay || 0);
					this.$_scheduleTimer = setTimeout(function () {
						if (!_this6.isOpen) {
							return;
						}

						// if we are hiding because of a mouseleave, we must check that the new
						// reference isn't the tooltip, because in this case we don't want to hide it
						if (event && event.type === 'mouseleave') {
							var isSet = _this6.$_setTooltipNodeEvent(event);

							// if we set the new event, don't hide the tooltip yet
							// the new event will take care to hide it if necessary
							if (isSet) {
								return;
							}
						}

						_this6.$_hide();
					}, computedDelay);
				}
			},
			$_setTooltipNodeEvent: function $_setTooltipNodeEvent(event) {
				var _this7 = this;

				var reference = this.$refs.trigger;
				var popoverNode = this.$refs.popover;

				var relatedreference = event.relatedreference || event.toElement || event.relatedTarget;

				var callback = function callback(event2) {
					var relatedreference2 = event2.relatedreference || event2.toElement || event2.relatedTarget;

					// Remove event listener after call
					popoverNode.removeEventListener(event.type, callback);

					// If the new reference is not the reference element
					if (!reference.contains(relatedreference2)) {
						// Schedule to hide tooltip
						_this7.hide({ event: event2 });
					}
				};

				if (popoverNode.contains(relatedreference)) {
					// listen to mouseleave on the tooltip element to be able to hide the tooltip
					popoverNode.addEventListener(event.type, callback);
					return true;
				}

				return false;
			},
			$_removeEventListeners: function $_removeEventListeners() {
				var reference = this.$refs.trigger;
				this.$_events.forEach(function (_ref3) {
					var func = _ref3.func,
					    event = _ref3.event;

					reference.removeEventListener(event, func);
				});
				this.$_events = [];
			},
			$_updatePopper: function $_updatePopper(cb) {
				if (this.popperInstance) {
					cb();
					if (this.isOpen) this.popperInstance.scheduleUpdate();
				}
			},
			$_restartPopper: function $_restartPopper() {
				if (this.popperInstance) {
					var isOpen = this.isOpen;
					this.dispose();
					this.$_isDisposed = false;
					this.$_init();
					if (isOpen) {
						this.show({ skipDelay: true, force: true });
					}
				}
			},
			$_handleGlobalClose: function $_handleGlobalClose(event) {
				var _this8 = this;

				var touch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

				if (this.$_beingShowed) return;

				this.hide({ event: event });

				if (event.closePopover) {
					this.$emit('close-directive');
				} else {
					this.$emit('auto-hide');
				}

				if (touch) {
					this.$_preventOpen = true;
					setTimeout(function () {
						_this8.$_preventOpen = false;
					}, 300);
				}
			},
			$_handleResize: function $_handleResize() {
				if (this.isOpen && this.popperInstance) {
					this.popperInstance.scheduleUpdate();
					this.$emit('resize');
				}
			}
		}
	};

	if (typeof document !== 'undefined' && typeof window !== 'undefined') {
		if (isIOS) {
			document.addEventListener('touchend', handleGlobalTouchend, supportsPassive ? {
				passive: true,
				capture: true
			} : true);
		} else {
			window.addEventListener('click', handleGlobalClick, true);
		}
	}

	function handleGlobalClick(event) {
		handleGlobalClose(event);
	}

	function handleGlobalTouchend(event) {
		handleGlobalClose(event, true);
	}

	function handleGlobalClose(event) {
		var touch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

		// Delay so that close directive has time to set values
		requestAnimationFrame(function () {
			var popover = void 0;
			for (var i = 0; i < openPopovers.length; i++) {
				popover = openPopovers[i];
				if (popover.$refs.popover) {
					var contains = popover.$refs.popover.contains(event.target);
					if (event.closeAllPopover || event.closePopover && contains || popover.autoHide && !contains) {
						popover.$_handleGlobalClose(event, touch);
					}
				}
			}
		});
	}

	var commonjsGlobal$1 = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};





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

	var lodash_merge = createCommonjsModule$1(function (module, exports) {
	/**
	 * Lodash (Custom Build) <https://lodash.com/>
	 * Build: `lodash modularize exports="npm" -o ./`
	 * Copyright JS Foundation and other contributors <https://js.foundation/>
	 * Released under MIT license <https://lodash.com/license>
	 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
	 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
	 */

	/** Used as the size to enable large array optimizations. */
	var LARGE_ARRAY_SIZE = 200;

	/** Used to stand-in for `undefined` hash values. */
	var HASH_UNDEFINED = '__lodash_hash_undefined__';

	/** Used to detect hot functions by number of calls within a span of milliseconds. */
	var HOT_COUNT = 800,
	    HOT_SPAN = 16;

	/** Used as references for various `Number` constants. */
	var MAX_SAFE_INTEGER = 9007199254740991;

	/** `Object#toString` result references. */
	var argsTag = '[object Arguments]',
	    arrayTag = '[object Array]',
	    asyncTag = '[object AsyncFunction]',
	    boolTag = '[object Boolean]',
	    dateTag = '[object Date]',
	    errorTag = '[object Error]',
	    funcTag = '[object Function]',
	    genTag = '[object GeneratorFunction]',
	    mapTag = '[object Map]',
	    numberTag = '[object Number]',
	    nullTag = '[object Null]',
	    objectTag = '[object Object]',
	    proxyTag = '[object Proxy]',
	    regexpTag = '[object RegExp]',
	    setTag = '[object Set]',
	    stringTag = '[object String]',
	    undefinedTag = '[object Undefined]',
	    weakMapTag = '[object WeakMap]';

	var arrayBufferTag = '[object ArrayBuffer]',
	    dataViewTag = '[object DataView]',
	    float32Tag = '[object Float32Array]',
	    float64Tag = '[object Float64Array]',
	    int8Tag = '[object Int8Array]',
	    int16Tag = '[object Int16Array]',
	    int32Tag = '[object Int32Array]',
	    uint8Tag = '[object Uint8Array]',
	    uint8ClampedTag = '[object Uint8ClampedArray]',
	    uint16Tag = '[object Uint16Array]',
	    uint32Tag = '[object Uint32Array]';

	/**
	 * Used to match `RegExp`
	 * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
	 */
	var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;

	/** Used to detect host constructors (Safari). */
	var reIsHostCtor = /^\[object .+?Constructor\]$/;

	/** Used to detect unsigned integer values. */
	var reIsUint = /^(?:0|[1-9]\d*)$/;

	/** Used to identify `toStringTag` values of typed arrays. */
	var typedArrayTags = {};
	typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
	typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
	typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
	typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
	typedArrayTags[uint32Tag] = true;
	typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
	typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
	typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
	typedArrayTags[errorTag] = typedArrayTags[funcTag] =
	typedArrayTags[mapTag] = typedArrayTags[numberTag] =
	typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
	typedArrayTags[setTag] = typedArrayTags[stringTag] =
	typedArrayTags[weakMapTag] = false;

	/** Detect free variable `global` from Node.js. */
	var freeGlobal = typeof commonjsGlobal$1 == 'object' && commonjsGlobal$1 && commonjsGlobal$1.Object === Object && commonjsGlobal$1;

	/** Detect free variable `self`. */
	var freeSelf = typeof self == 'object' && self && self.Object === Object && self;

	/** Used as a reference to the global object. */
	var root = freeGlobal || freeSelf || Function('return this')();

	/** Detect free variable `exports`. */
	var freeExports =  exports && !exports.nodeType && exports;

	/** Detect free variable `module`. */
	var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;

	/** Detect the popular CommonJS extension `module.exports`. */
	var moduleExports = freeModule && freeModule.exports === freeExports;

	/** Detect free variable `process` from Node.js. */
	var freeProcess = moduleExports && freeGlobal.process;

	/** Used to access faster Node.js helpers. */
	var nodeUtil = (function() {
	  try {
	    return freeProcess && freeProcess.binding && freeProcess.binding('util');
	  } catch (e) {}
	}());

	/* Node.js helper references. */
	var nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;

	/**
	 * A faster alternative to `Function#apply`, this function invokes `func`
	 * with the `this` binding of `thisArg` and the arguments of `args`.
	 *
	 * @private
	 * @param {Function} func The function to invoke.
	 * @param {*} thisArg The `this` binding of `func`.
	 * @param {Array} args The arguments to invoke `func` with.
	 * @returns {*} Returns the result of `func`.
	 */
	function apply(func, thisArg, args) {
	  switch (args.length) {
	    case 0: return func.call(thisArg);
	    case 1: return func.call(thisArg, args[0]);
	    case 2: return func.call(thisArg, args[0], args[1]);
	    case 3: return func.call(thisArg, args[0], args[1], args[2]);
	  }
	  return func.apply(thisArg, args);
	}

	/**
	 * The base implementation of `_.times` without support for iteratee shorthands
	 * or max array length checks.
	 *
	 * @private
	 * @param {number} n The number of times to invoke `iteratee`.
	 * @param {Function} iteratee The function invoked per iteration.
	 * @returns {Array} Returns the array of results.
	 */
	function baseTimes(n, iteratee) {
	  var index = -1,
	      result = Array(n);

	  while (++index < n) {
	    result[index] = iteratee(index);
	  }
	  return result;
	}

	/**
	 * The base implementation of `_.unary` without support for storing metadata.
	 *
	 * @private
	 * @param {Function} func The function to cap arguments for.
	 * @returns {Function} Returns the new capped function.
	 */
	function baseUnary(func) {
	  return function(value) {
	    return func(value);
	  };
	}

	/**
	 * 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];
	}

	/**
	 * Creates a unary function that invokes `func` with its argument transformed.
	 *
	 * @private
	 * @param {Function} func The function to wrap.
	 * @param {Function} transform The argument transform.
	 * @returns {Function} Returns the new function.
	 */
	function overArg(func, transform) {
	  return function(arg) {
	    return func(transform(arg));
	  };
	}

	/**
	 * Gets the value at `key`, unless `key` is "__proto__".
	 *
	 * @private
	 * @param {Object} object The object to query.
	 * @param {string} key The key of the property to get.
	 * @returns {*} Returns the property value.
	 */
	function safeGet(object, key) {
	  return key == '__proto__'
	    ? undefined
	    : object[key];
	}

	/** 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 resolve the decompiled source of functions. */
	var funcToString = funcProto.toString;

	/** Used to check objects for own properties. */
	var hasOwnProperty = objectProto.hasOwnProperty;

	/** 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
	 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
	 * of values.
	 */
	var nativeObjectToString = objectProto.toString;

	/** Used to infer the `Object` constructor. */
	var objectCtorString = funcToString.call(Object);

	/** 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 Buffer = moduleExports ? root.Buffer : undefined,
	    Symbol = root.Symbol,
	    Uint8Array = root.Uint8Array,
	    allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
	    getPrototype = overArg(Object.getPrototypeOf, Object),
	    objectCreate = Object.create,
	    propertyIsEnumerable = objectProto.propertyIsEnumerable,
	    splice = arrayProto.splice,
	    symToStringTag = Symbol ? Symbol.toStringTag : undefined;

	var defineProperty = (function() {
	  try {
	    var func = getNative(Object, 'defineProperty');
	    func({}, '', {});
	    return func;
	  } catch (e) {}
	}());

	/* Built-in method references for those with the same name as other `lodash` methods. */
	var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
	    nativeMax = Math.max,
	    nativeNow = Date.now;

	/* Built-in method references that are verified to be native. */
	var Map = getNative(root, 'Map'),
	    nativeCreate = getNative(Object, 'create');

	/**
	 * The base implementation of `_.create` without support for assigning
	 * properties to the created object.
	 *
	 * @private
	 * @param {Object} proto The object to inherit from.
	 * @returns {Object} Returns the new object.
	 */
	var baseCreate = (function() {
	  function object() {}
	  return function(proto) {
	    if (!isObject(proto)) {
	      return {};
	    }
	    if (objectCreate) {
	      return objectCreate(proto);
	    }
	    object.prototype = proto;
	    var result = new object;
	    object.prototype = undefined;
	    return result;
	  };
	}());

	/**
	 * Creates a hash object.
	 *
	 * @private
	 * @constructor
	 * @param {Array} [entries] The key-value pairs to cache.
	 */
	function Hash(entries) {
	  var index = -1,
	      length = entries == null ? 0 : entries.length;

	  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) : {};
	  this.size = 0;
	}

	/**
	 * 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) {
	  var result = this.has(key) && delete this.__data__[key];
	  this.size -= result ? 1 : 0;
	  return result;
	}

	/**
	 * 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__;
	  this.size += this.has(key) ? 0 : 1;
	  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 == null ? 0 : entries.length;

	  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__ = [];
	  this.size = 0;
	}

	/**
	 * 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);
	  }
	  --this.size;
	  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) {
	    ++this.size;
	    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 == null ? 0 : entries.length;

	  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.size = 0;
	  this.__data__ = {
	    'hash': new Hash,
	    'map': new (Map || 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) {
	  var result = getMapData(this, key)['delete'](key);
	  this.size -= result ? 1 : 0;
	  return result;
	}

	/**
	 * 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) {
	  var data = getMapData(this, key),
	      size = data.size;

	  data.set(key, value);
	  this.size += data.size == size ? 0 : 1;
	  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;

	/**
	 * Creates a stack cache object to store key-value pairs.
	 *
	 * @private
	 * @constructor
	 * @param {Array} [entries] The key-value pairs to cache.
	 */
	function Stack(entries) {
	  var data = this.__data__ = new ListCache(entries);
	  this.size = data.size;
	}

	/**
	 * Removes all key-value entries from the stack.
	 *
	 * @private
	 * @name clear
	 * @memberOf Stack
	 */
	function stackClear() {
	  this.__data__ = new ListCache;
	  this.size = 0;
	}

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

	  this.size = data.size;
	  return result;
	}

	/**
	 * Gets the stack value for `key`.
	 *
	 * @private
	 * @name get
	 * @memberOf Stack
	 * @param {string} key The key of the value to get.
	 * @returns {*} Returns the entry value.
	 */
	function stackGet(key) {
	  return this.__data__.get(key);
	}

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

	/**
	 * Sets the stack `key` to `value`.
	 *
	 * @private
	 * @name set
	 * @memberOf Stack
	 * @param {string} key The key of the value to set.
	 * @param {*} value The value to set.
	 * @returns {Object} Returns the stack cache instance.
	 */
	function stackSet(key, value) {
	  var data = this.__data__;
	  if (data instanceof ListCache) {
	    var pairs = data.__data__;
	    if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
	      pairs.push([key, value]);
	      this.size = ++data.size;
	      return this;
	    }
	    data = this.__data__ = new MapCache(pairs);
	  }
	  data.set(key, value);
	  this.size = data.size;
	  return this;
	}

	// Add methods to `Stack`.
	Stack.prototype.clear = stackClear;
	Stack.prototype['delete'] = stackDelete;
	Stack.prototype.get = stackGet;
	Stack.prototype.has = stackHas;
	Stack.prototype.set = stackSet;

	/**
	 * Creates an array of the enumerable property names of the array-like `value`.
	 *
	 * @private
	 * @param {*} value The value to query.
	 * @param {boolean} inherited Specify returning inherited property names.
	 * @returns {Array} Returns the array of property names.
	 */
	function arrayLikeKeys(value, inherited) {
	  var isArr = isArray(value),
	      isArg = !isArr && isArguments(value),
	      isBuff = !isArr && !isArg && isBuffer(value),
	      isType = !isArr && !isArg && !isBuff && isTypedArray(value),
	      skipIndexes = isArr || isArg || isBuff || isType,
	      result = skipIndexes ? baseTimes(value.length, String) : [],
	      length = result.length;

	  for (var key in value) {
	    if ((inherited || hasOwnProperty.call(value, key)) &&
	        !(skipIndexes && (
	           // Safari 9 has enumerable `arguments.length` in strict mode.
	           key == 'length' ||
	           // Node.js 0.10 has enumerable non-index properties on buffers.
	           (isBuff && (key == 'offset' || key == 'parent')) ||
	           // PhantomJS 2 has enumerable non-index properties on typed arrays.
	           (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
	           // Skip index properties.
	           isIndex(key, length)
	        ))) {
	      result.push(key);
	    }
	  }
	  return result;
	}

	/**
	 * This function is like `assignValue` except that it doesn't assign
	 * `undefined` values.
	 *
	 * @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 assignMergeValue(object, key, value) {
	  if ((value !== undefined && !eq(object[key], value)) ||
	      (value === undefined && !(key in object))) {
	    baseAssignValue(object, key, value);
	  }
	}

	/**
	 * 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);
	  }
	}

	/**
	 * 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 `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__' && defineProperty) {
	    defineProperty(object, key, {
	      'configurable': true,
	      'enumerable': true,
	      'value': value,
	      'writable': true
	    });
	  } else {
	    object[key] = value;
	  }
	}

	/**
	 * The base implementation of `baseForOwn` which iterates over `object`
	 * properties returned by `keysFunc` and invokes `iteratee` for each property.
	 * Iteratee functions may exit iteration early by explicitly returning `false`.
	 *
	 * @private
	 * @param {Object} object The object to iterate over.
	 * @param {Function} iteratee The function invoked per iteration.
	 * @param {Function} keysFunc The function to get the keys of `object`.
	 * @returns {Object} Returns `object`.
	 */
	var baseFor = createBaseFor();

	/**
	 * The base implementation of `getTag` without fallbacks for buggy environments.
	 *
	 * @private
	 * @param {*} value The value to query.
	 * @returns {string} Returns the `toStringTag`.
	 */
	function baseGetTag(value) {
	  if (value == null) {
	    return value === undefined ? undefinedTag : nullTag;
	  }
	  return (symToStringTag && symToStringTag in Object(value))
	    ? getRawTag(value)
	    : objectToString(value);
	}

	/**
	 * The base implementation of `_.isArguments`.
	 *
	 * @private
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is an `arguments` object,
	 */
	function baseIsArguments(value) {
	  return isObjectLike(value) && baseGetTag(value) == argsTag;
	}

	/**
	 * 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) ? reIsNative : reIsHostCtor;
	  return pattern.test(toSource(value));
	}

	/**
	 * The base implementation of `_.isTypedArray` without Node.js optimizations.
	 *
	 * @private
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
	 */
	function baseIsTypedArray(value) {
	  return isObjectLike(value) &&
	    isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
	}

	/**
	 * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
	 *
	 * @private
	 * @param {Object} object The object to query.
	 * @returns {Array} Returns the array of property names.
	 */
	function baseKeysIn(object) {
	  if (!isObject(object)) {
	    return nativeKeysIn(object);
	  }
	  var isProto = isPrototype(object),
	      result = [];

	  for (var key in object) {
	    if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
	      result.push(key);
	    }
	  }
	  return result;
	}

	/**
	 * The base implementation of `_.merge` without support for multiple sources.
	 *
	 * @private
	 * @param {Object} object The destination object.
	 * @param {Object} source The source object.
	 * @param {number} srcIndex The index of `source`.
	 * @param {Function} [customizer] The function to customize merged values.
	 * @param {Object} [stack] Tracks traversed source values and their merged
	 *  counterparts.
	 */
	function baseMerge(object, source, srcIndex, customizer, stack) {
	  if (object === source) {
	    return;
	  }
	  baseFor(source, function(srcValue, key) {
	    if (isObject(srcValue)) {
	      stack || (stack = new Stack);
	      baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
	    }
	    else {
	      var newValue = customizer
	        ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)
	        : undefined;

	      if (newValue === undefined) {
	        newValue = srcValue;
	      }
	      assignMergeValue(object, key, newValue);
	    }
	  }, keysIn);
	}

	/**
	 * A specialized version of `baseMerge` for arrays and objects which performs
	 * deep merges and tracks traversed objects enabling objects with circular
	 * references to be merged.
	 *
	 * @private
	 * @param {Object} object The destination object.
	 * @param {Object} source The source object.
	 * @param {string} key The key of the value to merge.
	 * @param {number} srcIndex The index of `source`.
	 * @param {Function} mergeFunc The function to merge values.
	 * @param {Function} [customizer] The function to customize assigned values.
	 * @param {Object} [stack] Tracks traversed source values and their merged
	 *  counterparts.
	 */
	function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
	  var objValue = safeGet(object, key),
	      srcValue = safeGet(source, key),
	      stacked = stack.get(srcValue);

	  if (stacked) {
	    assignMergeValue(object, key, stacked);
	    return;
	  }
	  var newValue = customizer
	    ? customizer(objValue, srcValue, (key + ''), object, source, stack)
	    : undefined;

	  var isCommon = newValue === undefined;

	  if (isCommon) {
	    var isArr = isArray(srcValue),
	        isBuff = !isArr && isBuffer(srcValue),
	        isTyped = !isArr && !isBuff && isTypedArray(srcValue);

	    newValue = srcValue;
	    if (isArr || isBuff || isTyped) {
	      if (isArray(objValue)) {
	        newValue = objValue;
	      }
	      else if (isArrayLikeObject(objValue)) {
	        newValue = copyArray(objValue);
	      }
	      else if (isBuff) {
	        isCommon = false;
	        newValue = cloneBuffer(srcValue, true);
	      }
	      else if (isTyped) {
	        isCommon = false;
	        newValue = cloneTypedArray(srcValue, true);
	      }
	      else {
	        newValue = [];
	      }
	    }
	    else if (isPlainObject(srcValue) || isArguments(srcValue)) {
	      newValue = objValue;
	      if (isArguments(objValue)) {
	        newValue = toPlainObject(objValue);
	      }
	      else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
	        newValue = initCloneObject(srcValue);
	      }
	    }
	    else {
	      isCommon = false;
	    }
	  }
	  if (isCommon) {
	    // Recursively merge objects and arrays (susceptible to call stack limits).
	    stack.set(srcValue, newValue);
	    mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
	    stack['delete'](srcValue);
	  }
	  assignMergeValue(object, key, newValue);
	}

	/**
	 * The base implementation of `_.rest` which doesn't validate or coerce arguments.
	 *
	 * @private
	 * @param {Function} func The function to apply a rest parameter to.
	 * @param {number} [start=func.length-1] The start position of the rest parameter.
	 * @returns {Function} Returns the new function.
	 */
	function baseRest(func, start) {
	  return setToString(overRest(func, start, identity), func + '');
	}

	/**
	 * The base implementation of `setToString` without support for hot loop shorting.
	 *
	 * @private
	 * @param {Function} func The function to modify.
	 * @param {Function} string The `toString` result.
	 * @returns {Function} Returns `func`.
	 */
	var baseSetToString = !defineProperty ? identity : function(func, string) {
	  return defineProperty(func, 'toString', {
	    'configurable': true,
	    'enumerable': false,
	    'value': constant(string),
	    'writable': true
	  });
	};

	/**
	 * Creates a clone of  `buffer`.
	 *
	 * @private
	 * @param {Buffer} buffer The buffer to clone.
	 * @param {boolean} [isDeep] Specify a deep clone.
	 * @returns {Buffer} Returns the cloned buffer.
	 */
	function cloneBuffer(buffer, isDeep) {
	  if (isDeep) {
	    return buffer.slice();
	  }
	  var length = buffer.length,
	      result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);

	  buffer.copy(result);
	  return result;
	}

	/**
	 * Creates a clone of `arrayBuffer`.
	 *
	 * @private
	 * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
	 * @returns {ArrayBuffer} Returns the cloned array buffer.
	 */
	function cloneArrayBuffer(arrayBuffer) {
	  var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
	  new Uint8Array(result).set(new Uint8Array(arrayBuffer));
	  return result;
	}

	/**
	 * Creates a clone of `typedArray`.
	 *
	 * @private
	 * @param {Object} typedArray The typed array to clone.
	 * @param {boolean} [isDeep] Specify a deep clone.
	 * @returns {Object} Returns the cloned typed array.
	 */
	function cloneTypedArray(typedArray, isDeep) {
	  var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
	  return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
	}

	/**
	 * Copies the values of `source` to `array`.
	 *
	 * @private
	 * @param {Array} source The array to copy values from.
	 * @param {Array} [array=[]] The array to copy values to.
	 * @returns {Array} Returns `array`.
	 */
	function copyArray(source, array) {
	  var index = -1,
	      length = source.length;

	  array || (array = Array(length));
	  while (++index < length) {
	    array[index] = source[index];
	  }
	  return array;
	}

	/**
	 * Copies properties of `source` to `object`.
	 *
	 * @private
	 * @param {Object} source The object to copy properties from.
	 * @param {Array} props The property identifiers to copy.
	 * @param {Object} [object={}] The object to copy properties to.
	 * @param {Function} [customizer] The function to customize copied values.
	 * @returns {Object} Returns `object`.
	 */
	function copyObject(source, props, object, customizer) {
	  var isNew = !object;
	  object || (object = {});

	  var index = -1,
	      length = props.length;

	  while (++index < length) {
	    var key = props[index];

	    var newValue = customizer
	      ? customizer(object[key], source[key], key, object, source)
	      : undefined;

	    if (newValue === undefined) {
	      newValue = source[key];
	    }
	    if (isNew) {
	      baseAssignValue(object, key, newValue);
	    } else {
	      assignValue(object, key, newValue);
	    }
	  }
	  return object;
	}

	/**
	 * Creates a function like `_.assign`.
	 *
	 * @private
	 * @param {Function} assigner The function to assign values.
	 * @returns {Function} Returns the new assigner function.
	 */
	function createAssigner(assigner) {
	  return baseRest(function(object, sources) {
	    var index = -1,
	        length = sources.length,
	        customizer = length > 1 ? sources[length - 1] : undefined,
	        guard = length > 2 ? sources[2] : undefined;

	    customizer = (assigner.length > 3 && typeof customizer == 'function')
	      ? (length--, customizer)
	      : undefined;

	    if (guard && isIterateeCall(sources[0], sources[1], guard)) {
	      customizer = length < 3 ? undefined : customizer;
	      length = 1;
	    }
	    object = Object(object);
	    while (++index < length) {
	      var source = sources[index];
	      if (source) {
	        assigner(object, source, index, customizer);
	      }
	    }
	    return object;
	  });
	}

	/**
	 * Creates a base function for methods like `_.forIn` and `_.forOwn`.
	 *
	 * @private
	 * @param {boolean} [fromRight] Specify iterating from right to left.
	 * @returns {Function} Returns the new base function.
	 */
	function createBaseFor(fromRight) {
	  return function(object, iteratee, keysFunc) {
	    var index = -1,
	        iterable = Object(object),
	        props = keysFunc(object),
	        length = props.length;

	    while (length--) {
	      var key = props[fromRight ? length : ++index];
	      if (iteratee(iterable[key], key, iterable) === false) {
	        break;
	      }
	    }
	    return object;
	  };
	}

	/**
	 * 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;
	}

	/**
	 * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
	 *
	 * @private
	 * @param {*} value The value to query.
	 * @returns {string} Returns the raw `toStringTag`.
	 */
	function getRawTag(value) {
	  var isOwn = hasOwnProperty.call(value, symToStringTag),
	      tag = value[symToStringTag];

	  try {
	    value[symToStringTag] = undefined;
	    var unmasked = true;
	  } catch (e) {}

	  var result = nativeObjectToString.call(value);
	  if (unmasked) {
	    if (isOwn) {
	      value[symToStringTag] = tag;
	    } else {
	      delete value[symToStringTag];
	    }
	  }
	  return result;
	}

	/**
	 * Initializes an object clone.
	 *
	 * @private
	 * @param {Object} object The object to clone.
	 * @returns {Object} Returns the initialized clone.
	 */
	function initCloneObject(object) {
	  return (typeof object.constructor == 'function' && !isPrototype(object))
	    ? baseCreate(getPrototype(object))
	    : {};
	}

	/**
	 * 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);
	}

	/**
	 * Checks if the given arguments are from an iteratee call.
	 *
	 * @private
	 * @param {*} value The potential iteratee value argument.
	 * @param {*} index The potential iteratee index or key argument.
	 * @param {*} object The potential iteratee object argument.
	 * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
	 *  else `false`.
	 */
	function isIterateeCall(value, index, object) {
	  if (!isObject(object)) {
	    return false;
	  }
	  var type = typeof index;
	  if (type == 'number'
	        ? (isArrayLike(object) && isIndex(index, object.length))
	        : (type == 'string' && index in object)
	      ) {
	    return eq(object[index], value);
	  }
	  return false;
	}

	/**
	 * 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);
	}

	/**
	 * Checks if `value` is likely a prototype object.
	 *
	 * @private
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
	 */
	function isPrototype(value) {
	  var Ctor = value && value.constructor,
	      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;

	  return value === proto;
	}

	/**
	 * This function is like
	 * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
	 * except that it includes inherited enumerable properties.
	 *
	 * @private
	 * @param {Object} object The object to query.
	 * @returns {Array} Returns the array of property names.
	 */
	function nativeKeysIn(object) {
	  var result = [];
	  if (object != null) {
	    for (var key in Object(object)) {
	      result.push(key);
	    }
	  }
	  return result;
	}

	/**
	 * Converts `value` to a string using `Object.prototype.toString`.
	 *
	 * @private
	 * @param {*} value The value to convert.
	 * @returns {string} Returns the converted string.
	 */
	function objectToString(value) {
	  return nativeObjectToString.call(value);
	}

	/**
	 * A specialized version of `baseRest` which transforms the rest array.
	 *
	 * @private
	 * @param {Function} func The function to apply a rest parameter to.
	 * @param {number} [start=func.length-1] The start position of the rest parameter.
	 * @param {Function} transform The rest array transform.
	 * @returns {Function} Returns the new function.
	 */
	function overRest(func, start, transform) {
	  start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
	  return function() {
	    var args = arguments,
	        index = -1,
	        length = nativeMax(args.length - start, 0),
	        array = Array(length);

	    while (++index < length) {
	      array[index] = args[start + index];
	    }
	    index = -1;
	    var otherArgs = Array(start + 1);
	    while (++index < start) {
	      otherArgs[index] = args[index];
	    }
	    otherArgs[start] = transform(array);
	    return apply(func, this, otherArgs);
	  };
	}

	/**
	 * Sets the `toString` method of `func` to return `string`.
	 *
	 * @private
	 * @param {Function} func The function to modify.
	 * @param {Function} string The `toString` result.
	 * @returns {Function} Returns `func`.
	 */
	var setToString = shortOut(baseSetToString);

	/**
	 * Creates a function that'll short out and invoke `identity` instead
	 * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
	 * milliseconds.
	 *
	 * @private
	 * @param {Function} func The function to restrict.
	 * @returns {Function} Returns the new shortable function.
	 */
	function shortOut(func) {
	  var count = 0,
	      lastCalled = 0;

	  return function() {
	    var stamp = nativeNow(),
	        remaining = HOT_SPAN - (stamp - lastCalled);

	    lastCalled = stamp;
	    if (remaining > 0) {
	      if (++count >= HOT_COUNT) {
	        return arguments[0];
	      }
	    } else {
	      count = 0;
	    }
	    return func.apply(undefined, arguments);
	  };
	}

	/**
	 * Converts `func` to its source code.
	 *
	 * @private
	 * @param {Function} func The function to convert.
	 * @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 '';
	}

	/**
	 * 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 likely an `arguments` object.
	 *
	 * @static
	 * @memberOf _
	 * @since 0.1.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is an `arguments` object,
	 *  else `false`.
	 * @example
	 *
	 * _.isArguments(function() { return arguments; }());
	 * // => true
	 *
	 * _.isArguments([1, 2, 3]);
	 * // => false
	 */
	var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
	  return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
	    !propertyIsEnumerable.call(value, 'callee');
	};

	/**
	 * 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 array-like. A value is considered array-like if it's
	 * not a function and has a `value.length` that's an integer greater than or
	 * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
	 * @example
	 *
	 * _.isArrayLike([1, 2, 3]);
	 * // => true
	 *
	 * _.isArrayLike(document.body.children);
	 * // => true
	 *
	 * _.isArrayLike('abc');
	 * // => true
	 *
	 * _.isArrayLike(_.noop);
	 * // => false
	 */
	function isArrayLike(value) {
	  return value != null && isLength(value.length) && !isFunction(value);
	}

	/**
	 * This method is like `_.isArrayLike` except that it also checks if `value`
	 * is an object.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is an array-like object,
	 *  else `false`.
	 * @example
	 *
	 * _.isArrayLikeObject([1, 2, 3]);
	 * // => true
	 *
	 * _.isArrayLikeObject(document.body.children);
	 * // => true
	 *
	 * _.isArrayLikeObject('abc');
	 * // => false
	 *
	 * _.isArrayLikeObject(_.noop);
	 * // => false
	 */
	function isArrayLikeObject(value) {
	  return isObjectLike(value) && isArrayLike(value);
	}

	/**
	 * Checks if `value` is a buffer.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.3.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
	 * @example
	 *
	 * _.isBuffer(new Buffer(2));
	 * // => true
	 *
	 * _.isBuffer(new Uint8Array(2));
	 * // => false
	 */
	var isBuffer = nativeIsBuffer || stubFalse;

	/**
	 * 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) {
	  if (!isObject(value)) {
	    return false;
	  }
	  // The use of `Object#toString` avoids issues with the `typeof` operator
	  // in Safari 9 which returns 'object' for typed arrays and other constructors.
	  var tag = baseGetTag(value);
	  return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
	}

	/**
	 * Checks if `value` is a valid array-like length.
	 *
	 * **Note:** This method is loosely based on
	 * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
	 *
	 * @static
	 * @memberOf _
	 * @since 4.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
	 * @example
	 *
	 * _.isLength(3);
	 * // => true
	 *
	 * _.isLength(Number.MIN_VALUE);
	 * // => false
	 *
	 * _.isLength(Infinity);
	 * // => false
	 *
	 * _.isLength('3');
	 * // => false
	 */
	function isLength(value) {
	  return typeof value == 'number' &&
	    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
	}

	/**
	 * 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 != null && (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 != null && typeof value == 'object';
	}

	/**
	 * Checks if `value` is a plain object, that is, an object created by the
	 * `Object` constructor or one with a `[[Prototype]]` of `null`.
	 *
	 * @static
	 * @memberOf _
	 * @since 0.8.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
	 * @example
	 *
	 * function Foo() {
	 *   this.a = 1;
	 * }
	 *
	 * _.isPlainObject(new Foo);
	 * // => false
	 *
	 * _.isPlainObject([1, 2, 3]);
	 * // => false
	 *
	 * _.isPlainObject({ 'x': 0, 'y': 0 });
	 * // => true
	 *
	 * _.isPlainObject(Object.create(null));
	 * // => true
	 */
	function isPlainObject(value) {
	  if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
	    return false;
	  }
	  var proto = getPrototype(value);
	  if (proto === null) {
	    return true;
	  }
	  var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
	  return typeof Ctor == 'function' && Ctor instanceof Ctor &&
	    funcToString.call(Ctor) == objectCtorString;
	}

	/**
	 * Checks if `value` is classified as a typed array.
	 *
	 * @static
	 * @memberOf _
	 * @since 3.0.0
	 * @category Lang
	 * @param {*} value The value to check.
	 * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
	 * @example
	 *
	 * _.isTypedArray(new Uint8Array);
	 * // => true
	 *
	 * _.isTypedArray([]);
	 * // => false
	 */
	var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;

	/**
	 * Converts `value` to a plain object flattening inherited enumerable string
	 * keyed properties of `value` to own properties of the plain object.
	 *
	 * @static
	 * @memberOf _
	 * @since 3.0.0
	 * @category Lang
	 * @param {*} value The value to convert.
	 * @returns {Object} Returns the converted plain object.
	 * @example
	 *
	 * function Foo() {
	 *   this.b = 2;
	 * }
	 *
	 * Foo.prototype.c = 3;
	 *
	 * _.assign({ 'a': 1 }, new Foo);
	 * // => { 'a': 1, 'b': 2 }
	 *
	 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
	 * // => { 'a': 1, 'b': 2, 'c': 3 }
	 */
	function toPlainObject(value) {
	  return copyObject(value, keysIn(value));
	}

	/**
	 * Creates an array of the own and inherited enumerable property names of `object`.
	 *
	 * **Note:** Non-object values are coerced to objects.
	 *
	 * @static
	 * @memberOf _
	 * @since 3.0.0
	 * @category Object
	 * @param {Object} object The object to query.
	 * @returns {Array} Returns the array of property names.
	 * @example
	 *
	 * function Foo() {
	 *   this.a = 1;
	 *   this.b = 2;
	 * }
	 *
	 * Foo.prototype.c = 3;
	 *
	 * _.keysIn(new Foo);
	 * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
	 */
	function keysIn(object) {
	  return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
	}

	/**
	 * This method is like `_.assign` except that it recursively merges own and
	 * inherited enumerable string keyed properties of source objects into the
	 * destination object. Source properties that resolve to `undefined` are
	 * skipped if a destination value exists. Array and plain object properties
	 * are merged recursively. Other objects and value types are overridden by
	 * assignment. Source objects are applied from left to right. Subsequent
	 * sources overwrite property assignments of previous sources.
	 *
	 * **Note:** This method mutates `object`.
	 *
	 * @static
	 * @memberOf _
	 * @since 0.5.0
	 * @category Object
	 * @param {Object} object The destination object.
	 * @param {...Object} [sources] The source objects.
	 * @returns {Object} Returns `object`.
	 * @example
	 *
	 * var object = {
	 *   'a': [{ 'b': 2 }, { 'd': 4 }]
	 * };
	 *
	 * var other = {
	 *   'a': [{ 'c': 3 }, { 'e': 5 }]
	 * };
	 *
	 * _.merge(object, other);
	 * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
	 */
	var merge = createAssigner(function(object, source, srcIndex) {
	  baseMerge(object, source, srcIndex);
	});

	/**
	 * Creates a function that returns `value`.
	 *
	 * @static
	 * @memberOf _
	 * @since 2.4.0
	 * @category Util
	 * @param {*} value The value to return from the new function.
	 * @returns {Function} Returns the new constant function.
	 * @example
	 *
	 * var objects = _.times(2, _.constant({ 'a': 1 }));
	 *
	 * console.log(objects);
	 * // => [{ 'a': 1 }, { 'a': 1 }]
	 *
	 * console.log(objects[0] === objects[1]);
	 * // => true
	 */
	function constant(value) {
	  return function() {
	    return value;
	  };
	}

	/**
	 * This method returns the first argument it receives.
	 *
	 * @static
	 * @since 0.1.0
	 * @memberOf _
	 * @category Util
	 * @param {*} value Any value.
	 * @returns {*} Returns `value`.
	 * @example
	 *
	 * var object = { 'a': 1 };
	 *
	 * console.log(_.identity(object) === object);
	 * // => true
	 */
	function identity(value) {
	  return value;
	}

	/**
	 * This method returns `false`.
	 *
	 * @static
	 * @memberOf _
	 * @since 4.13.0
	 * @category Util
	 * @returns {boolean} Returns `false`.
	 * @example
	 *
	 * _.times(2, _.stubFalse);
	 * // => [false, false]
	 */
	function stubFalse() {
	  return false;
	}

	module.exports = merge;
	});

	function install(Vue) {
		var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

		if (install.installed) return;
		install.installed = true;

		var finalOptions = {};
		lodash_merge(finalOptions, defaultOptions, options);

		plugin.options = finalOptions;
		directive.options = finalOptions;

		Vue.directive('tooltip', directive);
		Vue.directive('close-popover', vclosepopover);
		Vue.component('v-popover', Popover);
	}

	var plugin = {
		install: install,

		get enabled() {
			return state.enabled;
		},

		set enabled(value) {
			state.enabled = value;
		}
	};

	// Auto-install
	var GlobalVue = null;
	if (typeof window !== 'undefined') {
		GlobalVue = window.Vue;
	} else if (typeof global !== 'undefined') {
		GlobalVue = global.Vue;
	}
	if (GlobalVue) {
		GlobalVue.use(plugin);
	}

	var vue2Collapse = createCommonjsModule(function (module, exports) {
	!function(t,e){module.exports=e();}("undefined"!=typeof self?self:commonjsGlobal,function(){return function(t){function e(s){if(n[s])return n[s].exports;var o=n[s]={i:s,l:!1,exports:{}};return t[s].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};return e.m=t,e.c=n,e.d=function(t,n,s){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:s});},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="/",e(e.s=4)}([function(t,e,n){var s="v-collapse",o={prefix:s,basename:"collapse",togglerClassDefault:s+"-toggler",contentClassDefault:s+"-content",contentClassEnd:s+"-content-end"},i=function(t,e){t.classList.toggle(e.contentClassEnd);},r=function(t,e){t.classList.remove(e.contentClassEnd);},c=function(t,e){t.classList.add(e.contentClassEnd);};t.exports={defaults:o,toggleElement:i,closeElement:r,openElement:c};},function(t,e){t.exports=function(t,e,n,s,o,i){var r,c=t=t||{},u=typeof t.default;"object"!==u&&"function"!==u||(r=t,c=t.default);var l="function"==typeof c?c.options:c;e&&(l.render=e.render,l.staticRenderFns=e.staticRenderFns,l._compiled=!0),n&&(l.functional=!0),o&&(l._scopeId=o);var a;if(i?(a=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),s&&s.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(i);},l._ssrRegister=a):s&&(a=s),a){var f=l.functional,d=f?l.render:l.beforeCreate;f?(l._injectStyles=a,l.render=function(t,e){return a.call(e),d(t,e)}):l.beforeCreate=d?[].concat(d,a):[a];}return {esModule:r,exports:c,options:l}};},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var s=n(0);e.default={data:function(){return {nodes:{},status:!1}},props:["active"],watch:{active:function(t){null!=t&&(this.status=t);},status:function(t,e){if(this.$emit("onStatusChange",{vm:this,status:t,old_status:e}),!1===this.$parent.onlyOneActive)(0, s.toggleElement)(this.nodes.content,this.$options.$vc.settings);else if(!0===t&&!1===e){var n=this.$parent.$children.filter(function(t){return !0===t.status});n.length>1&&n.forEach(function(t){t.close(),(0, s.closeElement)(t.nodes.content,this.$options.$vc.settings);}.bind(this)),(0, s.openElement)(this.nodes.content,this.$options.$vc.settings),this.open();}else !0===e&&!1===t&&((0, s.closeElement)(this.nodes.content,this.$options.$vc.settings),this.close());}},methods:{toggle:function(){this.$emit("beforeToggle",this),this.status=!this.status,this.$emit("afterToggle",this);},close:function(){this.$emit("beforeClose",this),this.status=!1,this.$emit("afterClose",this);},open:function(){this.$emit("beforeOpen",this),this.status=!0,this.$emit("afterOpen",this);}},mounted:function(){var t=this;this.nodes.toggle=this.$el.querySelector("."+this.$options.$vc.settings.togglerClassDefault),this.nodes.content=this.$el.querySelector("."+this.$options.$vc.settings.contentClassDefault),this.$emit("afterNodesBinding",{vm:this,nodes:this.nodes}),null!==this.nodes.toggle&&this.nodes.toggle.addEventListener("click",function(){t.toggle();}),null!=this.active&&(this.status=this.active);}};},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});n(0);e.default={data:function(){return {}},props:{onlyOneActive:{default:!1,type:Boolean}},computed:{elements:function(){return this.$children},elements_count:function(){return this.$children.length},active_elements:function(){return this.$children.filter(function(t){return !0===t.status})}},methods:{closeAll:function(){this.$children.forEach(function(t){t.close();});},openAll:function(){this.$children.forEach(function(t){t.open();});}}};},function(t,e,n){function s(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(5),i=s(o),r=n(8),c=s(r),u=n(0),l={};l.install=function(t,e){var n=Object.assign(u.defaults,e);t.component(n.prefix+"-wrapper",i.default),t.component(n.prefix+"-group",c.default),t.mixin({created:function(){this.$options.$vc={settings:n};}}),t.directive(n.basename+"-content",{bind:function(t,e,n,s){n.elm.classList.add(n.context.$options.$vc.settings.contentClassDefault);}}),t.directive(n.basename+"-toggle",{bind:function(t,e,n,s){n.elm.classList.add(n.context.$options.$vc.settings.togglerClassDefault);},inserted:function(t,e,n,s){null!=e.value&&n.elm.addEventListener("click",function(){n.context.$refs[e.value].status=!n.context.$refs[e.value].status;}.bind(this));}});},"undefined"!=typeof window&&window.Vue&&window.Vue.use(l),e.default=l;},function(t,e,n){function s(t){n(6);}Object.defineProperty(e,"__esModule",{value:!0});var o=n(2),i=n.n(o);for(var r in o)"default"!==r&&function(t){n.d(e,t,function(){return o[t]});}(r);var c=n(7),u=n(1),l=s,a=u(i.a,c.a,!1,l,null,null);e.default=a.exports;},function(t,e){},function(t,e,n){var s=function(){var t=this,e=t.$createElement;return (t._self._c||e)("div",{class:"vc-"+t.$options.$vc.settings.basename},[t._t("default")],2)},o=[],i={render:s,staticRenderFns:o};e.a=i;},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var s=n(3),o=n.n(s);for(var i in s)"default"!==i&&function(t){n.d(e,t,function(){return s[t]});}(i);var r=n(9),c=n(1),u=c(o.a,r.a,!1,null,null,null);e.default=u.exports;},function(t,e,n){var s=function(){var t=this,e=t.$createElement;return (t._self._c||e)("div",{staticClass:"v-collapse-group"},[t._t("default")],2)},o=[],i={render:s,staticRenderFns:o};e.a=i;}])});
	});

	var VueCollapse = unwrapExports(vue2Collapse);

	const SearchwpMetricsColors = {};

	SearchwpMetricsColors.install = function (Vue, options) {

		const colorScheme = [
			'rgba(69,170,242,1)',
			'rgba(252,92,101,1)',
			'rgba(165,94,234,1)',
			'rgba(38,222,129,1)',
			'rgba(253,150,68,1)',
			'rgba(254,211,48,1)',
			'rgba(43,203,186,1)',
			'rgba(75,123,236,1)',
			'rgba(209,216,224,1)',
			'rgba(119,140,163,1)',
			'rgba(45,152,218,1)',
			'rgba(235,59,90,1)',
			'rgba(136,84,208,1)',
			'rgba(250,130,49,1)',
			'rgba(32,191,107,1)',
			'rgba(247,183,49,1)',
			'rgba(15,185,177,1)',
			'rgba(56,103,214,1)',
			'rgba(165,177,194,1)',
			'rgba(75,101,132,1)',
			'rgba(54, 162, 235, 1)',
			'rgba(255, 99, 132, 1)',
			'rgba(153, 102, 255, 1)',
			'rgba(255, 159, 64, 1)',
			'rgba(75, 192, 192, 1)',
			'rgba(201, 203, 207, 1)',
			// 'rgba(255, 205, 86, 1)',
			// '#59a14f',
			// '#b07aa1',
			// '#ff9da7',
			// '#4e79a7',
			// '#f28e2b',
			// '#e15759',
			// '#76b7b2',
			// '#edc948',
			// '#9c755f',
			// '#bab0ac',
			// '#4dc9f6',
			// '#f67019',
			// '#f53794',
			// '#537bc4',
			// '#acc236',
			// '#166a8f',
			// '#00a950',
			// '#58595b',
			// '#8549ba',
			// '#5cbae6',
			// '#b6d957',
			// '#fac364',
			// '#8cd3ff',
			// '#d998cb',
			// '#f2d249',
			// '#93b9c6',
			// '#ccc5a8',
			// '#52bacc',
			// '#dbdb46',
			// '#98aafb'
		];

		/**
		 * Implements a rotating color scheme
		 */
		Vue.SearchwpMetricsGetColor = function (i, opacity = 1, adjustment = 1) {
			while (i > colorScheme.length - 1) {
				i -= colorScheme.length;
			}

			let color = colorScheme[i].replace('1)', opacity + ')');

			let pieces = color.split(',');

			// Apply adjustment
			let r = parseInt(pieces[0].replace('rgba(', ''),10) * adjustment;
			let g = parseInt(pieces[1]) * adjustment;
			let b = parseInt(pieces[2]) * adjustment;

			// When adjusting, desaturate as well
			if (adjustment !== 1) {
				let f = 0.5; // desaturate by 20%
				let L = 0.3*r + 0.6*g + 0.1*b;

				let new_r = r + f * (L - r);
				let new_g = g + f * (L - g);
				let new_b = b + f * (L - b);

				r = new_r;
				g = new_g;
				b = new_b;
			}

			color = 'rgba(' + r + ',' + g + ',' + b + ',' + pieces[3];

			return color;
		};
	};

	const SearchwpMetricsFormatFor = {};

	SearchwpMetricsFormatFor.install = function (Vue, options) {

		const library = 'chartjs';

		Vue.SearchwpMetricsFormatForChart = function (data, options = {}) {
			switch (library) {
				case 'chartjs':
					data = Vue.SearchwpMetricsFormatForChartjs(data, options);
					break;

				default:
					data = data;
					break;
			}

			return data;
		};

		Vue.SearchwpMetricsFormatForChartjs = function (data, options = {}) {
			let chartData = {
				labels: data.labels,
				datasets: []
			};

			for (let i = 0; i < data.datasets.length; i++) {
				let dataset = data.datasets[i];
				let defaults = {
					label: dataset.engine,
					borderColor: Vue.SearchwpMetricsGetColor(i),
					backgroundColor: Vue.SearchwpMetricsGetColor(i, 0.15, 1.35),
					data: dataset.dataset
				};

				// Merge the defaults into any options set
				chartData.datasets.push({ ...options, ...defaults});
			}

			return chartData;
		};
	};

	/**
	 * Returns a function, that, as long as it continues to be invoked, will not
	 * be triggered. The function will be called after it stops being called for
	 * N milliseconds. If `immediate` is passed, trigger the function on the
	 * leading edge, instead of the trailing. The function also has a property 'clear' 
	 * that is a function which will clear the timer to prevent previously scheduled executions. 
	 *
	 * @source underscore.js
	 * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
	 * @param {Function} function to wrap
	 * @param {Number} timeout in ms (`100`)
	 * @param {Boolean} whether to execute at the beginning (`false`)
	 * @api public
	 */

	var debounce$1 = function debounce(func, wait, immediate){
	  var timeout, args, context, timestamp, result;
	  if (null == wait) wait = 100;

	  function later() {
	    var last = Date.now() - timestamp;

	    if (last < wait && last >= 0) {
	      timeout = setTimeout(later, wait - last);
	    } else {
	      timeout = null;
	      if (!immediate) {
	        result = func.apply(context, args);
	        context = args = null;
	      }
	    }
	  }
	  var debounced = function(){
	    context = this;
	    args = arguments;
	    timestamp = Date.now();
	    var callNow = immediate && !timeout;
	    if (!timeout) timeout = setTimeout(later, wait);
	    if (callNow) {
	      result = func.apply(context, args);
	      context = args = null;
	    }

	    return result;
	  };

	  debounced.clear = function() {
	    if (timeout) {
	      clearTimeout(timeout);
	      timeout = null;
	    }
	  };
	  
	  debounced.flush = function() {
	    if (timeout) {
	      result = func.apply(context, args);
	      context = args = null;
	      
	      clearTimeout(timeout);
	      timeout = null;
	    }
	  };

	  return debounced;
	};

	var isObject = function isObject(x) {
		return typeof x === "object" && x !== null;
	};

	/**
	 * isArray
	 */

	var isArray = Array.isArray;

	/**
	 * toString
	 */

	var str = Object.prototype.toString;

	/**
	 * Whether or not the given `val`
	 * is an array.
	 *
	 * example:
	 *
	 *        isArray([]);
	 *        // > true
	 *        isArray(arguments);
	 *        // > false
	 *        isArray('');
	 *        // > false
	 *
	 * @param {mixed} val
	 * @return {bool}
	 */

	var isArray_1 = isArray || function (val) {
	  return !! val && '[object Array]' == str.call(val);
	};

	var isFunction_1 = isFunction$1;

	var toString = Object.prototype.toString;

	function isFunction$1 (fn) {
	  var string = toString.call(fn);
	  return string === '[object Function]' ||
	    (typeof fn === 'function' && string !== '[object RegExp]') ||
	    (typeof window !== 'undefined' &&
	     // IE8 and below
	     (fn === window.setTimeout ||
	      fn === window.alert ||
	      fn === window.confirm ||
	      fn === window.prompt))
	}

	var lib = createCommonjsModule(function (module) {
	/*!
	 *   keyfinder - v1.0.0
	 *   Deep search for keys in objects and arrays and pluck their respective values.
	 *   https://github.com/simon-johansson/keyfinder
	 *   by Simon Johansson <mail@simon-johansson.com>
	 *   MIT License
	 */

	(function() {
	    var arrayify, find, isArray, isFunction, isObjectOrArray;
	    isObjectOrArray = isObject;
	    isArray = isArray_1;
	    isFunction = isFunction_1;
	    arrayify = function(obj) {
	        var key, _results;
	        _results = [];
	        for (key in obj) {
	            _results.push(key);
	        }
	        return _results;
	    };
	    find = function(haystack, needle, memo) {
	        var key, parent, val, _i, _len, _ref;
	        if (memo == null) {
	            memo = [];
	        }
	        if (needle && isObjectOrArray(haystack)) {
	            if (needle in haystack) {
	                memo.push(haystack[needle]);
	            }
	            _ref = arrayify(haystack);
	            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
	                key = _ref[_i];
	                val = haystack[key];
	                if (isFunction(needle)) {
	                    parent = isArray(haystack) ? "array" : "object";
	                    needle(key, val, parent);
	                }
	                if (isObjectOrArray(val)) {
	                    find(val, needle, memo);
	                }
	            }
	        }
	        return memo;
	    };
	    module.exports = function(obj, key) {
	        return find(obj, key);
	    };
	}).call(commonjsGlobal);
	});

	var vueMultiselect_min = createCommonjsModule(function (module, exports) {
	!function(t,e){module.exports=e();}(commonjsGlobal,function(){return function(t){function e(i){if(n[i])return n[i].exports;var r=n[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};return e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,i){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:i});},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="/",e(e.s=66)}([function(t,e){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n);},function(t,e,n){t.exports=!n(12)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a});},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)};},function(t,e,n){var i=n(10),r=n(43),o=n(31),s=Object.defineProperty;e.f=n(1)?Object.defineProperty:function(t,e,n){if(i(t),e=o(e,!0),i(n),r)try{return s(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return "value"in n&&(t[e]=n.value),t};},function(t,e,n){var i=n(77),r=n(21);t.exports=function(t){return i(r(t))};},function(t,e,n){var i=n(9),r=n(52),o=n(18),s=n(55),u=n(53),a=function(t,e,n){var l,c,f,p,h=t&a.F,d=t&a.G,v=t&a.S,y=t&a.P,g=t&a.B,b=d?i:v?i[e]||(i[e]={}):(i[e]||{}).prototype,m=d?r:r[e]||(r[e]={}),_=m.prototype||(m.prototype={});d&&(n=e);for(l in n)c=!h&&b&&void 0!==b[l],f=(c?b:n)[l],p=g&&c?u(f,i):y&&"function"==typeof f?u(Function.call,f):f,b&&s(b,l,f,t&a.U),m[l]!=f&&o(m,l,p),y&&_[l]!=f&&(_[l]=f);};i.core=r,a.F=1,a.G=2,a.S=4,a.P=8,a.B=16,a.W=32,a.U=64,a.R=128,t.exports=a;},function(t,e,n){var i=n(3),r=n(15);t.exports=n(1)?function(t,e,n){return i.f(t,e,r(1,n))}:function(t,e,n){return t[e]=n,t};},function(t,e,n){var i=n(29)("wks"),r=n(16),o=n(0).Symbol,s="function"==typeof o;(t.exports=function(t){return i[t]||(i[t]=s&&o[t]||(s?o:r)("Symbol."+t))}).store=i;},function(t,e){t.exports=function(t){try{return !!t()}catch(t){return !0}};},function(t,e){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n);},function(t,e,n){var i=n(13);t.exports=function(t){if(!i(t))throw TypeError(t+" is not an object!");return t};},function(t,e){var n=t.exports={version:"2.4.0"};"number"==typeof __e&&(__e=n);},function(t,e){t.exports=function(t){try{return !!t()}catch(t){return !0}};},function(t,e){t.exports=function(t){return "object"==typeof t?null!==t:"function"==typeof t};},function(t,e,n){var i=n(48),r=n(22);t.exports=Object.keys||function(t){return i(t,r)};},function(t,e){t.exports=function(t,e){return {enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}};},function(t,e){var n=0,i=Math.random();t.exports=function(t){return "Symbol(".concat(void 0===t?"":t,")_",(++n+i).toString(36))};},function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on  "+t);return t};},function(t,e,n){var i=n(109),r=n(110);t.exports=n(35)?function(t,e,n){return i.f(t,e,r(1,n))}:function(t,e,n){return t[e]=n,t};},function(t,e){t.exports=function(t){return "object"==typeof t?null!==t:"function"==typeof t};},function(t,e,n){var i=n(8);t.exports=function(t,e){return !!t&&i(function(){e?t.call(null,function(){},1):t.call(null);})};},function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on  "+t);return t};},function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",");},function(t,e,n){var i=n(0),r=n(11),o=n(74),s=n(6),u=function(t,e,n){var a,l,c,f=t&u.F,p=t&u.G,h=t&u.S,d=t&u.P,v=t&u.B,y=t&u.W,g=p?r:r[e]||(r[e]={}),b=g.prototype,m=p?i:h?i[e]:(i[e]||{}).prototype;p&&(n=e);for(a in n)(l=!f&&m&&void 0!==m[a])&&a in g||(c=l?m[a]:n[a],g[a]=p&&"function"!=typeof m[a]?n[a]:v&&l?o(c,i):y&&m[a]==c?function(t){var e=function(e,n,i){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,n)}return new t(e,n,i)}return t.apply(this,arguments)};return e.prototype=t.prototype,e}(c):d&&"function"==typeof c?o(Function.call,c):c,d&&((g.virtual||(g.virtual={}))[a]=c,t&u.R&&b&&!b[a]&&s(b,a,c)));};u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,t.exports=u;},function(t,e){t.exports={};},function(t,e){t.exports=!0;},function(t,e){e.f={}.propertyIsEnumerable;},function(t,e,n){var i=n(3).f,r=n(2),o=n(7)("toStringTag");t.exports=function(t,e,n){t&&!r(t=n?t:t.prototype,o)&&i(t,o,{configurable:!0,value:e});};},function(t,e,n){var i=n(29)("keys"),r=n(16);t.exports=function(t){return i[t]||(i[t]=r(t))};},function(t,e,n){var i=n(0),r=i["__core-js_shared__"]||(i["__core-js_shared__"]={});t.exports=function(t){return r[t]||(r[t]={})};},function(t,e){var n=Math.ceil,i=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?i:n)(t)};},function(t,e,n){var i=n(13);t.exports=function(t,e){if(!i(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!i(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!i(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!i(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")};},function(t,e,n){var i=n(0),r=n(11),o=n(25),s=n(33),u=n(3).f;t.exports=function(t){var e=r.Symbol||(r.Symbol=o?{}:i.Symbol||{});"_"==t.charAt(0)||t in e||u(e,t,{value:s.f(t)});};},function(t,e,n){e.f=n(7);},function(t,e,n){var i=n(53),r=n(36),o=n(57),s=n(37),u=n(104);t.exports=function(t,e){var n=1==t,a=2==t,l=3==t,c=4==t,f=6==t,p=5==t||f,h=e||u;return function(e,u,d){for(var v,y,g=o(e),b=r(g),m=i(u,d,3),_=s(b.length),x=0,w=n?h(e,_):a?h(e,0):void 0;_>x;x++)if((p||x in b)&&(v=b[x],y=m(v,x,g),t))if(n)w[x]=y;else if(y)switch(t){case 3:return !0;case 5:return v;case 6:return x;case 2:w.push(v);}else if(c)return !1;return f?-1:l||c?c:w}};},function(t,e,n){t.exports=!n(8)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a});},function(t,e,n){var i=n(51);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return "String"==i(t)?t.split(""):Object(t)};},function(t,e,n){var i=n(56),r=Math.min;t.exports=function(t){return t>0?r(i(t),9007199254740991):0};},function(t,e,n){var i=n(111)("wks"),r=n(58),o=n(9).Symbol,s="function"==typeof o;(t.exports=function(t){return i[t]||(i[t]=s&&o[t]||(s?o:r)("Symbol."+t))}).store=i;},function(t,e,n){function i(t){return 0!==t&&(!(!Array.isArray(t)||0!==t.length)||!t)}function r(t){return function(){return !t.apply(void 0,arguments)}}function o(t,e){return void 0===t&&(t="undefined"),null===t&&(t="null"),!1===t&&(t="false"),-1!==t.toString().toLowerCase().indexOf(e.trim())}function s(t,e,n,i){return t.filter(function(t){return o(i(t,n),e)})}function u(t){return t.filter(function(t){return !t.$isLabel})}function a(t,e){return function(n){return n.reduce(function(n,i){return i[t]&&i[t].length?(n.push({$groupLabel:i[e],$isLabel:!0}),n.concat(i[t])):n},[])}}function l(t,e,n,i,r){return function(o){return o.map(function(o){var u;if(!o[n])return console.warn("Options passed to vue-multiselect do not contain groups, despite the config."),[];var a=s(o[n],t,e,r);return a.length?(u={},v()(u,i,o[i]),v()(u,n,a),u):[]})}}var c=n(65),f=n.n(c),p=n(59),h=(n.n(p),n(122)),d=(n.n(h),n(64)),v=n.n(d),y=n(120),g=(n.n(y),n(121)),b=(n.n(g),n(117)),m=(n.n(b),n(123)),_=(n.n(m),n(118)),x=(n.n(_),n(119)),w=(n.n(x),function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];return function(t){return e.reduce(function(t,e){return e(t)},t)}});e.a={data:function(){return {search:"",isOpen:!1,prefferedOpenDirection:"below",optimizedHeight:this.maxHeight}},props:{internalSearch:{type:Boolean,default:!0},options:{type:Array,required:!0},multiple:{type:Boolean,default:!1},value:{type:null,default:function(){return []}},trackBy:{type:String},label:{type:String},searchable:{type:Boolean,default:!0},clearOnSelect:{type:Boolean,default:!0},hideSelected:{type:Boolean,default:!1},placeholder:{type:String,default:"Select option"},allowEmpty:{type:Boolean,default:!0},resetAfter:{type:Boolean,default:!1},closeOnSelect:{type:Boolean,default:!0},customLabel:{type:Function,default:function(t,e){return i(t)?"":e?t[e]:t}},taggable:{type:Boolean,default:!1},tagPlaceholder:{type:String,default:"Press enter to create a tag"},tagPosition:{type:String,default:"top"},max:{type:[Number,Boolean],default:!1},id:{default:null},optionsLimit:{type:Number,default:1e3},groupValues:{type:String},groupLabel:{type:String},groupSelect:{type:Boolean,default:!1},blockKeys:{type:Array,default:function(){return []}},preserveSearch:{type:Boolean,default:!1},preselectFirst:{type:Boolean,default:!1}},mounted:function(){this.multiple||this.clearOnSelect||console.warn("[Vue-Multiselect warn]: ClearOnSelect and Multiple props can’t be both set to false."),!this.multiple&&this.max&&console.warn("[Vue-Multiselect warn]: Max prop should not be used when prop Multiple equals false."),this.preselectFirst&&!this.internalValue.length&&this.options.length&&this.select(this.filteredOptions[0]);},computed:{internalValue:function(){return this.value||0===this.value?Array.isArray(this.value)?this.value:[this.value]:[]},filteredOptions:function(){var t=this.search||"",e=t.toLowerCase().trim(),n=this.options.concat();return n=this.internalSearch?this.groupValues?this.filterAndFlat(n,e,this.label):s(n,e,this.label,this.customLabel):this.groupValues?a(this.groupValues,this.groupLabel)(n):n,n=this.hideSelected?n.filter(r(this.isSelected)):n,this.taggable&&e.length&&!this.isExistingOption(e)&&("bottom"===this.tagPosition?n.push({isTag:!0,label:t}):n.unshift({isTag:!0,label:t})),n.slice(0,this.optionsLimit)},valueKeys:function(){var t=this;return this.trackBy?this.internalValue.map(function(e){return e[t.trackBy]}):this.internalValue},optionKeys:function(){var t=this;return (this.groupValues?this.flatAndStrip(this.options):this.options).map(function(e){return t.customLabel(e,t.label).toString().toLowerCase()})},currentOptionLabel:function(){return this.multiple?this.searchable?"":this.placeholder:this.internalValue.length?this.getOptionLabel(this.internalValue[0]):this.searchable?"":this.placeholder}},watch:{internalValue:function(){this.resetAfter&&this.internalValue.length&&(this.search="",this.$emit("input",this.multiple?[]:null));},search:function(){this.$emit("search-change",this.search,this.id);}},methods:{getValue:function(){return this.multiple?this.internalValue:0===this.internalValue.length?null:this.internalValue[0]},filterAndFlat:function(t,e,n){return w(l(e,n,this.groupValues,this.groupLabel,this.customLabel),a(this.groupValues,this.groupLabel))(t)},flatAndStrip:function(t){return w(a(this.groupValues,this.groupLabel),u)(t)},updateSearch:function(t){this.search=t;},isExistingOption:function(t){return !!this.options&&this.optionKeys.indexOf(t)>-1},isSelected:function(t){var e=this.trackBy?t[this.trackBy]:t;return this.valueKeys.indexOf(e)>-1},getOptionLabel:function(t){if(i(t))return "";if(t.isTag)return t.label;if(t.$isLabel)return t.$groupLabel;var e=this.customLabel(t,this.label);return i(e)?"":e},select:function(t,e){if(t.$isLabel&&this.groupSelect)return void this.selectGroup(t);if(!(-1!==this.blockKeys.indexOf(e)||this.disabled||t.$isDisabled||t.$isLabel)&&(!this.max||!this.multiple||this.internalValue.length!==this.max)&&("Tab"!==e||this.pointerDirty)){if(t.isTag)this.$emit("tag",t.label,this.id),this.search="",this.closeOnSelect&&!this.multiple&&this.deactivate();else {if(this.isSelected(t))return void("Tab"!==e&&this.removeElement(t));this.$emit("select",t,this.id),this.multiple?this.$emit("input",this.internalValue.concat([t]),this.id):this.$emit("input",t,this.id),this.clearOnSelect&&(this.search="");}this.closeOnSelect&&this.deactivate();}},selectGroup:function(t){var e=this,n=this.options.find(function(n){return n[e.groupLabel]===t.$groupLabel});if(n)if(this.wholeGroupSelected(n)){this.$emit("remove",n[this.groupValues],this.id);var i=this.internalValue.filter(function(t){return -1===n[e.groupValues].indexOf(t)});this.$emit("input",i,this.id);}else {var o=n[this.groupValues].filter(r(this.isSelected));this.$emit("select",o,this.id),this.$emit("input",this.internalValue.concat(o),this.id);}},wholeGroupSelected:function(t){return t[this.groupValues].every(this.isSelected)},removeElement:function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(!this.disabled){if(!this.allowEmpty&&this.internalValue.length<=1)return void this.deactivate();var n="object"===f()(t)?this.valueKeys.indexOf(t[this.trackBy]):this.valueKeys.indexOf(t);if(this.$emit("remove",t,this.id),this.multiple){var i=this.internalValue.slice(0,n).concat(this.internalValue.slice(n+1));this.$emit("input",i,this.id);}else this.$emit("input",null,this.id);this.closeOnSelect&&e&&this.deactivate();}},removeLastElement:function(){-1===this.blockKeys.indexOf("Delete")&&0===this.search.length&&Array.isArray(this.internalValue)&&this.removeElement(this.internalValue[this.internalValue.length-1],!1);},activate:function(){var t=this;this.isOpen||this.disabled||(this.adjustPosition(),this.groupValues&&0===this.pointer&&this.filteredOptions.length&&(this.pointer=1),this.isOpen=!0,this.searchable?(this.preserveSearch||(this.search=""),this.$nextTick(function(){return t.$refs.search.focus()})):this.$el.focus(),this.$emit("open",this.id));},deactivate:function(){this.isOpen&&(this.isOpen=!1,this.searchable?this.$refs.search.blur():this.$el.blur(),this.preserveSearch||(this.search=""),this.$emit("close",this.getValue(),this.id));},toggle:function(){this.isOpen?this.deactivate():this.activate();},adjustPosition:function(){if("undefined"!=typeof window){var t=this.$el.getBoundingClientRect().top,e=window.innerHeight-this.$el.getBoundingClientRect().bottom;e>this.maxHeight||e>t||"below"===this.openDirection||"bottom"===this.openDirection?(this.prefferedOpenDirection="below",this.optimizedHeight=Math.min(e-40,this.maxHeight)):(this.prefferedOpenDirection="above",this.optimizedHeight=Math.min(t-40,this.maxHeight));}}}};},function(t,e,n){var i=n(59);n.n(i);e.a={data:function(){return {pointer:0,pointerDirty:!1}},props:{showPointer:{type:Boolean,default:!0},optionHeight:{type:Number,default:40}},computed:{pointerPosition:function(){return this.pointer*this.optionHeight},visibleElements:function(){return this.optimizedHeight/this.optionHeight}},watch:{filteredOptions:function(){this.pointerAdjust();},isOpen:function(){this.pointerDirty=!1;}},methods:{optionHighlight:function(t,e){return {"multiselect__option--highlight":t===this.pointer&&this.showPointer,"multiselect__option--selected":this.isSelected(e)}},groupHighlight:function(t,e){var n=this;if(!this.groupSelect)return ["multiselect__option--disabled"];var i=this.options.find(function(t){return t[n.groupLabel]===e.$groupLabel});return [this.groupSelect?"multiselect__option--group":"multiselect__option--disabled",{"multiselect__option--highlight":t===this.pointer&&this.showPointer},{"multiselect__option--group-selected":this.wholeGroupSelected(i)}]},addPointerElement:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"Enter",e=t.key;this.filteredOptions.length>0&&this.select(this.filteredOptions[this.pointer],e),this.pointerReset();},pointerForward:function(){this.pointer<this.filteredOptions.length-1&&(this.pointer++,this.$refs.list.scrollTop<=this.pointerPosition-(this.visibleElements-1)*this.optionHeight&&(this.$refs.list.scrollTop=this.pointerPosition-(this.visibleElements-1)*this.optionHeight),this.filteredOptions[this.pointer]&&this.filteredOptions[this.pointer].$isLabel&&!this.groupSelect&&this.pointerForward()),this.pointerDirty=!0;},pointerBackward:function(){this.pointer>0?(this.pointer--,this.$refs.list.scrollTop>=this.pointerPosition&&(this.$refs.list.scrollTop=this.pointerPosition),this.filteredOptions[this.pointer]&&this.filteredOptions[this.pointer].$isLabel&&!this.groupSelect&&this.pointerBackward()):this.filteredOptions[this.pointer]&&this.filteredOptions[0].$isLabel&&!this.groupSelect&&this.pointerForward(),this.pointerDirty=!0;},pointerReset:function(){this.closeOnSelect&&(this.pointer=0,this.$refs.list&&(this.$refs.list.scrollTop=0));},pointerAdjust:function(){this.pointer>=this.filteredOptions.length-1&&(this.pointer=this.filteredOptions.length?this.filteredOptions.length-1:0),this.filteredOptions.length>0&&this.filteredOptions[this.pointer].$isLabel&&!this.groupSelect&&this.pointerForward();},pointerSet:function(t){this.pointer=t,this.pointerDirty=!0;}}};},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)};},function(t,e,n){var i=n(13),r=n(0).document,o=i(r)&&i(r.createElement);t.exports=function(t){return o?r.createElement(t):{}};},function(t,e,n){t.exports=!n(1)&&!n(12)(function(){return 7!=Object.defineProperty(n(42)("div"),"a",{get:function(){return 7}}).a});},function(t,e,n){var i=n(25),r=n(23),o=n(49),s=n(6),u=n(2),a=n(24),l=n(79),c=n(27),f=n(86),p=n(7)("iterator"),h=!([].keys&&"next"in[].keys()),d=function(){return this};t.exports=function(t,e,n,v,y,g,b){l(n,e,v);var m,_,x,w=function(t){if(!h&&t in P)return P[t];switch(t){case"keys":case"values":return function(){return new n(this,t)}}return function(){return new n(this,t)}},S=e+" Iterator",O="values"==y,L=!1,P=t.prototype,k=P[p]||P["@@iterator"]||y&&P[y],E=k||w(y),j=y?O?w("entries"):E:void 0,V="Array"==e?P.entries||k:k;if(V&&(x=f(V.call(new t)))!==Object.prototype&&(c(x,S,!0),i||u(x,p)||s(x,p,d)),O&&k&&"values"!==k.name&&(L=!0,E=function(){return k.call(this)}),i&&!b||!h&&!L&&P[p]||s(P,p,E),a[e]=E,a[S]=d,y)if(m={values:O?E:w("values"),keys:g?E:w("keys"),entries:j},b)for(_ in m)_ in P||o(P,_,m[_]);else r(r.P+r.F*(h||L),e,m);return m};},function(t,e,n){var i=n(10),r=n(83),o=n(22),s=n(28)("IE_PROTO"),u=function(){},a=function(){var t,e=n(42)("iframe"),i=o.length;for(e.style.display="none",n(76).appendChild(e),e.src="javascript:",t=e.contentWindow.document,t.open(),t.write("<script>document.F=Object<\/script>"),t.close(),a=t.F;i--;)delete a.prototype[o[i]];return a()};t.exports=Object.create||function(t,e){var n;return null!==t?(u.prototype=i(t),n=new u,u.prototype=null,n[s]=t):n=a(),void 0===e?n:r(n,e)};},function(t,e,n){var i=n(48),r=n(22).concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return i(t,r)};},function(t,e){e.f=Object.getOwnPropertySymbols;},function(t,e,n){var i=n(2),r=n(4),o=n(73)(!1),s=n(28)("IE_PROTO");t.exports=function(t,e){var n,u=r(t),a=0,l=[];for(n in u)n!=s&&i(u,n)&&l.push(n);for(;e.length>a;)i(u,n=e[a++])&&(~o(l,n)||l.push(n));return l};},function(t,e,n){t.exports=n(6);},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t};},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)};},function(t,e){var n=t.exports={version:"2.4.0"};"number"==typeof __e&&(__e=n);},function(t,e,n){var i=n(50);t.exports=function(t,e,n){if(i(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,i){return t.call(e,n,i)};case 3:return function(n,i,r){return t.call(e,n,i,r)}}return function(){return t.apply(e,arguments)}};},function(t,e,n){var i=n(51);t.exports=Array.isArray||function(t){return "Array"==i(t)};},function(t,e,n){var i=n(9),r=n(18),o=n(107),s=n(58)("src"),u=Function.toString,a=(""+u).split("toString");n(52).inspectSource=function(t){return u.call(t)},(t.exports=function(t,e,n,u){var l="function"==typeof n;l&&(o(n,"name")||r(n,"name",e)),t[e]!==n&&(l&&(o(n,s)||r(n,s,t[e]?""+t[e]:a.join(String(e)))),t===i?t[e]=n:u?t[e]?t[e]=n:r(t,e,n):(delete t[e],r(t,e,n)));})(Function.prototype,"toString",function(){return "function"==typeof this&&this[s]||u.call(this)});},function(t,e){var n=Math.ceil,i=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?i:n)(t)};},function(t,e,n){var i=n(17);t.exports=function(t){return Object(i(t))};},function(t,e){var n=0,i=Math.random();t.exports=function(t){return "Symbol(".concat(void 0===t?"":t,")_",(++n+i).toString(36))};},function(t,e,n){var i=n(5),r=n(34)(5),o=!0;"find"in[]&&Array(1).find(function(){o=!1;}),i(i.P+i.F*o,"Array",{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),n(99)("find");},function(t,e,n){function i(t){n(124);}var r=n(67),o=n(126),s=n(125),u=i,a=s(r.a,o.a,!1,u,null,null);e.a=a.exports;},function(t,e,n){t.exports=n(68);},function(t,e,n){t.exports=n(69);},function(t,e,n){t.exports=n(70);},function(t,e,n){function i(t,e,n){return e in t?r(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var r=n(61);t.exports=i;},function(t,e,n){function i(t){return (i="function"==typeof s&&"symbol"==typeof o?function(t){return typeof t}:function(t){return t&&"function"==typeof s&&t.constructor===s&&t!==s.prototype?"symbol":typeof t})(t)}function r(e){return "function"==typeof s&&"symbol"===i(o)?t.exports=r=function(t){return i(t)}:t.exports=r=function(t){return t&&"function"==typeof s&&t.constructor===s&&t!==s.prototype?"symbol":i(t)},r(e)}var o=n(63),s=n(62);t.exports=r;},function(t,e,n){Object.defineProperty(e,"__esModule",{value:!0});var i=n(60),r=n(39),o=n(40);n.d(e,"Multiselect",function(){return i.a}),n.d(e,"multiselectMixin",function(){return r.a}),n.d(e,"pointerMixin",function(){return o.a}),e.default=i.a;},function(t,e,n){var i=n(39),r=n(40);e.a={name:"vue-multiselect",mixins:[i.a,r.a],props:{name:{type:String,default:""},selectLabel:{type:String,default:"Press enter to select"},selectGroupLabel:{type:String,default:"Press enter to select group"},selectedLabel:{type:String,default:"Selected"},deselectLabel:{type:String,default:"Press enter to remove"},deselectGroupLabel:{type:String,default:"Press enter to deselect group"},showLabels:{type:Boolean,default:!0},limit:{type:Number,default:99999},maxHeight:{type:Number,default:300},limitText:{type:Function,default:function(t){return "and ".concat(t," more")}},loading:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},openDirection:{type:String,default:""},showNoResults:{type:Boolean,default:!0},tabindex:{type:Number,default:0}},computed:{isSingleLabelVisible:function(){return this.singleValue&&(!this.isOpen||!this.searchable)&&!this.visibleValues.length},isPlaceholderVisible:function(){return !(this.internalValue.length||this.searchable&&this.isOpen)},visibleValues:function(){return this.multiple?this.internalValue.slice(0,this.limit):[]},singleValue:function(){return this.internalValue[0]},deselectLabelText:function(){return this.showLabels?this.deselectLabel:""},deselectGroupLabelText:function(){return this.showLabels?this.deselectGroupLabel:""},selectLabelText:function(){return this.showLabels?this.selectLabel:""},selectGroupLabelText:function(){return this.showLabels?this.selectGroupLabel:""},selectedLabelText:function(){return this.showLabels?this.selectedLabel:""},inputStyle:function(){if(this.multiple&&this.value&&this.value.length)return this.isOpen?{width:"auto"}:{width:"0",position:"absolute",padding:"0"}},contentStyle:function(){return this.options.length?{display:"inline-block"}:{display:"block"}},isAbove:function(){return "above"===this.openDirection||"top"===this.openDirection||"below"!==this.openDirection&&"bottom"!==this.openDirection&&"above"===this.prefferedOpenDirection},showSearchInput:function(){return this.searchable&&(!this.hasSingleSelectedSlot||!this.visibleSingleValue&&0!==this.visibleSingleValue||this.isOpen)}}};},function(t,e,n){n(92);var i=n(11).Object;t.exports=function(t,e,n){return i.defineProperty(t,e,n)};},function(t,e,n){n(95),n(93),n(96),n(97),t.exports=n(11).Symbol;},function(t,e,n){n(94),n(98),t.exports=n(33).f("iterator");},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t};},function(t,e){t.exports=function(){};},function(t,e,n){var i=n(4),r=n(89),o=n(88);t.exports=function(t){return function(e,n,s){var u,a=i(e),l=r(a.length),c=o(s,l);if(t&&n!=n){for(;l>c;)if((u=a[c++])!=u)return !0}else for(;l>c;c++)if((t||c in a)&&a[c]===n)return t||c||0;return !t&&-1}};},function(t,e,n){var i=n(71);t.exports=function(t,e,n){if(i(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,i){return t.call(e,n,i)};case 3:return function(n,i,r){return t.call(e,n,i,r)}}return function(){return t.apply(e,arguments)}};},function(t,e,n){var i=n(14),r=n(47),o=n(26);t.exports=function(t){var e=i(t),n=r.f;if(n)for(var s,u=n(t),a=o.f,l=0;u.length>l;)a.call(t,s=u[l++])&&e.push(s);return e};},function(t,e,n){t.exports=n(0).document&&document.documentElement;},function(t,e,n){var i=n(41);t.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return "String"==i(t)?t.split(""):Object(t)};},function(t,e,n){var i=n(41);t.exports=Array.isArray||function(t){return "Array"==i(t)};},function(t,e,n){var i=n(45),r=n(15),o=n(27),s={};n(6)(s,n(7)("iterator"),function(){return this}),t.exports=function(t,e,n){t.prototype=i(s,{next:r(1,n)}),o(t,e+" Iterator");};},function(t,e){t.exports=function(t,e){return {value:e,done:!!t}};},function(t,e,n){var i=n(14),r=n(4);t.exports=function(t,e){for(var n,o=r(t),s=i(o),u=s.length,a=0;u>a;)if(o[n=s[a++]]===e)return n};},function(t,e,n){var i=n(16)("meta"),r=n(13),o=n(2),s=n(3).f,u=0,a=Object.isExtensible||function(){return !0},l=!n(12)(function(){return a(Object.preventExtensions({}))}),c=function(t){s(t,i,{value:{i:"O"+ ++u,w:{}}});},f=function(t,e){if(!r(t))return "symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!o(t,i)){if(!a(t))return "F";if(!e)return "E";c(t);}return t[i].i},p=function(t,e){if(!o(t,i)){if(!a(t))return !0;if(!e)return !1;c(t);}return t[i].w},h=function(t){return l&&d.NEED&&a(t)&&!o(t,i)&&c(t),t},d=t.exports={KEY:i,NEED:!1,fastKey:f,getWeak:p,onFreeze:h};},function(t,e,n){var i=n(3),r=n(10),o=n(14);t.exports=n(1)?Object.defineProperties:function(t,e){r(t);for(var n,s=o(e),u=s.length,a=0;u>a;)i.f(t,n=s[a++],e[n]);return t};},function(t,e,n){var i=n(26),r=n(15),o=n(4),s=n(31),u=n(2),a=n(43),l=Object.getOwnPropertyDescriptor;e.f=n(1)?l:function(t,e){if(t=o(t),e=s(e,!0),a)try{return l(t,e)}catch(t){}if(u(t,e))return r(!i.f.call(t,e),t[e])};},function(t,e,n){var i=n(4),r=n(46).f,o={}.toString,s="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],u=function(t){try{return r(t)}catch(t){return s.slice()}};t.exports.f=function(t){return s&&"[object Window]"==o.call(t)?u(t):r(i(t))};},function(t,e,n){var i=n(2),r=n(90),o=n(28)("IE_PROTO"),s=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=r(t),i(t,o)?t[o]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?s:null};},function(t,e,n){var i=n(30),r=n(21);t.exports=function(t){return function(e,n){var o,s,u=String(r(e)),a=i(n),l=u.length;return a<0||a>=l?t?"":void 0:(o=u.charCodeAt(a),o<55296||o>56319||a+1===l||(s=u.charCodeAt(a+1))<56320||s>57343?t?u.charAt(a):o:t?u.slice(a,a+2):s-56320+(o-55296<<10)+65536)}};},function(t,e,n){var i=n(30),r=Math.max,o=Math.min;t.exports=function(t,e){return t=i(t),t<0?r(t+e,0):o(t,e)};},function(t,e,n){var i=n(30),r=Math.min;t.exports=function(t){return t>0?r(i(t),9007199254740991):0};},function(t,e,n){var i=n(21);t.exports=function(t){return Object(i(t))};},function(t,e,n){var i=n(72),r=n(80),o=n(24),s=n(4);t.exports=n(44)(Array,"Array",function(t,e){this._t=s(t),this._i=0,this._k=e;},function(){var t=this._t,e=this._k,n=this._i++;return !t||n>=t.length?(this._t=void 0,r(1)):"keys"==e?r(0,n):"values"==e?r(0,t[n]):r(0,[n,t[n]])},"values"),o.Arguments=o.Array,i("keys"),i("values"),i("entries");},function(t,e,n){var i=n(23);i(i.S+i.F*!n(1),"Object",{defineProperty:n(3).f});},function(t,e){},function(t,e,n){var i=n(87)(!0);n(44)(String,"String",function(t){this._t=String(t),this._i=0;},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=i(e,n),this._i+=t.length,{value:t,done:!1})});},function(t,e,n){var i=n(0),r=n(2),o=n(1),s=n(23),u=n(49),a=n(82).KEY,l=n(12),c=n(29),f=n(27),p=n(16),h=n(7),d=n(33),v=n(32),y=n(81),g=n(75),b=n(78),m=n(10),_=n(4),x=n(31),w=n(15),S=n(45),O=n(85),L=n(84),P=n(3),k=n(14),E=L.f,j=P.f,V=O.f,C=i.Symbol,T=i.JSON,A=T&&T.stringify,$=h("_hidden"),D=h("toPrimitive"),F={}.propertyIsEnumerable,M=c("symbol-registry"),B=c("symbols"),N=c("op-symbols"),R=Object.prototype,H="function"==typeof C,G=i.QObject,I=!G||!G.prototype||!G.prototype.findChild,K=o&&l(function(){return 7!=S(j({},"a",{get:function(){return j(this,"a",{value:7}).a}})).a})?function(t,e,n){var i=E(R,e);i&&delete R[e],j(t,e,n),i&&t!==R&&j(R,e,i);}:j,z=function(t){var e=B[t]=S(C.prototype);return e._k=t,e},U=H&&"symbol"==typeof C.iterator?function(t){return "symbol"==typeof t}:function(t){return t instanceof C},W=function(t,e,n){return t===R&&W(N,e,n),m(t),e=x(e,!0),m(n),r(B,e)?(n.enumerable?(r(t,$)&&t[$][e]&&(t[$][e]=!1),n=S(n,{enumerable:w(0,!1)})):(r(t,$)||j(t,$,w(1,{})),t[$][e]=!0),K(t,e,n)):j(t,e,n)},J=function(t,e){m(t);for(var n,i=g(e=_(e)),r=0,o=i.length;o>r;)W(t,n=i[r++],e[n]);return t},q=function(t,e){return void 0===e?S(t):J(S(t),e)},X=function(t){var e=F.call(this,t=x(t,!0));return !(this===R&&r(B,t)&&!r(N,t))&&(!(e||!r(this,t)||!r(B,t)||r(this,$)&&this[$][t])||e)},Y=function(t,e){if(t=_(t),e=x(e,!0),t!==R||!r(B,e)||r(N,e)){var n=E(t,e);return !n||!r(B,e)||r(t,$)&&t[$][e]||(n.enumerable=!0),n}},Q=function(t){for(var e,n=V(_(t)),i=[],o=0;n.length>o;)r(B,e=n[o++])||e==$||e==a||i.push(e);return i},Z=function(t){for(var e,n=t===R,i=V(n?N:_(t)),o=[],s=0;i.length>s;)!r(B,e=i[s++])||n&&!r(R,e)||o.push(B[e]);return o};H||(C=function(){if(this instanceof C)throw TypeError("Symbol is not a constructor!");var t=p(arguments.length>0?arguments[0]:void 0),e=function(n){this===R&&e.call(N,n),r(this,$)&&r(this[$],t)&&(this[$][t]=!1),K(this,t,w(1,n));};return o&&I&&K(R,t,{configurable:!0,set:e}),z(t)},u(C.prototype,"toString",function(){return this._k}),L.f=Y,P.f=W,n(46).f=O.f=Q,n(26).f=X,n(47).f=Z,o&&!n(25)&&u(R,"propertyIsEnumerable",X,!0),d.f=function(t){return z(h(t))}),s(s.G+s.W+s.F*!H,{Symbol:C});for(var tt="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),et=0;tt.length>et;)h(tt[et++]);for(var tt=k(h.store),et=0;tt.length>et;)v(tt[et++]);s(s.S+s.F*!H,"Symbol",{for:function(t){return r(M,t+="")?M[t]:M[t]=C(t)},keyFor:function(t){if(U(t))return y(M,t);throw TypeError(t+" is not a symbol!")},useSetter:function(){I=!0;},useSimple:function(){I=!1;}}),s(s.S+s.F*!H,"Object",{create:q,defineProperty:W,defineProperties:J,getOwnPropertyDescriptor:Y,getOwnPropertyNames:Q,getOwnPropertySymbols:Z}),T&&s(s.S+s.F*(!H||l(function(){var t=C();return "[null]"!=A([t])||"{}"!=A({a:t})||"{}"!=A(Object(t))})),"JSON",{stringify:function(t){if(void 0!==t&&!U(t)){for(var e,n,i=[t],r=1;arguments.length>r;)i.push(arguments[r++]);return e=i[1],"function"==typeof e&&(n=e),!n&&b(e)||(e=function(t,e){if(n&&(e=n.call(this,t,e)),!U(e))return e}),i[1]=e,A.apply(T,i)}}}),C.prototype[D]||n(6)(C.prototype,D,C.prototype.valueOf),f(C,"Symbol"),f(Math,"Math",!0),f(i.JSON,"JSON",!0);},function(t,e,n){n(32)("asyncIterator");},function(t,e,n){n(32)("observable");},function(t,e,n){n(91);for(var i=n(0),r=n(6),o=n(24),s=n(7)("toStringTag"),u=["NodeList","DOMTokenList","MediaList","StyleSheetList","CSSRuleList"],a=0;a<5;a++){var l=u[a],c=i[l],f=c&&c.prototype;f&&!f[s]&&r(f,s,l),o[l]=o.Array;}},function(t,e,n){var i=n(38)("unscopables"),r=Array.prototype;void 0==r[i]&&n(18)(r,i,{}),t.exports=function(t){r[i][t]=!0;};},function(t,e,n){var i=n(19);t.exports=function(t){if(!i(t))throw TypeError(t+" is not an object!");return t};},function(t,e,n){var i=n(115),r=n(37),o=n(114);t.exports=function(t){return function(e,n,s){var u,a=i(e),l=r(a.length),c=o(s,l);if(t&&n!=n){for(;l>c;)if((u=a[c++])!=u)return !0}else for(;l>c;c++)if((t||c in a)&&a[c]===n)return t||c||0;return !t&&-1}};},function(t,e,n){var i=n(50),r=n(57),o=n(36),s=n(37);t.exports=function(t,e,n,u,a){i(e);var l=r(t),c=o(l),f=s(l.length),p=a?f-1:0,h=a?-1:1;if(n<2)for(;;){if(p in c){u=c[p],p+=h;break}if(p+=h,a?p<0:f<=p)throw TypeError("Reduce of empty array with no initial value")}for(;a?p>=0:f>p;p+=h)p in c&&(u=e(u,c[p],p,l));return u};},function(t,e,n){var i=n(19),r=n(54),o=n(38)("species");t.exports=function(t){var e;return r(t)&&(e=t.constructor,"function"!=typeof e||e!==Array&&!r(e.prototype)||(e=void 0),i(e)&&null===(e=e[o])&&(e=void 0)),void 0===e?Array:e};},function(t,e,n){var i=n(103);t.exports=function(t,e){return new(i(t))(e)};},function(t,e,n){var i=n(19),r=n(9).document,o=i(r)&&i(r.createElement);t.exports=function(t){return o?r.createElement(t):{}};},function(t,e,n){var i=n(18),r=n(55),o=n(8),s=n(17),u=n(38);t.exports=function(t,e,n){var a=u(t),l=n(s,a,""[t]),c=l[0],f=l[1];o(function(){var e={};return e[a]=function(){return 7},7!=""[t](e)})&&(r(String.prototype,t,c),i(RegExp.prototype,a,2==e?function(t,e){return f.call(t,this,e)}:function(t){return f.call(t,this)}));};},function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)};},function(t,e,n){t.exports=!n(35)&&!n(8)(function(){return 7!=Object.defineProperty(n(105)("div"),"a",{get:function(){return 7}}).a});},function(t,e,n){var i=n(100),r=n(108),o=n(116),s=Object.defineProperty;e.f=n(35)?Object.defineProperty:function(t,e,n){if(i(t),e=o(e,!0),i(n),r)try{return s(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return "value"in n&&(t[e]=n.value),t};},function(t,e){t.exports=function(t,e){return {enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}};},function(t,e,n){var i=n(9),r=i["__core-js_shared__"]||(i["__core-js_shared__"]={});t.exports=function(t){return r[t]||(r[t]={})};},function(t,e,n){var i=n(5),r=n(17),o=n(8),s=n(113),u="["+s+"]",a="​…",l=RegExp("^"+u+u+"*"),c=RegExp(u+u+"*$"),f=function(t,e,n){var r={},u=o(function(){return !!s[t]()||a[t]()!=a}),l=r[t]=u?e(p):s[t];n&&(r[n]=l),i(i.P+i.F*u,"String",r);},p=f.trim=function(t,e){return t=String(r(t)),1&e&&(t=t.replace(l,"")),2&e&&(t=t.replace(c,"")),t};t.exports=f;},function(t,e){t.exports="\t\n\v\f\r   ᠎              \u2028\u2029\ufeff";},function(t,e,n){var i=n(56),r=Math.max,o=Math.min;t.exports=function(t,e){return t=i(t),t<0?r(t+e,0):o(t,e)};},function(t,e,n){var i=n(36),r=n(17);t.exports=function(t){return i(r(t))};},function(t,e,n){var i=n(19);t.exports=function(t,e){if(!i(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!i(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!i(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!i(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")};},function(t,e,n){var i=n(5),r=n(34)(2);i(i.P+i.F*!n(20)([].filter,!0),"Array",{filter:function(t){return r(this,t,arguments[1])}});},function(t,e,n){var i=n(5),r=n(101)(!1),o=[].indexOf,s=!!o&&1/[1].indexOf(1,-0)<0;i(i.P+i.F*(s||!n(20)(o)),"Array",{indexOf:function(t){return s?o.apply(this,arguments)||0:r(this,t,arguments[1])}});},function(t,e,n){var i=n(5);i(i.S,"Array",{isArray:n(54)});},function(t,e,n){var i=n(5),r=n(34)(1);i(i.P+i.F*!n(20)([].map,!0),"Array",{map:function(t){return r(this,t,arguments[1])}});},function(t,e,n){var i=n(5),r=n(102);i(i.P+i.F*!n(20)([].reduce,!0),"Array",{reduce:function(t){return r(this,t,arguments.length,arguments[1],!1)}});},function(t,e,n){n(106)("search",1,function(t,e,n){return [function(n){var i=t(this),r=void 0==n?void 0:n[e];return void 0!==r?r.call(n,i):new RegExp(n)[e](String(i))},n]});},function(t,e,n){n(112)("trim",function(t){return function(){return t(this,3)}});},function(t,e){},function(t,e){t.exports=function(t,e,n,i,r,o){var s,u=t=t||{},a=typeof t.default;"object"!==a&&"function"!==a||(s=t,u=t.default);var l="function"==typeof u?u.options:u;e&&(l.render=e.render,l.staticRenderFns=e.staticRenderFns,l._compiled=!0),n&&(l.functional=!0),r&&(l._scopeId=r);var c;if(o?(c=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),i&&i.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(o);},l._ssrRegister=c):i&&(c=i),c){var f=l.functional,p=f?l.render:l.beforeCreate;f?(l._injectStyles=c,l.render=function(t,e){return c.call(e),p(t,e)}):l.beforeCreate=p?[].concat(p,c):[c];}return {esModule:s,exports:u,options:l}};},function(t,e,n){var i=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"multiselect",class:{"multiselect--active":t.isOpen,"multiselect--disabled":t.disabled,"multiselect--above":t.isAbove},attrs:{tabindex:t.searchable?-1:t.tabindex},on:{focus:function(e){t.activate();},blur:function(e){!t.searchable&&t.deactivate();},keydown:[function(e){return "button"in e||!t._k(e.keyCode,"down",40,e.key,"ArrowDown")?e.target!==e.currentTarget?null:(e.preventDefault(),void t.pointerForward()):null},function(e){return "button"in e||!t._k(e.keyCode,"up",38,e.key,"ArrowUp")?e.target!==e.currentTarget?null:(e.preventDefault(),void t.pointerBackward()):null},function(e){return "button"in e||!t._k(e.keyCode,"enter",13,e.key,"Enter")||!t._k(e.keyCode,"tab",9,e.key,"Tab")?(e.stopPropagation(),e.target!==e.currentTarget?null:void t.addPointerElement(e)):null}],keyup:function(e){if(!("button"in e)&&t._k(e.keyCode,"esc",27,e.key,"Escape"))return null;t.deactivate();}}},[t._t("caret",[n("div",{staticClass:"multiselect__select",on:{mousedown:function(e){e.preventDefault(),e.stopPropagation(),t.toggle();}}})],{toggle:t.toggle}),t._v(" "),t._t("clear",null,{search:t.search}),t._v(" "),n("div",{ref:"tags",staticClass:"multiselect__tags"},[n("div",{directives:[{name:"show",rawName:"v-show",value:t.visibleValues.length>0,expression:"visibleValues.length > 0"}],staticClass:"multiselect__tags-wrap"},[t._l(t.visibleValues,function(e){return [t._t("tag",[n("span",{staticClass:"multiselect__tag"},[n("span",{domProps:{textContent:t._s(t.getOptionLabel(e))}}),t._v(" "),n("i",{staticClass:"multiselect__tag-icon",attrs:{"aria-hidden":"true",tabindex:"1"},on:{keydown:function(n){if(!("button"in n)&&t._k(n.keyCode,"enter",13,n.key,"Enter"))return null;n.preventDefault(),t.removeElement(e);},mousedown:function(n){n.preventDefault(),t.removeElement(e);}}})])],{option:e,search:t.search,remove:t.removeElement})]})],2),t._v(" "),t.internalValue&&t.internalValue.length>t.limit?[t._t("limit",[n("strong",{staticClass:"multiselect__strong",domProps:{textContent:t._s(t.limitText(t.internalValue.length-t.limit))}})])]:t._e(),t._v(" "),n("transition",{attrs:{name:"multiselect__loading"}},[t._t("loading",[n("div",{directives:[{name:"show",rawName:"v-show",value:t.loading,expression:"loading"}],staticClass:"multiselect__spinner"})])],2),t._v(" "),n("input",{directives:[{name:"show",rawName:"v-show",value:t.isOpen&&t.searchable,expression:"isOpen && searchable"}],ref:"search",staticClass:"multiselect__input",style:t.inputStyle,attrs:{name:t.name,id:t.id,type:"text",autocomplete:"off",placeholder:t.placeholder,disabled:t.disabled,tabindex:t.tabindex},domProps:{value:t.search},on:{input:function(e){t.updateSearch(e.target.value);},focus:function(e){e.preventDefault(),t.activate();},blur:function(e){e.preventDefault(),t.deactivate();},keyup:function(e){if(!("button"in e)&&t._k(e.keyCode,"esc",27,e.key,"Escape"))return null;t.deactivate();},keydown:[function(e){if(!("button"in e)&&t._k(e.keyCode,"down",40,e.key,"ArrowDown"))return null;e.preventDefault(),t.pointerForward();},function(e){if(!("button"in e)&&t._k(e.keyCode,"up",38,e.key,"ArrowUp"))return null;e.preventDefault(),t.pointerBackward();},function(e){return "button"in e||!t._k(e.keyCode,"enter",13,e.key,"Enter")?(e.preventDefault(),e.stopPropagation(),e.target!==e.currentTarget?null:void t.addPointerElement(e)):null},function(e){if(!("button"in e)&&t._k(e.keyCode,"delete",[8,46],e.key,["Backspace","Delete"]))return null;e.stopPropagation(),t.removeLastElement();}]}}),t._v(" "),t.isSingleLabelVisible?n("span",{staticClass:"multiselect__single",on:{mousedown:function(e){return e.preventDefault(),t.toggle(e)}}},[t._t("singleLabel",[[t._v(t._s(t.currentOptionLabel))]],{option:t.singleValue})],2):t._e(),t._v(" "),t.isPlaceholderVisible?n("span",{on:{mousedown:function(e){return e.preventDefault(),t.toggle(e)}}},[t._t("placeholder",[n("span",{staticClass:"multiselect__single"},[t._v("\n            "+t._s(t.placeholder)+"\n          ")])])],2):t._e()],2),t._v(" "),n("transition",{attrs:{name:"multiselect"}},[n("div",{directives:[{name:"show",rawName:"v-show",value:t.isOpen,expression:"isOpen"}],ref:"list",staticClass:"multiselect__content-wrapper",style:{maxHeight:t.optimizedHeight+"px"},on:{focus:t.activate,mousedown:function(t){t.preventDefault();}}},[n("ul",{staticClass:"multiselect__content",style:t.contentStyle},[t._t("beforeList"),t._v(" "),t.multiple&&t.max===t.internalValue.length?n("li",[n("span",{staticClass:"multiselect__option"},[t._t("maxElements",[t._v("Maximum of "+t._s(t.max)+" options selected. First remove a selected option to select another.")])],2)]):t._e(),t._v(" "),!t.max||t.internalValue.length<t.max?t._l(t.filteredOptions,function(e,i){return n("li",{key:i,staticClass:"multiselect__element"},[e&&(e.$isLabel||e.$isDisabled)?t._e():n("span",{staticClass:"multiselect__option",class:t.optionHighlight(i,e),attrs:{"data-select":e&&e.isTag?t.tagPlaceholder:t.selectLabelText,"data-selected":t.selectedLabelText,"data-deselect":t.deselectLabelText},on:{click:function(n){n.stopPropagation(),t.select(e);},mouseenter:function(e){if(e.target!==e.currentTarget)return null;t.pointerSet(i);}}},[t._t("option",[n("span",[t._v(t._s(t.getOptionLabel(e)))])],{option:e,search:t.search})],2),t._v(" "),e&&(e.$isLabel||e.$isDisabled)?n("span",{staticClass:"multiselect__option",class:t.groupHighlight(i,e),attrs:{"data-select":t.groupSelect&&t.selectGroupLabelText,"data-deselect":t.groupSelect&&t.deselectGroupLabelText},on:{mouseenter:function(e){if(e.target!==e.currentTarget)return null;t.groupSelect&&t.pointerSet(i);},mousedown:function(n){n.preventDefault(),t.selectGroup(e);}}},[t._t("option",[n("span",[t._v(t._s(t.getOptionLabel(e)))])],{option:e,search:t.search})],2):t._e()])}):t._e(),t._v(" "),n("li",{directives:[{name:"show",rawName:"v-show",value:t.showNoResults&&0===t.filteredOptions.length&&t.search&&!t.loading,expression:"showNoResults && (filteredOptions.length === 0 && search && !loading)"}]},[n("span",{staticClass:"multiselect__option"},[t._t("noResult",[t._v("No elements found. Consider changing the search query.")])],2)]),t._v(" "),t._t("afterList")],2)])])],2)},r=[],o={render:i,staticRenderFns:r};e.a=o;}])});
	});

	var Multiselect = unwrapExports(vueMultiselect_min);
	var vueMultiselect_min_1 = vueMultiselect_min.VueMultiselect;

	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//
	//

	var script = {
	  name: 'VueDatepickerLocalCalendar',
	  props: {
	    value: null,
	    left: false,
	    right: false
	  },
	  data () {
	    const time = this.get(this.value);
	    return {
	      pre: 'calendar',
	      m: 'D',
	      showYears: false,
	      showMonths: false,
	      showHours: false,
	      showMinutes: false,
	      showSeconds: false,
	      year: time.year,
	      month: time.month,
	      day: time.day,
	      hour: time.hour,
	      minute: time.minute,
	      second: time.second
	    }
	  },
	  watch: {
	    value (val) {
	      const $this = this;
	      const time = $this.get(val);
	      $this.year = time.year;
	      $this.month = time.month;
	      $this.day = time.day;
	      $this.hour = time.hour;
	      $this.minute = time.minute;
	      $this.second = time.second;
	    }
	  },
	  computed: {
	    local () {
	      return this.$parent.local
	    },
	    format () {
	      return this.$parent.format
	    },
	    start () {
	      return this.parse(this.$parent.dates[0])
	    },
	    end () {
	      return this.parse(this.$parent.dates[1])
	    },
	    ys () {
	      return parseInt(this.year / 10) * 10
	    },
	    ye () {
	      return this.ys + 10
	    },
	    years () {
	      const arr = [];
	      let start = this.ys - 1;
	      while (arr.length < 12) {
	        arr.push(start++);
	      }
	      return arr
	    },
	    days () {
	      const days = [];
	      const $this = this;
	      const year = $this.year;
	      const month = $this.month;
	      const time = new Date(year, month, 1);
	      const dow = $this.local.dow || 7;
	      time.setDate(0); // switch to the last day of last month
	      let lastDay = time.getDate();
	      const week = time.getDay() || 7;
	      let count = dow <= week ? (week - dow + 1) : (week + (7 - dow + 1));
	      while (count > 0) {
	        days.push({
	          i: lastDay - count + 1,
	          y: month > 0 ? year : year - 1,
	          m: month > 0 ? month - 1 : 11,
	          p: true
	        });
	        count--;
	      }
	      time.setMonth(time.getMonth() + 2, 0); // switch to the last day of the current month
	      lastDay = time.getDate();
	      let i = 1;
	      for (i = 1; i <= lastDay; i++) {
	        days.push({
	          i: i,
	          y: year,
	          m: month
	        });
	      }
	      for (i = 1; days.length < 42; i++) {
	        days.push({
	          i: i,
	          y: month < 11 ? year : year + 1,
	          m: month < 11 ? month + 1 : 0,
	          n: true
	        });
	      }
	      return days
	    }
	  },
	  filters: {
	    dd: val => ('0' + val).slice(-2)
	  },
	  methods: {
	    get (time) {
	      return {
	        year: time.getFullYear(),
	        month: time.getMonth(),
	        day: time.getDate(),
	        hour: time.getHours(),
	        minute: time.getMinutes(),
	        second: time.getSeconds()
	      }
	    },
	    parse (num) {
	      return parseInt(num / 1000)
	    },
	    status (year, month, day, hour, minute, second, format) {
	      const $this = this;
	      const maxDay = new Date(year, month + 1, 0).getDate();
	      const time = new Date(year, month, day > maxDay ? maxDay : day, hour, minute, second);
	      const t = $this.parse(time);
	      const f = $this.$parent.tf;
	      const classObj = {};
	      let flag = false;
	      if (format === 'YYYY') {
	        flag = year === $this.year;
	      } else if (format === 'YYYYMM') {
	        flag = month === $this.month;
	      } else {
	        flag = f($this.value, format) === f(time, format);
	      }
	      classObj[`${$this.pre}-date`] = true;
	      classObj[`${$this.pre}-date-disabled`] = ($this.right && t < $this.start) || ($this.left && t > $this.end) || $this.$parent.disabledDate(time, format);
	      classObj[`${$this.pre}-date-on`] = ($this.left && t > $this.start) || ($this.right && t < $this.end);
	      classObj[`${$this.pre}-date-selected`] = flag;
	      return classObj
	    },
	    nm () {
	      if (this.month < 11) {
	        this.month++;
	      } else {
	        this.month = 0;
	        this.year++;
	      }
	    },
	    pm () {
	      if (this.month > 0) {
	        this.month--;
	      } else {
	        this.month = 11;
	        this.year--;
	      }
	    },
	    is (e) {
	      return e.target.className.indexOf(`${this.pre}-date-disabled`) === -1
	    },
	    ok (info) {
	      const $this = this;
	      let year = '';
	      let month = '';
	      info && info.n && $this.nm();
	      info && info.p && $this.pm();
	      if (info === 'h') {
	        const time = $this.get(this.value);
	        year = time.year;
	        month = time.month;
	      }
	      $this.$emit('input', new Date(year || $this.year, month || $this.month, $this.day, $this.hour, $this.minute, $this.second));
	      $this.$parent.ok(info === 'h');
	    }
	  },
	  mounted () {
	    const $this = this;
	    const is = c => $this.format.indexOf(c) !== -1;
	    if (is('s') && is('m') && (is('h') || is('H'))) {
	      $this.m = 'H';
	    } else if (is('D')) {
	      $this.m = 'D';
	    } else if (is('M')) {
	      $this.m = 'M';
	      $this.showMonths = true;
	    } else if (is('Y')) {
	      $this.m = 'Y';
	      $this.showYears = true;
	    }
	  }
	};

	function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
	    if (typeof shadowMode !== 'boolean') {
	        createInjectorSSR = createInjector;
	        createInjector = shadowMode;
	        shadowMode = false;
	    }
	    // Vue.extend constructor export interop.
	    const options = typeof script === 'function' ? script.options : script;
	    // render functions
	    if (template && template.render) {
	        options.render = template.render;
	        options.staticRenderFns = template.staticRenderFns;
	        options._compiled = true;
	        // functional template
	        if (isFunctionalTemplate) {
	            options.functional = true;
	        }
	    }
	    // scopedId
	    if (scopeId) {
	        options._scopeId = scopeId;
	    }
	    let hook;
	    if (moduleIdentifier) {
	        // server build
	        hook = function (context) {
	            // 2.3 injection
	            context =
	                context || // cached call
	                    (this.$vnode && this.$vnode.ssrContext) || // stateful
	                    (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional
	            // 2.2 with runInNewContext: true
	            if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
	                context = __VUE_SSR_CONTEXT__;
	            }
	            // inject component styles
	            if (style) {
	                style.call(this, createInjectorSSR(context));
	            }
	            // register component module identifier for async chunk inference
	            if (context && context._registeredComponents) {
	                context._registeredComponents.add(moduleIdentifier);
	            }
	        };
	        // used by ssr in case component is cached and beforeCreate
	        // never gets called
	        options._ssrRegister = hook;
	    }
	    else if (style) {
	        hook = shadowMode
	            ? function (context) {
	                style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
	            }
	            : function (context) {
	                style.call(this, createInjector(context));
	            };
	    }
	    if (hook) {
	        if (options.functional) {
	            // register for functional component in vue file
	            const originalRender = options.render;
	            options.render = function renderWithStyleInjection(h, context) {
	                hook.call(context);
	                return originalRender(h, context);
	            };
	        }
	        else {
	            // inject component registration as beforeCreate hook
	            const existing = options.beforeCreate;
	            options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
	        }
	    }
	    return script;
	}

	/* script */
	const __vue_script__ = script;
	/* template */
	var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{class:("" + _vm.pre)},[_c('div',{class:(_vm.pre + "-head")},[_c('a',{directives:[{name:"show",rawName:"v-show",value:(_vm.showYears),expression:"showYears"}],class:(_vm.pre + "-prev-decade-btn"),on:{"click":function($event){_vm.year-=10;}}},[_vm._v("«")]),_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears),expression:"!showYears"}],class:(_vm.pre + "-prev-year-btn"),on:{"click":function($event){_vm.year--;}}},[_vm._v("«")]),_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears&&!_vm.showMonths),expression:"!showYears&&!showMonths"}],class:(_vm.pre + "-prev-month-btn"),on:{"click":_vm.pm}},[_vm._v("‹")]),_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(_vm.showYears),expression:"showYears"}],class:(_vm.pre + "-year-select")},[_vm._v(_vm._s(_vm.ys+'-'+_vm.ye))]),_vm._v(" "),(_vm.local.yearSuffix)?[_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears),expression:"!showYears"}],class:(_vm.pre + "-year-select"),on:{"click":function($event){_vm.showYears=!_vm.showYears;}}},[_vm._v(_vm._s(_vm.year)+_vm._s(_vm.local.yearSuffix))]),_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears&&!_vm.showMonths),expression:"!showYears&&!showMonths"}],class:(_vm.pre + "-month-select"),on:{"click":function($event){_vm.showMonths=!_vm.showMonths;}}},[_vm._v(_vm._s(_vm.local.monthsHead[_vm.month]))])]:[_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears&&!_vm.showMonths),expression:"!showYears&&!showMonths"}],class:(_vm.pre + "-month-select"),on:{"click":function($event){_vm.showMonths=!_vm.showMonths;}}},[_vm._v(_vm._s(_vm.local.monthsHead[_vm.month]))]),_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears),expression:"!showYears"}],class:(_vm.pre + "-year-select"),on:{"click":function($event){_vm.showYears=!_vm.showYears;}}},[_vm._v(_vm._s(_vm.year))])],_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears&&!_vm.showMonths),expression:"!showYears&&!showMonths"}],class:(_vm.pre + "-next-month-btn"),on:{"click":_vm.nm}},[_vm._v("›")]),_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(!_vm.showYears),expression:"!showYears"}],class:(_vm.pre + "-next-year-btn"),on:{"click":function($event){_vm.year++;}}},[_vm._v("»")]),_vm._v(" "),_c('a',{directives:[{name:"show",rawName:"v-show",value:(_vm.showYears),expression:"showYears"}],class:(_vm.pre + "-next-decade-btn"),on:{"click":function($event){_vm.year+=10;}}},[_vm._v("»")])],2),_vm._v(" "),_c('div',{class:(_vm.pre + "-body")},[_c('div',{class:(_vm.pre + "-days")},[_vm._l((_vm.local.weeks),function(i){return _c('a',{key:i,class:(_vm.pre + "-week")},[_vm._v(_vm._s(i))])}),_vm._v(" "),_vm._l((_vm.days),function(j,i){return _c('a',{key:i,class:[(j.p||j.n)?(_vm.pre + "-date-out"):'',_vm.status(j.y,j.m,j.i,_vm.hour,_vm.minute,_vm.second,'YYYYMMDD')],on:{"click":function($event){_vm.is($event)&&(_vm.day=j.i,_vm.ok(j));}}},[_vm._v(_vm._s(j.i))])})],2),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.showMonths),expression:"showMonths"}],class:(_vm.pre + "-months")},_vm._l((_vm.local.months),function(i,j){return _c('a',{key:j,class:[_vm.status(_vm.year,j,_vm.day,_vm.hour,_vm.minute,_vm.second,'YYYYMM')],on:{"click":function($event){_vm.is($event)&&(_vm.showMonths=(_vm.m==='M'),_vm.month=j,(_vm.m==='M'&&_vm.ok()));}}},[_vm._v(_vm._s(i))])}),0),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.showYears),expression:"showYears"}],class:(_vm.pre + "-years")},_vm._l((_vm.years),function(i,j){return _c('a',{key:j,class:[(j===0||j===11)?(_vm.pre + "-date-out"):'',_vm.status(i,_vm.month,_vm.day,_vm.hour,_vm.minute,_vm.second,'YYYY')],on:{"click":function($event){_vm.is($event)&&(_vm.showYears=(_vm.m==='Y'),_vm.year=i,(_vm.m==='Y'&&_vm.ok()));}}},[_vm._v(_vm._s(i))])}),0),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.showHours),expression:"showHours"}],class:(_vm.pre + "-hours")},[_c('div',{class:(_vm.pre + "-title")},[_vm._v(_vm._s(_vm.local.hourTip))]),_vm._v(" "),_vm._l((24),function(j,i){return _c('a',{key:i,class:[_vm.status(_vm.year,_vm.month,_vm.day,i,_vm.minute,_vm.second,'YYYYMMDDHH')],on:{"click":function($event){_vm.is($event)&&(_vm.showHours=false,_vm.hour=i,_vm.ok('h'));}}},[_vm._v(_vm._s(i))])})],2),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.showMinutes),expression:"showMinutes"}],class:(_vm.pre + "-minutes")},[_c('div',{class:(_vm.pre + "-title")},[_vm._v(_vm._s(_vm.local.minuteTip))]),_vm._v(" "),_vm._l((60),function(j,i){return _c('a',{key:i,class:[_vm.status(_vm.year,_vm.month,_vm.day,_vm.hour,i,_vm.second,'YYYYMMDDHHmm')],on:{"click":function($event){_vm.is($event)&&(_vm.showMinutes=false,_vm.minute=i,_vm.ok('h'));}}},[_vm._v(_vm._s(i))])})],2),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.showSeconds),expression:"showSeconds"}],class:(_vm.pre + "-seconds")},[_c('div',{class:(_vm.pre + "-title")},[_vm._v(_vm._s(_vm.local.secondTip))]),_vm._v(" "),_vm._l((60),function(j,i){return _c('a',{key:i,class:[_vm.status(_vm.year,_vm.month,_vm.day,_vm.hour,_vm.minute,i,'YYYYMMDDHHmmss')],on:{"click":function($event){_vm.is($event)&&(_vm.showSeconds=false,_vm.second=i,_vm.ok('h'));}}},[_vm._v(_vm._s(i))])})],2)]),_vm._v(" "),(_vm.m==='H')?_c('div',{class:(_vm.pre + "-foot")},[_c('div',{class:(_vm.pre + "-hour")},[_c('a',{class:{on:_vm.showHours},attrs:{"title":_vm.local.hourTip},on:{"click":function($event){_vm.showHours=!_vm.showHours,_vm.showMinutes=_vm.showSeconds=false;}}},[_vm._v(_vm._s(_vm._f("dd")(_vm.hour)))]),_vm._v(" "),_c('span',[_vm._v(":")]),_vm._v(" "),_c('a',{class:{on:_vm.showMinutes},attrs:{"title":_vm.local.minuteTip},on:{"click":function($event){_vm.showMinutes=!_vm.showMinutes,_vm.showHours=_vm.showSeconds=false;}}},[_vm._v(_vm._s(_vm._f("dd")(_vm.minute)))]),_vm._v(" "),_c('span',[_vm._v(":")]),_vm._v(" "),_c('a',{class:{on:_vm.showSeconds},attrs:{"title":_vm.local.secondTip},on:{"click":function($event){_vm.showSeconds=!_vm.showSeconds,_vm.showHours=_vm.showMinutes=false;}}},[_vm._v(_vm._s(_vm._f("dd")(_vm.second)))])])]):_vm._e()])};
	var __vue_staticRenderFns__ = [];

	  /* style */
	  const __vue_inject_styles__ = undefined;
	  /* scoped */
	  const __vue_scope_id__ = undefined;
	  /* module identifier */
	  const __vue_module_identifier__ = undefined;
	  /* functional template */
	  const __vue_is_functional_template__ = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__ = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
	    __vue_inject_styles__,
	    __vue_script__,
	    __vue_scope_id__,
	    __vue_is_functional_template__,
	    __vue_module_identifier__,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	//
	var script$1 = {
	  name: 'VueDatepickerLocal',
	  components: { VueDatepickerLocalCalendar: __vue_component__ },
	  props: {
	    name: [String],
	    inputClass: [String],
	    popupClass: [String],
	    value: [Date, Array, String],
	    disabled: [Boolean],
	    type: {
	      type: String,
	      default: 'normal'
	    },
	    rangeSeparator: {
	      type: String,
	      default: '~'
	    },
	    clearable: {
	      type: Boolean,
	      default: false
	    },
	    placeholder: [String],
	    disabledDate: {
	      type: Function,
	      default: () => {
	        return false
	      }
	    },
	    format: {
	      type: String,
	      default: 'YYYY-MM-DD'
	    },
	    local: {
	      type: Object,
	      default () {
	        return {
	          dow: 1, // Monday is the first day of the week
	          hourTip: '选择小时', // tip of select hour
	          minuteTip: '选择分钟', // tip of select minute
	          secondTip: '选择秒数', // tip of select second
	          yearSuffix: '年', // format of head
	          monthsHead: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), // months of head
	          months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), // months of panel
	          weeks: '一_二_三_四_五_六_日'.split('_'), // weeks
	          cancelTip: '取消', // default text for cancel button
	          submitTip: '确定' // default text for submit button
	        }
	      }
	    },
	    showButtons: {
	      type: Boolean,
	      default: false
	    },
	    dateRangeSelect: [Function]
	  },
	  data () {
	    return {
	      show: false,
	      dates: this.vi(this.value)
	    }
	  },
	  computed: {
	    range () {
	      return this.dates.length === 2
	    },
	    text () {
	      const val = this.value;
	      const txt = this.dates.map(date => this.tf(date)).join(` ${this.rangeSeparator} `);
	      if (Array.isArray(val)) {
	        return val.length > 1 ? txt : ''
	      } else {
	        return val ? txt : ''
	      }
	    }
	  },
	  watch: {
	    value (val) {
	      this.dates = this.vi(this.value);
	    }
	  },
	  methods: {
	    get () {
	      return Array.isArray(this.value) ? this.dates : this.dates[0]
	    },
	    cls () {
	      this.$emit('input', this.range ? [] : '');
	    },
	    vi (val) {
	      if (Array.isArray(val)) {
	        return val.length > 1 ? val.map(item => new Date(item)) : [new Date(), new Date()]
	      } else {
	        return val ? new Array(new Date(val)) : [new Date()]
	      }
	    },
	    ok (leaveOpened) {
	      const $this = this;
	      $this.$emit('input', $this.get());
	      !leaveOpened && !$this.showButtons && setTimeout(() => {
	        $this.show = $this.range;
	      });
	    },
	    tf (time, format) {
	      const year = time.getFullYear();
	      const month = time.getMonth();
	      const day = time.getDate();
	      const hours24 = time.getHours();
	      const hours = hours24 % 12 === 0 ? 12 : hours24 % 12;
	      const minutes = time.getMinutes();
	      const seconds = time.getSeconds();
	      const milliseconds = time.getMilliseconds();
	      const dd = t => ('0' + t).slice(-2);
	      const map = {
	        YYYY: year,
	        MM: dd(month + 1),
	        MMM: this.local.months[month],
	        MMMM: this.local.monthsHead[month],
	        M: month + 1,
	        DD: dd(day),
	        D: day,
	        HH: dd(hours24),
	        H: hours24,
	        hh: dd(hours),
	        h: hours,
	        mm: dd(minutes),
	        m: minutes,
	        ss: dd(seconds),
	        s: seconds,
	        S: milliseconds
	      };
	      return (format || this.format).replace(/Y+|M+|D+|H+|h+|m+|s+|S+/g, str => map[str])
	    },
	    dc (e) {
	      this.show = this.$el.contains(e.target) && !this.disabled;
	    },
	    submit () {
	      this.$emit('confirm', this.get());
	      this.show = false;
	    },
	    cancel () {
	      this.show = false;
	    }
	  },
	  mounted () {
	    document.addEventListener('click', this.dc, true);
	  },
	  beforeDestroy () {
	    document.removeEventListener('click', this.dc, true);
	  }
	};

	/* script */
	const __vue_script__$1 = script$1;
	/* template */
	var __vue_render__$1 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"datepicker",class:{'datepicker-range':_vm.range,'datepicker__clearable':_vm.clearable&&_vm.text&&!_vm.disabled}},[(_vm.type!=='inline')?_c('input',{class:[_vm.show ? 'focus' : '', _vm.inputClass],attrs:{"readonly":"","disabled":_vm.disabled,"placeholder":_vm.placeholder,"name":_vm.name},domProps:{"value":_vm.text}}):_vm._e(),_vm._v(" "),_c('a',{staticClass:"datepicker-close",on:{"click":function($event){$event.stopPropagation();return _vm.cls($event)}}}),_vm._v(" "),_c('transition',{attrs:{"name":"datepicker-anim"}},[(_vm.show||_vm.type==='inline')?_c('div',{staticClass:"datepicker-popup",class:[_vm.popupClass,{'datepicker-inline':_vm.type==='inline'}],attrs:{"tabindex":"-1"}},[(_vm.range)?[_c('vue-datepicker-local-calendar',{attrs:{"left":true},model:{value:(_vm.dates[0]),callback:function ($$v) {_vm.$set(_vm.dates, 0, $$v);},expression:"dates[0]"}}),_vm._v(" "),_c('vue-datepicker-local-calendar',{attrs:{"right":true},model:{value:(_vm.dates[1]),callback:function ($$v) {_vm.$set(_vm.dates, 1, $$v);},expression:"dates[1]"}})]:[_c('vue-datepicker-local-calendar',{model:{value:(_vm.dates[0]),callback:function ($$v) {_vm.$set(_vm.dates, 0, $$v);},expression:"dates[0]"}})],_vm._v(" "),(_vm.showButtons)?_c('div',{staticClass:"datepicker__buttons"},[_c('button',{staticClass:"datepicker__button-cancel",on:{"click":function($event){$event.preventDefault();$event.stopPropagation();return _vm.cancel($event)}}},[_vm._v(_vm._s(this.local.cancelTip))]),_vm._v(" "),_c('button',{staticClass:"datepicker__button-select",on:{"click":function($event){$event.preventDefault();$event.stopPropagation();return _vm.submit($event)}}},[_vm._v(_vm._s(this.local.submitTip))])]):_vm._e()],2):_vm._e()])],1)};
	var __vue_staticRenderFns__$1 = [];

	  /* style */
	  const __vue_inject_styles__$1 = undefined;
	  /* scoped */
	  const __vue_scope_id__$1 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$1 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$1 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$1 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 },
	    __vue_inject_styles__$1,
	    __vue_script__$1,
	    __vue_scope_id__$1,
	    __vue_is_functional_template__$1,
	    __vue_module_identifier__$1,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	function install$2 (Vue) {
	  Vue.component(__vue_component__$1.name, __vue_component__$1);
	}
	__vue_component__$1.install = install$2;
	if (typeof window !== 'undefined' && window.Vue) {
	  install$2(window.Vue);
	}

	//

	var script$2 = {
		props: {
			content: String
		},
		data () {
			return {}
		}
	};

	/* script */
	const __vue_script__$2 = script$2;
	/* template */
	var __vue_render__$2 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('span',{staticClass:"searchwp-tooltip"},[_c('span',[_vm._t("default")],2),_vm._v(" "),_c('span',{directives:[{name:"tooltip",rawName:"v-tooltip",value:(_vm.content),expression:"content"}],staticClass:"dashicons dashicons-editor-help"})])};
	var __vue_staticRenderFns__$2 = [];

	  /* style */
	  const __vue_inject_styles__$2 = undefined;
	  /* scoped */
	  const __vue_scope_id__$2 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$2 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$2 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$2 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$2, staticRenderFns: __vue_staticRenderFns__$2 },
	    __vue_inject_styles__$2,
	    __vue_script__$2,
	    __vue_scope_id__$2,
	    __vue_is_functional_template__$2,
	    __vue_module_identifier__$2,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	/**
	 * @namespace Chart.helpers
	 */
	var helpers = {
		/**
		 * An empty function that can be used, for example, for optional callback.
		 */
		noop: function() {},

		/**
		 * Returns a unique id, sequentially generated from a global variable.
		 * @returns {Number}
		 * @function
		 */
		uid: (function() {
			var id = 0;
			return function() {
				return id++;
			};
		}()),

		/**
		 * Returns true if `value` is neither null nor undefined, else returns false.
		 * @param {*} value - The value to test.
		 * @returns {Boolean}
		 * @since 2.7.0
		 */
		isNullOrUndef: function(value) {
			return value === null || typeof value === 'undefined';
		},

		/**
		 * Returns true if `value` is an array, else returns false.
		 * @param {*} value - The value to test.
		 * @returns {Boolean}
		 * @function
		 */
		isArray: Array.isArray ? Array.isArray : function(value) {
			return Object.prototype.toString.call(value) === '[object Array]';
		},

		/**
		 * Returns true if `value` is an object (excluding null), else returns false.
		 * @param {*} value - The value to test.
		 * @returns {Boolean}
		 * @since 2.7.0
		 */
		isObject: function(value) {
			return value !== null && Object.prototype.toString.call(value) === '[object Object]';
		},

		/**
		 * Returns `value` if defined, else returns `defaultValue`.
		 * @param {*} value - The value to return if defined.
		 * @param {*} defaultValue - The value to return if `value` is undefined.
		 * @returns {*}
		 */
		valueOrDefault: function(value, defaultValue) {
			return typeof value === 'undefined' ? defaultValue : value;
		},

		/**
		 * Returns value at the given `index` in array if defined, else returns `defaultValue`.
		 * @param {Array} value - The array to lookup for value at `index`.
		 * @param {Number} index - The index in `value` to lookup for value.
		 * @param {*} defaultValue - The value to return if `value[index]` is undefined.
		 * @returns {*}
		 */
		valueAtIndexOrDefault: function(value, index, defaultValue) {
			return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
		},

		/**
		 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
		 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
		 * @param {Function} fn - The function to call.
		 * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
		 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
		 * @returns {*}
		 */
		callback: function(fn, args, thisArg) {
			if (fn && typeof fn.call === 'function') {
				return fn.apply(thisArg, args);
			}
		},

		/**
		 * Note(SB) for performance sake, this method should only be used when loopable type
		 * is unknown or in none intensive code (not called often and small loopable). Else
		 * it's preferable to use a regular for() loop and save extra function calls.
		 * @param {Object|Array} loopable - The object or array to be iterated.
		 * @param {Function} fn - The function to call for each item.
		 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
		 * @param {Boolean} [reverse] - If true, iterates backward on the loopable.
		 */
		each: function(loopable, fn, thisArg, reverse) {
			var i, len, keys;
			if (helpers.isArray(loopable)) {
				len = loopable.length;
				if (reverse) {
					for (i = len - 1; i >= 0; i--) {
						fn.call(thisArg, loopable[i], i);
					}
				} else {
					for (i = 0; i < len; i++) {
						fn.call(thisArg, loopable[i], i);
					}
				}
			} else if (helpers.isObject(loopable)) {
				keys = Object.keys(loopable);
				len = keys.length;
				for (i = 0; i < len; i++) {
					fn.call(thisArg, loopable[keys[i]], keys[i]);
				}
			}
		},

		/**
		 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
		 * @see http://stackoverflow.com/a/14853974
		 * @param {Array} a0 - The array to compare
		 * @param {Array} a1 - The array to compare
		 * @returns {Boolean}
		 */
		arrayEquals: function(a0, a1) {
			var i, ilen, v0, v1;

			if (!a0 || !a1 || a0.length !== a1.length) {
				return false;
			}

			for (i = 0, ilen = a0.length; i < ilen; ++i) {
				v0 = a0[i];
				v1 = a1[i];

				if (v0 instanceof Array && v1 instanceof Array) {
					if (!helpers.arrayEquals(v0, v1)) {
						return false;
					}
				} else if (v0 !== v1) {
					// NOTE: two different object instances will never be equal: {x:20} != {x:20}
					return false;
				}
			}

			return true;
		},

		/**
		 * Returns a deep copy of `source` without keeping references on objects and arrays.
		 * @param {*} source - The value to clone.
		 * @returns {*}
		 */
		clone: function(source) {
			if (helpers.isArray(source)) {
				return source.map(helpers.clone);
			}

			if (helpers.isObject(source)) {
				var target = {};
				var keys = Object.keys(source);
				var klen = keys.length;
				var k = 0;

				for (; k < klen; ++k) {
					target[keys[k]] = helpers.clone(source[keys[k]]);
				}

				return target;
			}

			return source;
		},

		/**
		 * The default merger when Chart.helpers.merge is called without merger option.
		 * Note(SB): this method is also used by configMerge and scaleMerge as fallback.
		 * @private
		 */
		_merger: function(key, target, source, options) {
			var tval = target[key];
			var sval = source[key];

			if (helpers.isObject(tval) && helpers.isObject(sval)) {
				helpers.merge(tval, sval, options);
			} else {
				target[key] = helpers.clone(sval);
			}
		},

		/**
		 * Merges source[key] in target[key] only if target[key] is undefined.
		 * @private
		 */
		_mergerIf: function(key, target, source) {
			var tval = target[key];
			var sval = source[key];

			if (helpers.isObject(tval) && helpers.isObject(sval)) {
				helpers.mergeIf(tval, sval);
			} else if (!target.hasOwnProperty(key)) {
				target[key] = helpers.clone(sval);
			}
		},

		/**
		 * Recursively deep copies `source` properties into `target` with the given `options`.
		 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
		 * @param {Object} target - The target object in which all sources are merged into.
		 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
		 * @param {Object} [options] - Merging options:
		 * @param {Function} [options.merger] - The merge method (key, target, source, options)
		 * @returns {Object} The `target` object.
		 */
		merge: function(target, source, options) {
			var sources = helpers.isArray(source) ? source : [source];
			var ilen = sources.length;
			var merge, i, keys, klen, k;

			if (!helpers.isObject(target)) {
				return target;
			}

			options = options || {};
			merge = options.merger || helpers._merger;

			for (i = 0; i < ilen; ++i) {
				source = sources[i];
				if (!helpers.isObject(source)) {
					continue;
				}

				keys = Object.keys(source);
				for (k = 0, klen = keys.length; k < klen; ++k) {
					merge(keys[k], target, source, options);
				}
			}

			return target;
		},

		/**
		 * Recursively deep copies `source` properties into `target` *only* if not defined in target.
		 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
		 * @param {Object} target - The target object in which all sources are merged into.
		 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
		 * @returns {Object} The `target` object.
		 */
		mergeIf: function(target, source) {
			return helpers.merge(target, source, {merger: helpers._mergerIf});
		},

		/**
		 * Applies the contents of two or more objects together into the first object.
		 * @param {Object} target - The target object in which all objects are merged into.
		 * @param {Object} arg1 - Object containing additional properties to merge in target.
		 * @param {Object} argN - Additional objects containing properties to merge in target.
		 * @returns {Object} The `target` object.
		 */
		extend: function(target) {
			var setFn = function(value, key) {
				target[key] = value;
			};
			for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
				helpers.each(arguments[i], setFn);
			}
			return target;
		},

		/**
		 * Basic javascript inheritance based on the model created in Backbone.js
		 */
		inherits: function(extensions) {
			var me = this;
			var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
				return me.apply(this, arguments);
			};

			var Surrogate = function() {
				this.constructor = ChartElement;
			};

			Surrogate.prototype = me.prototype;
			ChartElement.prototype = new Surrogate();
			ChartElement.extend = helpers.inherits;

			if (extensions) {
				helpers.extend(ChartElement.prototype, extensions);
			}

			ChartElement.__super__ = me.prototype;
			return ChartElement;
		}
	};

	var helpers_core = helpers;

	// DEPRECATIONS

	/**
	 * Provided for backward compatibility, use Chart.helpers.callback instead.
	 * @function Chart.helpers.callCallback
	 * @deprecated since version 2.6.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers.callCallback = helpers.callback;

	/**
	 * Provided for backward compatibility, use Array.prototype.indexOf instead.
	 * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
	 * @function Chart.helpers.indexOf
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers.indexOf = function(array, item, fromIndex) {
		return Array.prototype.indexOf.call(array, item, fromIndex);
	};

	/**
	 * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
	 * @function Chart.helpers.getValueOrDefault
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers.getValueOrDefault = helpers.valueOrDefault;

	/**
	 * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
	 * @function Chart.helpers.getValueAtIndexOrDefault
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;

	/**
	 * Easing functions adapted from Robert Penner's easing equations.
	 * @namespace Chart.helpers.easingEffects
	 * @see http://www.robertpenner.com/easing/
	 */
	var effects = {
		linear: function(t) {
			return t;
		},

		easeInQuad: function(t) {
			return t * t;
		},

		easeOutQuad: function(t) {
			return -t * (t - 2);
		},

		easeInOutQuad: function(t) {
			if ((t /= 0.5) < 1) {
				return 0.5 * t * t;
			}
			return -0.5 * ((--t) * (t - 2) - 1);
		},

		easeInCubic: function(t) {
			return t * t * t;
		},

		easeOutCubic: function(t) {
			return (t = t - 1) * t * t + 1;
		},

		easeInOutCubic: function(t) {
			if ((t /= 0.5) < 1) {
				return 0.5 * t * t * t;
			}
			return 0.5 * ((t -= 2) * t * t + 2);
		},

		easeInQuart: function(t) {
			return t * t * t * t;
		},

		easeOutQuart: function(t) {
			return -((t = t - 1) * t * t * t - 1);
		},

		easeInOutQuart: function(t) {
			if ((t /= 0.5) < 1) {
				return 0.5 * t * t * t * t;
			}
			return -0.5 * ((t -= 2) * t * t * t - 2);
		},

		easeInQuint: function(t) {
			return t * t * t * t * t;
		},

		easeOutQuint: function(t) {
			return (t = t - 1) * t * t * t * t + 1;
		},

		easeInOutQuint: function(t) {
			if ((t /= 0.5) < 1) {
				return 0.5 * t * t * t * t * t;
			}
			return 0.5 * ((t -= 2) * t * t * t * t + 2);
		},

		easeInSine: function(t) {
			return -Math.cos(t * (Math.PI / 2)) + 1;
		},

		easeOutSine: function(t) {
			return Math.sin(t * (Math.PI / 2));
		},

		easeInOutSine: function(t) {
			return -0.5 * (Math.cos(Math.PI * t) - 1);
		},

		easeInExpo: function(t) {
			return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
		},

		easeOutExpo: function(t) {
			return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
		},

		easeInOutExpo: function(t) {
			if (t === 0) {
				return 0;
			}
			if (t === 1) {
				return 1;
			}
			if ((t /= 0.5) < 1) {
				return 0.5 * Math.pow(2, 10 * (t - 1));
			}
			return 0.5 * (-Math.pow(2, -10 * --t) + 2);
		},

		easeInCirc: function(t) {
			if (t >= 1) {
				return t;
			}
			return -(Math.sqrt(1 - t * t) - 1);
		},

		easeOutCirc: function(t) {
			return Math.sqrt(1 - (t = t - 1) * t);
		},

		easeInOutCirc: function(t) {
			if ((t /= 0.5) < 1) {
				return -0.5 * (Math.sqrt(1 - t * t) - 1);
			}
			return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
		},

		easeInElastic: function(t) {
			var s = 1.70158;
			var p = 0;
			var a = 1;
			if (t === 0) {
				return 0;
			}
			if (t === 1) {
				return 1;
			}
			if (!p) {
				p = 0.3;
			}
			{
				s = p / (2 * Math.PI) * Math.asin(1 / a);
			}
			return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
		},

		easeOutElastic: function(t) {
			var s = 1.70158;
			var p = 0;
			var a = 1;
			if (t === 0) {
				return 0;
			}
			if (t === 1) {
				return 1;
			}
			if (!p) {
				p = 0.3;
			}
			{
				s = p / (2 * Math.PI) * Math.asin(1 / a);
			}
			return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
		},

		easeInOutElastic: function(t) {
			var s = 1.70158;
			var p = 0;
			var a = 1;
			if (t === 0) {
				return 0;
			}
			if ((t /= 0.5) === 2) {
				return 1;
			}
			if (!p) {
				p = 0.45;
			}
			{
				s = p / (2 * Math.PI) * Math.asin(1 / a);
			}
			if (t < 1) {
				return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
			}
			return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
		},
		easeInBack: function(t) {
			var s = 1.70158;
			return t * t * ((s + 1) * t - s);
		},

		easeOutBack: function(t) {
			var s = 1.70158;
			return (t = t - 1) * t * ((s + 1) * t + s) + 1;
		},

		easeInOutBack: function(t) {
			var s = 1.70158;
			if ((t /= 0.5) < 1) {
				return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
			}
			return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
		},

		easeInBounce: function(t) {
			return 1 - effects.easeOutBounce(1 - t);
		},

		easeOutBounce: function(t) {
			if (t < (1 / 2.75)) {
				return 7.5625 * t * t;
			}
			if (t < (2 / 2.75)) {
				return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
			}
			if (t < (2.5 / 2.75)) {
				return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
			}
			return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
		},

		easeInOutBounce: function(t) {
			if (t < 0.5) {
				return effects.easeInBounce(t * 2) * 0.5;
			}
			return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
		}
	};

	var helpers_easing = {
		effects: effects
	};

	// DEPRECATIONS

	/**
	 * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
	 * @function Chart.helpers.easingEffects
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers_core.easingEffects = effects;

	var helpers_canvas = createCommonjsModule(function (module) {



	/**
	 * @namespace Chart.helpers.canvas
	 */
	var exports = module.exports = {
		/**
		 * Clears the entire canvas associated to the given `chart`.
		 * @param {Chart} chart - The chart for which to clear the canvas.
		 */
		clear: function(chart) {
			chart.ctx.clearRect(0, 0, chart.width, chart.height);
		},

		/**
		 * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
		 * given size (width, height) and the same `radius` for all corners.
		 * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
		 * @param {Number} x - The x axis of the coordinate for the rectangle starting point.
		 * @param {Number} y - The y axis of the coordinate for the rectangle starting point.
		 * @param {Number} width - The rectangle's width.
		 * @param {Number} height - The rectangle's height.
		 * @param {Number} radius - The rounded amount (in pixels) for the four corners.
		 * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
		 */
		roundedRect: function(ctx, x, y, width, height, radius) {
			if (radius) {
				var rx = Math.min(radius, width / 2);
				var ry = Math.min(radius, height / 2);

				ctx.moveTo(x + rx, y);
				ctx.lineTo(x + width - rx, y);
				ctx.quadraticCurveTo(x + width, y, x + width, y + ry);
				ctx.lineTo(x + width, y + height - ry);
				ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height);
				ctx.lineTo(x + rx, y + height);
				ctx.quadraticCurveTo(x, y + height, x, y + height - ry);
				ctx.lineTo(x, y + ry);
				ctx.quadraticCurveTo(x, y, x + rx, y);
			} else {
				ctx.rect(x, y, width, height);
			}
		},

		drawPoint: function(ctx, style, radius, x, y) {
			var type, edgeLength, xOffset, yOffset, height, size;

			if (style && typeof style === 'object') {
				type = style.toString();
				if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
					ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
					return;
				}
			}

			if (isNaN(radius) || radius <= 0) {
				return;
			}

			switch (style) {
			// Default includes circle
			default:
				ctx.beginPath();
				ctx.arc(x, y, radius, 0, Math.PI * 2);
				ctx.closePath();
				ctx.fill();
				break;
			case 'triangle':
				ctx.beginPath();
				edgeLength = 3 * radius / Math.sqrt(3);
				height = edgeLength * Math.sqrt(3) / 2;
				ctx.moveTo(x - edgeLength / 2, y + height / 3);
				ctx.lineTo(x + edgeLength / 2, y + height / 3);
				ctx.lineTo(x, y - 2 * height / 3);
				ctx.closePath();
				ctx.fill();
				break;
			case 'rect':
				size = 1 / Math.SQRT2 * radius;
				ctx.beginPath();
				ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
				ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
				break;
			case 'rectRounded':
				var offset = radius / Math.SQRT2;
				var leftX = x - offset;
				var topY = y - offset;
				var sideSize = Math.SQRT2 * radius;
				ctx.beginPath();
				this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2);
				ctx.closePath();
				ctx.fill();
				break;
			case 'rectRot':
				size = 1 / Math.SQRT2 * radius;
				ctx.beginPath();
				ctx.moveTo(x - size, y);
				ctx.lineTo(x, y + size);
				ctx.lineTo(x + size, y);
				ctx.lineTo(x, y - size);
				ctx.closePath();
				ctx.fill();
				break;
			case 'cross':
				ctx.beginPath();
				ctx.moveTo(x, y + radius);
				ctx.lineTo(x, y - radius);
				ctx.moveTo(x - radius, y);
				ctx.lineTo(x + radius, y);
				ctx.closePath();
				break;
			case 'crossRot':
				ctx.beginPath();
				xOffset = Math.cos(Math.PI / 4) * radius;
				yOffset = Math.sin(Math.PI / 4) * radius;
				ctx.moveTo(x - xOffset, y - yOffset);
				ctx.lineTo(x + xOffset, y + yOffset);
				ctx.moveTo(x - xOffset, y + yOffset);
				ctx.lineTo(x + xOffset, y - yOffset);
				ctx.closePath();
				break;
			case 'star':
				ctx.beginPath();
				ctx.moveTo(x, y + radius);
				ctx.lineTo(x, y - radius);
				ctx.moveTo(x - radius, y);
				ctx.lineTo(x + radius, y);
				xOffset = Math.cos(Math.PI / 4) * radius;
				yOffset = Math.sin(Math.PI / 4) * radius;
				ctx.moveTo(x - xOffset, y - yOffset);
				ctx.lineTo(x + xOffset, y + yOffset);
				ctx.moveTo(x - xOffset, y + yOffset);
				ctx.lineTo(x + xOffset, y - yOffset);
				ctx.closePath();
				break;
			case 'line':
				ctx.beginPath();
				ctx.moveTo(x - radius, y);
				ctx.lineTo(x + radius, y);
				ctx.closePath();
				break;
			case 'dash':
				ctx.beginPath();
				ctx.moveTo(x, y);
				ctx.lineTo(x + radius, y);
				ctx.closePath();
				break;
			}

			ctx.stroke();
		},

		clipArea: function(ctx, area) {
			ctx.save();
			ctx.beginPath();
			ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
			ctx.clip();
		},

		unclipArea: function(ctx) {
			ctx.restore();
		},

		lineTo: function(ctx, previous, target, flip) {
			if (target.steppedLine) {
				if ((target.steppedLine === 'after' && !flip) || (target.steppedLine !== 'after' && flip)) {
					ctx.lineTo(previous.x, target.y);
				} else {
					ctx.lineTo(target.x, previous.y);
				}
				ctx.lineTo(target.x, target.y);
				return;
			}

			if (!target.tension) {
				ctx.lineTo(target.x, target.y);
				return;
			}

			ctx.bezierCurveTo(
				flip ? previous.controlPointPreviousX : previous.controlPointNextX,
				flip ? previous.controlPointPreviousY : previous.controlPointNextY,
				flip ? target.controlPointNextX : target.controlPointPreviousX,
				flip ? target.controlPointNextY : target.controlPointPreviousY,
				target.x,
				target.y);
		}
	};

	// DEPRECATIONS

	/**
	 * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
	 * @namespace Chart.helpers.clear
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers_core.clear = exports.clear;

	/**
	 * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
	 * @namespace Chart.helpers.drawRoundedRectangle
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers_core.drawRoundedRectangle = function(ctx) {
		ctx.beginPath();
		exports.roundedRect.apply(exports, arguments);
		ctx.closePath();
	};
	});
	var helpers_canvas_1 = helpers_canvas.clear;
	var helpers_canvas_2 = helpers_canvas.roundedRect;
	var helpers_canvas_3 = helpers_canvas.drawPoint;
	var helpers_canvas_4 = helpers_canvas.clipArea;
	var helpers_canvas_5 = helpers_canvas.unclipArea;
	var helpers_canvas_6 = helpers_canvas.lineTo;

	/**
	 * @alias Chart.helpers.options
	 * @namespace
	 */
	var helpers_options = {
		/**
		 * Converts the given line height `value` in pixels for a specific font `size`.
		 * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
		 * @param {Number} size - The font size (in pixels) used to resolve relative `value`.
		 * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid).
		 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
		 * @since 2.7.0
		 */
		toLineHeight: function(value, size) {
			var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
			if (!matches || matches[1] === 'normal') {
				return size * 1.2;
			}

			value = +matches[2];

			switch (matches[3]) {
			case 'px':
				return value;
			case '%':
				value /= 100;
				break;
			}

			return size * value;
		},

		/**
		 * Converts the given value into a padding object with pre-computed width/height.
		 * @param {Number|Object} value - If a number, set the value to all TRBL component,
		 *  else, if and object, use defined properties and sets undefined ones to 0.
		 * @returns {Object} The padding values (top, right, bottom, left, width, height)
		 * @since 2.7.0
		 */
		toPadding: function(value) {
			var t, r, b, l;

			if (helpers_core.isObject(value)) {
				t = +value.top || 0;
				r = +value.right || 0;
				b = +value.bottom || 0;
				l = +value.left || 0;
			} else {
				t = r = b = l = +value || 0;
			}

			return {
				top: t,
				right: r,
				bottom: b,
				left: l,
				height: t + b,
				width: l + r
			};
		},

		/**
		 * Evaluates the given `inputs` sequentially and returns the first defined value.
		 * @param {Array[]} inputs - An array of values, falling back to the last value.
		 * @param {Object} [context] - If defined and the current value is a function, the value
		 * is called with `context` as first argument and the result becomes the new input.
		 * @param {Number} [index] - If defined and the current value is an array, the value
		 * at `index` become the new input.
		 * @since 2.7.0
		 */
		resolve: function(inputs, context, index) {
			var i, ilen, value;

			for (i = 0, ilen = inputs.length; i < ilen; ++i) {
				value = inputs[i];
				if (value === undefined) {
					continue;
				}
				if (context !== undefined && typeof value === 'function') {
					value = value(context);
				}
				if (index !== undefined && helpers_core.isArray(value)) {
					value = value[index];
				}
				if (value !== undefined) {
					return value;
				}
			}
		}
	};

	var helpers$1 = helpers_core;
	var easing = helpers_easing;
	var canvas = helpers_canvas;
	var options = helpers_options;
	helpers$1.easing = easing;
	helpers$1.canvas = canvas;
	helpers$1.options = options;

	var core_defaults = {
		/**
		 * @private
		 */
		_set: function(scope, values) {
			return helpers$1.merge(this[scope] || (this[scope] = {}), values);
		}
	};

	core_defaults._set('global', {
		responsive: true,
		responsiveAnimationDuration: 0,
		maintainAspectRatio: true,
		events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
		hover: {
			onHover: null,
			mode: 'nearest',
			intersect: true,
			animationDuration: 400
		},
		onClick: null,
		defaultColor: 'rgba(0,0,0,0.1)',
		defaultFontColor: '#666',
		defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
		defaultFontSize: 12,
		defaultFontStyle: 'normal',
		showLines: true,

		// Element defaults defined in element extensions
		elements: {},

		// Layout options such as padding
		layout: {
			padding: {
				top: 0,
				right: 0,
				bottom: 0,
				left: 0
			}
		}
	});

	var core = function() {

		// Occupy the global variable of Chart, and create a simple base class
		var Chart = function(item, config) {
			this.construct(item, config);
			return this;
		};

		Chart.Chart = Chart;

		return Chart;
	};

	/* MIT license */

	var conversions = {
	  rgb2hsl: rgb2hsl,
	  rgb2hsv: rgb2hsv,
	  rgb2hwb: rgb2hwb,
	  rgb2cmyk: rgb2cmyk,
	  rgb2keyword: rgb2keyword,
	  rgb2xyz: rgb2xyz,
	  rgb2lab: rgb2lab,
	  rgb2lch: rgb2lch,

	  hsl2rgb: hsl2rgb,
	  hsl2hsv: hsl2hsv,
	  hsl2hwb: hsl2hwb,
	  hsl2cmyk: hsl2cmyk,
	  hsl2keyword: hsl2keyword,

	  hsv2rgb: hsv2rgb,
	  hsv2hsl: hsv2hsl,
	  hsv2hwb: hsv2hwb,
	  hsv2cmyk: hsv2cmyk,
	  hsv2keyword: hsv2keyword,

	  hwb2rgb: hwb2rgb,
	  hwb2hsl: hwb2hsl,
	  hwb2hsv: hwb2hsv,
	  hwb2cmyk: hwb2cmyk,
	  hwb2keyword: hwb2keyword,

	  cmyk2rgb: cmyk2rgb,
	  cmyk2hsl: cmyk2hsl,
	  cmyk2hsv: cmyk2hsv,
	  cmyk2hwb: cmyk2hwb,
	  cmyk2keyword: cmyk2keyword,

	  keyword2rgb: keyword2rgb,
	  keyword2hsl: keyword2hsl,
	  keyword2hsv: keyword2hsv,
	  keyword2hwb: keyword2hwb,
	  keyword2cmyk: keyword2cmyk,
	  keyword2lab: keyword2lab,
	  keyword2xyz: keyword2xyz,

	  xyz2rgb: xyz2rgb,
	  xyz2lab: xyz2lab,
	  xyz2lch: xyz2lch,

	  lab2xyz: lab2xyz,
	  lab2rgb: lab2rgb,
	  lab2lch: lab2lch,

	  lch2lab: lch2lab,
	  lch2xyz: lch2xyz,
	  lch2rgb: lch2rgb
	};


	function rgb2hsl(rgb) {
	  var r = rgb[0]/255,
	      g = rgb[1]/255,
	      b = rgb[2]/255,
	      min = Math.min(r, g, b),
	      max = Math.max(r, g, b),
	      delta = max - min,
	      h, s, l;

	  if (max == min)
	    h = 0;
	  else if (r == max)
	    h = (g - b) / delta;
	  else if (g == max)
	    h = 2 + (b - r) / delta;
	  else if (b == max)
	    h = 4 + (r - g)/ delta;

	  h = Math.min(h * 60, 360);

	  if (h < 0)
	    h += 360;

	  l = (min + max) / 2;

	  if (max == min)
	    s = 0;
	  else if (l <= 0.5)
	    s = delta / (max + min);
	  else
	    s = delta / (2 - max - min);

	  return [h, s * 100, l * 100];
	}

	function rgb2hsv(rgb) {
	  var r = rgb[0],
	      g = rgb[1],
	      b = rgb[2],
	      min = Math.min(r, g, b),
	      max = Math.max(r, g, b),
	      delta = max - min,
	      h, s, v;

	  if (max == 0)
	    s = 0;
	  else
	    s = (delta/max * 1000)/10;

	  if (max == min)
	    h = 0;
	  else if (r == max)
	    h = (g - b) / delta;
	  else if (g == max)
	    h = 2 + (b - r) / delta;
	  else if (b == max)
	    h = 4 + (r - g) / delta;

	  h = Math.min(h * 60, 360);

	  if (h < 0)
	    h += 360;

	  v = ((max / 255) * 1000) / 10;

	  return [h, s, v];
	}

	function rgb2hwb(rgb) {
	  var r = rgb[0],
	      g = rgb[1],
	      b = rgb[2],
	      h = rgb2hsl(rgb)[0],
	      w = 1/255 * Math.min(r, Math.min(g, b)),
	      b = 1 - 1/255 * Math.max(r, Math.max(g, b));

	  return [h, w * 100, b * 100];
	}

	function rgb2cmyk(rgb) {
	  var r = rgb[0] / 255,
	      g = rgb[1] / 255,
	      b = rgb[2] / 255,
	      c, m, y, k;

	  k = Math.min(1 - r, 1 - g, 1 - b);
	  c = (1 - r - k) / (1 - k) || 0;
	  m = (1 - g - k) / (1 - k) || 0;
	  y = (1 - b - k) / (1 - k) || 0;
	  return [c * 100, m * 100, y * 100, k * 100];
	}

	function rgb2keyword(rgb) {
	  return reverseKeywords[JSON.stringify(rgb)];
	}

	function rgb2xyz(rgb) {
	  var r = rgb[0] / 255,
	      g = rgb[1] / 255,
	      b = rgb[2] / 255;

	  // assume sRGB
	  r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
	  g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
	  b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);

	  var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
	  var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
	  var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);

	  return [x * 100, y *100, z * 100];
	}

	function rgb2lab(rgb) {
	  var xyz = rgb2xyz(rgb),
	        x = xyz[0],
	        y = xyz[1],
	        z = xyz[2],
	        l, a, b;

	  x /= 95.047;
	  y /= 100;
	  z /= 108.883;

	  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
	  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
	  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);

	  l = (116 * y) - 16;
	  a = 500 * (x - y);
	  b = 200 * (y - z);

	  return [l, a, b];
	}

	function rgb2lch(args) {
	  return lab2lch(rgb2lab(args));
	}

	function hsl2rgb(hsl) {
	  var h = hsl[0] / 360,
	      s = hsl[1] / 100,
	      l = hsl[2] / 100,
	      t1, t2, t3, rgb, val;

	  if (s == 0) {
	    val = l * 255;
	    return [val, val, val];
	  }

	  if (l < 0.5)
	    t2 = l * (1 + s);
	  else
	    t2 = l + s - l * s;
	  t1 = 2 * l - t2;

	  rgb = [0, 0, 0];
	  for (var i = 0; i < 3; i++) {
	    t3 = h + 1 / 3 * - (i - 1);
	    t3 < 0 && t3++;
	    t3 > 1 && t3--;

	    if (6 * t3 < 1)
	      val = t1 + (t2 - t1) * 6 * t3;
	    else if (2 * t3 < 1)
	      val = t2;
	    else if (3 * t3 < 2)
	      val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
	    else
	      val = t1;

	    rgb[i] = val * 255;
	  }

	  return rgb;
	}

	function hsl2hsv(hsl) {
	  var h = hsl[0],
	      s = hsl[1] / 100,
	      l = hsl[2] / 100,
	      sv, v;

	  if(l === 0) {
	      // no need to do calc on black
	      // also avoids divide by 0 error
	      return [0, 0, 0];
	  }

	  l *= 2;
	  s *= (l <= 1) ? l : 2 - l;
	  v = (l + s) / 2;
	  sv = (2 * s) / (l + s);
	  return [h, sv * 100, v * 100];
	}

	function hsl2hwb(args) {
	  return rgb2hwb(hsl2rgb(args));
	}

	function hsl2cmyk(args) {
	  return rgb2cmyk(hsl2rgb(args));
	}

	function hsl2keyword(args) {
	  return rgb2keyword(hsl2rgb(args));
	}


	function hsv2rgb(hsv) {
	  var h = hsv[0] / 60,
	      s = hsv[1] / 100,
	      v = hsv[2] / 100,
	      hi = Math.floor(h) % 6;

	  var f = h - Math.floor(h),
	      p = 255 * v * (1 - s),
	      q = 255 * v * (1 - (s * f)),
	      t = 255 * v * (1 - (s * (1 - f))),
	      v = 255 * v;

	  switch(hi) {
	    case 0:
	      return [v, t, p];
	    case 1:
	      return [q, v, p];
	    case 2:
	      return [p, v, t];
	    case 3:
	      return [p, q, v];
	    case 4:
	      return [t, p, v];
	    case 5:
	      return [v, p, q];
	  }
	}

	function hsv2hsl(hsv) {
	  var h = hsv[0],
	      s = hsv[1] / 100,
	      v = hsv[2] / 100,
	      sl, l;

	  l = (2 - s) * v;
	  sl = s * v;
	  sl /= (l <= 1) ? l : 2 - l;
	  sl = sl || 0;
	  l /= 2;
	  return [h, sl * 100, l * 100];
	}

	function hsv2hwb(args) {
	  return rgb2hwb(hsv2rgb(args))
	}

	function hsv2cmyk(args) {
	  return rgb2cmyk(hsv2rgb(args));
	}

	function hsv2keyword(args) {
	  return rgb2keyword(hsv2rgb(args));
	}

	// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
	function hwb2rgb(hwb) {
	  var h = hwb[0] / 360,
	      wh = hwb[1] / 100,
	      bl = hwb[2] / 100,
	      ratio = wh + bl,
	      i, v, f, n;

	  // wh + bl cant be > 1
	  if (ratio > 1) {
	    wh /= ratio;
	    bl /= ratio;
	  }

	  i = Math.floor(6 * h);
	  v = 1 - bl;
	  f = 6 * h - i;
	  if ((i & 0x01) != 0) {
	    f = 1 - f;
	  }
	  n = wh + f * (v - wh);  // linear interpolation

	  switch (i) {
	    default:
	    case 6:
	    case 0: r = v; g = n; b = wh; break;
	    case 1: r = n; g = v; b = wh; break;
	    case 2: r = wh; g = v; b = n; break;
	    case 3: r = wh; g = n; b = v; break;
	    case 4: r = n; g = wh; b = v; break;
	    case 5: r = v; g = wh; b = n; break;
	  }

	  return [r * 255, g * 255, b * 255];
	}

	function hwb2hsl(args) {
	  return rgb2hsl(hwb2rgb(args));
	}

	function hwb2hsv(args) {
	  return rgb2hsv(hwb2rgb(args));
	}

	function hwb2cmyk(args) {
	  return rgb2cmyk(hwb2rgb(args));
	}

	function hwb2keyword(args) {
	  return rgb2keyword(hwb2rgb(args));
	}

	function cmyk2rgb(cmyk) {
	  var c = cmyk[0] / 100,
	      m = cmyk[1] / 100,
	      y = cmyk[2] / 100,
	      k = cmyk[3] / 100,
	      r, g, b;

	  r = 1 - Math.min(1, c * (1 - k) + k);
	  g = 1 - Math.min(1, m * (1 - k) + k);
	  b = 1 - Math.min(1, y * (1 - k) + k);
	  return [r * 255, g * 255, b * 255];
	}

	function cmyk2hsl(args) {
	  return rgb2hsl(cmyk2rgb(args));
	}

	function cmyk2hsv(args) {
	  return rgb2hsv(cmyk2rgb(args));
	}

	function cmyk2hwb(args) {
	  return rgb2hwb(cmyk2rgb(args));
	}

	function cmyk2keyword(args) {
	  return rgb2keyword(cmyk2rgb(args));
	}


	function xyz2rgb(xyz) {
	  var x = xyz[0] / 100,
	      y = xyz[1] / 100,
	      z = xyz[2] / 100,
	      r, g, b;

	  r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
	  g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
	  b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);

	  // assume sRGB
	  r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
	    : r = (r * 12.92);

	  g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
	    : g = (g * 12.92);

	  b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
	    : b = (b * 12.92);

	  r = Math.min(Math.max(0, r), 1);
	  g = Math.min(Math.max(0, g), 1);
	  b = Math.min(Math.max(0, b), 1);

	  return [r * 255, g * 255, b * 255];
	}

	function xyz2lab(xyz) {
	  var x = xyz[0],
	      y = xyz[1],
	      z = xyz[2],
	      l, a, b;

	  x /= 95.047;
	  y /= 100;
	  z /= 108.883;

	  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
	  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
	  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);

	  l = (116 * y) - 16;
	  a = 500 * (x - y);
	  b = 200 * (y - z);

	  return [l, a, b];
	}

	function xyz2lch(args) {
	  return lab2lch(xyz2lab(args));
	}

	function lab2xyz(lab) {
	  var l = lab[0],
	      a = lab[1],
	      b = lab[2],
	      x, y, z, y2;

	  if (l <= 8) {
	    y = (l * 100) / 903.3;
	    y2 = (7.787 * (y / 100)) + (16 / 116);
	  } else {
	    y = 100 * Math.pow((l + 16) / 116, 3);
	    y2 = Math.pow(y / 100, 1/3);
	  }

	  x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);

	  z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);

	  return [x, y, z];
	}

	function lab2lch(lab) {
	  var l = lab[0],
	      a = lab[1],
	      b = lab[2],
	      hr, h, c;

	  hr = Math.atan2(b, a);
	  h = hr * 360 / 2 / Math.PI;
	  if (h < 0) {
	    h += 360;
	  }
	  c = Math.sqrt(a * a + b * b);
	  return [l, c, h];
	}

	function lab2rgb(args) {
	  return xyz2rgb(lab2xyz(args));
	}

	function lch2lab(lch) {
	  var l = lch[0],
	      c = lch[1],
	      h = lch[2],
	      a, b, hr;

	  hr = h / 360 * 2 * Math.PI;
	  a = c * Math.cos(hr);
	  b = c * Math.sin(hr);
	  return [l, a, b];
	}

	function lch2xyz(args) {
	  return lab2xyz(lch2lab(args));
	}

	function lch2rgb(args) {
	  return lab2rgb(lch2lab(args));
	}

	function keyword2rgb(keyword) {
	  return cssKeywords[keyword];
	}

	function keyword2hsl(args) {
	  return rgb2hsl(keyword2rgb(args));
	}

	function keyword2hsv(args) {
	  return rgb2hsv(keyword2rgb(args));
	}

	function keyword2hwb(args) {
	  return rgb2hwb(keyword2rgb(args));
	}

	function keyword2cmyk(args) {
	  return rgb2cmyk(keyword2rgb(args));
	}

	function keyword2lab(args) {
	  return rgb2lab(keyword2rgb(args));
	}

	function keyword2xyz(args) {
	  return rgb2xyz(keyword2rgb(args));
	}

	var cssKeywords = {
	  aliceblue:  [240,248,255],
	  antiquewhite: [250,235,215],
	  aqua: [0,255,255],
	  aquamarine: [127,255,212],
	  azure:  [240,255,255],
	  beige:  [245,245,220],
	  bisque: [255,228,196],
	  black:  [0,0,0],
	  blanchedalmond: [255,235,205],
	  blue: [0,0,255],
	  blueviolet: [138,43,226],
	  brown:  [165,42,42],
	  burlywood:  [222,184,135],
	  cadetblue:  [95,158,160],
	  chartreuse: [127,255,0],
	  chocolate:  [210,105,30],
	  coral:  [255,127,80],
	  cornflowerblue: [100,149,237],
	  cornsilk: [255,248,220],
	  crimson:  [220,20,60],
	  cyan: [0,255,255],
	  darkblue: [0,0,139],
	  darkcyan: [0,139,139],
	  darkgoldenrod:  [184,134,11],
	  darkgray: [169,169,169],
	  darkgreen:  [0,100,0],
	  darkgrey: [169,169,169],
	  darkkhaki:  [189,183,107],
	  darkmagenta:  [139,0,139],
	  darkolivegreen: [85,107,47],
	  darkorange: [255,140,0],
	  darkorchid: [153,50,204],
	  darkred:  [139,0,0],
	  darksalmon: [233,150,122],
	  darkseagreen: [143,188,143],
	  darkslateblue:  [72,61,139],
	  darkslategray:  [47,79,79],
	  darkslategrey:  [47,79,79],
	  darkturquoise:  [0,206,209],
	  darkviolet: [148,0,211],
	  deeppink: [255,20,147],
	  deepskyblue:  [0,191,255],
	  dimgray:  [105,105,105],
	  dimgrey:  [105,105,105],
	  dodgerblue: [30,144,255],
	  firebrick:  [178,34,34],
	  floralwhite:  [255,250,240],
	  forestgreen:  [34,139,34],
	  fuchsia:  [255,0,255],
	  gainsboro:  [220,220,220],
	  ghostwhite: [248,248,255],
	  gold: [255,215,0],
	  goldenrod:  [218,165,32],
	  gray: [128,128,128],
	  green:  [0,128,0],
	  greenyellow:  [173,255,47],
	  grey: [128,128,128],
	  honeydew: [240,255,240],
	  hotpink:  [255,105,180],
	  indianred:  [205,92,92],
	  indigo: [75,0,130],
	  ivory:  [255,255,240],
	  khaki:  [240,230,140],
	  lavender: [230,230,250],
	  lavenderblush:  [255,240,245],
	  lawngreen:  [124,252,0],
	  lemonchiffon: [255,250,205],
	  lightblue:  [173,216,230],
	  lightcoral: [240,128,128],
	  lightcyan:  [224,255,255],
	  lightgoldenrodyellow: [250,250,210],
	  lightgray:  [211,211,211],
	  lightgreen: [144,238,144],
	  lightgrey:  [211,211,211],
	  lightpink:  [255,182,193],
	  lightsalmon:  [255,160,122],
	  lightseagreen:  [32,178,170],
	  lightskyblue: [135,206,250],
	  lightslategray: [119,136,153],
	  lightslategrey: [119,136,153],
	  lightsteelblue: [176,196,222],
	  lightyellow:  [255,255,224],
	  lime: [0,255,0],
	  limegreen:  [50,205,50],
	  linen:  [250,240,230],
	  magenta:  [255,0,255],
	  maroon: [128,0,0],
	  mediumaquamarine: [102,205,170],
	  mediumblue: [0,0,205],
	  mediumorchid: [186,85,211],
	  mediumpurple: [147,112,219],
	  mediumseagreen: [60,179,113],
	  mediumslateblue:  [123,104,238],
	  mediumspringgreen:  [0,250,154],
	  mediumturquoise:  [72,209,204],
	  mediumvioletred:  [199,21,133],
	  midnightblue: [25,25,112],
	  mintcream:  [245,255,250],
	  mistyrose:  [255,228,225],
	  moccasin: [255,228,181],
	  navajowhite:  [255,222,173],
	  navy: [0,0,128],
	  oldlace:  [253,245,230],
	  olive:  [128,128,0],
	  olivedrab:  [107,142,35],
	  orange: [255,165,0],
	  orangered:  [255,69,0],
	  orchid: [218,112,214],
	  palegoldenrod:  [238,232,170],
	  palegreen:  [152,251,152],
	  paleturquoise:  [175,238,238],
	  palevioletred:  [219,112,147],
	  papayawhip: [255,239,213],
	  peachpuff:  [255,218,185],
	  peru: [205,133,63],
	  pink: [255,192,203],
	  plum: [221,160,221],
	  powderblue: [176,224,230],
	  purple: [128,0,128],
	  rebeccapurple: [102, 51, 153],
	  red:  [255,0,0],
	  rosybrown:  [188,143,143],
	  royalblue:  [65,105,225],
	  saddlebrown:  [139,69,19],
	  salmon: [250,128,114],
	  sandybrown: [244,164,96],
	  seagreen: [46,139,87],
	  seashell: [255,245,238],
	  sienna: [160,82,45],
	  silver: [192,192,192],
	  skyblue:  [135,206,235],
	  slateblue:  [106,90,205],
	  slategray:  [112,128,144],
	  slategrey:  [112,128,144],
	  snow: [255,250,250],
	  springgreen:  [0,255,127],
	  steelblue:  [70,130,180],
	  tan:  [210,180,140],
	  teal: [0,128,128],
	  thistle:  [216,191,216],
	  tomato: [255,99,71],
	  turquoise:  [64,224,208],
	  violet: [238,130,238],
	  wheat:  [245,222,179],
	  white:  [255,255,255],
	  whitesmoke: [245,245,245],
	  yellow: [255,255,0],
	  yellowgreen:  [154,205,50]
	};

	var reverseKeywords = {};
	for (var key in cssKeywords) {
	  reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
	}

	var convert = function() {
	   return new Converter();
	};

	for (var func in conversions) {
	  // export Raw versions
	  convert[func + "Raw"] =  (function(func) {
	    // accept array or plain args
	    return function(arg) {
	      if (typeof arg == "number")
	        arg = Array.prototype.slice.call(arguments);
	      return conversions[func](arg);
	    }
	  })(func);

	  var pair = /(\w+)2(\w+)/.exec(func),
	      from = pair[1],
	      to = pair[2];

	  // export rgb2hsl and ["rgb"]["hsl"]
	  convert[from] = convert[from] || {};

	  convert[from][to] = convert[func] = (function(func) { 
	    return function(arg) {
	      if (typeof arg == "number")
	        arg = Array.prototype.slice.call(arguments);
	      
	      var val = conversions[func](arg);
	      if (typeof val == "string" || val === undefined)
	        return val; // keyword

	      for (var i = 0; i < val.length; i++)
	        val[i] = Math.round(val[i]);
	      return val;
	    }
	  })(func);
	}


	/* Converter does lazy conversion and caching */
	var Converter = function() {
	   this.convs = {};
	};

	/* Either get the values for a space or
	  set the values for a space, depending on args */
	Converter.prototype.routeSpace = function(space, args) {
	   var values = args[0];
	   if (values === undefined) {
	      // color.rgb()
	      return this.getValues(space);
	   }
	   // color.rgb(10, 10, 10)
	   if (typeof values == "number") {
	      values = Array.prototype.slice.call(args);        
	   }

	   return this.setValues(space, values);
	};
	  
	/* Set the values for a space, invalidating cache */
	Converter.prototype.setValues = function(space, values) {
	   this.space = space;
	   this.convs = {};
	   this.convs[space] = values;
	   return this;
	};

	/* Get the values for a space. If there's already
	  a conversion for the space, fetch it, otherwise
	  compute it */
	Converter.prototype.getValues = function(space) {
	   var vals = this.convs[space];
	   if (!vals) {
	      var fspace = this.space,
	          from = this.convs[fspace];
	      vals = convert[fspace][space](from);

	      this.convs[space] = vals;
	   }
	  return vals;
	};

	["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
	   Converter.prototype[space] = function(vals) {
	      return this.routeSpace(space, arguments);
	   };
	});

	var colorConvert = convert;

	var colorName = {
		"aliceblue": [240, 248, 255],
		"antiquewhite": [250, 235, 215],
		"aqua": [0, 255, 255],
		"aquamarine": [127, 255, 212],
		"azure": [240, 255, 255],
		"beige": [245, 245, 220],
		"bisque": [255, 228, 196],
		"black": [0, 0, 0],
		"blanchedalmond": [255, 235, 205],
		"blue": [0, 0, 255],
		"blueviolet": [138, 43, 226],
		"brown": [165, 42, 42],
		"burlywood": [222, 184, 135],
		"cadetblue": [95, 158, 160],
		"chartreuse": [127, 255, 0],
		"chocolate": [210, 105, 30],
		"coral": [255, 127, 80],
		"cornflowerblue": [100, 149, 237],
		"cornsilk": [255, 248, 220],
		"crimson": [220, 20, 60],
		"cyan": [0, 255, 255],
		"darkblue": [0, 0, 139],
		"darkcyan": [0, 139, 139],
		"darkgoldenrod": [184, 134, 11],
		"darkgray": [169, 169, 169],
		"darkgreen": [0, 100, 0],
		"darkgrey": [169, 169, 169],
		"darkkhaki": [189, 183, 107],
		"darkmagenta": [139, 0, 139],
		"darkolivegreen": [85, 107, 47],
		"darkorange": [255, 140, 0],
		"darkorchid": [153, 50, 204],
		"darkred": [139, 0, 0],
		"darksalmon": [233, 150, 122],
		"darkseagreen": [143, 188, 143],
		"darkslateblue": [72, 61, 139],
		"darkslategray": [47, 79, 79],
		"darkslategrey": [47, 79, 79],
		"darkturquoise": [0, 206, 209],
		"darkviolet": [148, 0, 211],
		"deeppink": [255, 20, 147],
		"deepskyblue": [0, 191, 255],
		"dimgray": [105, 105, 105],
		"dimgrey": [105, 105, 105],
		"dodgerblue": [30, 144, 255],
		"firebrick": [178, 34, 34],
		"floralwhite": [255, 250, 240],
		"forestgreen": [34, 139, 34],
		"fuchsia": [255, 0, 255],
		"gainsboro": [220, 220, 220],
		"ghostwhite": [248, 248, 255],
		"gold": [255, 215, 0],
		"goldenrod": [218, 165, 32],
		"gray": [128, 128, 128],
		"green": [0, 128, 0],
		"greenyellow": [173, 255, 47],
		"grey": [128, 128, 128],
		"honeydew": [240, 255, 240],
		"hotpink": [255, 105, 180],
		"indianred": [205, 92, 92],
		"indigo": [75, 0, 130],
		"ivory": [255, 255, 240],
		"khaki": [240, 230, 140],
		"lavender": [230, 230, 250],
		"lavenderblush": [255, 240, 245],
		"lawngreen": [124, 252, 0],
		"lemonchiffon": [255, 250, 205],
		"lightblue": [173, 216, 230],
		"lightcoral": [240, 128, 128],
		"lightcyan": [224, 255, 255],
		"lightgoldenrodyellow": [250, 250, 210],
		"lightgray": [211, 211, 211],
		"lightgreen": [144, 238, 144],
		"lightgrey": [211, 211, 211],
		"lightpink": [255, 182, 193],
		"lightsalmon": [255, 160, 122],
		"lightseagreen": [32, 178, 170],
		"lightskyblue": [135, 206, 250],
		"lightslategray": [119, 136, 153],
		"lightslategrey": [119, 136, 153],
		"lightsteelblue": [176, 196, 222],
		"lightyellow": [255, 255, 224],
		"lime": [0, 255, 0],
		"limegreen": [50, 205, 50],
		"linen": [250, 240, 230],
		"magenta": [255, 0, 255],
		"maroon": [128, 0, 0],
		"mediumaquamarine": [102, 205, 170],
		"mediumblue": [0, 0, 205],
		"mediumorchid": [186, 85, 211],
		"mediumpurple": [147, 112, 219],
		"mediumseagreen": [60, 179, 113],
		"mediumslateblue": [123, 104, 238],
		"mediumspringgreen": [0, 250, 154],
		"mediumturquoise": [72, 209, 204],
		"mediumvioletred": [199, 21, 133],
		"midnightblue": [25, 25, 112],
		"mintcream": [245, 255, 250],
		"mistyrose": [255, 228, 225],
		"moccasin": [255, 228, 181],
		"navajowhite": [255, 222, 173],
		"navy": [0, 0, 128],
		"oldlace": [253, 245, 230],
		"olive": [128, 128, 0],
		"olivedrab": [107, 142, 35],
		"orange": [255, 165, 0],
		"orangered": [255, 69, 0],
		"orchid": [218, 112, 214],
		"palegoldenrod": [238, 232, 170],
		"palegreen": [152, 251, 152],
		"paleturquoise": [175, 238, 238],
		"palevioletred": [219, 112, 147],
		"papayawhip": [255, 239, 213],
		"peachpuff": [255, 218, 185],
		"peru": [205, 133, 63],
		"pink": [255, 192, 203],
		"plum": [221, 160, 221],
		"powderblue": [176, 224, 230],
		"purple": [128, 0, 128],
		"rebeccapurple": [102, 51, 153],
		"red": [255, 0, 0],
		"rosybrown": [188, 143, 143],
		"royalblue": [65, 105, 225],
		"saddlebrown": [139, 69, 19],
		"salmon": [250, 128, 114],
		"sandybrown": [244, 164, 96],
		"seagreen": [46, 139, 87],
		"seashell": [255, 245, 238],
		"sienna": [160, 82, 45],
		"silver": [192, 192, 192],
		"skyblue": [135, 206, 235],
		"slateblue": [106, 90, 205],
		"slategray": [112, 128, 144],
		"slategrey": [112, 128, 144],
		"snow": [255, 250, 250],
		"springgreen": [0, 255, 127],
		"steelblue": [70, 130, 180],
		"tan": [210, 180, 140],
		"teal": [0, 128, 128],
		"thistle": [216, 191, 216],
		"tomato": [255, 99, 71],
		"turquoise": [64, 224, 208],
		"violet": [238, 130, 238],
		"wheat": [245, 222, 179],
		"white": [255, 255, 255],
		"whitesmoke": [245, 245, 245],
		"yellow": [255, 255, 0],
		"yellowgreen": [154, 205, 50]
	};

	/* MIT license */


	var colorString = {
	   getRgba: getRgba,
	   getHsla: getHsla,
	   getRgb: getRgb,
	   getHsl: getHsl,
	   getHwb: getHwb,
	   getAlpha: getAlpha,

	   hexString: hexString,
	   rgbString: rgbString,
	   rgbaString: rgbaString,
	   percentString: percentString,
	   percentaString: percentaString,
	   hslString: hslString,
	   hslaString: hslaString,
	   hwbString: hwbString,
	   keyword: keyword
	};

	function getRgba(string) {
	   if (!string) {
	      return;
	   }
	   var abbr =  /^#([a-fA-F0-9]{3})$/i,
	       hex =  /^#([a-fA-F0-9]{6})$/i,
	       rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
	       per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
	       keyword = /(\w+)/;

	   var rgb = [0, 0, 0],
	       a = 1,
	       match = string.match(abbr);
	   if (match) {
	      match = match[1];
	      for (var i = 0; i < rgb.length; i++) {
	         rgb[i] = parseInt(match[i] + match[i], 16);
	      }
	   }
	   else if (match = string.match(hex)) {
	      match = match[1];
	      for (var i = 0; i < rgb.length; i++) {
	         rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
	      }
	   }
	   else if (match = string.match(rgba)) {
	      for (var i = 0; i < rgb.length; i++) {
	         rgb[i] = parseInt(match[i + 1]);
	      }
	      a = parseFloat(match[4]);
	   }
	   else if (match = string.match(per)) {
	      for (var i = 0; i < rgb.length; i++) {
	         rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
	      }
	      a = parseFloat(match[4]);
	   }
	   else if (match = string.match(keyword)) {
	      if (match[1] == "transparent") {
	         return [0, 0, 0, 0];
	      }
	      rgb = colorName[match[1]];
	      if (!rgb) {
	         return;
	      }
	   }

	   for (var i = 0; i < rgb.length; i++) {
	      rgb[i] = scale(rgb[i], 0, 255);
	   }
	   if (!a && a != 0) {
	      a = 1;
	   }
	   else {
	      a = scale(a, 0, 1);
	   }
	   rgb[3] = a;
	   return rgb;
	}

	function getHsla(string) {
	   if (!string) {
	      return;
	   }
	   var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
	   var match = string.match(hsl);
	   if (match) {
	      var alpha = parseFloat(match[4]);
	      var h = scale(parseInt(match[1]), 0, 360),
	          s = scale(parseFloat(match[2]), 0, 100),
	          l = scale(parseFloat(match[3]), 0, 100),
	          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
	      return [h, s, l, a];
	   }
	}

	function getHwb(string) {
	   if (!string) {
	      return;
	   }
	   var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
	   var match = string.match(hwb);
	   if (match) {
	    var alpha = parseFloat(match[4]);
	      var h = scale(parseInt(match[1]), 0, 360),
	          w = scale(parseFloat(match[2]), 0, 100),
	          b = scale(parseFloat(match[3]), 0, 100),
	          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
	      return [h, w, b, a];
	   }
	}

	function getRgb(string) {
	   var rgba = getRgba(string);
	   return rgba && rgba.slice(0, 3);
	}

	function getHsl(string) {
	  var hsla = getHsla(string);
	  return hsla && hsla.slice(0, 3);
	}

	function getAlpha(string) {
	   var vals = getRgba(string);
	   if (vals) {
	      return vals[3];
	   }
	   else if (vals = getHsla(string)) {
	      return vals[3];
	   }
	   else if (vals = getHwb(string)) {
	      return vals[3];
	   }
	}

	// generators
	function hexString(rgb) {
	   return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
	              + hexDouble(rgb[2]);
	}

	function rgbString(rgba, alpha) {
	   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
	      return rgbaString(rgba, alpha);
	   }
	   return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
	}

	function rgbaString(rgba, alpha) {
	   if (alpha === undefined) {
	      alpha = (rgba[3] !== undefined ? rgba[3] : 1);
	   }
	   return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
	           + ", " + alpha + ")";
	}

	function percentString(rgba, alpha) {
	   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
	      return percentaString(rgba, alpha);
	   }
	   var r = Math.round(rgba[0]/255 * 100),
	       g = Math.round(rgba[1]/255 * 100),
	       b = Math.round(rgba[2]/255 * 100);

	   return "rgb(" + r + "%, " + g + "%, " + b + "%)";
	}

	function percentaString(rgba, alpha) {
	   var r = Math.round(rgba[0]/255 * 100),
	       g = Math.round(rgba[1]/255 * 100),
	       b = Math.round(rgba[2]/255 * 100);
	   return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
	}

	function hslString(hsla, alpha) {
	   if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
	      return hslaString(hsla, alpha);
	   }
	   return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
	}

	function hslaString(hsla, alpha) {
	   if (alpha === undefined) {
	      alpha = (hsla[3] !== undefined ? hsla[3] : 1);
	   }
	   return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
	           + alpha + ")";
	}

	// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
	// (hwb have alpha optional & 1 is default value)
	function hwbString(hwb, alpha) {
	   if (alpha === undefined) {
	      alpha = (hwb[3] !== undefined ? hwb[3] : 1);
	   }
	   return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
	           + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
	}

	function keyword(rgb) {
	  return reverseNames[rgb.slice(0, 3)];
	}

	// helpers
	function scale(num, min, max) {
	   return Math.min(Math.max(min, num), max);
	}

	function hexDouble(num) {
	  var str = num.toString(16).toUpperCase();
	  return (str.length < 2) ? "0" + str : str;
	}


	//create a list of reverse color names
	var reverseNames = {};
	for (var name in colorName) {
	   reverseNames[colorName[name]] = name;
	}

	/* MIT license */



	var Color = function (obj) {
		if (obj instanceof Color) {
			return obj;
		}
		if (!(this instanceof Color)) {
			return new Color(obj);
		}

		this.valid = false;
		this.values = {
			rgb: [0, 0, 0],
			hsl: [0, 0, 0],
			hsv: [0, 0, 0],
			hwb: [0, 0, 0],
			cmyk: [0, 0, 0, 0],
			alpha: 1
		};

		// parse Color() argument
		var vals;
		if (typeof obj === 'string') {
			vals = colorString.getRgba(obj);
			if (vals) {
				this.setValues('rgb', vals);
			} else if (vals = colorString.getHsla(obj)) {
				this.setValues('hsl', vals);
			} else if (vals = colorString.getHwb(obj)) {
				this.setValues('hwb', vals);
			}
		} else if (typeof obj === 'object') {
			vals = obj;
			if (vals.r !== undefined || vals.red !== undefined) {
				this.setValues('rgb', vals);
			} else if (vals.l !== undefined || vals.lightness !== undefined) {
				this.setValues('hsl', vals);
			} else if (vals.v !== undefined || vals.value !== undefined) {
				this.setValues('hsv', vals);
			} else if (vals.w !== undefined || vals.whiteness !== undefined) {
				this.setValues('hwb', vals);
			} else if (vals.c !== undefined || vals.cyan !== undefined) {
				this.setValues('cmyk', vals);
			}
		}
	};

	Color.prototype = {
		isValid: function () {
			return this.valid;
		},
		rgb: function () {
			return this.setSpace('rgb', arguments);
		},
		hsl: function () {
			return this.setSpace('hsl', arguments);
		},
		hsv: function () {
			return this.setSpace('hsv', arguments);
		},
		hwb: function () {
			return this.setSpace('hwb', arguments);
		},
		cmyk: function () {
			return this.setSpace('cmyk', arguments);
		},

		rgbArray: function () {
			return this.values.rgb;
		},
		hslArray: function () {
			return this.values.hsl;
		},
		hsvArray: function () {
			return this.values.hsv;
		},
		hwbArray: function () {
			var values = this.values;
			if (values.alpha !== 1) {
				return values.hwb.concat([values.alpha]);
			}
			return values.hwb;
		},
		cmykArray: function () {
			return this.values.cmyk;
		},
		rgbaArray: function () {
			var values = this.values;
			return values.rgb.concat([values.alpha]);
		},
		hslaArray: function () {
			var values = this.values;
			return values.hsl.concat([values.alpha]);
		},
		alpha: function (val) {
			if (val === undefined) {
				return this.values.alpha;
			}
			this.setValues('alpha', val);
			return this;
		},

		red: function (val) {
			return this.setChannel('rgb', 0, val);
		},
		green: function (val) {
			return this.setChannel('rgb', 1, val);
		},
		blue: function (val) {
			return this.setChannel('rgb', 2, val);
		},
		hue: function (val) {
			if (val) {
				val %= 360;
				val = val < 0 ? 360 + val : val;
			}
			return this.setChannel('hsl', 0, val);
		},
		saturation: function (val) {
			return this.setChannel('hsl', 1, val);
		},
		lightness: function (val) {
			return this.setChannel('hsl', 2, val);
		},
		saturationv: function (val) {
			return this.setChannel('hsv', 1, val);
		},
		whiteness: function (val) {
			return this.setChannel('hwb', 1, val);
		},
		blackness: function (val) {
			return this.setChannel('hwb', 2, val);
		},
		value: function (val) {
			return this.setChannel('hsv', 2, val);
		},
		cyan: function (val) {
			return this.setChannel('cmyk', 0, val);
		},
		magenta: function (val) {
			return this.setChannel('cmyk', 1, val);
		},
		yellow: function (val) {
			return this.setChannel('cmyk', 2, val);
		},
		black: function (val) {
			return this.setChannel('cmyk', 3, val);
		},

		hexString: function () {
			return colorString.hexString(this.values.rgb);
		},
		rgbString: function () {
			return colorString.rgbString(this.values.rgb, this.values.alpha);
		},
		rgbaString: function () {
			return colorString.rgbaString(this.values.rgb, this.values.alpha);
		},
		percentString: function () {
			return colorString.percentString(this.values.rgb, this.values.alpha);
		},
		hslString: function () {
			return colorString.hslString(this.values.hsl, this.values.alpha);
		},
		hslaString: function () {
			return colorString.hslaString(this.values.hsl, this.values.alpha);
		},
		hwbString: function () {
			return colorString.hwbString(this.values.hwb, this.values.alpha);
		},
		keyword: function () {
			return colorString.keyword(this.values.rgb, this.values.alpha);
		},

		rgbNumber: function () {
			var rgb = this.values.rgb;
			return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
		},

		luminosity: function () {
			// http://www.w3.org/TR/WCAG20/#relativeluminancedef
			var rgb = this.values.rgb;
			var lum = [];
			for (var i = 0; i < rgb.length; i++) {
				var chan = rgb[i] / 255;
				lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
			}
			return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
		},

		contrast: function (color2) {
			// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
			var lum1 = this.luminosity();
			var lum2 = color2.luminosity();
			if (lum1 > lum2) {
				return (lum1 + 0.05) / (lum2 + 0.05);
			}
			return (lum2 + 0.05) / (lum1 + 0.05);
		},

		level: function (color2) {
			var contrastRatio = this.contrast(color2);
			if (contrastRatio >= 7.1) {
				return 'AAA';
			}

			return (contrastRatio >= 4.5) ? 'AA' : '';
		},

		dark: function () {
			// YIQ equation from http://24ways.org/2010/calculating-color-contrast
			var rgb = this.values.rgb;
			var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
			return yiq < 128;
		},

		light: function () {
			return !this.dark();
		},

		negate: function () {
			var rgb = [];
			for (var i = 0; i < 3; i++) {
				rgb[i] = 255 - this.values.rgb[i];
			}
			this.setValues('rgb', rgb);
			return this;
		},

		lighten: function (ratio) {
			var hsl = this.values.hsl;
			hsl[2] += hsl[2] * ratio;
			this.setValues('hsl', hsl);
			return this;
		},

		darken: function (ratio) {
			var hsl = this.values.hsl;
			hsl[2] -= hsl[2] * ratio;
			this.setValues('hsl', hsl);
			return this;
		},

		saturate: function (ratio) {
			var hsl = this.values.hsl;
			hsl[1] += hsl[1] * ratio;
			this.setValues('hsl', hsl);
			return this;
		},

		desaturate: function (ratio) {
			var hsl = this.values.hsl;
			hsl[1] -= hsl[1] * ratio;
			this.setValues('hsl', hsl);
			return this;
		},

		whiten: function (ratio) {
			var hwb = this.values.hwb;
			hwb[1] += hwb[1] * ratio;
			this.setValues('hwb', hwb);
			return this;
		},

		blacken: function (ratio) {
			var hwb = this.values.hwb;
			hwb[2] += hwb[2] * ratio;
			this.setValues('hwb', hwb);
			return this;
		},

		greyscale: function () {
			var rgb = this.values.rgb;
			// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
			var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
			this.setValues('rgb', [val, val, val]);
			return this;
		},

		clearer: function (ratio) {
			var alpha = this.values.alpha;
			this.setValues('alpha', alpha - (alpha * ratio));
			return this;
		},

		opaquer: function (ratio) {
			var alpha = this.values.alpha;
			this.setValues('alpha', alpha + (alpha * ratio));
			return this;
		},

		rotate: function (degrees) {
			var hsl = this.values.hsl;
			var hue = (hsl[0] + degrees) % 360;
			hsl[0] = hue < 0 ? 360 + hue : hue;
			this.setValues('hsl', hsl);
			return this;
		},

		/**
		 * Ported from sass implementation in C
		 * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
		 */
		mix: function (mixinColor, weight) {
			var color1 = this;
			var color2 = mixinColor;
			var p = weight === undefined ? 0.5 : weight;

			var w = 2 * p - 1;
			var a = color1.alpha() - color2.alpha();

			var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
			var w2 = 1 - w1;

			return this
				.rgb(
					w1 * color1.red() + w2 * color2.red(),
					w1 * color1.green() + w2 * color2.green(),
					w1 * color1.blue() + w2 * color2.blue()
				)
				.alpha(color1.alpha() * p + color2.alpha() * (1 - p));
		},

		toJSON: function () {
			return this.rgb();
		},

		clone: function () {
			// NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
			// making the final build way to big to embed in Chart.js. So let's do it manually,
			// assuming that values to clone are 1 dimension arrays containing only numbers,
			// except 'alpha' which is a number.
			var result = new Color();
			var source = this.values;
			var target = result.values;
			var value, type;

			for (var prop in source) {
				if (source.hasOwnProperty(prop)) {
					value = source[prop];
					type = ({}).toString.call(value);
					if (type === '[object Array]') {
						target[prop] = value.slice(0);
					} else if (type === '[object Number]') {
						target[prop] = value;
					} else {
						console.error('unexpected color value:', value);
					}
				}
			}

			return result;
		}
	};

	Color.prototype.spaces = {
		rgb: ['red', 'green', 'blue'],
		hsl: ['hue', 'saturation', 'lightness'],
		hsv: ['hue', 'saturation', 'value'],
		hwb: ['hue', 'whiteness', 'blackness'],
		cmyk: ['cyan', 'magenta', 'yellow', 'black']
	};

	Color.prototype.maxes = {
		rgb: [255, 255, 255],
		hsl: [360, 100, 100],
		hsv: [360, 100, 100],
		hwb: [360, 100, 100],
		cmyk: [100, 100, 100, 100]
	};

	Color.prototype.getValues = function (space) {
		var values = this.values;
		var vals = {};

		for (var i = 0; i < space.length; i++) {
			vals[space.charAt(i)] = values[space][i];
		}

		if (values.alpha !== 1) {
			vals.a = values.alpha;
		}

		// {r: 255, g: 255, b: 255, a: 0.4}
		return vals;
	};

	Color.prototype.setValues = function (space, vals) {
		var values = this.values;
		var spaces = this.spaces;
		var maxes = this.maxes;
		var alpha = 1;
		var i;

		this.valid = true;

		if (space === 'alpha') {
			alpha = vals;
		} else if (vals.length) {
			// [10, 10, 10]
			values[space] = vals.slice(0, space.length);
			alpha = vals[space.length];
		} else if (vals[space.charAt(0)] !== undefined) {
			// {r: 10, g: 10, b: 10}
			for (i = 0; i < space.length; i++) {
				values[space][i] = vals[space.charAt(i)];
			}

			alpha = vals.a;
		} else if (vals[spaces[space][0]] !== undefined) {
			// {red: 10, green: 10, blue: 10}
			var chans = spaces[space];

			for (i = 0; i < space.length; i++) {
				values[space][i] = vals[chans[i]];
			}

			alpha = vals.alpha;
		}

		values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));

		if (space === 'alpha') {
			return false;
		}

		var capped;

		// cap values of the space prior converting all values
		for (i = 0; i < space.length; i++) {
			capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
			values[space][i] = Math.round(capped);
		}

		// convert to all the other color spaces
		for (var sname in spaces) {
			if (sname !== space) {
				values[sname] = colorConvert[space][sname](values[space]);
			}
		}

		return true;
	};

	Color.prototype.setSpace = function (space, args) {
		var vals = args[0];

		if (vals === undefined) {
			// color.rgb()
			return this.getValues(space);
		}

		// color.rgb(10, 10, 10)
		if (typeof vals === 'number') {
			vals = Array.prototype.slice.call(args);
		}

		this.setValues(space, vals);
		return this;
	};

	Color.prototype.setChannel = function (space, index, val) {
		var svalues = this.values[space];
		if (val === undefined) {
			// color.red()
			return svalues[index];
		} else if (val === svalues[index]) {
			// color.red(color.red())
			return this;
		}

		// color.red(100)
		svalues[index] = val;
		this.setValues(space, svalues);

		return this;
	};

	if (typeof window !== 'undefined') {
		window.Color = Color;
	}

	var chartjsColor = Color;

	var core_helpers = function(Chart) {

		// -- Basic js utility methods

		helpers$1.configMerge = function(/* objects ... */) {
			return helpers$1.merge(helpers$1.clone(arguments[0]), [].slice.call(arguments, 1), {
				merger: function(key, target, source, options) {
					var tval = target[key] || {};
					var sval = source[key];

					if (key === 'scales') {
						// scale config merging is complex. Add our own function here for that
						target[key] = helpers$1.scaleMerge(tval, sval);
					} else if (key === 'scale') {
						// used in polar area & radar charts since there is only one scale
						target[key] = helpers$1.merge(tval, [Chart.scaleService.getScaleDefaults(sval.type), sval]);
					} else {
						helpers$1._merger(key, target, source, options);
					}
				}
			});
		};

		helpers$1.scaleMerge = function(/* objects ... */) {
			return helpers$1.merge(helpers$1.clone(arguments[0]), [].slice.call(arguments, 1), {
				merger: function(key, target, source, options) {
					if (key === 'xAxes' || key === 'yAxes') {
						var slen = source[key].length;
						var i, type, scale;

						if (!target[key]) {
							target[key] = [];
						}

						for (i = 0; i < slen; ++i) {
							scale = source[key][i];
							type = helpers$1.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear');

							if (i >= target[key].length) {
								target[key].push({});
							}

							if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
								// new/untyped scale or type changed: let's apply the new defaults
								// then merge source scale to correctly overwrite the defaults.
								helpers$1.merge(target[key][i], [Chart.scaleService.getScaleDefaults(type), scale]);
							} else {
								// scales type are the same
								helpers$1.merge(target[key][i], scale);
							}
						}
					} else {
						helpers$1._merger(key, target, source, options);
					}
				}
			});
		};

		helpers$1.where = function(collection, filterCallback) {
			if (helpers$1.isArray(collection) && Array.prototype.filter) {
				return collection.filter(filterCallback);
			}
			var filtered = [];

			helpers$1.each(collection, function(item) {
				if (filterCallback(item)) {
					filtered.push(item);
				}
			});

			return filtered;
		};
		helpers$1.findIndex = Array.prototype.findIndex ?
			function(array, callback, scope) {
				return array.findIndex(callback, scope);
			} :
			function(array, callback, scope) {
				scope = scope === undefined ? array : scope;
				for (var i = 0, ilen = array.length; i < ilen; ++i) {
					if (callback.call(scope, array[i], i, array)) {
						return i;
					}
				}
				return -1;
			};
		helpers$1.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
			// Default to start of the array
			if (helpers$1.isNullOrUndef(startIndex)) {
				startIndex = -1;
			}
			for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
				var currentItem = arrayToSearch[i];
				if (filterCallback(currentItem)) {
					return currentItem;
				}
			}
		};
		helpers$1.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
			// Default to end of the array
			if (helpers$1.isNullOrUndef(startIndex)) {
				startIndex = arrayToSearch.length;
			}
			for (var i = startIndex - 1; i >= 0; i--) {
				var currentItem = arrayToSearch[i];
				if (filterCallback(currentItem)) {
					return currentItem;
				}
			}
		};

		// -- Math methods
		helpers$1.isNumber = function(n) {
			return !isNaN(parseFloat(n)) && isFinite(n);
		};
		helpers$1.almostEquals = function(x, y, epsilon) {
			return Math.abs(x - y) < epsilon;
		};
		helpers$1.almostWhole = function(x, epsilon) {
			var rounded = Math.round(x);
			return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
		};
		helpers$1.max = function(array) {
			return array.reduce(function(max, value) {
				if (!isNaN(value)) {
					return Math.max(max, value);
				}
				return max;
			}, Number.NEGATIVE_INFINITY);
		};
		helpers$1.min = function(array) {
			return array.reduce(function(min, value) {
				if (!isNaN(value)) {
					return Math.min(min, value);
				}
				return min;
			}, Number.POSITIVE_INFINITY);
		};
		helpers$1.sign = Math.sign ?
			function(x) {
				return Math.sign(x);
			} :
			function(x) {
				x = +x; // convert to a number
				if (x === 0 || isNaN(x)) {
					return x;
				}
				return x > 0 ? 1 : -1;
			};
		helpers$1.log10 = Math.log10 ?
			function(x) {
				return Math.log10(x);
			} :
			function(x) {
				var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
				// Check for whole powers of 10,
				// which due to floating point rounding error should be corrected.
				var powerOf10 = Math.round(exponent);
				var isPowerOf10 = x === Math.pow(10, powerOf10);

				return isPowerOf10 ? powerOf10 : exponent;
			};
		helpers$1.toRadians = function(degrees) {
			return degrees * (Math.PI / 180);
		};
		helpers$1.toDegrees = function(radians) {
			return radians * (180 / Math.PI);
		};
		// Gets the angle from vertical upright to the point about a centre.
		helpers$1.getAngleFromPoint = function(centrePoint, anglePoint) {
			var distanceFromXCenter = anglePoint.x - centrePoint.x;
			var distanceFromYCenter = anglePoint.y - centrePoint.y;
			var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);

			var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);

			if (angle < (-0.5 * Math.PI)) {
				angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
			}

			return {
				angle: angle,
				distance: radialDistanceFromCenter
			};
		};
		helpers$1.distanceBetweenPoints = function(pt1, pt2) {
			return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
		};
		helpers$1.aliasPixel = function(pixelWidth) {
			return (pixelWidth % 2 === 0) ? 0 : 0.5;
		};
		helpers$1.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
			// Props to Rob Spencer at scaled innovation for his post on splining between points
			// http://scaledinnovation.com/analytics/splines/aboutSplines.html

			// This function must also respect "skipped" points

			var previous = firstPoint.skip ? middlePoint : firstPoint;
			var current = middlePoint;
			var next = afterPoint.skip ? middlePoint : afterPoint;

			var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
			var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));

			var s01 = d01 / (d01 + d12);
			var s12 = d12 / (d01 + d12);

			// If all points are the same, s01 & s02 will be inf
			s01 = isNaN(s01) ? 0 : s01;
			s12 = isNaN(s12) ? 0 : s12;

			var fa = t * s01; // scaling factor for triangle Ta
			var fb = t * s12;

			return {
				previous: {
					x: current.x - fa * (next.x - previous.x),
					y: current.y - fa * (next.y - previous.y)
				},
				next: {
					x: current.x + fb * (next.x - previous.x),
					y: current.y + fb * (next.y - previous.y)
				}
			};
		};
		helpers$1.EPSILON = Number.EPSILON || 1e-14;
		helpers$1.splineCurveMonotone = function(points) {
			// This function calculates Bézier control points in a similar way than |splineCurve|,
			// but preserves monotonicity of the provided data and ensures no local extremums are added
			// between the dataset discrete points due to the interpolation.
			// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation

			var pointsWithTangents = (points || []).map(function(point) {
				return {
					model: point._model,
					deltaK: 0,
					mK: 0
				};
			});

			// Calculate slopes (deltaK) and initialize tangents (mK)
			var pointsLen = pointsWithTangents.length;
			var i, pointBefore, pointCurrent, pointAfter;
			for (i = 0; i < pointsLen; ++i) {
				pointCurrent = pointsWithTangents[i];
				if (pointCurrent.model.skip) {
					continue;
				}

				pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
				pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
				if (pointAfter && !pointAfter.model.skip) {
					var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);

					// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
					pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
				}

				if (!pointBefore || pointBefore.model.skip) {
					pointCurrent.mK = pointCurrent.deltaK;
				} else if (!pointAfter || pointAfter.model.skip) {
					pointCurrent.mK = pointBefore.deltaK;
				} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
					pointCurrent.mK = 0;
				} else {
					pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
				}
			}

			// Adjust tangents to ensure monotonic properties
			var alphaK, betaK, tauK, squaredMagnitude;
			for (i = 0; i < pointsLen - 1; ++i) {
				pointCurrent = pointsWithTangents[i];
				pointAfter = pointsWithTangents[i + 1];
				if (pointCurrent.model.skip || pointAfter.model.skip) {
					continue;
				}

				if (helpers$1.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
					pointCurrent.mK = pointAfter.mK = 0;
					continue;
				}

				alphaK = pointCurrent.mK / pointCurrent.deltaK;
				betaK = pointAfter.mK / pointCurrent.deltaK;
				squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
				if (squaredMagnitude <= 9) {
					continue;
				}

				tauK = 3 / Math.sqrt(squaredMagnitude);
				pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
				pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
			}

			// Compute control points
			var deltaX;
			for (i = 0; i < pointsLen; ++i) {
				pointCurrent = pointsWithTangents[i];
				if (pointCurrent.model.skip) {
					continue;
				}

				pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
				pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
				if (pointBefore && !pointBefore.model.skip) {
					deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
					pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
					pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
				}
				if (pointAfter && !pointAfter.model.skip) {
					deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
					pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
					pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
				}
			}
		};
		helpers$1.nextItem = function(collection, index, loop) {
			if (loop) {
				return index >= collection.length - 1 ? collection[0] : collection[index + 1];
			}
			return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
		};
		helpers$1.previousItem = function(collection, index, loop) {
			if (loop) {
				return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
			}
			return index <= 0 ? collection[0] : collection[index - 1];
		};
		// Implementation of the nice number algorithm used in determining where axis labels will go
		helpers$1.niceNum = function(range, round) {
			var exponent = Math.floor(helpers$1.log10(range));
			var fraction = range / Math.pow(10, exponent);
			var niceFraction;

			if (round) {
				if (fraction < 1.5) {
					niceFraction = 1;
				} else if (fraction < 3) {
					niceFraction = 2;
				} else if (fraction < 7) {
					niceFraction = 5;
				} else {
					niceFraction = 10;
				}
			} else if (fraction <= 1.0) {
				niceFraction = 1;
			} else if (fraction <= 2) {
				niceFraction = 2;
			} else if (fraction <= 5) {
				niceFraction = 5;
			} else {
				niceFraction = 10;
			}

			return niceFraction * Math.pow(10, exponent);
		};
		// Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
		helpers$1.requestAnimFrame = (function() {
			if (typeof window === 'undefined') {
				return function(callback) {
					callback();
				};
			}
			return window.requestAnimationFrame ||
				window.webkitRequestAnimationFrame ||
				window.mozRequestAnimationFrame ||
				window.oRequestAnimationFrame ||
				window.msRequestAnimationFrame ||
				function(callback) {
					return window.setTimeout(callback, 1000 / 60);
				};
		}());
		// -- DOM methods
		helpers$1.getRelativePosition = function(evt, chart) {
			var mouseX, mouseY;
			var e = evt.originalEvent || evt;
			var canvas = evt.currentTarget || evt.srcElement;
			var boundingRect = canvas.getBoundingClientRect();

			var touches = e.touches;
			if (touches && touches.length > 0) {
				mouseX = touches[0].clientX;
				mouseY = touches[0].clientY;

			} else {
				mouseX = e.clientX;
				mouseY = e.clientY;
			}

			// Scale mouse coordinates into canvas coordinates
			// by following the pattern laid out by 'jerryj' in the comments of
			// http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
			var paddingLeft = parseFloat(helpers$1.getStyle(canvas, 'padding-left'));
			var paddingTop = parseFloat(helpers$1.getStyle(canvas, 'padding-top'));
			var paddingRight = parseFloat(helpers$1.getStyle(canvas, 'padding-right'));
			var paddingBottom = parseFloat(helpers$1.getStyle(canvas, 'padding-bottom'));
			var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
			var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;

			// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
			// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
			mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
			mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);

			return {
				x: mouseX,
				y: mouseY
			};

		};

		// Private helper function to convert max-width/max-height values that may be percentages into a number
		function parseMaxStyle(styleValue, node, parentProperty) {
			var valueInPixels;
			if (typeof styleValue === 'string') {
				valueInPixels = parseInt(styleValue, 10);

				if (styleValue.indexOf('%') !== -1) {
					// percentage * size in dimension
					valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
				}
			} else {
				valueInPixels = styleValue;
			}

			return valueInPixels;
		}

		/**
		 * Returns if the given value contains an effective constraint.
		 * @private
		 */
		function isConstrainedValue(value) {
			return value !== undefined && value !== null && value !== 'none';
		}

		// Private helper to get a constraint dimension
		// @param domNode : the node to check the constraint on
		// @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
		// @param percentageProperty : property of parent to use when calculating width as a percentage
		// @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
		function getConstraintDimension(domNode, maxStyle, percentageProperty) {
			var view = document.defaultView;
			var parentNode = domNode.parentNode;
			var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
			var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
			var hasCNode = isConstrainedValue(constrainedNode);
			var hasCContainer = isConstrainedValue(constrainedContainer);
			var infinity = Number.POSITIVE_INFINITY;

			if (hasCNode || hasCContainer) {
				return Math.min(
					hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
					hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
			}

			return 'none';
		}
		// returns Number or undefined if no constraint
		helpers$1.getConstraintWidth = function(domNode) {
			return getConstraintDimension(domNode, 'max-width', 'clientWidth');
		};
		// returns Number or undefined if no constraint
		helpers$1.getConstraintHeight = function(domNode) {
			return getConstraintDimension(domNode, 'max-height', 'clientHeight');
		};
		helpers$1.getMaximumWidth = function(domNode) {
			var container = domNode.parentNode;
			if (!container) {
				return domNode.clientWidth;
			}

			var paddingLeft = parseInt(helpers$1.getStyle(container, 'padding-left'), 10);
			var paddingRight = parseInt(helpers$1.getStyle(container, 'padding-right'), 10);
			var w = container.clientWidth - paddingLeft - paddingRight;
			var cw = helpers$1.getConstraintWidth(domNode);
			return isNaN(cw) ? w : Math.min(w, cw);
		};
		helpers$1.getMaximumHeight = function(domNode) {
			var container = domNode.parentNode;
			if (!container) {
				return domNode.clientHeight;
			}

			var paddingTop = parseInt(helpers$1.getStyle(container, 'padding-top'), 10);
			var paddingBottom = parseInt(helpers$1.getStyle(container, 'padding-bottom'), 10);
			var h = container.clientHeight - paddingTop - paddingBottom;
			var ch = helpers$1.getConstraintHeight(domNode);
			return isNaN(ch) ? h : Math.min(h, ch);
		};
		helpers$1.getStyle = function(el, property) {
			return el.currentStyle ?
				el.currentStyle[property] :
				document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
		};
		helpers$1.retinaScale = function(chart, forceRatio) {
			var pixelRatio = chart.currentDevicePixelRatio = forceRatio || window.devicePixelRatio || 1;
			if (pixelRatio === 1) {
				return;
			}

			var canvas = chart.canvas;
			var height = chart.height;
			var width = chart.width;

			canvas.height = height * pixelRatio;
			canvas.width = width * pixelRatio;
			chart.ctx.scale(pixelRatio, pixelRatio);

			// If no style has been set on the canvas, the render size is used as display size,
			// making the chart visually bigger, so let's enforce it to the "correct" values.
			// See https://github.com/chartjs/Chart.js/issues/3575
			if (!canvas.style.height && !canvas.style.width) {
				canvas.style.height = height + 'px';
				canvas.style.width = width + 'px';
			}
		};
		// -- Canvas methods
		helpers$1.fontString = function(pixelSize, fontStyle, fontFamily) {
			return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
		};
		helpers$1.longestText = function(ctx, font, arrayOfThings, cache) {
			cache = cache || {};
			var data = cache.data = cache.data || {};
			var gc = cache.garbageCollect = cache.garbageCollect || [];

			if (cache.font !== font) {
				data = cache.data = {};
				gc = cache.garbageCollect = [];
				cache.font = font;
			}

			ctx.font = font;
			var longest = 0;
			helpers$1.each(arrayOfThings, function(thing) {
				// Undefined strings and arrays should not be measured
				if (thing !== undefined && thing !== null && helpers$1.isArray(thing) !== true) {
					longest = helpers$1.measureText(ctx, data, gc, longest, thing);
				} else if (helpers$1.isArray(thing)) {
					// if it is an array lets measure each element
					// to do maybe simplify this function a bit so we can do this more recursively?
					helpers$1.each(thing, function(nestedThing) {
						// Undefined strings and arrays should not be measured
						if (nestedThing !== undefined && nestedThing !== null && !helpers$1.isArray(nestedThing)) {
							longest = helpers$1.measureText(ctx, data, gc, longest, nestedThing);
						}
					});
				}
			});

			var gcLen = gc.length / 2;
			if (gcLen > arrayOfThings.length) {
				for (var i = 0; i < gcLen; i++) {
					delete data[gc[i]];
				}
				gc.splice(0, gcLen);
			}
			return longest;
		};
		helpers$1.measureText = function(ctx, data, gc, longest, string) {
			var textWidth = data[string];
			if (!textWidth) {
				textWidth = data[string] = ctx.measureText(string).width;
				gc.push(string);
			}
			if (textWidth > longest) {
				longest = textWidth;
			}
			return longest;
		};
		helpers$1.numberOfLabelLines = function(arrayOfThings) {
			var numberOfLines = 1;
			helpers$1.each(arrayOfThings, function(thing) {
				if (helpers$1.isArray(thing)) {
					if (thing.length > numberOfLines) {
						numberOfLines = thing.length;
					}
				}
			});
			return numberOfLines;
		};

		helpers$1.color = !chartjsColor ?
			function(value) {
				console.error('Color.js not found!');
				return value;
			} :
			function(value) {
				/* global CanvasGradient */
				if (value instanceof CanvasGradient) {
					value = core_defaults.global.defaultColor;
				}

				return chartjsColor(value);
			};

		helpers$1.getHoverColor = function(colorValue) {
			/* global CanvasPattern */
			return (colorValue instanceof CanvasPattern) ?
				colorValue :
				helpers$1.color(colorValue).saturate(0.5).darken(0.1).rgbString();
		};
	};

	function interpolate(start, view, model, ease) {
		var keys = Object.keys(model);
		var i, ilen, key, actual, origin, target, type, c0, c1;

		for (i = 0, ilen = keys.length; i < ilen; ++i) {
			key = keys[i];

			target = model[key];

			// if a value is added to the model after pivot() has been called, the view
			// doesn't contain it, so let's initialize the view to the target value.
			if (!view.hasOwnProperty(key)) {
				view[key] = target;
			}

			actual = view[key];

			if (actual === target || key[0] === '_') {
				continue;
			}

			if (!start.hasOwnProperty(key)) {
				start[key] = actual;
			}

			origin = start[key];

			type = typeof target;

			if (type === typeof origin) {
				if (type === 'string') {
					c0 = chartjsColor(origin);
					if (c0.valid) {
						c1 = chartjsColor(target);
						if (c1.valid) {
							view[key] = c1.mix(c0, ease).rgbString();
							continue;
						}
					}
				} else if (type === 'number' && isFinite(origin) && isFinite(target)) {
					view[key] = origin + (target - origin) * ease;
					continue;
				}
			}

			view[key] = target;
		}
	}

	var Element$1 = function(configuration) {
		helpers$1.extend(this, configuration);
		this.initialize.apply(this, arguments);
	};

	helpers$1.extend(Element$1.prototype, {

		initialize: function() {
			this.hidden = false;
		},

		pivot: function() {
			var me = this;
			if (!me._view) {
				me._view = helpers$1.clone(me._model);
			}
			me._start = {};
			return me;
		},

		transition: function(ease) {
			var me = this;
			var model = me._model;
			var start = me._start;
			var view = me._view;

			// No animation -> No Transition
			if (!model || ease === 1) {
				me._view = model;
				me._start = null;
				return me;
			}

			if (!view) {
				view = me._view = {};
			}

			if (!start) {
				start = me._start = {};
			}

			interpolate(start, view, model, ease);

			return me;
		},

		tooltipPosition: function() {
			return {
				x: this._model.x,
				y: this._model.y
			};
		},

		hasValue: function() {
			return helpers$1.isNumber(this._model.x) && helpers$1.isNumber(this._model.y);
		}
	});

	Element$1.extend = helpers$1.inherits;

	var core_element = Element$1;

	core_defaults._set('global', {
		elements: {
			arc: {
				backgroundColor: core_defaults.global.defaultColor,
				borderColor: '#fff',
				borderWidth: 2
			}
		}
	});

	var element_arc = core_element.extend({
		inLabelRange: function(mouseX) {
			var vm = this._view;

			if (vm) {
				return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
			}
			return false;
		},

		inRange: function(chartX, chartY) {
			var vm = this._view;

			if (vm) {
				var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY});
				var	angle = pointRelativePosition.angle;
				var distance = pointRelativePosition.distance;

				// Sanitise angle range
				var startAngle = vm.startAngle;
				var endAngle = vm.endAngle;
				while (endAngle < startAngle) {
					endAngle += 2.0 * Math.PI;
				}
				while (angle > endAngle) {
					angle -= 2.0 * Math.PI;
				}
				while (angle < startAngle) {
					angle += 2.0 * Math.PI;
				}

				// Check if within the range of the open/close angle
				var betweenAngles = (angle >= startAngle && angle <= endAngle);
				var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);

				return (betweenAngles && withinRadius);
			}
			return false;
		},

		getCenterPoint: function() {
			var vm = this._view;
			var halfAngle = (vm.startAngle + vm.endAngle) / 2;
			var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
			return {
				x: vm.x + Math.cos(halfAngle) * halfRadius,
				y: vm.y + Math.sin(halfAngle) * halfRadius
			};
		},

		getArea: function() {
			var vm = this._view;
			return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
		},

		tooltipPosition: function() {
			var vm = this._view;
			var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
			var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;

			return {
				x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
				y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
			};
		},

		draw: function() {
			var ctx = this._chart.ctx;
			var vm = this._view;
			var sA = vm.startAngle;
			var eA = vm.endAngle;

			ctx.beginPath();

			ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
			ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);

			ctx.closePath();
			ctx.strokeStyle = vm.borderColor;
			ctx.lineWidth = vm.borderWidth;

			ctx.fillStyle = vm.backgroundColor;

			ctx.fill();
			ctx.lineJoin = 'bevel';

			if (vm.borderWidth) {
				ctx.stroke();
			}
		}
	});

	var globalDefaults = core_defaults.global;

	core_defaults._set('global', {
		elements: {
			line: {
				tension: 0.4,
				backgroundColor: globalDefaults.defaultColor,
				borderWidth: 3,
				borderColor: globalDefaults.defaultColor,
				borderCapStyle: 'butt',
				borderDash: [],
				borderDashOffset: 0.0,
				borderJoinStyle: 'miter',
				capBezierPoints: true,
				fill: true, // do we fill in the area between the line and its base axis
			}
		}
	});

	var element_line = core_element.extend({
		draw: function() {
			var me = this;
			var vm = me._view;
			var ctx = me._chart.ctx;
			var spanGaps = vm.spanGaps;
			var points = me._children.slice(); // clone array
			var globalOptionLineElements = globalDefaults.elements.line;
			var lastDrawnIndex = -1;
			var index, current, previous, currentVM;

			// If we are looping, adding the first point again
			if (me._loop && points.length) {
				points.push(points[0]);
			}

			ctx.save();

			// Stroke Line Options
			ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;

			// IE 9 and 10 do not support line dash
			if (ctx.setLineDash) {
				ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
			}

			ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
			ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
			ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
			ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;

			// Stroke Line
			ctx.beginPath();
			lastDrawnIndex = -1;

			for (index = 0; index < points.length; ++index) {
				current = points[index];
				previous = helpers$1.previousItem(points, index);
				currentVM = current._view;

				// First point moves to it's starting position no matter what
				if (index === 0) {
					if (!currentVM.skip) {
						ctx.moveTo(currentVM.x, currentVM.y);
						lastDrawnIndex = index;
					}
				} else {
					previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];

					if (!currentVM.skip) {
						if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
							// There was a gap and this is the first point after the gap
							ctx.moveTo(currentVM.x, currentVM.y);
						} else {
							// Line to next point
							helpers$1.canvas.lineTo(ctx, previous._view, current._view);
						}
						lastDrawnIndex = index;
					}
				}
			}

			ctx.stroke();
			ctx.restore();
		}
	});

	var defaultColor = core_defaults.global.defaultColor;

	core_defaults._set('global', {
		elements: {
			point: {
				radius: 3,
				pointStyle: 'circle',
				backgroundColor: defaultColor,
				borderColor: defaultColor,
				borderWidth: 1,
				// Hover
				hitRadius: 1,
				hoverRadius: 4,
				hoverBorderWidth: 1
			}
		}
	});

	function xRange(mouseX) {
		var vm = this._view;
		return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
	}

	function yRange(mouseY) {
		var vm = this._view;
		return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
	}

	var element_point = core_element.extend({
		inRange: function(mouseX, mouseY) {
			var vm = this._view;
			return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
		},

		inLabelRange: xRange,
		inXRange: xRange,
		inYRange: yRange,

		getCenterPoint: function() {
			var vm = this._view;
			return {
				x: vm.x,
				y: vm.y
			};
		},

		getArea: function() {
			return Math.PI * Math.pow(this._view.radius, 2);
		},

		tooltipPosition: function() {
			var vm = this._view;
			return {
				x: vm.x,
				y: vm.y,
				padding: vm.radius + vm.borderWidth
			};
		},

		draw: function(chartArea) {
			var vm = this._view;
			var model = this._model;
			var ctx = this._chart.ctx;
			var pointStyle = vm.pointStyle;
			var radius = vm.radius;
			var x = vm.x;
			var y = vm.y;
			var color = helpers$1.color;
			var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
			var ratio = 0;

			if (vm.skip) {
				return;
			}

			ctx.strokeStyle = vm.borderColor || defaultColor;
			ctx.lineWidth = helpers$1.valueOrDefault(vm.borderWidth, core_defaults.global.elements.point.borderWidth);
			ctx.fillStyle = vm.backgroundColor || defaultColor;

			// Cliping for Points.
			// going out from inner charArea?
			if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) {
				// Point fade out
				if (model.x < chartArea.left) {
					ratio = (x - model.x) / (chartArea.left - model.x);
				} else if (chartArea.right * errMargin < model.x) {
					ratio = (model.x - x) / (model.x - chartArea.right);
				} else if (model.y < chartArea.top) {
					ratio = (y - model.y) / (chartArea.top - model.y);
				} else if (chartArea.bottom * errMargin < model.y) {
					ratio = (model.y - y) / (model.y - chartArea.bottom);
				}
				ratio = Math.round(ratio * 100) / 100;
				ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
				ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
			}

			helpers$1.canvas.drawPoint(ctx, pointStyle, radius, x, y);
		}
	});

	core_defaults._set('global', {
		elements: {
			rectangle: {
				backgroundColor: core_defaults.global.defaultColor,
				borderColor: core_defaults.global.defaultColor,
				borderSkipped: 'bottom',
				borderWidth: 0
			}
		}
	});

	function isVertical(bar) {
		return bar._view.width !== undefined;
	}

	/**
	 * Helper function to get the bounds of the bar regardless of the orientation
	 * @param bar {Chart.Element.Rectangle} the bar
	 * @return {Bounds} bounds of the bar
	 * @private
	 */
	function getBarBounds(bar) {
		var vm = bar._view;
		var x1, x2, y1, y2;

		if (isVertical(bar)) {
			// vertical
			var halfWidth = vm.width / 2;
			x1 = vm.x - halfWidth;
			x2 = vm.x + halfWidth;
			y1 = Math.min(vm.y, vm.base);
			y2 = Math.max(vm.y, vm.base);
		} else {
			// horizontal bar
			var halfHeight = vm.height / 2;
			x1 = Math.min(vm.x, vm.base);
			x2 = Math.max(vm.x, vm.base);
			y1 = vm.y - halfHeight;
			y2 = vm.y + halfHeight;
		}

		return {
			left: x1,
			top: y1,
			right: x2,
			bottom: y2
		};
	}

	var element_rectangle = core_element.extend({
		draw: function() {
			var ctx = this._chart.ctx;
			var vm = this._view;
			var left, right, top, bottom, signX, signY, borderSkipped;
			var borderWidth = vm.borderWidth;

			if (!vm.horizontal) {
				// bar
				left = vm.x - vm.width / 2;
				right = vm.x + vm.width / 2;
				top = vm.y;
				bottom = vm.base;
				signX = 1;
				signY = bottom > top ? 1 : -1;
				borderSkipped = vm.borderSkipped || 'bottom';
			} else {
				// horizontal bar
				left = vm.base;
				right = vm.x;
				top = vm.y - vm.height / 2;
				bottom = vm.y + vm.height / 2;
				signX = right > left ? 1 : -1;
				signY = 1;
				borderSkipped = vm.borderSkipped || 'left';
			}

			// Canvas doesn't allow us to stroke inside the width so we can
			// adjust the sizes to fit if we're setting a stroke on the line
			if (borderWidth) {
				// borderWidth shold be less than bar width and bar height.
				var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
				borderWidth = borderWidth > barSize ? barSize : borderWidth;
				var halfStroke = borderWidth / 2;
				// Adjust borderWidth when bar top position is near vm.base(zero).
				var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
				var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
				var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
				var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
				// not become a vertical line?
				if (borderLeft !== borderRight) {
					top = borderTop;
					bottom = borderBottom;
				}
				// not become a horizontal line?
				if (borderTop !== borderBottom) {
					left = borderLeft;
					right = borderRight;
				}
			}

			ctx.beginPath();
			ctx.fillStyle = vm.backgroundColor;
			ctx.strokeStyle = vm.borderColor;
			ctx.lineWidth = borderWidth;

			// Corner points, from bottom-left to bottom-right clockwise
			// | 1 2 |
			// | 0 3 |
			var corners = [
				[left, bottom],
				[left, top],
				[right, top],
				[right, bottom]
			];

			// Find first (starting) corner with fallback to 'bottom'
			var borders = ['bottom', 'left', 'top', 'right'];
			var startCorner = borders.indexOf(borderSkipped, 0);
			if (startCorner === -1) {
				startCorner = 0;
			}

			function cornerAt(index) {
				return corners[(startCorner + index) % 4];
			}

			// Draw rectangle from 'startCorner'
			var corner = cornerAt(0);
			ctx.moveTo(corner[0], corner[1]);

			for (var i = 1; i < 4; i++) {
				corner = cornerAt(i);
				ctx.lineTo(corner[0], corner[1]);
			}

			ctx.fill();
			if (borderWidth) {
				ctx.stroke();
			}
		},

		height: function() {
			var vm = this._view;
			return vm.base - vm.y;
		},

		inRange: function(mouseX, mouseY) {
			var inRange = false;

			if (this._view) {
				var bounds = getBarBounds(this);
				inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
			}

			return inRange;
		},

		inLabelRange: function(mouseX, mouseY) {
			var me = this;
			if (!me._view) {
				return false;
			}

			var inRange = false;
			var bounds = getBarBounds(me);

			if (isVertical(me)) {
				inRange = mouseX >= bounds.left && mouseX <= bounds.right;
			} else {
				inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
			}

			return inRange;
		},

		inXRange: function(mouseX) {
			var bounds = getBarBounds(this);
			return mouseX >= bounds.left && mouseX <= bounds.right;
		},

		inYRange: function(mouseY) {
			var bounds = getBarBounds(this);
			return mouseY >= bounds.top && mouseY <= bounds.bottom;
		},

		getCenterPoint: function() {
			var vm = this._view;
			var x, y;
			if (isVertical(this)) {
				x = vm.x;
				y = (vm.y + vm.base) / 2;
			} else {
				x = (vm.x + vm.base) / 2;
				y = vm.y;
			}

			return {x: x, y: y};
		},

		getArea: function() {
			var vm = this._view;
			return vm.width * Math.abs(vm.y - vm.base);
		},

		tooltipPosition: function() {
			var vm = this._view;
			return {
				x: vm.x,
				y: vm.y
			};
		}
	});

	var elements = {};
	var Arc = element_arc;
	var Line = element_line;
	var Point = element_point;
	var Rectangle = element_rectangle;
	elements.Arc = Arc;
	elements.Line = Line;
	elements.Point = Point;
	elements.Rectangle = Rectangle;

	/**
	 * Helper function to get relative position for an event
	 * @param {Event|IEvent} event - The event to get the position for
	 * @param {Chart} chart - The chart
	 * @returns {Point} the event position
	 */
	function getRelativePosition(e, chart) {
		if (e.native) {
			return {
				x: e.x,
				y: e.y
			};
		}

		return helpers$1.getRelativePosition(e, chart);
	}

	/**
	 * Helper function to traverse all of the visible elements in the chart
	 * @param chart {chart} the chart
	 * @param handler {Function} the callback to execute for each visible item
	 */
	function parseVisibleItems(chart, handler) {
		var datasets = chart.data.datasets;
		var meta, i, j, ilen, jlen;

		for (i = 0, ilen = datasets.length; i < ilen; ++i) {
			if (!chart.isDatasetVisible(i)) {
				continue;
			}

			meta = chart.getDatasetMeta(i);
			for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
				var element = meta.data[j];
				if (!element._view.skip) {
					handler(element);
				}
			}
		}
	}

	/**
	 * Helper function to get the items that intersect the event position
	 * @param items {ChartElement[]} elements to filter
	 * @param position {Point} the point to be nearest to
	 * @return {ChartElement[]} the nearest items
	 */
	function getIntersectItems(chart, position) {
		var elements = [];

		parseVisibleItems(chart, function(element) {
			if (element.inRange(position.x, position.y)) {
				elements.push(element);
			}
		});

		return elements;
	}

	/**
	 * Helper function to get the items nearest to the event position considering all visible items in teh chart
	 * @param chart {Chart} the chart to look at elements from
	 * @param position {Point} the point to be nearest to
	 * @param intersect {Boolean} if true, only consider items that intersect the position
	 * @param distanceMetric {Function} function to provide the distance between points
	 * @return {ChartElement[]} the nearest items
	 */
	function getNearestItems(chart, position, intersect, distanceMetric) {
		var minDistance = Number.POSITIVE_INFINITY;
		var nearestItems = [];

		parseVisibleItems(chart, function(element) {
			if (intersect && !element.inRange(position.x, position.y)) {
				return;
			}

			var center = element.getCenterPoint();
			var distance = distanceMetric(position, center);

			if (distance < minDistance) {
				nearestItems = [element];
				minDistance = distance;
			} else if (distance === minDistance) {
				// Can have multiple items at the same distance in which case we sort by size
				nearestItems.push(element);
			}
		});

		return nearestItems;
	}

	/**
	 * Get a distance metric function for two points based on the
	 * axis mode setting
	 * @param {String} axis the axis mode. x|y|xy
	 */
	function getDistanceMetricForAxis(axis) {
		var useX = axis.indexOf('x') !== -1;
		var useY = axis.indexOf('y') !== -1;

		return function(pt1, pt2) {
			var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
			var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
			return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
		};
	}

	function indexMode(chart, e, options) {
		var position = getRelativePosition(e, chart);
		// Default axis for index mode is 'x' to match old behaviour
		options.axis = options.axis || 'x';
		var distanceMetric = getDistanceMetricForAxis(options.axis);
		var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
		var elements = [];

		if (!items.length) {
			return [];
		}

		chart.data.datasets.forEach(function(dataset, datasetIndex) {
			if (chart.isDatasetVisible(datasetIndex)) {
				var meta = chart.getDatasetMeta(datasetIndex);
				var element = meta.data[items[0]._index];

				// don't count items that are skipped (null data)
				if (element && !element._view.skip) {
					elements.push(element);
				}
			}
		});

		return elements;
	}

	/**
	 * @interface IInteractionOptions
	 */
	/**
	 * If true, only consider items that intersect the point
	 * @name IInterfaceOptions#boolean
	 * @type Boolean
	 */

	/**
	 * Contains interaction related functions
	 * @namespace Chart.Interaction
	 */
	var core_interaction = {
		// Helper function for different modes
		modes: {
			single: function(chart, e) {
				var position = getRelativePosition(e, chart);
				var elements = [];

				parseVisibleItems(chart, function(element) {
					if (element.inRange(position.x, position.y)) {
						elements.push(element);
						return elements;
					}
				});

				return elements.slice(0, 1);
			},

			/**
			 * @function Chart.Interaction.modes.label
			 * @deprecated since version 2.4.0
			 * @todo remove at version 3
			 * @private
			 */
			label: indexMode,

			/**
			 * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
			 * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
			 * @function Chart.Interaction.modes.index
			 * @since v2.4.0
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use during interaction
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			index: indexMode,

			/**
			 * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
			 * If the options.intersect is false, we find the nearest item and return the items in that dataset
			 * @function Chart.Interaction.modes.dataset
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use during interaction
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			dataset: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				options.axis = options.axis || 'xy';
				var distanceMetric = getDistanceMetricForAxis(options.axis);
				var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);

				if (items.length > 0) {
					items = chart.getDatasetMeta(items[0]._datasetIndex).data;
				}

				return items;
			},

			/**
			 * @function Chart.Interaction.modes.x-axis
			 * @deprecated since version 2.4.0. Use index mode and intersect == true
			 * @todo remove at version 3
			 * @private
			 */
			'x-axis': function(chart, e) {
				return indexMode(chart, e, {intersect: false});
			},

			/**
			 * Point mode returns all elements that hit test based on the event position
			 * of the event
			 * @function Chart.Interaction.modes.intersect
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			point: function(chart, e) {
				var position = getRelativePosition(e, chart);
				return getIntersectItems(chart, position);
			},

			/**
			 * nearest mode returns the element closest to the point
			 * @function Chart.Interaction.modes.intersect
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			nearest: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				options.axis = options.axis || 'xy';
				var distanceMetric = getDistanceMetricForAxis(options.axis);
				var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric);

				// We have multiple items at the same distance from the event. Now sort by smallest
				if (nearestItems.length > 1) {
					nearestItems.sort(function(a, b) {
						var sizeA = a.getArea();
						var sizeB = b.getArea();
						var ret = sizeA - sizeB;

						if (ret === 0) {
							// if equal sort by dataset index
							ret = a._datasetIndex - b._datasetIndex;
						}

						return ret;
					});
				}

				// Return only 1 item
				return nearestItems.slice(0, 1);
			},

			/**
			 * x mode returns the elements that hit-test at the current x coordinate
			 * @function Chart.Interaction.modes.x
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			x: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				var items = [];
				var intersectsItem = false;

				parseVisibleItems(chart, function(element) {
					if (element.inXRange(position.x)) {
						items.push(element);
					}

					if (element.inRange(position.x, position.y)) {
						intersectsItem = true;
					}
				});

				// If we want to trigger on an intersect and we don't have any items
				// that intersect the position, return nothing
				if (options.intersect && !intersectsItem) {
					items = [];
				}
				return items;
			},

			/**
			 * y mode returns the elements that hit-test at the current y coordinate
			 * @function Chart.Interaction.modes.y
			 * @param chart {chart} the chart we are returning items from
			 * @param e {Event} the event we are find things at
			 * @param options {IInteractionOptions} options to use
			 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
			 */
			y: function(chart, e, options) {
				var position = getRelativePosition(e, chart);
				var items = [];
				var intersectsItem = false;

				parseVisibleItems(chart, function(element) {
					if (element.inYRange(position.y)) {
						items.push(element);
					}

					if (element.inRange(position.x, position.y)) {
						intersectsItem = true;
					}
				});

				// If we want to trigger on an intersect and we don't have any items
				// that intersect the position, return nothing
				if (options.intersect && !intersectsItem) {
					items = [];
				}
				return items;
			}
		}
	};

	function filterByPosition(array, position) {
		return helpers$1.where(array, function(v) {
			return v.position === position;
		});
	}

	function sortByWeight(array, reverse) {
		array.forEach(function(v, i) {
			v._tmpIndex_ = i;
			return v;
		});
		array.sort(function(a, b) {
			var v0 = reverse ? b : a;
			var v1 = reverse ? a : b;
			return v0.weight === v1.weight ?
				v0._tmpIndex_ - v1._tmpIndex_ :
				v0.weight - v1.weight;
		});
		array.forEach(function(v) {
			delete v._tmpIndex_;
		});
	}

	/**
	 * @interface ILayoutItem
	 * @prop {String} position - The position of the item in the chart layout. Possible values are
	 * 'left', 'top', 'right', 'bottom', and 'chartArea'
	 * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
	 * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
	 * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
	 * @prop {Function} update - Takes two parameters: width and height. Returns size of item
	 * @prop {Function} getPadding -  Returns an object with padding on the edges
	 * @prop {Number} width - Width of item. Must be valid after update()
	 * @prop {Number} height - Height of item. Must be valid after update()
	 * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
	 * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
	 * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
	 * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
	 */

	// The layout service is very self explanatory.  It's responsible for the layout within a chart.
	// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
	// It is this service's responsibility of carrying out that layout.
	var core_layouts = {
		defaults: {},

		/**
		 * Register a box to a chart.
		 * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
		 * @param {Chart} chart - the chart to use
		 * @param {ILayoutItem} item - the item to add to be layed out
		 */
		addBox: function(chart, item) {
			if (!chart.boxes) {
				chart.boxes = [];
			}

			// initialize item with default values
			item.fullWidth = item.fullWidth || false;
			item.position = item.position || 'top';
			item.weight = item.weight || 0;

			chart.boxes.push(item);
		},

		/**
		 * Remove a layoutItem from a chart
		 * @param {Chart} chart - the chart to remove the box from
		 * @param {Object} layoutItem - the item to remove from the layout
		 */
		removeBox: function(chart, layoutItem) {
			var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
			if (index !== -1) {
				chart.boxes.splice(index, 1);
			}
		},

		/**
		 * Sets (or updates) options on the given `item`.
		 * @param {Chart} chart - the chart in which the item lives (or will be added to)
		 * @param {Object} item - the item to configure with the given options
		 * @param {Object} options - the new item options.
		 */
		configure: function(chart, item, options) {
			var props = ['fullWidth', 'position', 'weight'];
			var ilen = props.length;
			var i = 0;
			var prop;

			for (; i < ilen; ++i) {
				prop = props[i];
				if (options.hasOwnProperty(prop)) {
					item[prop] = options[prop];
				}
			}
		},

		/**
		 * Fits boxes of the given chart into the given size by having each box measure itself
		 * then running a fitting algorithm
		 * @param {Chart} chart - the chart
		 * @param {Number} width - the width to fit into
		 * @param {Number} height - the height to fit into
		 */
		update: function(chart, width, height) {
			if (!chart) {
				return;
			}

			var layoutOptions = chart.options.layout || {};
			var padding = helpers$1.options.toPadding(layoutOptions.padding);
			var leftPadding = padding.left;
			var rightPadding = padding.right;
			var topPadding = padding.top;
			var bottomPadding = padding.bottom;

			var leftBoxes = filterByPosition(chart.boxes, 'left');
			var rightBoxes = filterByPosition(chart.boxes, 'right');
			var topBoxes = filterByPosition(chart.boxes, 'top');
			var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
			var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');

			// Sort boxes by weight. A higher weight is further away from the chart area
			sortByWeight(leftBoxes, true);
			sortByWeight(rightBoxes, false);
			sortByWeight(topBoxes, true);
			sortByWeight(bottomBoxes, false);

			// Essentially we now have any number of boxes on each of the 4 sides.
			// Our canvas looks like the following.
			// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
			// B1 is the bottom axis
			// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
			// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
			// an error will be thrown.
			//
			// |----------------------------------------------------|
			// |                  T1 (Full Width)                   |
			// |----------------------------------------------------|
			// |    |    |                 T2                  |    |
			// |    |----|-------------------------------------|----|
			// |    |    | C1 |                           | C2 |    |
			// |    |    |----|                           |----|    |
			// |    |    |                                     |    |
			// | L1 | L2 |           ChartArea (C0)            | R1 |
			// |    |    |                                     |    |
			// |    |    |----|                           |----|    |
			// |    |    | C3 |                           | C4 |    |
			// |    |----|-------------------------------------|----|
			// |    |    |                 B1                  |    |
			// |----------------------------------------------------|
			// |                  B2 (Full Width)                   |
			// |----------------------------------------------------|
			//
			// What we do to find the best sizing, we do the following
			// 1. Determine the minimum size of the chart area.
			// 2. Split the remaining width equally between each vertical axis
			// 3. Split the remaining height equally between each horizontal axis
			// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
			// 5. Adjust the sizes of each axis based on it's minimum reported size.
			// 6. Refit each axis
			// 7. Position each axis in the final location
			// 8. Tell the chart the final location of the chart area
			// 9. Tell any axes that overlay the chart area the positions of the chart area

			// Step 1
			var chartWidth = width - leftPadding - rightPadding;
			var chartHeight = height - topPadding - bottomPadding;
			var chartAreaWidth = chartWidth / 2; // min 50%
			var chartAreaHeight = chartHeight / 2; // min 50%

			// Step 2
			var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);

			// Step 3
			var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);

			// Step 4
			var maxChartAreaWidth = chartWidth;
			var maxChartAreaHeight = chartHeight;
			var minBoxSizes = [];

			function getMinimumBoxSize(box) {
				var minSize;
				var isHorizontal = box.isHorizontal();

				if (isHorizontal) {
					minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
					maxChartAreaHeight -= minSize.height;
				} else {
					minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
					maxChartAreaWidth -= minSize.width;
				}

				minBoxSizes.push({
					horizontal: isHorizontal,
					minSize: minSize,
					box: box,
				});
			}

			helpers$1.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);

			// If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
			var maxHorizontalLeftPadding = 0;
			var maxHorizontalRightPadding = 0;
			var maxVerticalTopPadding = 0;
			var maxVerticalBottomPadding = 0;

			helpers$1.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
				if (horizontalBox.getPadding) {
					var boxPadding = horizontalBox.getPadding();
					maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
					maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
				}
			});

			helpers$1.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
				if (verticalBox.getPadding) {
					var boxPadding = verticalBox.getPadding();
					maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
					maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
				}
			});

			// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
			// be if the axes are drawn at their minimum sizes.
			// Steps 5 & 6
			var totalLeftBoxesWidth = leftPadding;
			var totalRightBoxesWidth = rightPadding;
			var totalTopBoxesHeight = topPadding;
			var totalBottomBoxesHeight = bottomPadding;

			// Function to fit a box
			function fitBox(box) {
				var minBoxSize = helpers$1.findNextWhere(minBoxSizes, function(minBox) {
					return minBox.box === box;
				});

				if (minBoxSize) {
					if (box.isHorizontal()) {
						var scaleMargin = {
							left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
							right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
							top: 0,
							bottom: 0
						};

						// Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
						// on the margin. Sometimes they need to increase in size slightly
						box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
					} else {
						box.update(minBoxSize.minSize.width, maxChartAreaHeight);
					}
				}
			}

			// Update, and calculate the left and right margins for the horizontal boxes
			helpers$1.each(leftBoxes.concat(rightBoxes), fitBox);

			helpers$1.each(leftBoxes, function(box) {
				totalLeftBoxesWidth += box.width;
			});

			helpers$1.each(rightBoxes, function(box) {
				totalRightBoxesWidth += box.width;
			});

			// Set the Left and Right margins for the horizontal boxes
			helpers$1.each(topBoxes.concat(bottomBoxes), fitBox);

			// Figure out how much margin is on the top and bottom of the vertical boxes
			helpers$1.each(topBoxes, function(box) {
				totalTopBoxesHeight += box.height;
			});

			helpers$1.each(bottomBoxes, function(box) {
				totalBottomBoxesHeight += box.height;
			});

			function finalFitVerticalBox(box) {
				var minBoxSize = helpers$1.findNextWhere(minBoxSizes, function(minSize) {
					return minSize.box === box;
				});

				var scaleMargin = {
					left: 0,
					right: 0,
					top: totalTopBoxesHeight,
					bottom: totalBottomBoxesHeight
				};

				if (minBoxSize) {
					box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
				}
			}

			// Let the left layout know the final margin
			helpers$1.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);

			// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
			totalLeftBoxesWidth = leftPadding;
			totalRightBoxesWidth = rightPadding;
			totalTopBoxesHeight = topPadding;
			totalBottomBoxesHeight = bottomPadding;

			helpers$1.each(leftBoxes, function(box) {
				totalLeftBoxesWidth += box.width;
			});

			helpers$1.each(rightBoxes, function(box) {
				totalRightBoxesWidth += box.width;
			});

			helpers$1.each(topBoxes, function(box) {
				totalTopBoxesHeight += box.height;
			});
			helpers$1.each(bottomBoxes, function(box) {
				totalBottomBoxesHeight += box.height;
			});

			// We may be adding some padding to account for rotated x axis labels
			var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
			totalLeftBoxesWidth += leftPaddingAddition;
			totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);

			var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
			totalTopBoxesHeight += topPaddingAddition;
			totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);

			// Figure out if our chart area changed. This would occur if the dataset layout label rotation
			// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
			// without calling `fit` again
			var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
			var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;

			if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
				helpers$1.each(leftBoxes, function(box) {
					box.height = newMaxChartAreaHeight;
				});

				helpers$1.each(rightBoxes, function(box) {
					box.height = newMaxChartAreaHeight;
				});

				helpers$1.each(topBoxes, function(box) {
					if (!box.fullWidth) {
						box.width = newMaxChartAreaWidth;
					}
				});

				helpers$1.each(bottomBoxes, function(box) {
					if (!box.fullWidth) {
						box.width = newMaxChartAreaWidth;
					}
				});

				maxChartAreaHeight = newMaxChartAreaHeight;
				maxChartAreaWidth = newMaxChartAreaWidth;
			}

			// Step 7 - Position the boxes
			var left = leftPadding + leftPaddingAddition;
			var top = topPadding + topPaddingAddition;

			function placeBox(box) {
				if (box.isHorizontal()) {
					box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
					box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
					box.top = top;
					box.bottom = top + box.height;

					// Move to next point
					top = box.bottom;

				} else {

					box.left = left;
					box.right = left + box.width;
					box.top = totalTopBoxesHeight;
					box.bottom = totalTopBoxesHeight + maxChartAreaHeight;

					// Move to next point
					left = box.right;
				}
			}

			helpers$1.each(leftBoxes.concat(topBoxes), placeBox);

			// Account for chart width and height
			left += maxChartAreaWidth;
			top += maxChartAreaHeight;

			helpers$1.each(rightBoxes, placeBox);
			helpers$1.each(bottomBoxes, placeBox);

			// Step 8
			chart.chartArea = {
				left: totalLeftBoxesWidth,
				top: totalTopBoxesHeight,
				right: totalLeftBoxesWidth + maxChartAreaWidth,
				bottom: totalTopBoxesHeight + maxChartAreaHeight
			};

			// Step 9
			helpers$1.each(chartAreaBoxes, function(box) {
				box.left = chart.chartArea.left;
				box.top = chart.chartArea.top;
				box.right = chart.chartArea.right;
				box.bottom = chart.chartArea.bottom;

				box.update(maxChartAreaWidth, maxChartAreaHeight);
			});
		}
	};

	/**
	 * Platform fallback implementation (minimal).
	 * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
	 */

	var platform_basic = {
		acquireContext: function(item) {
			if (item && item.canvas) {
				// Support for any object associated to a canvas (including a context2d)
				item = item.canvas;
			}

			return item && item.getContext('2d') || null;
		}
	};

	var EXPANDO_KEY = '$chartjs';
	var CSS_PREFIX = 'chartjs-';
	var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
	var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
	var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];

	/**
	 * DOM event types -> Chart.js event types.
	 * Note: only events with different types are mapped.
	 * @see https://developer.mozilla.org/en-US/docs/Web/Events
	 */
	var EVENT_TYPES = {
		touchstart: 'mousedown',
		touchmove: 'mousemove',
		touchend: 'mouseup',
		pointerenter: 'mouseenter',
		pointerdown: 'mousedown',
		pointermove: 'mousemove',
		pointerup: 'mouseup',
		pointerleave: 'mouseout',
		pointerout: 'mouseout'
	};

	/**
	 * The "used" size is the final value of a dimension property after all calculations have
	 * been performed. This method uses the computed style of `element` but returns undefined
	 * if the computed style is not expressed in pixels. That can happen in some cases where
	 * `element` has a size relative to its parent and this last one is not yet displayed,
	 * for example because of `display: none` on a parent node.
	 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
	 * @returns {Number} Size in pixels or undefined if unknown.
	 */
	function readUsedSize(element, property) {
		var value = helpers$1.getStyle(element, property);
		var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
		return matches ? Number(matches[1]) : undefined;
	}

	/**
	 * Initializes the canvas style and render size without modifying the canvas display size,
	 * since responsiveness is handled by the controller.resize() method. The config is used
	 * to determine the aspect ratio to apply in case no explicit height has been specified.
	 */
	function initCanvas(canvas, config) {
		var style = canvas.style;

		// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
		// returns null or '' if no explicit value has been set to the canvas attribute.
		var renderHeight = canvas.getAttribute('height');
		var renderWidth = canvas.getAttribute('width');

		// Chart.js modifies some canvas values that we want to restore on destroy
		canvas[EXPANDO_KEY] = {
			initial: {
				height: renderHeight,
				width: renderWidth,
				style: {
					display: style.display,
					height: style.height,
					width: style.width
				}
			}
		};

		// Force canvas to display as block to avoid extra space caused by inline
		// elements, which would interfere with the responsive resize process.
		// https://github.com/chartjs/Chart.js/issues/2538
		style.display = style.display || 'block';

		if (renderWidth === null || renderWidth === '') {
			var displayWidth = readUsedSize(canvas, 'width');
			if (displayWidth !== undefined) {
				canvas.width = displayWidth;
			}
		}

		if (renderHeight === null || renderHeight === '') {
			if (canvas.style.height === '') {
				// If no explicit render height and style height, let's apply the aspect ratio,
				// which one can be specified by the user but also by charts as default option
				// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
				canvas.height = canvas.width / (config.options.aspectRatio || 2);
			} else {
				var displayHeight = readUsedSize(canvas, 'height');
				if (displayWidth !== undefined) {
					canvas.height = displayHeight;
				}
			}
		}

		return canvas;
	}

	/**
	 * Detects support for options object argument in addEventListener.
	 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
	 * @private
	 */
	var supportsEventListenerOptions = (function() {
		var supports = false;
		try {
			var options = Object.defineProperty({}, 'passive', {
				get: function() {
					supports = true;
				}
			});
			window.addEventListener('e', null, options);
		} catch (e) {
			// continue regardless of error
		}
		return supports;
	}());

	// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
	// https://github.com/chartjs/Chart.js/issues/4287
	var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;

	function addEventListener(node, type, listener) {
		node.addEventListener(type, listener, eventListenerOptions);
	}

	function removeEventListener(node, type, listener) {
		node.removeEventListener(type, listener, eventListenerOptions);
	}

	function createEvent(type, chart, x, y, nativeEvent) {
		return {
			type: type,
			chart: chart,
			native: nativeEvent || null,
			x: x !== undefined ? x : null,
			y: y !== undefined ? y : null,
		};
	}

	function fromNativeEvent(event, chart) {
		var type = EVENT_TYPES[event.type] || event.type;
		var pos = helpers$1.getRelativePosition(event, chart);
		return createEvent(type, chart, pos.x, pos.y, event);
	}

	function throttled(fn, thisArg) {
		var ticking = false;
		var args = [];

		return function() {
			args = Array.prototype.slice.call(arguments);
			thisArg = thisArg || this;

			if (!ticking) {
				ticking = true;
				helpers$1.requestAnimFrame.call(window, function() {
					ticking = false;
					fn.apply(thisArg, args);
				});
			}
		};
	}

	// Implementation based on https://github.com/marcj/css-element-queries
	function createResizer(handler) {
		var resizer = document.createElement('div');
		var cls = CSS_PREFIX + 'size-monitor';
		var maxSize = 1000000;
		var style =
			'position:absolute;' +
			'left:0;' +
			'top:0;' +
			'right:0;' +
			'bottom:0;' +
			'overflow:hidden;' +
			'pointer-events:none;' +
			'visibility:hidden;' +
			'z-index:-1;';

		resizer.style.cssText = style;
		resizer.className = cls;
		resizer.innerHTML =
			'<div class="' + cls + '-expand" style="' + style + '">' +
				'<div style="' +
					'position:absolute;' +
					'width:' + maxSize + 'px;' +
					'height:' + maxSize + 'px;' +
					'left:0;' +
					'top:0">' +
				'</div>' +
			'</div>' +
			'<div class="' + cls + '-shrink" style="' + style + '">' +
				'<div style="' +
					'position:absolute;' +
					'width:200%;' +
					'height:200%;' +
					'left:0; ' +
					'top:0">' +
				'</div>' +
			'</div>';

		var expand = resizer.childNodes[0];
		var shrink = resizer.childNodes[1];

		resizer._reset = function() {
			expand.scrollLeft = maxSize;
			expand.scrollTop = maxSize;
			shrink.scrollLeft = maxSize;
			shrink.scrollTop = maxSize;
		};
		var onScroll = function() {
			resizer._reset();
			handler();
		};

		addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
		addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));

		return resizer;
	}

	// https://davidwalsh.name/detect-node-insertion
	function watchForRender(node, handler) {
		var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
		var proxy = expando.renderProxy = function(e) {
			if (e.animationName === CSS_RENDER_ANIMATION) {
				handler();
			}
		};

		helpers$1.each(ANIMATION_START_EVENTS, function(type) {
			addEventListener(node, type, proxy);
		});

		// #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
		// is removed then added back immediately (same animation frame?). Accessing the
		// `offsetParent` property will force a reflow and re-evaluate the CSS animation.
		// https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
		// https://github.com/chartjs/Chart.js/issues/4737
		expando.reflow = !!node.offsetParent;

		node.classList.add(CSS_RENDER_MONITOR);
	}

	function unwatchForRender(node) {
		var expando = node[EXPANDO_KEY] || {};
		var proxy = expando.renderProxy;

		if (proxy) {
			helpers$1.each(ANIMATION_START_EVENTS, function(type) {
				removeEventListener(node, type, proxy);
			});

			delete expando.renderProxy;
		}

		node.classList.remove(CSS_RENDER_MONITOR);
	}

	function addResizeListener(node, listener, chart) {
		var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});

		// Let's keep track of this added resizer and thus avoid DOM query when removing it.
		var resizer = expando.resizer = createResizer(throttled(function() {
			if (expando.resizer) {
				return listener(createEvent('resize', chart));
			}
		}));

		// The resizer needs to be attached to the node parent, so we first need to be
		// sure that `node` is attached to the DOM before injecting the resizer element.
		watchForRender(node, function() {
			if (expando.resizer) {
				var container = node.parentNode;
				if (container && container !== resizer.parentNode) {
					container.insertBefore(resizer, container.firstChild);
				}

				// The container size might have changed, let's reset the resizer state.
				resizer._reset();
			}
		});
	}

	function removeResizeListener(node) {
		var expando = node[EXPANDO_KEY] || {};
		var resizer = expando.resizer;

		delete expando.resizer;
		unwatchForRender(node);

		if (resizer && resizer.parentNode) {
			resizer.parentNode.removeChild(resizer);
		}
	}

	function injectCSS(platform, css) {
		// http://stackoverflow.com/q/3922139
		var style = platform._style || document.createElement('style');
		if (!platform._style) {
			platform._style = style;
			css = '/* Chart.js */\n' + css;
			style.setAttribute('type', 'text/css');
			document.getElementsByTagName('head')[0].appendChild(style);
		}

		style.appendChild(document.createTextNode(css));
	}

	var platform_dom = {
		/**
		 * This property holds whether this platform is enabled for the current environment.
		 * Currently used by platform.js to select the proper implementation.
		 * @private
		 */
		_enabled: typeof window !== 'undefined' && typeof document !== 'undefined',

		initialize: function() {
			var keyframes = 'from{opacity:0.99}to{opacity:1}';

			injectCSS(this,
				// DOM rendering detection
				// https://davidwalsh.name/detect-node-insertion
				'@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
				'@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
				'.' + CSS_RENDER_MONITOR + '{' +
					'-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
					'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
				'}'
			);
		},

		acquireContext: function(item, config) {
			if (typeof item === 'string') {
				item = document.getElementById(item);
			} else if (item.length) {
				// Support for array based queries (such as jQuery)
				item = item[0];
			}

			if (item && item.canvas) {
				// Support for any object associated to a canvas (including a context2d)
				item = item.canvas;
			}

			// To prevent canvas fingerprinting, some add-ons undefine the getContext
			// method, for example: https://github.com/kkapsner/CanvasBlocker
			// https://github.com/chartjs/Chart.js/issues/2807
			var context = item && item.getContext && item.getContext('2d');

			// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
			// inside an iframe or when running in a protected environment. We could guess the
			// types from their toString() value but let's keep things flexible and assume it's
			// a sufficient condition if the item has a context2D which has item as `canvas`.
			// https://github.com/chartjs/Chart.js/issues/3887
			// https://github.com/chartjs/Chart.js/issues/4102
			// https://github.com/chartjs/Chart.js/issues/4152
			if (context && context.canvas === item) {
				initCanvas(item, config);
				return context;
			}

			return null;
		},

		releaseContext: function(context) {
			var canvas = context.canvas;
			if (!canvas[EXPANDO_KEY]) {
				return;
			}

			var initial = canvas[EXPANDO_KEY].initial;
			['height', 'width'].forEach(function(prop) {
				var value = initial[prop];
				if (helpers$1.isNullOrUndef(value)) {
					canvas.removeAttribute(prop);
				} else {
					canvas.setAttribute(prop, value);
				}
			});

			helpers$1.each(initial.style || {}, function(value, key) {
				canvas.style[key] = value;
			});

			// The canvas render size might have been changed (and thus the state stack discarded),
			// we can't use save() and restore() to restore the initial state. So make sure that at
			// least the canvas context is reset to the default state by setting the canvas width.
			// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
			canvas.width = canvas.width;

			delete canvas[EXPANDO_KEY];
		},

		addEventListener: function(chart, type, listener) {
			var canvas = chart.canvas;
			if (type === 'resize') {
				// Note: the resize event is not supported on all browsers.
				addResizeListener(canvas, listener, chart);
				return;
			}

			var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
			var proxies = expando.proxies || (expando.proxies = {});
			var proxy = proxies[chart.id + '_' + type] = function(event) {
				listener(fromNativeEvent(event, chart));
			};

			addEventListener(canvas, type, proxy);
		},

		removeEventListener: function(chart, type, listener) {
			var canvas = chart.canvas;
			if (type === 'resize') {
				// Note: the resize event is not supported on all browsers.
				removeResizeListener(canvas);
				return;
			}

			var expando = listener[EXPANDO_KEY] || {};
			var proxies = expando.proxies || {};
			var proxy = proxies[chart.id + '_' + type];
			if (!proxy) {
				return;
			}

			removeEventListener(canvas, type, proxy);
		}
	};

	// DEPRECATIONS

	/**
	 * Provided for backward compatibility, use EventTarget.addEventListener instead.
	 * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
	 * @function Chart.helpers.addEvent
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers$1.addEvent = addEventListener;

	/**
	 * Provided for backward compatibility, use EventTarget.removeEventListener instead.
	 * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
	 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
	 * @function Chart.helpers.removeEvent
	 * @deprecated since version 2.7.0
	 * @todo remove at version 3
	 * @private
	 */
	helpers$1.removeEvent = removeEventListener;

	// @TODO Make possible to select another platform at build time.
	var implementation = platform_dom._enabled ? platform_dom : platform_basic;

	/**
	 * @namespace Chart.platform
	 * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
	 * @since 2.4.0
	 */
	var platform = helpers$1.extend({
		/**
		 * @since 2.7.0
		 */
		initialize: function() {},

		/**
		 * Called at chart construction time, returns a context2d instance implementing
		 * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
		 * @param {*} item - The native item from which to acquire context (platform specific)
		 * @param {Object} options - The chart options
		 * @returns {CanvasRenderingContext2D} context2d instance
		 */
		acquireContext: function() {},

		/**
		 * Called at chart destruction time, releases any resources associated to the context
		 * previously returned by the acquireContext() method.
		 * @param {CanvasRenderingContext2D} context - The context2d instance
		 * @returns {Boolean} true if the method succeeded, else false
		 */
		releaseContext: function() {},

		/**
		 * Registers the specified listener on the given chart.
		 * @param {Chart} chart - Chart from which to listen for event
		 * @param {String} type - The ({@link IEvent}) type to listen for
		 * @param {Function} listener - Receives a notification (an object that implements
		 * the {@link IEvent} interface) when an event of the specified type occurs.
		 */
		addEventListener: function() {},

		/**
		 * Removes the specified listener previously registered with addEventListener.
		 * @param {Chart} chart -Chart from which to remove the listener
		 * @param {String} type - The ({@link IEvent}) type to remove
		 * @param {Function} listener - The listener function to remove from the event target.
		 */
		removeEventListener: function() {}

	}, implementation);

	core_defaults._set('global', {
		plugins: {}
	});

	/**
	 * The plugin service singleton
	 * @namespace Chart.plugins
	 * @since 2.1.0
	 */
	var core_plugins = {
		/**
		 * Globally registered plugins.
		 * @private
		 */
		_plugins: [],

		/**
		 * This identifier is used to invalidate the descriptors cache attached to each chart
		 * when a global plugin is registered or unregistered. In this case, the cache ID is
		 * incremented and descriptors are regenerated during following API calls.
		 * @private
		 */
		_cacheId: 0,

		/**
		 * Registers the given plugin(s) if not already registered.
		 * @param {Array|Object} plugins plugin instance(s).
		 */
		register: function(plugins) {
			var p = this._plugins;
			([]).concat(plugins).forEach(function(plugin) {
				if (p.indexOf(plugin) === -1) {
					p.push(plugin);
				}
			});

			this._cacheId++;
		},

		/**
		 * Unregisters the given plugin(s) only if registered.
		 * @param {Array|Object} plugins plugin instance(s).
		 */
		unregister: function(plugins) {
			var p = this._plugins;
			([]).concat(plugins).forEach(function(plugin) {
				var idx = p.indexOf(plugin);
				if (idx !== -1) {
					p.splice(idx, 1);
				}
			});

			this._cacheId++;
		},

		/**
		 * Remove all registered plugins.
		 * @since 2.1.5
		 */
		clear: function() {
			this._plugins = [];
			this._cacheId++;
		},

		/**
		 * Returns the number of registered plugins?
		 * @returns {Number}
		 * @since 2.1.5
		 */
		count: function() {
			return this._plugins.length;
		},

		/**
		 * Returns all registered plugin instances.
		 * @returns {Array} array of plugin objects.
		 * @since 2.1.5
		 */
		getAll: function() {
			return this._plugins;
		},

		/**
		 * Calls enabled plugins for `chart` on the specified hook and with the given args.
		 * This method immediately returns as soon as a plugin explicitly returns false. The
		 * returned value can be used, for instance, to interrupt the current action.
		 * @param {Object} chart - The chart instance for which plugins should be called.
		 * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
		 * @param {Array} [args] - Extra arguments to apply to the hook call.
		 * @returns {Boolean} false if any of the plugins return false, else returns true.
		 */
		notify: function(chart, hook, args) {
			var descriptors = this.descriptors(chart);
			var ilen = descriptors.length;
			var i, descriptor, plugin, params, method;

			for (i = 0; i < ilen; ++i) {
				descriptor = descriptors[i];
				plugin = descriptor.plugin;
				method = plugin[hook];
				if (typeof method === 'function') {
					params = [chart].concat(args || []);
					params.push(descriptor.options);
					if (method.apply(plugin, params) === false) {
						return false;
					}
				}
			}

			return true;
		},

		/**
		 * Returns descriptors of enabled plugins for the given chart.
		 * @returns {Array} [{ plugin, options }]
		 * @private
		 */
		descriptors: function(chart) {
			var cache = chart.$plugins || (chart.$plugins = {});
			if (cache.id === this._cacheId) {
				return cache.descriptors;
			}

			var plugins = [];
			var descriptors = [];
			var config = (chart && chart.config) || {};
			var options = (config.options && config.options.plugins) || {};

			this._plugins.concat(config.plugins || []).forEach(function(plugin) {
				var idx = plugins.indexOf(plugin);
				if (idx !== -1) {
					return;
				}

				var id = plugin.id;
				var opts = options[id];
				if (opts === false) {
					return;
				}

				if (opts === true) {
					opts = helpers$1.clone(core_defaults.global.plugins[id]);
				}

				plugins.push(plugin);
				descriptors.push({
					plugin: plugin,
					options: opts || {}
				});
			});

			cache.descriptors = descriptors;
			cache.id = this._cacheId;
			return descriptors;
		},

		/**
		 * Invalidates cache for the given chart: descriptors hold a reference on plugin option,
		 * but in some cases, this reference can be changed by the user when updating options.
		 * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
		 * @private
		 */
		_invalidate: function(chart) {
			delete chart.$plugins;
		}
	};

	/**
	 * Namespace to hold static tick generation functions
	 * @namespace Chart.Ticks
	 */
	var core_ticks = {
		/**
		 * Namespace to hold formatters for different types of ticks
		 * @namespace Chart.Ticks.formatters
		 */
		formatters: {
			/**
			 * Formatter for value labels
			 * @method Chart.Ticks.formatters.values
			 * @param value the value to display
			 * @return {String|Array} the label to display
			 */
			values: function(value) {
				return helpers$1.isArray(value) ? value : '' + value;
			},

			/**
			 * Formatter for linear numeric ticks
			 * @method Chart.Ticks.formatters.linear
			 * @param tickValue {Number} the value to be formatted
			 * @param index {Number} the position of the tickValue parameter in the ticks array
			 * @param ticks {Array<Number>} the list of ticks being converted
			 * @return {String} string representation of the tickValue parameter
			 */
			linear: function(tickValue, index, ticks) {
				// If we have lots of ticks, don't use the ones
				var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];

				// If we have a number like 2.5 as the delta, figure out how many decimal places we need
				if (Math.abs(delta) > 1) {
					if (tickValue !== Math.floor(tickValue)) {
						// not an integer
						delta = tickValue - Math.floor(tickValue);
					}
				}

				var logDelta = helpers$1.log10(Math.abs(delta));
				var tickString = '';

				if (tickValue !== 0) {
					var numDecimal = -1 * Math.floor(logDelta);
					numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
					tickString = tickValue.toFixed(numDecimal);
				} else {
					tickString = '0'; // never show decimal places for 0
				}

				return tickString;
			},

			logarithmic: function(tickValue, index, ticks) {
				var remain = tickValue / (Math.pow(10, Math.floor(helpers$1.log10(tickValue))));

				if (tickValue === 0) {
					return '0';
				} else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
					return tickValue.toExponential();
				}
				return '';
			}
		}
	};

	core_defaults._set('global', {
		animation: {
			duration: 1000,
			easing: 'easeOutQuart',
			onProgress: helpers$1.noop,
			onComplete: helpers$1.noop
		}
	});

	var core_animation = function(Chart) {

		Chart.Animation = core_element.extend({
			chart: null, // the animation associated chart instance
			currentStep: 0, // the current animation step
			numSteps: 60, // default number of steps
			easing: '', // the easing to use for this animation
			render: null, // render function used by the animation service

			onAnimationProgress: null, // user specified callback to fire on each step of the animation
			onAnimationComplete: null, // user specified callback to fire when the animation finishes
		});

		Chart.animationService = {
			frameDuration: 17,
			animations: [],
			dropFrames: 0,
			request: null,

			/**
			 * @param {Chart} chart - The chart to animate.
			 * @param {Chart.Animation} animation - The animation that we will animate.
			 * @param {Number} duration - The animation duration in ms.
			 * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
			 */
			addAnimation: function(chart, animation, duration, lazy) {
				var animations = this.animations;
				var i, ilen;

				animation.chart = chart;

				if (!lazy) {
					chart.animating = true;
				}

				for (i = 0, ilen = animations.length; i < ilen; ++i) {
					if (animations[i].chart === chart) {
						animations[i] = animation;
						return;
					}
				}

				animations.push(animation);

				// If there are no animations queued, manually kickstart a digest, for lack of a better word
				if (animations.length === 1) {
					this.requestAnimationFrame();
				}
			},

			cancelAnimation: function(chart) {
				var index = helpers$1.findIndex(this.animations, function(animation) {
					return animation.chart === chart;
				});

				if (index !== -1) {
					this.animations.splice(index, 1);
					chart.animating = false;
				}
			},

			requestAnimationFrame: function() {
				var me = this;
				if (me.request === null) {
					// Skip animation frame requests until the active one is executed.
					// This can happen when processing mouse events, e.g. 'mousemove'
					// and 'mouseout' events will trigger multiple renders.
					me.request = helpers$1.requestAnimFrame.call(window, function() {
						me.request = null;
						me.startDigest();
					});
				}
			},

			/**
			 * @private
			 */
			startDigest: function() {
				var me = this;
				var startTime = Date.now();
				var framesToDrop = 0;

				if (me.dropFrames > 1) {
					framesToDrop = Math.floor(me.dropFrames);
					me.dropFrames = me.dropFrames % 1;
				}

				me.advance(1 + framesToDrop);

				var endTime = Date.now();

				me.dropFrames += (endTime - startTime) / me.frameDuration;

				// Do we have more stuff to animate?
				if (me.animations.length > 0) {
					me.requestAnimationFrame();
				}
			},

			/**
			 * @private
			 */
			advance: function(count) {
				var animations = this.animations;
				var animation, chart;
				var i = 0;

				while (i < animations.length) {
					animation = animations[i];
					chart = animation.chart;

					animation.currentStep = (animation.currentStep || 0) + count;
					animation.currentStep = Math.min(animation.currentStep, animation.numSteps);

					helpers$1.callback(animation.render, [chart, animation], chart);
					helpers$1.callback(animation.onAnimationProgress, [animation], chart);

					if (animation.currentStep >= animation.numSteps) {
						helpers$1.callback(animation.onAnimationComplete, [animation], chart);
						chart.animating = false;
						animations.splice(i, 1);
					} else {
						++i;
					}
				}
			}
		};

		/**
		 * Provided for backward compatibility, use Chart.Animation instead
		 * @prop Chart.Animation#animationObject
		 * @deprecated since version 2.6.0
		 * @todo remove at version 3
		 */
		Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
			get: function() {
				return this;
			}
		});

		/**
		 * Provided for backward compatibility, use Chart.Animation#chart instead
		 * @prop Chart.Animation#chartInstance
		 * @deprecated since version 2.6.0
		 * @todo remove at version 3
		 */
		Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
			get: function() {
				return this.chart;
			},
			set: function(value) {
				this.chart = value;
			}
		});

	};

	var core_controller = function(Chart) {

		// Create a dictionary of chart types, to allow for extension of existing types
		Chart.types = {};

		// Store a reference to each instance - allowing us to globally resize chart instances on window resize.
		// Destroy method on the chart will remove the instance of the chart from this reference.
		Chart.instances = {};

		// Controllers available for dataset visualization eg. bar, line, slice, etc.
		Chart.controllers = {};

		/**
		 * Initializes the given config with global and chart default values.
		 */
		function initConfig(config) {
			config = config || {};

			// Do NOT use configMerge() for the data object because this method merges arrays
			// and so would change references to labels and datasets, preventing data updates.
			var data = config.data = config.data || {};
			data.datasets = data.datasets || [];
			data.labels = data.labels || [];

			config.options = helpers$1.configMerge(
				core_defaults.global,
				core_defaults[config.type],
				config.options || {});

			return config;
		}

		/**
		 * Updates the config of the chart
		 * @param chart {Chart} chart to update the options for
		 */
		function updateConfig(chart) {
			var newOptions = chart.options;

			helpers$1.each(chart.scales, function(scale) {
				core_layouts.removeBox(chart, scale);
			});

			newOptions = helpers$1.configMerge(
				Chart.defaults.global,
				Chart.defaults[chart.config.type],
				newOptions);

			chart.options = chart.config.options = newOptions;
			chart.ensureScalesHaveIDs();
			chart.buildOrUpdateScales();
			// Tooltip
			chart.tooltip._options = newOptions.tooltips;
			chart.tooltip.initialize();
		}

		function positionIsHorizontal(position) {
			return position === 'top' || position === 'bottom';
		}

		helpers$1.extend(Chart.prototype, /** @lends Chart */ {
			/**
			 * @private
			 */
			construct: function(item, config) {
				var me = this;

				config = initConfig(config);

				var context = platform.acquireContext(item, config);
				var canvas = context && context.canvas;
				var height = canvas && canvas.height;
				var width = canvas && canvas.width;

				me.id = helpers$1.uid();
				me.ctx = context;
				me.canvas = canvas;
				me.config = config;
				me.width = width;
				me.height = height;
				me.aspectRatio = height ? width / height : null;
				me.options = config.options;
				me._bufferedRender = false;

				/**
				 * Provided for backward compatibility, Chart and Chart.Controller have been merged,
				 * the "instance" still need to be defined since it might be called from plugins.
				 * @prop Chart#chart
				 * @deprecated since version 2.6.0
				 * @todo remove at version 3
				 * @private
				 */
				me.chart = me;
				me.controller = me; // chart.chart.controller #inception

				// Add the chart instance to the global namespace
				Chart.instances[me.id] = me;

				// Define alias to the config data: `chart.data === chart.config.data`
				Object.defineProperty(me, 'data', {
					get: function() {
						return me.config.data;
					},
					set: function(value) {
						me.config.data = value;
					}
				});

				if (!context || !canvas) {
					// The given item is not a compatible context2d element, let's return before finalizing
					// the chart initialization but after setting basic chart / controller properties that
					// can help to figure out that the chart is not valid (e.g chart.canvas !== null);
					// https://github.com/chartjs/Chart.js/issues/2807
					console.error("Failed to create chart: can't acquire context from the given item");
					return;
				}

				me.initialize();
				me.update();
			},

			/**
			 * @private
			 */
			initialize: function() {
				var me = this;

				// Before init plugin notification
				core_plugins.notify(me, 'beforeInit');

				helpers$1.retinaScale(me, me.options.devicePixelRatio);

				me.bindEvents();

				if (me.options.responsive) {
					// Initial resize before chart draws (must be silent to preserve initial animations).
					me.resize(true);
				}

				// Make sure scales have IDs and are built before we build any controllers.
				me.ensureScalesHaveIDs();
				me.buildOrUpdateScales();
				me.initToolTip();

				// After init plugin notification
				core_plugins.notify(me, 'afterInit');

				return me;
			},

			clear: function() {
				helpers$1.canvas.clear(this);
				return this;
			},

			stop: function() {
				// Stops any current animation loop occurring
				Chart.animationService.cancelAnimation(this);
				return this;
			},

			resize: function(silent) {
				var me = this;
				var options = me.options;
				var canvas = me.canvas;
				var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;

				// the canvas render width and height will be casted to integers so make sure that
				// the canvas display style uses the same integer values to avoid blurring effect.

				// Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collased
				var newWidth = Math.max(0, Math.floor(helpers$1.getMaximumWidth(canvas)));
				var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers$1.getMaximumHeight(canvas)));

				if (me.width === newWidth && me.height === newHeight) {
					return;
				}

				canvas.width = me.width = newWidth;
				canvas.height = me.height = newHeight;
				canvas.style.width = newWidth + 'px';
				canvas.style.height = newHeight + 'px';

				helpers$1.retinaScale(me, options.devicePixelRatio);

				if (!silent) {
					// Notify any plugins about the resize
					var newSize = {width: newWidth, height: newHeight};
					core_plugins.notify(me, 'resize', [newSize]);

					// Notify of resize
					if (me.options.onResize) {
						me.options.onResize(me, newSize);
					}

					me.stop();
					me.update(me.options.responsiveAnimationDuration);
				}
			},

			ensureScalesHaveIDs: function() {
				var options = this.options;
				var scalesOptions = options.scales || {};
				var scaleOptions = options.scale;

				helpers$1.each(scalesOptions.xAxes, function(xAxisOptions, index) {
					xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
				});

				helpers$1.each(scalesOptions.yAxes, function(yAxisOptions, index) {
					yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
				});

				if (scaleOptions) {
					scaleOptions.id = scaleOptions.id || 'scale';
				}
			},

			/**
			 * Builds a map of scale ID to scale object for future lookup.
			 */
			buildOrUpdateScales: function() {
				var me = this;
				var options = me.options;
				var scales = me.scales || {};
				var items = [];
				var updated = Object.keys(scales).reduce(function(obj, id) {
					obj[id] = false;
					return obj;
				}, {});

				if (options.scales) {
					items = items.concat(
						(options.scales.xAxes || []).map(function(xAxisOptions) {
							return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
						}),
						(options.scales.yAxes || []).map(function(yAxisOptions) {
							return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
						})
					);
				}

				if (options.scale) {
					items.push({
						options: options.scale,
						dtype: 'radialLinear',
						isDefault: true,
						dposition: 'chartArea'
					});
				}

				helpers$1.each(items, function(item) {
					var scaleOptions = item.options;
					var id = scaleOptions.id;
					var scaleType = helpers$1.valueOrDefault(scaleOptions.type, item.dtype);

					if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
						scaleOptions.position = item.dposition;
					}

					updated[id] = true;
					var scale = null;
					if (id in scales && scales[id].type === scaleType) {
						scale = scales[id];
						scale.options = scaleOptions;
						scale.ctx = me.ctx;
						scale.chart = me;
					} else {
						var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
						if (!scaleClass) {
							return;
						}
						scale = new scaleClass({
							id: id,
							type: scaleType,
							options: scaleOptions,
							ctx: me.ctx,
							chart: me
						});
						scales[scale.id] = scale;
					}

					scale.mergeTicksOptions();

					// TODO(SB): I think we should be able to remove this custom case (options.scale)
					// and consider it as a regular scale part of the "scales"" map only! This would
					// make the logic easier and remove some useless? custom code.
					if (item.isDefault) {
						me.scale = scale;
					}
				});
				// clear up discarded scales
				helpers$1.each(updated, function(hasUpdated, id) {
					if (!hasUpdated) {
						delete scales[id];
					}
				});

				me.scales = scales;

				Chart.scaleService.addScalesToLayout(this);
			},

			buildOrUpdateControllers: function() {
				var me = this;
				var types = [];
				var newControllers = [];

				helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
					var meta = me.getDatasetMeta(datasetIndex);
					var type = dataset.type || me.config.type;

					if (meta.type && meta.type !== type) {
						me.destroyDatasetMeta(datasetIndex);
						meta = me.getDatasetMeta(datasetIndex);
					}
					meta.type = type;

					types.push(meta.type);

					if (meta.controller) {
						meta.controller.updateIndex(datasetIndex);
						meta.controller.linkScales();
					} else {
						var ControllerClass = Chart.controllers[meta.type];
						if (ControllerClass === undefined) {
							throw new Error('"' + meta.type + '" is not a chart type.');
						}

						meta.controller = new ControllerClass(me, datasetIndex);
						newControllers.push(meta.controller);
					}
				}, me);

				return newControllers;
			},

			/**
			 * Reset the elements of all datasets
			 * @private
			 */
			resetElements: function() {
				var me = this;
				helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
					me.getDatasetMeta(datasetIndex).controller.reset();
				}, me);
			},

			/**
			* Resets the chart back to it's state before the initial animation
			*/
			reset: function() {
				this.resetElements();
				this.tooltip.initialize();
			},

			update: function(config) {
				var me = this;

				if (!config || typeof config !== 'object') {
					// backwards compatibility
					config = {
						duration: config,
						lazy: arguments[1]
					};
				}

				updateConfig(me);

				// plugins options references might have change, let's invalidate the cache
				// https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
				core_plugins._invalidate(me);

				if (core_plugins.notify(me, 'beforeUpdate') === false) {
					return;
				}

				// In case the entire data object changed
				me.tooltip._data = me.data;

				// Make sure dataset controllers are updated and new controllers are reset
				var newControllers = me.buildOrUpdateControllers();

				// Make sure all dataset controllers have correct meta data counts
				helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {
					me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
				}, me);

				me.updateLayout();

				// Can only reset the new controllers after the scales have been updated
				if (me.options.animation && me.options.animation.duration) {
					helpers$1.each(newControllers, function(controller) {
						controller.reset();
					});
				}

				me.updateDatasets();

				// Need to reset tooltip in case it is displayed with elements that are removed
				// after update.
				me.tooltip.initialize();

				// Last active contains items that were previously in the tooltip.
				// When we reset the tooltip, we need to clear it
				me.lastActive = [];

				// Do this before render so that any plugins that need final scale updates can use it
				core_plugins.notify(me, 'afterUpdate');

				if (me._bufferedRender) {
					me._bufferedRequest = {
						duration: config.duration,
						easing: config.easing,
						lazy: config.lazy
					};
				} else {
					me.render(config);
				}
			},

			/**
			 * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
			 * hook, in which case, plugins will not be called on `afterLayout`.
			 * @private
			 */
			updateLayout: function() {
				var me = this;

				if (core_plugins.notify(me, 'beforeLayout') === false) {
					return;
				}

				core_layouts.update(this, this.width, this.height);

				/**
				 * Provided for backward compatibility, use `afterLayout` instead.
				 * @method IPlugin#afterScaleUpdate
				 * @deprecated since version 2.5.0
				 * @todo remove at version 3
				 * @private
				 */
				core_plugins.notify(me, 'afterScaleUpdate');
				core_plugins.notify(me, 'afterLayout');
			},

			/**
			 * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
			 * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
			 * @private
			 */
			updateDatasets: function() {
				var me = this;

				if (core_plugins.notify(me, 'beforeDatasetsUpdate') === false) {
					return;
				}

				for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
					me.updateDataset(i);
				}

				core_plugins.notify(me, 'afterDatasetsUpdate');
			},

			/**
			 * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
			 * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
			 * @private
			 */
			updateDataset: function(index) {
				var me = this;
				var meta = me.getDatasetMeta(index);
				var args = {
					meta: meta,
					index: index
				};

				if (core_plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
					return;
				}

				meta.controller.update();

				core_plugins.notify(me, 'afterDatasetUpdate', [args]);
			},

			render: function(config) {
				var me = this;

				if (!config || typeof config !== 'object') {
					// backwards compatibility
					config = {
						duration: config,
						lazy: arguments[1]
					};
				}

				var duration = config.duration;
				var lazy = config.lazy;

				if (core_plugins.notify(me, 'beforeRender') === false) {
					return;
				}

				var animationOptions = me.options.animation;
				var onComplete = function(animation) {
					core_plugins.notify(me, 'afterRender');
					helpers$1.callback(animationOptions && animationOptions.onComplete, [animation], me);
				};

				if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
					var animation = new Chart.Animation({
						numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
						easing: config.easing || animationOptions.easing,

						render: function(chart, animationObject) {
							var easingFunction = helpers$1.easing.effects[animationObject.easing];
							var currentStep = animationObject.currentStep;
							var stepDecimal = currentStep / animationObject.numSteps;

							chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
						},

						onAnimationProgress: animationOptions.onProgress,
						onAnimationComplete: onComplete
					});

					Chart.animationService.addAnimation(me, animation, duration, lazy);
				} else {
					me.draw();

					// See https://github.com/chartjs/Chart.js/issues/3781
					onComplete(new Chart.Animation({numSteps: 0, chart: me}));
				}

				return me;
			},

			draw: function(easingValue) {
				var me = this;

				me.clear();

				if (helpers$1.isNullOrUndef(easingValue)) {
					easingValue = 1;
				}

				me.transition(easingValue);

				if (core_plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
					return;
				}

				// Draw all the scales
				helpers$1.each(me.boxes, function(box) {
					box.draw(me.chartArea);
				}, me);

				if (me.scale) {
					me.scale.draw();
				}

				me.drawDatasets(easingValue);
				me._drawTooltip(easingValue);

				core_plugins.notify(me, 'afterDraw', [easingValue]);
			},

			/**
			 * @private
			 */
			transition: function(easingValue) {
				var me = this;

				for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
					if (me.isDatasetVisible(i)) {
						me.getDatasetMeta(i).controller.transition(easingValue);
					}
				}

				me.tooltip.transition(easingValue);
			},

			/**
			 * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
			 * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
			 * @private
			 */
			drawDatasets: function(easingValue) {
				var me = this;

				if (core_plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
					return;
				}

				// Draw datasets reversed to support proper line stacking
				for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) {
					if (me.isDatasetVisible(i)) {
						me.drawDataset(i, easingValue);
					}
				}

				core_plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
			},

			/**
			 * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
			 * hook, in which case, plugins will not be called on `afterDatasetDraw`.
			 * @private
			 */
			drawDataset: function(index, easingValue) {
				var me = this;
				var meta = me.getDatasetMeta(index);
				var args = {
					meta: meta,
					index: index,
					easingValue: easingValue
				};

				if (core_plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
					return;
				}

				meta.controller.draw(easingValue);

				core_plugins.notify(me, 'afterDatasetDraw', [args]);
			},

			/**
			 * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
			 * hook, in which case, plugins will not be called on `afterTooltipDraw`.
			 * @private
			 */
			_drawTooltip: function(easingValue) {
				var me = this;
				var tooltip = me.tooltip;
				var args = {
					tooltip: tooltip,
					easingValue: easingValue
				};

				if (core_plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
					return;
				}

				tooltip.draw();

				core_plugins.notify(me, 'afterTooltipDraw', [args]);
			},

			// Get the single element that was clicked on
			// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
			getElementAtEvent: function(e) {
				return core_interaction.modes.single(this, e);
			},

			getElementsAtEvent: function(e) {
				return core_interaction.modes.label(this, e, {intersect: true});
			},

			getElementsAtXAxis: function(e) {
				return core_interaction.modes['x-axis'](this, e, {intersect: true});
			},

			getElementsAtEventForMode: function(e, mode, options) {
				var method = core_interaction.modes[mode];
				if (typeof method === 'function') {
					return method(this, e, options);
				}

				return [];
			},

			getDatasetAtEvent: function(e) {
				return core_interaction.modes.dataset(this, e, {intersect: true});
			},

			getDatasetMeta: function(datasetIndex) {
				var me = this;
				var dataset = me.data.datasets[datasetIndex];
				if (!dataset._meta) {
					dataset._meta = {};
				}

				var meta = dataset._meta[me.id];
				if (!meta) {
					meta = dataset._meta[me.id] = {
						type: null,
						data: [],
						dataset: null,
						controller: null,
						hidden: null,			// See isDatasetVisible() comment
						xAxisID: null,
						yAxisID: null
					};
				}

				return meta;
			},

			getVisibleDatasetCount: function() {
				var count = 0;
				for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
					if (this.isDatasetVisible(i)) {
						count++;
					}
				}
				return count;
			},

			isDatasetVisible: function(datasetIndex) {
				var meta = this.getDatasetMeta(datasetIndex);

				// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
				// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
				return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
			},

			generateLegend: function() {
				return this.options.legendCallback(this);
			},

			/**
			 * @private
			 */
			destroyDatasetMeta: function(datasetIndex) {
				var id = this.id;
				var dataset = this.data.datasets[datasetIndex];
				var meta = dataset._meta && dataset._meta[id];

				if (meta) {
					meta.controller.destroy();
					delete dataset._meta[id];
				}
			},

			destroy: function() {
				var me = this;
				var canvas = me.canvas;
				var i, ilen;

				me.stop();

				// dataset controllers need to cleanup associated data
				for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
					me.destroyDatasetMeta(i);
				}

				if (canvas) {
					me.unbindEvents();
					helpers$1.canvas.clear(me);
					platform.releaseContext(me.ctx);
					me.canvas = null;
					me.ctx = null;
				}

				core_plugins.notify(me, 'destroy');

				delete Chart.instances[me.id];
			},

			toBase64Image: function() {
				return this.canvas.toDataURL.apply(this.canvas, arguments);
			},

			initToolTip: function() {
				var me = this;
				me.tooltip = new Chart.Tooltip({
					_chart: me,
					_chartInstance: me, // deprecated, backward compatibility
					_data: me.data,
					_options: me.options.tooltips
				}, me);
			},

			/**
			 * @private
			 */
			bindEvents: function() {
				var me = this;
				var listeners = me._listeners = {};
				var listener = function() {
					me.eventHandler.apply(me, arguments);
				};

				helpers$1.each(me.options.events, function(type) {
					platform.addEventListener(me, type, listener);
					listeners[type] = listener;
				});

				// Elements used to detect size change should not be injected for non responsive charts.
				// See https://github.com/chartjs/Chart.js/issues/2210
				if (me.options.responsive) {
					listener = function() {
						me.resize();
					};

					platform.addEventListener(me, 'resize', listener);
					listeners.resize = listener;
				}
			},

			/**
			 * @private
			 */
			unbindEvents: function() {
				var me = this;
				var listeners = me._listeners;
				if (!listeners) {
					return;
				}

				delete me._listeners;
				helpers$1.each(listeners, function(listener, type) {
					platform.removeEventListener(me, type, listener);
				});
			},

			updateHoverStyle: function(elements, mode, enabled) {
				var method = enabled ? 'setHoverStyle' : 'removeHoverStyle';
				var element, i, ilen;

				for (i = 0, ilen = elements.length; i < ilen; ++i) {
					element = elements[i];
					if (element) {
						this.getDatasetMeta(element._datasetIndex).controller[method](element);
					}
				}
			},

			/**
			 * @private
			 */
			eventHandler: function(e) {
				var me = this;
				var tooltip = me.tooltip;

				if (core_plugins.notify(me, 'beforeEvent', [e]) === false) {
					return;
				}

				// Buffer any update calls so that renders do not occur
				me._bufferedRender = true;
				me._bufferedRequest = null;

				var changed = me.handleEvent(e);
				// for smooth tooltip animations issue #4989
				// the tooltip should be the source of change
				// Animation check workaround:
				// tooltip._start will be null when tooltip isn't animating
				if (tooltip) {
					changed = tooltip._start
						? tooltip.handleEvent(e)
						: changed | tooltip.handleEvent(e);
				}

				core_plugins.notify(me, 'afterEvent', [e]);

				var bufferedRequest = me._bufferedRequest;
				if (bufferedRequest) {
					// If we have an update that was triggered, we need to do a normal render
					me.render(bufferedRequest);
				} else if (changed && !me.animating) {
					// If entering, leaving, or changing elements, animate the change via pivot
					me.stop();

					// We only need to render at this point. Updating will cause scales to be
					// recomputed generating flicker & using more memory than necessary.
					me.render(me.options.hover.animationDuration, true);
				}

				me._bufferedRender = false;
				me._bufferedRequest = null;

				return me;
			},

			/**
			 * Handle an event
			 * @private
			 * @param {IEvent} event the event to handle
			 * @return {Boolean} true if the chart needs to re-render
			 */
			handleEvent: function(e) {
				var me = this;
				var options = me.options || {};
				var hoverOptions = options.hover;
				var changed = false;

				me.lastActive = me.lastActive || [];

				// Find Active Elements for hover and tooltips
				if (e.type === 'mouseout') {
					me.active = [];
				} else {
					me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
				}

				// Invoke onHover hook
				// Need to call with native event here to not break backwards compatibility
				helpers$1.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);

				if (e.type === 'mouseup' || e.type === 'click') {
					if (options.onClick) {
						// Use e.native here for backwards compatibility
						options.onClick.call(me, e.native, me.active);
					}
				}

				// Remove styling for last active (even if it may still be active)
				if (me.lastActive.length) {
					me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
				}

				// Built in hover styling
				if (me.active.length && hoverOptions.mode) {
					me.updateHoverStyle(me.active, hoverOptions.mode, true);
				}

				changed = !helpers$1.arrayEquals(me.active, me.lastActive);

				// Remember Last Actives
				me.lastActive = me.active;

				return changed;
			}
		});

		/**
		 * Provided for backward compatibility, use Chart instead.
		 * @class Chart.Controller
		 * @deprecated since version 2.6.0
		 * @todo remove at version 3
		 * @private
		 */
		Chart.Controller = Chart;
	};

	var core_datasetController = function(Chart) {

		var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];

		/**
		 * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
		 * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
		 * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
		 */
		function listenArrayEvents(array, listener) {
			if (array._chartjs) {
				array._chartjs.listeners.push(listener);
				return;
			}

			Object.defineProperty(array, '_chartjs', {
				configurable: true,
				enumerable: false,
				value: {
					listeners: [listener]
				}
			});

			arrayEvents.forEach(function(key) {
				var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
				var base = array[key];

				Object.defineProperty(array, key, {
					configurable: true,
					enumerable: false,
					value: function() {
						var args = Array.prototype.slice.call(arguments);
						var res = base.apply(this, args);

						helpers$1.each(array._chartjs.listeners, function(object) {
							if (typeof object[method] === 'function') {
								object[method].apply(object, args);
							}
						});

						return res;
					}
				});
			});
		}

		/**
		 * Removes the given array event listener and cleanup extra attached properties (such as
		 * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
		 */
		function unlistenArrayEvents(array, listener) {
			var stub = array._chartjs;
			if (!stub) {
				return;
			}

			var listeners = stub.listeners;
			var index = listeners.indexOf(listener);
			if (index !== -1) {
				listeners.splice(index, 1);
			}

			if (listeners.length > 0) {
				return;
			}

			arrayEvents.forEach(function(key) {
				delete array[key];
			});

			delete array._chartjs;
		}

		// Base class for all dataset controllers (line, bar, etc)
		Chart.DatasetController = function(chart, datasetIndex) {
			this.initialize(chart, datasetIndex);
		};

		helpers$1.extend(Chart.DatasetController.prototype, {

			/**
			 * Element type used to generate a meta dataset (e.g. Chart.element.Line).
			 * @type {Chart.core.element}
			 */
			datasetElementType: null,

			/**
			 * Element type used to generate a meta data (e.g. Chart.element.Point).
			 * @type {Chart.core.element}
			 */
			dataElementType: null,

			initialize: function(chart, datasetIndex) {
				var me = this;
				me.chart = chart;
				me.index = datasetIndex;
				me.linkScales();
				me.addElements();
			},

			updateIndex: function(datasetIndex) {
				this.index = datasetIndex;
			},

			linkScales: function() {
				var me = this;
				var meta = me.getMeta();
				var dataset = me.getDataset();

				if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) {
					meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
				}
				if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
					meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
				}
			},

			getDataset: function() {
				return this.chart.data.datasets[this.index];
			},

			getMeta: function() {
				return this.chart.getDatasetMeta(this.index);
			},

			getScaleForId: function(scaleID) {
				return this.chart.scales[scaleID];
			},

			reset: function() {
				this.update(true);
			},

			/**
			 * @private
			 */
			destroy: function() {
				if (this._data) {
					unlistenArrayEvents(this._data, this);
				}
			},

			createMetaDataset: function() {
				var me = this;
				var type = me.datasetElementType;
				return type && new type({
					_chart: me.chart,
					_datasetIndex: me.index
				});
			},

			createMetaData: function(index) {
				var me = this;
				var type = me.dataElementType;
				return type && new type({
					_chart: me.chart,
					_datasetIndex: me.index,
					_index: index
				});
			},

			addElements: function() {
				var me = this;
				var meta = me.getMeta();
				var data = me.getDataset().data || [];
				var metaData = meta.data;
				var i, ilen;

				for (i = 0, ilen = data.length; i < ilen; ++i) {
					metaData[i] = metaData[i] || me.createMetaData(i);
				}

				meta.dataset = meta.dataset || me.createMetaDataset();
			},

			addElementAndReset: function(index) {
				var element = this.createMetaData(index);
				this.getMeta().data.splice(index, 0, element);
				this.updateElement(element, index, true);
			},

			buildOrUpdateElements: function() {
				var me = this;
				var dataset = me.getDataset();
				var data = dataset.data || (dataset.data = []);

				// In order to correctly handle data addition/deletion animation (an thus simulate
				// real-time charts), we need to monitor these data modifications and synchronize
				// the internal meta data accordingly.
				if (me._data !== data) {
					if (me._data) {
						// This case happens when the user replaced the data array instance.
						unlistenArrayEvents(me._data, me);
					}

					listenArrayEvents(data, me);
					me._data = data;
				}

				// Re-sync meta data in case the user replaced the data array or if we missed
				// any updates and so make sure that we handle number of datapoints changing.
				me.resyncElements();
			},

			update: helpers$1.noop,

			transition: function(easingValue) {
				var meta = this.getMeta();
				var elements = meta.data || [];
				var ilen = elements.length;
				var i = 0;

				for (; i < ilen; ++i) {
					elements[i].transition(easingValue);
				}

				if (meta.dataset) {
					meta.dataset.transition(easingValue);
				}
			},

			draw: function() {
				var meta = this.getMeta();
				var elements = meta.data || [];
				var ilen = elements.length;
				var i = 0;

				if (meta.dataset) {
					meta.dataset.draw();
				}

				for (; i < ilen; ++i) {
					elements[i].draw();
				}
			},

			removeHoverStyle: function(element, elementOpts) {
				var dataset = this.chart.data.datasets[element._datasetIndex];
				var index = element._index;
				var custom = element.custom || {};
				var valueOrDefault = helpers$1.valueAtIndexOrDefault;
				var model = element._model;

				model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
				model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
				model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
			},

			setHoverStyle: function(element) {
				var dataset = this.chart.data.datasets[element._datasetIndex];
				var index = element._index;
				var custom = element.custom || {};
				var valueOrDefault = helpers$1.valueAtIndexOrDefault;
				var getHoverColor = helpers$1.getHoverColor;
				var model = element._model;

				model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
				model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
				model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
			},

			/**
			 * @private
			 */
			resyncElements: function() {
				var me = this;
				var meta = me.getMeta();
				var data = me.getDataset().data;
				var numMeta = meta.data.length;
				var numData = data.length;

				if (numData < numMeta) {
					meta.data.splice(numData, numMeta - numData);
				} else if (numData > numMeta) {
					me.insertElements(numMeta, numData - numMeta);
				}
			},

			/**
			 * @private
			 */
			insertElements: function(start, count) {
				for (var i = 0; i < count; ++i) {
					this.addElementAndReset(start + i);
				}
			},

			/**
			 * @private
			 */
			onDataPush: function() {
				this.insertElements(this.getDataset().data.length - 1, arguments.length);
			},

			/**
			 * @private
			 */
			onDataPop: function() {
				this.getMeta().data.pop();
			},

			/**
			 * @private
			 */
			onDataShift: function() {
				this.getMeta().data.shift();
			},

			/**
			 * @private
			 */
			onDataSplice: function(start, count) {
				this.getMeta().data.splice(start, count);
				this.insertElements(start, arguments.length - 2);
			},

			/**
			 * @private
			 */
			onDataUnshift: function() {
				this.insertElements(0, arguments.length);
			}
		});

		Chart.DatasetController.extend = helpers$1.inherits;
	};

	var core_scaleService = function(Chart) {

		Chart.scaleService = {
			// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
			// use the new chart options to grab the correct scale
			constructors: {},
			// Use a registration function so that we can move to an ES6 map when we no longer need to support
			// old browsers

			// Scale config defaults
			defaults: {},
			registerScaleType: function(type, scaleConstructor, scaleDefaults) {
				this.constructors[type] = scaleConstructor;
				this.defaults[type] = helpers$1.clone(scaleDefaults);
			},
			getScaleConstructor: function(type) {
				return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
			},
			getScaleDefaults: function(type) {
				// Return the scale defaults merged with the global settings so that we always use the latest ones
				return this.defaults.hasOwnProperty(type) ? helpers$1.merge({}, [core_defaults.scale, this.defaults[type]]) : {};
			},
			updateScaleDefaults: function(type, additions) {
				var me = this;
				if (me.defaults.hasOwnProperty(type)) {
					me.defaults[type] = helpers$1.extend(me.defaults[type], additions);
				}
			},
			addScalesToLayout: function(chart) {
				// Adds each scale to the chart.boxes array to be sized accordingly
				helpers$1.each(chart.scales, function(scale) {
					// Set ILayoutItem parameters for backwards compatibility
					scale.fullWidth = scale.options.fullWidth;
					scale.position = scale.options.position;
					scale.weight = scale.options.weight;
					core_layouts.addBox(chart, scale);
				});
			}
		};
	};

	core_defaults._set('scale', {
		display: true,
		position: 'left',
		offset: false,

		// grid line settings
		gridLines: {
			display: true,
			color: 'rgba(0, 0, 0, 0.1)',
			lineWidth: 1,
			drawBorder: true,
			drawOnChartArea: true,
			drawTicks: true,
			tickMarkLength: 10,
			zeroLineWidth: 1,
			zeroLineColor: 'rgba(0,0,0,0.25)',
			zeroLineBorderDash: [],
			zeroLineBorderDashOffset: 0.0,
			offsetGridLines: false,
			borderDash: [],
			borderDashOffset: 0.0
		},

		// scale label
		scaleLabel: {
			// display property
			display: false,

			// actual label
			labelString: '',

			// line height
			lineHeight: 1.2,

			// top/bottom padding
			padding: {
				top: 4,
				bottom: 4
			}
		},

		// label settings
		ticks: {
			beginAtZero: false,
			minRotation: 0,
			maxRotation: 50,
			mirror: false,
			padding: 0,
			reverse: false,
			display: true,
			autoSkip: true,
			autoSkipPadding: 0,
			labelOffset: 0,
			// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
			callback: core_ticks.formatters.values,
			minor: {},
			major: {}
		}
	});

	function labelsFromTicks(ticks) {
		var labels = [];
		var i, ilen;

		for (i = 0, ilen = ticks.length; i < ilen; ++i) {
			labels.push(ticks[i].label);
		}

		return labels;
	}

	function getLineValue(scale, index, offsetGridLines) {
		var lineValue = scale.getPixelForTick(index);

		if (offsetGridLines) {
			if (index === 0) {
				lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
			} else {
				lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2;
			}
		}
		return lineValue;
	}

	var core_scale = function(Chart) {

		function computeTextSize(context, tick, font) {
			return helpers$1.isArray(tick) ?
				helpers$1.longestText(context, font, tick) :
				context.measureText(tick).width;
		}

		function parseFontOptions(options) {
			var valueOrDefault = helpers$1.valueOrDefault;
			var globalDefaults = core_defaults.global;
			var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
			var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
			var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);

			return {
				size: size,
				style: style,
				family: family,
				font: helpers$1.fontString(size, style, family)
			};
		}

		function parseLineHeight(options) {
			return helpers$1.options.toLineHeight(
				helpers$1.valueOrDefault(options.lineHeight, 1.2),
				helpers$1.valueOrDefault(options.fontSize, core_defaults.global.defaultFontSize));
		}

		Chart.Scale = core_element.extend({
			/**
			 * Get the padding needed for the scale
			 * @method getPadding
			 * @private
			 * @returns {Padding} the necessary padding
			 */
			getPadding: function() {
				var me = this;
				return {
					left: me.paddingLeft || 0,
					top: me.paddingTop || 0,
					right: me.paddingRight || 0,
					bottom: me.paddingBottom || 0
				};
			},

			/**
			 * Returns the scale tick objects ({label, major})
			 * @since 2.7
			 */
			getTicks: function() {
				return this._ticks;
			},

			// These methods are ordered by lifecyle. Utilities then follow.
			// Any function defined here is inherited by all scale types.
			// Any function can be extended by the scale type

			mergeTicksOptions: function() {
				var ticks = this.options.ticks;
				if (ticks.minor === false) {
					ticks.minor = {
						display: false
					};
				}
				if (ticks.major === false) {
					ticks.major = {
						display: false
					};
				}
				for (var key in ticks) {
					if (key !== 'major' && key !== 'minor') {
						if (typeof ticks.minor[key] === 'undefined') {
							ticks.minor[key] = ticks[key];
						}
						if (typeof ticks.major[key] === 'undefined') {
							ticks.major[key] = ticks[key];
						}
					}
				}
			},
			beforeUpdate: function() {
				helpers$1.callback(this.options.beforeUpdate, [this]);
			},
			update: function(maxWidth, maxHeight, margins) {
				var me = this;
				var i, ilen, labels, label, ticks, tick;

				// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
				me.beforeUpdate();

				// Absorb the master measurements
				me.maxWidth = maxWidth;
				me.maxHeight = maxHeight;
				me.margins = helpers$1.extend({
					left: 0,
					right: 0,
					top: 0,
					bottom: 0
				}, margins);
				me.longestTextCache = me.longestTextCache || {};

				// Dimensions
				me.beforeSetDimensions();
				me.setDimensions();
				me.afterSetDimensions();

				// Data min/max
				me.beforeDataLimits();
				me.determineDataLimits();
				me.afterDataLimits();

				// Ticks - `this.ticks` is now DEPRECATED!
				// Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
				// and must not be accessed directly from outside this class. `this.ticks` being
				// around for long time and not marked as private, we can't change its structure
				// without unexpected breaking changes. If you need to access the scale ticks,
				// use scale.getTicks() instead.

				me.beforeBuildTicks();

				// New implementations should return an array of objects but for BACKWARD COMPAT,
				// we still support no return (`this.ticks` internally set by calling this method).
				ticks = me.buildTicks() || [];

				me.afterBuildTicks();

				me.beforeTickToLabelConversion();

				// New implementations should return the formatted tick labels but for BACKWARD
				// COMPAT, we still support no return (`this.ticks` internally changed by calling
				// this method and supposed to contain only string values).
				labels = me.convertTicksToLabels(ticks) || me.ticks;

				me.afterTickToLabelConversion();

				me.ticks = labels;   // BACKWARD COMPATIBILITY

				// IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!

				// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
				for (i = 0, ilen = labels.length; i < ilen; ++i) {
					label = labels[i];
					tick = ticks[i];
					if (!tick) {
						ticks.push(tick = {
							label: label,
							major: false
						});
					} else {
						tick.label = label;
					}
				}

				me._ticks = ticks;

				// Tick Rotation
				me.beforeCalculateTickRotation();
				me.calculateTickRotation();
				me.afterCalculateTickRotation();
				// Fit
				me.beforeFit();
				me.fit();
				me.afterFit();
				//
				me.afterUpdate();

				return me.minSize;

			},
			afterUpdate: function() {
				helpers$1.callback(this.options.afterUpdate, [this]);
			},

			//

			beforeSetDimensions: function() {
				helpers$1.callback(this.options.beforeSetDimensions, [this]);
			},
			setDimensions: function() {
				var me = this;
				// Set the unconstrained dimension before label rotation
				if (me.isHorizontal()) {
					// Reset position before calculating rotation
					me.width = me.maxWidth;
					me.left = 0;
					me.right = me.width;
				} else {
					me.height = me.maxHeight;

					// Reset position before calculating rotation
					me.top = 0;
					me.bottom = me.height;
				}

				// Reset padding
				me.paddingLeft = 0;
				me.paddingTop = 0;
				me.paddingRight = 0;
				me.paddingBottom = 0;
			},
			afterSetDimensions: function() {
				helpers$1.callback(this.options.afterSetDimensions, [this]);
			},

			// Data limits
			beforeDataLimits: function() {
				helpers$1.callback(this.options.beforeDataLimits, [this]);
			},
			determineDataLimits: helpers$1.noop,
			afterDataLimits: function() {
				helpers$1.callback(this.options.afterDataLimits, [this]);
			},

			//
			beforeBuildTicks: function() {
				helpers$1.callback(this.options.beforeBuildTicks, [this]);
			},
			buildTicks: helpers$1.noop,
			afterBuildTicks: function() {
				helpers$1.callback(this.options.afterBuildTicks, [this]);
			},

			beforeTickToLabelConversion: function() {
				helpers$1.callback(this.options.beforeTickToLabelConversion, [this]);
			},
			convertTicksToLabels: function() {
				var me = this;
				// Convert ticks to strings
				var tickOpts = me.options.ticks;
				me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
			},
			afterTickToLabelConversion: function() {
				helpers$1.callback(this.options.afterTickToLabelConversion, [this]);
			},

			//

			beforeCalculateTickRotation: function() {
				helpers$1.callback(this.options.beforeCalculateTickRotation, [this]);
			},
			calculateTickRotation: function() {
				var me = this;
				var context = me.ctx;
				var tickOpts = me.options.ticks;
				var labels = labelsFromTicks(me._ticks);

				// Get the width of each grid by calculating the difference
				// between x offsets between 0 and 1.
				var tickFont = parseFontOptions(tickOpts);
				context.font = tickFont.font;

				var labelRotation = tickOpts.minRotation || 0;

				if (labels.length && me.options.display && me.isHorizontal()) {
					var originalLabelWidth = helpers$1.longestText(context, tickFont.font, labels, me.longestTextCache);
					var labelWidth = originalLabelWidth;
					var cosRotation, sinRotation;

					// Allow 3 pixels x2 padding either side for label readability
					var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;

					// Max label rotation can be set or default to 90 - also act as a loop counter
					while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
						var angleRadians = helpers$1.toRadians(labelRotation);
						cosRotation = Math.cos(angleRadians);
						sinRotation = Math.sin(angleRadians);

						if (sinRotation * originalLabelWidth > me.maxHeight) {
							// go back one step
							labelRotation--;
							break;
						}

						labelRotation++;
						labelWidth = cosRotation * originalLabelWidth;
					}
				}

				me.labelRotation = labelRotation;
			},
			afterCalculateTickRotation: function() {
				helpers$1.callback(this.options.afterCalculateTickRotation, [this]);
			},

			//

			beforeFit: function() {
				helpers$1.callback(this.options.beforeFit, [this]);
			},
			fit: function() {
				var me = this;
				// Reset
				var minSize = me.minSize = {
					width: 0,
					height: 0
				};

				var labels = labelsFromTicks(me._ticks);

				var opts = me.options;
				var tickOpts = opts.ticks;
				var scaleLabelOpts = opts.scaleLabel;
				var gridLineOpts = opts.gridLines;
				var display = opts.display;
				var isHorizontal = me.isHorizontal();

				var tickFont = parseFontOptions(tickOpts);
				var tickMarkLength = opts.gridLines.tickMarkLength;

				// Width
				if (isHorizontal) {
					// subtract the margins to line up with the chartArea if we are a full width scale
					minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
				} else {
					minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
				}

				// height
				if (isHorizontal) {
					minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
				} else {
					minSize.height = me.maxHeight; // fill all the height
				}

				// Are we showing a title for the scale?
				if (scaleLabelOpts.display && display) {
					var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
					var scaleLabelPadding = helpers$1.options.toPadding(scaleLabelOpts.padding);
					var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;

					if (isHorizontal) {
						minSize.height += deltaHeight;
					} else {
						minSize.width += deltaHeight;
					}
				}

				// Don't bother fitting the ticks if we are not showing them
				if (tickOpts.display && display) {
					var largestTextWidth = helpers$1.longestText(me.ctx, tickFont.font, labels, me.longestTextCache);
					var tallestLabelHeightInLines = helpers$1.numberOfLabelLines(labels);
					var lineSpace = tickFont.size * 0.5;
					var tickPadding = me.options.ticks.padding;

					if (isHorizontal) {
						// A horizontal axis is more constrained by the height.
						me.longestLabelWidth = largestTextWidth;

						var angleRadians = helpers$1.toRadians(me.labelRotation);
						var cosRotation = Math.cos(angleRadians);
						var sinRotation = Math.sin(angleRadians);

						// TODO - improve this calculation
						var labelHeight = (sinRotation * largestTextWidth)
							+ (tickFont.size * tallestLabelHeightInLines)
							+ (lineSpace * (tallestLabelHeightInLines - 1))
							+ lineSpace; // padding

						minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);

						me.ctx.font = tickFont.font;
						var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font);
						var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font);

						// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
						// which means that the right padding is dominated by the font height
						if (me.labelRotation !== 0) {
							me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
							me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3;
						} else {
							me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
							me.paddingRight = lastLabelWidth / 2 + 3;
						}
					} else {
						// A vertical axis is more constrained by the width. Labels are the
						// dominant factor here, so get that length first and account for padding
						if (tickOpts.mirror) {
							largestTextWidth = 0;
						} else {
							// use lineSpace for consistency with horizontal axis
							// tickPadding is not implemented for horizontal
							largestTextWidth += tickPadding + lineSpace;
						}

						minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);

						me.paddingTop = tickFont.size / 2;
						me.paddingBottom = tickFont.size / 2;
					}
				}

				me.handleMargins();

				me.width = minSize.width;
				me.height = minSize.height;
			},

			/**
			 * Handle margins and padding interactions
			 * @private
			 */
			handleMargins: function() {
				var me = this;
				if (me.margins) {
					me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
					me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
					me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
					me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
				}
			},

			afterFit: function() {
				helpers$1.callback(this.options.afterFit, [this]);
			},

			// Shared Methods
			isHorizontal: function() {
				return this.options.position === 'top' || this.options.position === 'bottom';
			},
			isFullWidth: function() {
				return (this.options.fullWidth);
			},

			// Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
			getRightValue: function(rawValue) {
				// Null and undefined values first
				if (helpers$1.isNullOrUndef(rawValue)) {
					return NaN;
				}
				// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
				if (typeof rawValue === 'number' && !isFinite(rawValue)) {
					return NaN;
				}
				// If it is in fact an object, dive in one more level
				if (rawValue) {
					if (this.isHorizontal()) {
						if (rawValue.x !== undefined) {
							return this.getRightValue(rawValue.x);
						}
					} else if (rawValue.y !== undefined) {
						return this.getRightValue(rawValue.y);
					}
				}

				// Value is good, return it
				return rawValue;
			},

			/**
			 * Used to get the value to display in the tooltip for the data at the given index
			 * @param index
			 * @param datasetIndex
			 */
			getLabelForIndex: helpers$1.noop,

			/**
			 * Returns the location of the given data point. Value can either be an index or a numerical value
			 * The coordinate (0, 0) is at the upper-left corner of the canvas
			 * @param value
			 * @param index
			 * @param datasetIndex
			 */
			getPixelForValue: helpers$1.noop,

			/**
			 * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
			 * The coordinate (0, 0) is at the upper-left corner of the canvas
			 * @param pixel
			 */
			getValueForPixel: helpers$1.noop,

			/**
			 * Returns the location of the tick at the given index
			 * The coordinate (0, 0) is at the upper-left corner of the canvas
			 */
			getPixelForTick: function(index) {
				var me = this;
				var offset = me.options.offset;
				if (me.isHorizontal()) {
					var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
					var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
					var pixel = (tickWidth * index) + me.paddingLeft;

					if (offset) {
						pixel += tickWidth / 2;
					}

					var finalVal = me.left + Math.round(pixel);
					finalVal += me.isFullWidth() ? me.margins.left : 0;
					return finalVal;
				}
				var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
				return me.top + (index * (innerHeight / (me._ticks.length - 1)));
			},

			/**
			 * Utility for getting the pixel location of a percentage of scale
			 * The coordinate (0, 0) is at the upper-left corner of the canvas
			 */
			getPixelForDecimal: function(decimal) {
				var me = this;
				if (me.isHorizontal()) {
					var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
					var valueOffset = (innerWidth * decimal) + me.paddingLeft;

					var finalVal = me.left + Math.round(valueOffset);
					finalVal += me.isFullWidth() ? me.margins.left : 0;
					return finalVal;
				}
				return me.top + (decimal * me.height);
			},

			/**
			 * Returns the pixel for the minimum chart value
			 * The coordinate (0, 0) is at the upper-left corner of the canvas
			 */
			getBasePixel: function() {
				return this.getPixelForValue(this.getBaseValue());
			},

			getBaseValue: function() {
				var me = this;
				var min = me.min;
				var max = me.max;

				return me.beginAtZero ? 0 :
					min < 0 && max < 0 ? max :
					min > 0 && max > 0 ? min :
					0;
			},

			/**
			 * Returns a subset of ticks to be plotted to avoid overlapping labels.
			 * @private
			 */
			_autoSkip: function(ticks) {
				var skipRatio;
				var me = this;
				var isHorizontal = me.isHorizontal();
				var optionTicks = me.options.ticks.minor;
				var tickCount = ticks.length;
				var labelRotationRadians = helpers$1.toRadians(me.labelRotation);
				var cosRotation = Math.cos(labelRotationRadians);
				var longestRotatedLabel = me.longestLabelWidth * cosRotation;
				var result = [];
				var i, tick, shouldSkip;

				// figure out the maximum number of gridlines to show
				var maxTicks;
				if (optionTicks.maxTicksLimit) {
					maxTicks = optionTicks.maxTicksLimit;
				}

				if (isHorizontal) {
					skipRatio = false;

					if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) {
						skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight)));
					}

					// if they defined a max number of optionTicks,
					// increase skipRatio until that number is met
					if (maxTicks && tickCount > maxTicks) {
						skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks));
					}
				}

				for (i = 0; i < tickCount; i++) {
					tick = ticks[i];

					// Since we always show the last tick,we need may need to hide the last shown one before
					shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
					if (shouldSkip && i !== tickCount - 1) {
						// leave tick in place but make sure it's not displayed (#4635)
						delete tick.label;
					}
					result.push(tick);
				}
				return result;
			},

			// Actually draw the scale on the canvas
			// @param {rectangle} chartArea : the area of the chart to draw full grid lines on
			draw: function(chartArea) {
				var me = this;
				var options = me.options;
				if (!options.display) {
					return;
				}

				var context = me.ctx;
				var globalDefaults = core_defaults.global;
				var optionTicks = options.ticks.minor;
				var optionMajorTicks = options.ticks.major || optionTicks;
				var gridLines = options.gridLines;
				var scaleLabel = options.scaleLabel;

				var isRotated = me.labelRotation !== 0;
				var isHorizontal = me.isHorizontal();

				var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
				var tickFontColor = helpers$1.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
				var tickFont = parseFontOptions(optionTicks);
				var majorTickFontColor = helpers$1.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
				var majorTickFont = parseFontOptions(optionMajorTicks);

				var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;

				var scaleLabelFontColor = helpers$1.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
				var scaleLabelFont = parseFontOptions(scaleLabel);
				var scaleLabelPadding = helpers$1.options.toPadding(scaleLabel.padding);
				var labelRotationRadians = helpers$1.toRadians(me.labelRotation);

				var itemsToDraw = [];

				var axisWidth = me.options.gridLines.lineWidth;
				var xTickStart = options.position === 'right' ? me.right : me.right - axisWidth - tl;
				var xTickEnd = options.position === 'right' ? me.right + tl : me.right;
				var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth;
				var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth;

				helpers$1.each(ticks, function(tick, index) {
					// autoskipper skipped this tick (#4635)
					if (helpers$1.isNullOrUndef(tick.label)) {
						return;
					}

					var label = tick.label;
					var lineWidth, lineColor, borderDash, borderDashOffset;
					if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
						// Draw the first index specially
						lineWidth = gridLines.zeroLineWidth;
						lineColor = gridLines.zeroLineColor;
						borderDash = gridLines.zeroLineBorderDash;
						borderDashOffset = gridLines.zeroLineBorderDashOffset;
					} else {
						lineWidth = helpers$1.valueAtIndexOrDefault(gridLines.lineWidth, index);
						lineColor = helpers$1.valueAtIndexOrDefault(gridLines.color, index);
						borderDash = helpers$1.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
						borderDashOffset = helpers$1.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
					}

					// Common properties
					var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
					var textAlign = 'middle';
					var textBaseline = 'middle';
					var tickPadding = optionTicks.padding;

					if (isHorizontal) {
						var labelYOffset = tl + tickPadding;

						if (options.position === 'bottom') {
							// bottom
							textBaseline = !isRotated ? 'top' : 'middle';
							textAlign = !isRotated ? 'center' : 'right';
							labelY = me.top + labelYOffset;
						} else {
							// top
							textBaseline = !isRotated ? 'bottom' : 'middle';
							textAlign = !isRotated ? 'center' : 'left';
							labelY = me.bottom - labelYOffset;
						}

						var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
						if (xLineValue < me.left) {
							lineColor = 'rgba(0,0,0,0)';
						}
						xLineValue += helpers$1.aliasPixel(lineWidth);

						labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)

						tx1 = tx2 = x1 = x2 = xLineValue;
						ty1 = yTickStart;
						ty2 = yTickEnd;
						y1 = chartArea.top;
						y2 = chartArea.bottom + axisWidth;
					} else {
						var isLeft = options.position === 'left';
						var labelXOffset;

						if (optionTicks.mirror) {
							textAlign = isLeft ? 'left' : 'right';
							labelXOffset = tickPadding;
						} else {
							textAlign = isLeft ? 'right' : 'left';
							labelXOffset = tl + tickPadding;
						}

						labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;

						var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
						if (yLineValue < me.top) {
							lineColor = 'rgba(0,0,0,0)';
						}
						yLineValue += helpers$1.aliasPixel(lineWidth);

						labelY = me.getPixelForTick(index) + optionTicks.labelOffset;

						tx1 = xTickStart;
						tx2 = xTickEnd;
						x1 = chartArea.left;
						x2 = chartArea.right + axisWidth;
						ty1 = ty2 = y1 = y2 = yLineValue;
					}

					itemsToDraw.push({
						tx1: tx1,
						ty1: ty1,
						tx2: tx2,
						ty2: ty2,
						x1: x1,
						y1: y1,
						x2: x2,
						y2: y2,
						labelX: labelX,
						labelY: labelY,
						glWidth: lineWidth,
						glColor: lineColor,
						glBorderDash: borderDash,
						glBorderDashOffset: borderDashOffset,
						rotation: -1 * labelRotationRadians,
						label: label,
						major: tick.major,
						textBaseline: textBaseline,
						textAlign: textAlign
					});
				});

				// Draw all of the tick labels, tick marks, and grid lines at the correct places
				helpers$1.each(itemsToDraw, function(itemToDraw) {
					if (gridLines.display) {
						context.save();
						context.lineWidth = itemToDraw.glWidth;
						context.strokeStyle = itemToDraw.glColor;
						if (context.setLineDash) {
							context.setLineDash(itemToDraw.glBorderDash);
							context.lineDashOffset = itemToDraw.glBorderDashOffset;
						}

						context.beginPath();

						if (gridLines.drawTicks) {
							context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
							context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
						}

						if (gridLines.drawOnChartArea) {
							context.moveTo(itemToDraw.x1, itemToDraw.y1);
							context.lineTo(itemToDraw.x2, itemToDraw.y2);
						}

						context.stroke();
						context.restore();
					}

					if (optionTicks.display) {
						// Make sure we draw text in the correct color and font
						context.save();
						context.translate(itemToDraw.labelX, itemToDraw.labelY);
						context.rotate(itemToDraw.rotation);
						context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
						context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
						context.textBaseline = itemToDraw.textBaseline;
						context.textAlign = itemToDraw.textAlign;

						var label = itemToDraw.label;
						if (helpers$1.isArray(label)) {
							var lineCount = label.length;
							var lineHeight = tickFont.size * 1.5;
							var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2;

							for (var i = 0; i < lineCount; ++i) {
								// We just make sure the multiline element is a string here..
								context.fillText('' + label[i], 0, y);
								// apply same lineSpacing as calculated @ L#320
								y += lineHeight;
							}
						} else {
							context.fillText(label, 0, 0);
						}
						context.restore();
					}
				});

				if (scaleLabel.display) {
					// Draw the scale label
					var scaleLabelX;
					var scaleLabelY;
					var rotation = 0;
					var halfLineHeight = parseLineHeight(scaleLabel) / 2;

					if (isHorizontal) {
						scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
						scaleLabelY = options.position === 'bottom'
							? me.bottom - halfLineHeight - scaleLabelPadding.bottom
							: me.top + halfLineHeight + scaleLabelPadding.top;
					} else {
						var isLeft = options.position === 'left';
						scaleLabelX = isLeft
							? me.left + halfLineHeight + scaleLabelPadding.top
							: me.right - halfLineHeight - scaleLabelPadding.top;
						scaleLabelY = me.top + ((me.bottom - me.top) / 2);
						rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
					}

					context.save();
					context.translate(scaleLabelX, scaleLabelY);
					context.rotate(rotation);
					context.textAlign = 'center';
					context.textBaseline = 'middle';
					context.fillStyle = scaleLabelFontColor; // render in correct colour
					context.font = scaleLabelFont.font;
					context.fillText(scaleLabel.labelString, 0, 0);
					context.restore();
				}

				if (gridLines.drawBorder) {
					// Draw the line at the edge of the axis
					context.lineWidth = helpers$1.valueAtIndexOrDefault(gridLines.lineWidth, 0);
					context.strokeStyle = helpers$1.valueAtIndexOrDefault(gridLines.color, 0);
					var x1 = me.left;
					var x2 = me.right + axisWidth;
					var y1 = me.top;
					var y2 = me.bottom + axisWidth;

					var aliasPixel = helpers$1.aliasPixel(context.lineWidth);
					if (isHorizontal) {
						y1 = y2 = options.position === 'top' ? me.bottom : me.top;
						y1 += aliasPixel;
						y2 += aliasPixel;
					} else {
						x1 = x2 = options.position === 'left' ? me.right : me.left;
						x1 += aliasPixel;
						x2 += aliasPixel;
					}

					context.beginPath();
					context.moveTo(x1, y1);
					context.lineTo(x2, y2);
					context.stroke();
				}
			}
		});
	};

	core_defaults._set('global', {
		tooltips: {
			enabled: true,
			custom: null,
			mode: 'nearest',
			position: 'average',
			intersect: true,
			backgroundColor: 'rgba(0,0,0,0.8)',
			titleFontStyle: 'bold',
			titleSpacing: 2,
			titleMarginBottom: 6,
			titleFontColor: '#fff',
			titleAlign: 'left',
			bodySpacing: 2,
			bodyFontColor: '#fff',
			bodyAlign: 'left',
			footerFontStyle: 'bold',
			footerSpacing: 2,
			footerMarginTop: 6,
			footerFontColor: '#fff',
			footerAlign: 'left',
			yPadding: 6,
			xPadding: 6,
			caretPadding: 2,
			caretSize: 5,
			cornerRadius: 6,
			multiKeyBackground: '#fff',
			displayColors: true,
			borderColor: 'rgba(0,0,0,0)',
			borderWidth: 0,
			callbacks: {
				// Args are: (tooltipItems, data)
				beforeTitle: helpers$1.noop,
				title: function(tooltipItems, data) {
					// Pick first xLabel for now
					var title = '';
					var labels = data.labels;
					var labelCount = labels ? labels.length : 0;

					if (tooltipItems.length > 0) {
						var item = tooltipItems[0];

						if (item.xLabel) {
							title = item.xLabel;
						} else if (labelCount > 0 && item.index < labelCount) {
							title = labels[item.index];
						}
					}

					return title;
				},
				afterTitle: helpers$1.noop,

				// Args are: (tooltipItems, data)
				beforeBody: helpers$1.noop,

				// Args are: (tooltipItem, data)
				beforeLabel: helpers$1.noop,
				label: function(tooltipItem, data) {
					var label = data.datasets[tooltipItem.datasetIndex].label || '';

					if (label) {
						label += ': ';
					}
					label += tooltipItem.yLabel;
					return label;
				},
				labelColor: function(tooltipItem, chart) {
					var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
					var activeElement = meta.data[tooltipItem.index];
					var view = activeElement._view;
					return {
						borderColor: view.borderColor,
						backgroundColor: view.backgroundColor
					};
				},
				labelTextColor: function() {
					return this._options.bodyFontColor;
				},
				afterLabel: helpers$1.noop,

				// Args are: (tooltipItems, data)
				afterBody: helpers$1.noop,

				// Args are: (tooltipItems, data)
				beforeFooter: helpers$1.noop,
				footer: helpers$1.noop,
				afterFooter: helpers$1.noop
			}
		}
	});

	var core_tooltip = function(Chart) {

		/**
	 	 * Helper method to merge the opacity into a color
	 	 */
		function mergeOpacity(colorString, opacity) {
			var color = helpers$1.color(colorString);
			return color.alpha(opacity * color.alpha()).rgbaString();
		}

		// Helper to push or concat based on if the 2nd parameter is an array or not
		function pushOrConcat(base, toPush) {
			if (toPush) {
				if (helpers$1.isArray(toPush)) {
					// base = base.concat(toPush);
					Array.prototype.push.apply(base, toPush);
				} else {
					base.push(toPush);
				}
			}

			return base;
		}

		// Private helper to create a tooltip item model
		// @param element : the chart element (point, arc, bar) to create the tooltip item for
		// @return : new tooltip item
		function createTooltipItem(element) {
			var xScale = element._xScale;
			var yScale = element._yScale || element._scale; // handle radar || polarArea charts
			var index = element._index;
			var datasetIndex = element._datasetIndex;

			return {
				xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
				yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
				index: index,
				datasetIndex: datasetIndex,
				x: element._model.x,
				y: element._model.y
			};
		}

		/**
		 * Helper to get the reset model for the tooltip
		 * @param tooltipOpts {Object} the tooltip options
		 */
		function getBaseModel(tooltipOpts) {
			var globalDefaults = core_defaults.global;
			var valueOrDefault = helpers$1.valueOrDefault;

			return {
				// Positioning
				xPadding: tooltipOpts.xPadding,
				yPadding: tooltipOpts.yPadding,
				xAlign: tooltipOpts.xAlign,
				yAlign: tooltipOpts.yAlign,

				// Body
				bodyFontColor: tooltipOpts.bodyFontColor,
				_bodyFontFamily: valueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
				_bodyFontStyle: valueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
				_bodyAlign: tooltipOpts.bodyAlign,
				bodyFontSize: valueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
				bodySpacing: tooltipOpts.bodySpacing,

				// Title
				titleFontColor: tooltipOpts.titleFontColor,
				_titleFontFamily: valueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
				_titleFontStyle: valueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
				titleFontSize: valueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
				_titleAlign: tooltipOpts.titleAlign,
				titleSpacing: tooltipOpts.titleSpacing,
				titleMarginBottom: tooltipOpts.titleMarginBottom,

				// Footer
				footerFontColor: tooltipOpts.footerFontColor,
				_footerFontFamily: valueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
				_footerFontStyle: valueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
				footerFontSize: valueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
				_footerAlign: tooltipOpts.footerAlign,
				footerSpacing: tooltipOpts.footerSpacing,
				footerMarginTop: tooltipOpts.footerMarginTop,

				// Appearance
				caretSize: tooltipOpts.caretSize,
				cornerRadius: tooltipOpts.cornerRadius,
				backgroundColor: tooltipOpts.backgroundColor,
				opacity: 0,
				legendColorBackground: tooltipOpts.multiKeyBackground,
				displayColors: tooltipOpts.displayColors,
				borderColor: tooltipOpts.borderColor,
				borderWidth: tooltipOpts.borderWidth
			};
		}

		/**
		 * Get the size of the tooltip
		 */
		function getTooltipSize(tooltip, model) {
			var ctx = tooltip._chart.ctx;

			var height = model.yPadding * 2; // Tooltip Padding
			var width = 0;

			// Count of all lines in the body
			var body = model.body;
			var combinedBodyLength = body.reduce(function(count, bodyItem) {
				return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
			}, 0);
			combinedBodyLength += model.beforeBody.length + model.afterBody.length;

			var titleLineCount = model.title.length;
			var footerLineCount = model.footer.length;
			var titleFontSize = model.titleFontSize;
			var bodyFontSize = model.bodyFontSize;
			var footerFontSize = model.footerFontSize;

			height += titleLineCount * titleFontSize; // Title Lines
			height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
			height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
			height += combinedBodyLength * bodyFontSize; // Body Lines
			height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
			height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
			height += footerLineCount * (footerFontSize); // Footer Lines
			height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing

			// Title width
			var widthPadding = 0;
			var maxLineWidth = function(line) {
				width = Math.max(width, ctx.measureText(line).width + widthPadding);
			};

			ctx.font = helpers$1.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
			helpers$1.each(model.title, maxLineWidth);

			// Body width
			ctx.font = helpers$1.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
			helpers$1.each(model.beforeBody.concat(model.afterBody), maxLineWidth);

			// Body lines may include some extra width due to the color box
			widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
			helpers$1.each(body, function(bodyItem) {
				helpers$1.each(bodyItem.before, maxLineWidth);
				helpers$1.each(bodyItem.lines, maxLineWidth);
				helpers$1.each(bodyItem.after, maxLineWidth);
			});

			// Reset back to 0
			widthPadding = 0;

			// Footer width
			ctx.font = helpers$1.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
			helpers$1.each(model.footer, maxLineWidth);

			// Add padding
			width += 2 * model.xPadding;

			return {
				width: width,
				height: height
			};
		}

		/**
		 * Helper to get the alignment of a tooltip given the size
		 */
		function determineAlignment(tooltip, size) {
			var model = tooltip._model;
			var chart = tooltip._chart;
			var chartArea = tooltip._chart.chartArea;
			var xAlign = 'center';
			var yAlign = 'center';

			if (model.y < size.height) {
				yAlign = 'top';
			} else if (model.y > (chart.height - size.height)) {
				yAlign = 'bottom';
			}

			var lf, rf; // functions to determine left, right alignment
			var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
			var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
			var midX = (chartArea.left + chartArea.right) / 2;
			var midY = (chartArea.top + chartArea.bottom) / 2;

			if (yAlign === 'center') {
				lf = function(x) {
					return x <= midX;
				};
				rf = function(x) {
					return x > midX;
				};
			} else {
				lf = function(x) {
					return x <= (size.width / 2);
				};
				rf = function(x) {
					return x >= (chart.width - (size.width / 2));
				};
			}

			olf = function(x) {
				return x + size.width + model.caretSize + model.caretPadding > chart.width;
			};
			orf = function(x) {
				return x - size.width - model.caretSize - model.caretPadding < 0;
			};
			yf = function(y) {
				return y <= midY ? 'top' : 'bottom';
			};

			if (lf(model.x)) {
				xAlign = 'left';

				// Is tooltip too wide and goes over the right side of the chart.?
				if (olf(model.x)) {
					xAlign = 'center';
					yAlign = yf(model.y);
				}
			} else if (rf(model.x)) {
				xAlign = 'right';

				// Is tooltip too wide and goes outside left edge of canvas?
				if (orf(model.x)) {
					xAlign = 'center';
					yAlign = yf(model.y);
				}
			}

			var opts = tooltip._options;
			return {
				xAlign: opts.xAlign ? opts.xAlign : xAlign,
				yAlign: opts.yAlign ? opts.yAlign : yAlign
			};
		}

		/**
		 * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
		 */
		function getBackgroundPoint(vm, size, alignment, chart) {
			// Background Position
			var x = vm.x;
			var y = vm.y;

			var caretSize = vm.caretSize;
			var caretPadding = vm.caretPadding;
			var cornerRadius = vm.cornerRadius;
			var xAlign = alignment.xAlign;
			var yAlign = alignment.yAlign;
			var paddingAndSize = caretSize + caretPadding;
			var radiusAndPadding = cornerRadius + caretPadding;

			if (xAlign === 'right') {
				x -= size.width;
			} else if (xAlign === 'center') {
				x -= (size.width / 2);
				if (x + size.width > chart.width) {
					x = chart.width - size.width;
				}
				if (x < 0) {
					x = 0;
				}
			}

			if (yAlign === 'top') {
				y += paddingAndSize;
			} else if (yAlign === 'bottom') {
				y -= size.height + paddingAndSize;
			} else {
				y -= (size.height / 2);
			}

			if (yAlign === 'center') {
				if (xAlign === 'left') {
					x += paddingAndSize;
				} else if (xAlign === 'right') {
					x -= paddingAndSize;
				}
			} else if (xAlign === 'left') {
				x -= radiusAndPadding;
			} else if (xAlign === 'right') {
				x += radiusAndPadding;
			}

			return {
				x: x,
				y: y
			};
		}

		Chart.Tooltip = core_element.extend({
			initialize: function() {
				this._model = getBaseModel(this._options);
				this._lastActive = [];
			},

			// Get the title
			// Args are: (tooltipItem, data)
			getTitle: function() {
				var me = this;
				var opts = me._options;
				var callbacks = opts.callbacks;

				var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
				var title = callbacks.title.apply(me, arguments);
				var afterTitle = callbacks.afterTitle.apply(me, arguments);

				var lines = [];
				lines = pushOrConcat(lines, beforeTitle);
				lines = pushOrConcat(lines, title);
				lines = pushOrConcat(lines, afterTitle);

				return lines;
			},

			// Args are: (tooltipItem, data)
			getBeforeBody: function() {
				var lines = this._options.callbacks.beforeBody.apply(this, arguments);
				return helpers$1.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
			},

			// Args are: (tooltipItem, data)
			getBody: function(tooltipItems, data) {
				var me = this;
				var callbacks = me._options.callbacks;
				var bodyItems = [];

				helpers$1.each(tooltipItems, function(tooltipItem) {
					var bodyItem = {
						before: [],
						lines: [],
						after: []
					};
					pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
					pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
					pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));

					bodyItems.push(bodyItem);
				});

				return bodyItems;
			},

			// Args are: (tooltipItem, data)
			getAfterBody: function() {
				var lines = this._options.callbacks.afterBody.apply(this, arguments);
				return helpers$1.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
			},

			// Get the footer and beforeFooter and afterFooter lines
			// Args are: (tooltipItem, data)
			getFooter: function() {
				var me = this;
				var callbacks = me._options.callbacks;

				var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
				var footer = callbacks.footer.apply(me, arguments);
				var afterFooter = callbacks.afterFooter.apply(me, arguments);

				var lines = [];
				lines = pushOrConcat(lines, beforeFooter);
				lines = pushOrConcat(lines, footer);
				lines = pushOrConcat(lines, afterFooter);

				return lines;
			},

			update: function(changed) {
				var me = this;
				var opts = me._options;

				// Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
				// that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
				// which breaks any animations.
				var existingModel = me._model;
				var model = me._model = getBaseModel(opts);
				var active = me._active;

				var data = me._data;

				// In the case where active.length === 0 we need to keep these at existing values for good animations
				var alignment = {
					xAlign: existingModel.xAlign,
					yAlign: existingModel.yAlign
				};
				var backgroundPoint = {
					x: existingModel.x,
					y: existingModel.y
				};
				var tooltipSize = {
					width: existingModel.width,
					height: existingModel.height
				};
				var tooltipPosition = {
					x: existingModel.caretX,
					y: existingModel.caretY
				};

				var i, len;

				if (active.length) {
					model.opacity = 1;

					var labelColors = [];
					var labelTextColors = [];
					tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition);

					var tooltipItems = [];
					for (i = 0, len = active.length; i < len; ++i) {
						tooltipItems.push(createTooltipItem(active[i]));
					}

					// If the user provided a filter function, use it to modify the tooltip items
					if (opts.filter) {
						tooltipItems = tooltipItems.filter(function(a) {
							return opts.filter(a, data);
						});
					}

					// If the user provided a sorting function, use it to modify the tooltip items
					if (opts.itemSort) {
						tooltipItems = tooltipItems.sort(function(a, b) {
							return opts.itemSort(a, b, data);
						});
					}

					// Determine colors for boxes
					helpers$1.each(tooltipItems, function(tooltipItem) {
						labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
						labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
					});


					// Build the Text Lines
					model.title = me.getTitle(tooltipItems, data);
					model.beforeBody = me.getBeforeBody(tooltipItems, data);
					model.body = me.getBody(tooltipItems, data);
					model.afterBody = me.getAfterBody(tooltipItems, data);
					model.footer = me.getFooter(tooltipItems, data);

					// Initial positioning and colors
					model.x = Math.round(tooltipPosition.x);
					model.y = Math.round(tooltipPosition.y);
					model.caretPadding = opts.caretPadding;
					model.labelColors = labelColors;
					model.labelTextColors = labelTextColors;

					// data points
					model.dataPoints = tooltipItems;

					// We need to determine alignment of the tooltip
					tooltipSize = getTooltipSize(this, model);
					alignment = determineAlignment(this, tooltipSize);
					// Final Size and Position
					backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
				} else {
					model.opacity = 0;
				}

				model.xAlign = alignment.xAlign;
				model.yAlign = alignment.yAlign;
				model.x = backgroundPoint.x;
				model.y = backgroundPoint.y;
				model.width = tooltipSize.width;
				model.height = tooltipSize.height;

				// Point where the caret on the tooltip points to
				model.caretX = tooltipPosition.x;
				model.caretY = tooltipPosition.y;

				me._model = model;

				if (changed && opts.custom) {
					opts.custom.call(me, model);
				}

				return me;
			},
			drawCaret: function(tooltipPoint, size) {
				var ctx = this._chart.ctx;
				var vm = this._view;
				var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);

				ctx.lineTo(caretPosition.x1, caretPosition.y1);
				ctx.lineTo(caretPosition.x2, caretPosition.y2);
				ctx.lineTo(caretPosition.x3, caretPosition.y3);
			},
			getCaretPosition: function(tooltipPoint, size, vm) {
				var x1, x2, x3, y1, y2, y3;
				var caretSize = vm.caretSize;
				var cornerRadius = vm.cornerRadius;
				var xAlign = vm.xAlign;
				var yAlign = vm.yAlign;
				var ptX = tooltipPoint.x;
				var ptY = tooltipPoint.y;
				var width = size.width;
				var height = size.height;

				if (yAlign === 'center') {
					y2 = ptY + (height / 2);

					if (xAlign === 'left') {
						x1 = ptX;
						x2 = x1 - caretSize;
						x3 = x1;

						y1 = y2 + caretSize;
						y3 = y2 - caretSize;
					} else {
						x1 = ptX + width;
						x2 = x1 + caretSize;
						x3 = x1;

						y1 = y2 - caretSize;
						y3 = y2 + caretSize;
					}
				} else {
					if (xAlign === 'left') {
						x2 = ptX + cornerRadius + (caretSize);
						x1 = x2 - caretSize;
						x3 = x2 + caretSize;
					} else if (xAlign === 'right') {
						x2 = ptX + width - cornerRadius - caretSize;
						x1 = x2 - caretSize;
						x3 = x2 + caretSize;
					} else {
						x2 = vm.caretX;
						x1 = x2 - caretSize;
						x3 = x2 + caretSize;
					}
					if (yAlign === 'top') {
						y1 = ptY;
						y2 = y1 - caretSize;
						y3 = y1;
					} else {
						y1 = ptY + height;
						y2 = y1 + caretSize;
						y3 = y1;
						// invert drawing order
						var tmp = x3;
						x3 = x1;
						x1 = tmp;
					}
				}
				return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
			},
			drawTitle: function(pt, vm, ctx, opacity) {
				var title = vm.title;

				if (title.length) {
					ctx.textAlign = vm._titleAlign;
					ctx.textBaseline = 'top';

					var titleFontSize = vm.titleFontSize;
					var titleSpacing = vm.titleSpacing;

					ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
					ctx.font = helpers$1.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);

					var i, len;
					for (i = 0, len = title.length; i < len; ++i) {
						ctx.fillText(title[i], pt.x, pt.y);
						pt.y += titleFontSize + titleSpacing; // Line Height and spacing

						if (i + 1 === title.length) {
							pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
						}
					}
				}
			},
			drawBody: function(pt, vm, ctx, opacity) {
				var bodyFontSize = vm.bodyFontSize;
				var bodySpacing = vm.bodySpacing;
				var body = vm.body;

				ctx.textAlign = vm._bodyAlign;
				ctx.textBaseline = 'top';
				ctx.font = helpers$1.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);

				// Before Body
				var xLinePadding = 0;
				var fillLineOfText = function(line) {
					ctx.fillText(line, pt.x + xLinePadding, pt.y);
					pt.y += bodyFontSize + bodySpacing;
				};

				// Before body lines
				ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity);
				helpers$1.each(vm.beforeBody, fillLineOfText);

				var drawColorBoxes = vm.displayColors;
				xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;

				// Draw body lines now
				helpers$1.each(body, function(bodyItem, i) {
					var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
					ctx.fillStyle = textColor;
					helpers$1.each(bodyItem.before, fillLineOfText);

					helpers$1.each(bodyItem.lines, function(line) {
						// Draw Legend-like boxes if needed
						if (drawColorBoxes) {
							// Fill a white rect so that colours merge nicely if the opacity is < 1
							ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
							ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);

							// Border
							ctx.lineWidth = 1;
							ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
							ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);

							// Inner square
							ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
							ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
							ctx.fillStyle = textColor;
						}

						fillLineOfText(line);
					});

					helpers$1.each(bodyItem.after, fillLineOfText);
				});

				// Reset back to 0 for after body
				xLinePadding = 0;

				// After body lines
				helpers$1.each(vm.afterBody, fillLineOfText);
				pt.y -= bodySpacing; // Remove last body spacing
			},
			drawFooter: function(pt, vm, ctx, opacity) {
				var footer = vm.footer;

				if (footer.length) {
					pt.y += vm.footerMarginTop;

					ctx.textAlign = vm._footerAlign;
					ctx.textBaseline = 'top';

					ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
					ctx.font = helpers$1.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);

					helpers$1.each(footer, function(line) {
						ctx.fillText(line, pt.x, pt.y);
						pt.y += vm.footerFontSize + vm.footerSpacing;
					});
				}
			},
			drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
				ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
				ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
				ctx.lineWidth = vm.borderWidth;
				var xAlign = vm.xAlign;
				var yAlign = vm.yAlign;
				var x = pt.x;
				var y = pt.y;
				var width = tooltipSize.width;
				var height = tooltipSize.height;
				var radius = vm.cornerRadius;

				ctx.beginPath();
				ctx.moveTo(x + radius, y);
				if (yAlign === 'top') {
					this.drawCaret(pt, tooltipSize);
				}
				ctx.lineTo(x + width - radius, y);
				ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
				if (yAlign === 'center' && xAlign === 'right') {
					this.drawCaret(pt, tooltipSize);
				}
				ctx.lineTo(x + width, y + height - radius);
				ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
				if (yAlign === 'bottom') {
					this.drawCaret(pt, tooltipSize);
				}
				ctx.lineTo(x + radius, y + height);
				ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
				if (yAlign === 'center' && xAlign === 'left') {
					this.drawCaret(pt, tooltipSize);
				}
				ctx.lineTo(x, y + radius);
				ctx.quadraticCurveTo(x, y, x + radius, y);
				ctx.closePath();

				ctx.fill();

				if (vm.borderWidth > 0) {
					ctx.stroke();
				}
			},
			draw: function() {
				var ctx = this._chart.ctx;
				var vm = this._view;

				if (vm.opacity === 0) {
					return;
				}

				var tooltipSize = {
					width: vm.width,
					height: vm.height
				};
				var pt = {
					x: vm.x,
					y: vm.y
				};

				// IE11/Edge does not like very small opacities, so snap to 0
				var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;

				// Truthy/falsey value for empty tooltip
				var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;

				if (this._options.enabled && hasTooltipContent) {
					// Draw Background
					this.drawBackground(pt, vm, ctx, tooltipSize, opacity);

					// Draw Title, Body, and Footer
					pt.x += vm.xPadding;
					pt.y += vm.yPadding;

					// Titles
					this.drawTitle(pt, vm, ctx, opacity);

					// Body
					this.drawBody(pt, vm, ctx, opacity);

					// Footer
					this.drawFooter(pt, vm, ctx, opacity);
				}
			},

			/**
			 * Handle an event
			 * @private
			 * @param {IEvent} event - The event to handle
			 * @returns {Boolean} true if the tooltip changed
			 */
			handleEvent: function(e) {
				var me = this;
				var options = me._options;
				var changed = false;

				me._lastActive = me._lastActive || [];

				// Find Active Elements for tooltips
				if (e.type === 'mouseout') {
					me._active = [];
				} else {
					me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
				}

				// Remember Last Actives
				changed = !helpers$1.arrayEquals(me._active, me._lastActive);

				// Only handle target event on tooltip change
				if (changed) {
					me._lastActive = me._active;

					if (options.enabled || options.custom) {
						me._eventPosition = {
							x: e.x,
							y: e.y
						};

						me.update(true);
						me.pivot();
					}
				}

				return changed;
			}
		});

		/**
		 * @namespace Chart.Tooltip.positioners
		 */
		Chart.Tooltip.positioners = {
			/**
			 * Average mode places the tooltip at the average position of the elements shown
			 * @function Chart.Tooltip.positioners.average
			 * @param elements {ChartElement[]} the elements being displayed in the tooltip
			 * @returns {Point} tooltip position
			 */
			average: function(elements) {
				if (!elements.length) {
					return false;
				}

				var i, len;
				var x = 0;
				var y = 0;
				var count = 0;

				for (i = 0, len = elements.length; i < len; ++i) {
					var el = elements[i];
					if (el && el.hasValue()) {
						var pos = el.tooltipPosition();
						x += pos.x;
						y += pos.y;
						++count;
					}
				}

				return {
					x: Math.round(x / count),
					y: Math.round(y / count)
				};
			},

			/**
			 * Gets the tooltip position nearest of the item nearest to the event position
			 * @function Chart.Tooltip.positioners.nearest
			 * @param elements {Chart.Element[]} the tooltip elements
			 * @param eventPosition {Point} the position of the event in canvas coordinates
			 * @returns {Point} the tooltip position
			 */
			nearest: function(elements, eventPosition) {
				var x = eventPosition.x;
				var y = eventPosition.y;
				var minDistance = Number.POSITIVE_INFINITY;
				var i, len, nearestElement;

				for (i = 0, len = elements.length; i < len; ++i) {
					var el = elements[i];
					if (el && el.hasValue()) {
						var center = el.getCenterPoint();
						var d = helpers$1.distanceBetweenPoints(eventPosition, center);

						if (d < minDistance) {
							minDistance = d;
							nearestElement = el;
						}
					}
				}

				if (nearestElement) {
					var tp = nearestElement.tooltipPosition();
					x = tp.x;
					y = tp.y;
				}

				return {
					x: x,
					y: y
				};
			}
		};
	};

	/**
	 * Generate a set of linear ticks
	 * @param generationOptions the options used to generate the ticks
	 * @param dataRange the range of the data
	 * @returns {Array<Number>} array of tick values
	 */
	function generateTicks(generationOptions, dataRange) {
		var ticks = [];
		// To get a "nice" value for the tick spacing, we will use the appropriately named
		// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
		// for details.

		var spacing;
		if (generationOptions.stepSize && generationOptions.stepSize > 0) {
			spacing = generationOptions.stepSize;
		} else {
			var niceRange = helpers$1.niceNum(dataRange.max - dataRange.min, false);
			spacing = helpers$1.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
		}
		var niceMin = Math.floor(dataRange.min / spacing) * spacing;
		var niceMax = Math.ceil(dataRange.max / spacing) * spacing;

		// If min, max and stepSize is set and they make an evenly spaced scale use it.
		if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
			// If very close to our whole number, use it.
			if (helpers$1.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
				niceMin = generationOptions.min;
				niceMax = generationOptions.max;
			}
		}

		var numSpaces = (niceMax - niceMin) / spacing;
		// If very close to our rounded value, use it.
		if (helpers$1.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
			numSpaces = Math.round(numSpaces);
		} else {
			numSpaces = Math.ceil(numSpaces);
		}

		var precision = 1;
		if (spacing < 1) {
			precision = Math.pow(10, spacing.toString().length - 2);
			niceMin = Math.round(niceMin * precision) / precision;
			niceMax = Math.round(niceMax * precision) / precision;
		}
		ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
		for (var j = 1; j < numSpaces; ++j) {
			ticks.push(Math.round((niceMin + j * spacing) * precision) / precision);
		}
		ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);

		return ticks;
	}


	var scale_linearbase = function(Chart) {

		var noop = helpers$1.noop;

		Chart.LinearScaleBase = Chart.Scale.extend({
			getRightValue: function(value) {
				if (typeof value === 'string') {
					return +value;
				}
				return Chart.Scale.prototype.getRightValue.call(this, value);
			},

			handleTickRangeOptions: function() {
				var me = this;
				var opts = me.options;
				var tickOpts = opts.ticks;

				// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
				// do nothing since that would make the chart weird. If the user really wants a weird chart
				// axis, they can manually override it
				if (tickOpts.beginAtZero) {
					var minSign = helpers$1.sign(me.min);
					var maxSign = helpers$1.sign(me.max);

					if (minSign < 0 && maxSign < 0) {
						// move the top up to 0
						me.max = 0;
					} else if (minSign > 0 && maxSign > 0) {
						// move the bottom down to 0
						me.min = 0;
					}
				}

				var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
				var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;

				if (tickOpts.min !== undefined) {
					me.min = tickOpts.min;
				} else if (tickOpts.suggestedMin !== undefined) {
					if (me.min === null) {
						me.min = tickOpts.suggestedMin;
					} else {
						me.min = Math.min(me.min, tickOpts.suggestedMin);
					}
				}

				if (tickOpts.max !== undefined) {
					me.max = tickOpts.max;
				} else if (tickOpts.suggestedMax !== undefined) {
					if (me.max === null) {
						me.max = tickOpts.suggestedMax;
					} else {
						me.max = Math.max(me.max, tickOpts.suggestedMax);
					}
				}

				if (setMin !== setMax) {
					// We set the min or the max but not both.
					// So ensure that our range is good
					// Inverted or 0 length range can happen when
					// ticks.min is set, and no datasets are visible
					if (me.min >= me.max) {
						if (setMin) {
							me.max = me.min + 1;
						} else {
							me.min = me.max - 1;
						}
					}
				}

				if (me.min === me.max) {
					me.max++;

					if (!tickOpts.beginAtZero) {
						me.min--;
					}
				}
			},
			getTickLimit: noop,
			handleDirectionalChanges: noop,

			buildTicks: function() {
				var me = this;
				var opts = me.options;
				var tickOpts = opts.ticks;

				// Figure out what the max number of ticks we can support it is based on the size of
				// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
				// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
				// the graph. Make sure we always have at least 2 ticks
				var maxTicks = me.getTickLimit();
				maxTicks = Math.max(2, maxTicks);

				var numericGeneratorOptions = {
					maxTicks: maxTicks,
					min: tickOpts.min,
					max: tickOpts.max,
					stepSize: helpers$1.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
				};
				var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);

				me.handleDirectionalChanges();

				// At this point, we need to update our max and min given the tick values since we have expanded the
				// range of the scale
				me.max = helpers$1.max(ticks);
				me.min = helpers$1.min(ticks);

				if (tickOpts.reverse) {
					ticks.reverse();

					me.start = me.max;
					me.end = me.min;
				} else {
					me.start = me.min;
					me.end = me.max;
				}
			},
			convertTicksToLabels: function() {
				var me = this;
				me.ticksAsNumbers = me.ticks.slice();
				me.zeroLineIndex = me.ticks.indexOf(0);

				Chart.Scale.prototype.convertTicksToLabels.call(me);
			}
		});
	};

	var scale_category = function(Chart) {

		// Default config for a category scale
		var defaultConfig = {
			position: 'bottom'
		};

		var DatasetScale = Chart.Scale.extend({
			/**
			* Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
			* else fall back to data.labels
			* @private
			*/
			getLabels: function() {
				var data = this.chart.data;
				return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
			},

			determineDataLimits: function() {
				var me = this;
				var labels = me.getLabels();
				me.minIndex = 0;
				me.maxIndex = labels.length - 1;
				var findIndex;

				if (me.options.ticks.min !== undefined) {
					// user specified min value
					findIndex = labels.indexOf(me.options.ticks.min);
					me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
				}

				if (me.options.ticks.max !== undefined) {
					// user specified max value
					findIndex = labels.indexOf(me.options.ticks.max);
					me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
				}

				me.min = labels[me.minIndex];
				me.max = labels[me.maxIndex];
			},

			buildTicks: function() {
				var me = this;
				var labels = me.getLabels();
				// If we are viewing some subset of labels, slice the original array
				me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
			},

			getLabelForIndex: function(index, datasetIndex) {
				var me = this;
				var data = me.chart.data;
				var isHorizontal = me.isHorizontal();

				if (data.yLabels && !isHorizontal) {
					return me.getRightValue(data.datasets[datasetIndex].data[index]);
				}
				return me.ticks[index - me.minIndex];
			},

			// Used to get data value locations.  Value can either be an index or a numerical value
			getPixelForValue: function(value, index) {
				var me = this;
				var offset = me.options.offset;
				// 1 is added because we need the length but we have the indexes
				var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);

				// If value is a data object, then index is the index in the data array,
				// not the index of the scale. We need to change that.
				var valueCategory;
				if (value !== undefined && value !== null) {
					valueCategory = me.isHorizontal() ? value.x : value.y;
				}
				if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
					var labels = me.getLabels();
					value = valueCategory || value;
					var idx = labels.indexOf(value);
					index = idx !== -1 ? idx : index;
				}

				if (me.isHorizontal()) {
					var valueWidth = me.width / offsetAmt;
					var widthOffset = (valueWidth * (index - me.minIndex));

					if (offset) {
						widthOffset += (valueWidth / 2);
					}

					return me.left + Math.round(widthOffset);
				}
				var valueHeight = me.height / offsetAmt;
				var heightOffset = (valueHeight * (index - me.minIndex));

				if (offset) {
					heightOffset += (valueHeight / 2);
				}

				return me.top + Math.round(heightOffset);
			},
			getPixelForTick: function(index) {
				return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
			},
			getValueForPixel: function(pixel) {
				var me = this;
				var offset = me.options.offset;
				var value;
				var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
				var horz = me.isHorizontal();
				var valueDimension = (horz ? me.width : me.height) / offsetAmt;

				pixel -= horz ? me.left : me.top;

				if (offset) {
					pixel -= (valueDimension / 2);
				}

				if (pixel <= 0) {
					value = 0;
				} else {
					value = Math.round(pixel / valueDimension);
				}

				return value + me.minIndex;
			},
			getBasePixel: function() {
				return this.bottom;
			}
		});

		Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);

	};

	var scale_linear = function(Chart) {

		var defaultConfig = {
			position: 'left',
			ticks: {
				callback: core_ticks.formatters.linear
			}
		};

		var LinearScale = Chart.LinearScaleBase.extend({

			determineDataLimits: function() {
				var me = this;
				var opts = me.options;
				var chart = me.chart;
				var data = chart.data;
				var datasets = data.datasets;
				var isHorizontal = me.isHorizontal();
				var DEFAULT_MIN = 0;
				var DEFAULT_MAX = 1;

				function IDMatches(meta) {
					return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
				}

				// First Calculate the range
				me.min = null;
				me.max = null;

				var hasStacks = opts.stacked;
				if (hasStacks === undefined) {
					helpers$1.each(datasets, function(dataset, datasetIndex) {
						if (hasStacks) {
							return;
						}

						var meta = chart.getDatasetMeta(datasetIndex);
						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
							meta.stack !== undefined) {
							hasStacks = true;
						}
					});
				}

				if (opts.stacked || hasStacks) {
					var valuesPerStack = {};

					helpers$1.each(datasets, function(dataset, datasetIndex) {
						var meta = chart.getDatasetMeta(datasetIndex);
						var key = [
							meta.type,
							// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
							((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
							meta.stack
						].join('.');

						if (valuesPerStack[key] === undefined) {
							valuesPerStack[key] = {
								positiveValues: [],
								negativeValues: []
							};
						}

						// Store these per type
						var positiveValues = valuesPerStack[key].positiveValues;
						var negativeValues = valuesPerStack[key].negativeValues;

						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
							helpers$1.each(dataset.data, function(rawValue, index) {
								var value = +me.getRightValue(rawValue);
								if (isNaN(value) || meta.data[index].hidden) {
									return;
								}

								positiveValues[index] = positiveValues[index] || 0;
								negativeValues[index] = negativeValues[index] || 0;

								if (opts.relativePoints) {
									positiveValues[index] = 100;
								} else if (value < 0) {
									negativeValues[index] += value;
								} else {
									positiveValues[index] += value;
								}
							});
						}
					});

					helpers$1.each(valuesPerStack, function(valuesForType) {
						var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
						var minVal = helpers$1.min(values);
						var maxVal = helpers$1.max(values);
						me.min = me.min === null ? minVal : Math.min(me.min, minVal);
						me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
					});

				} else {
					helpers$1.each(datasets, function(dataset, datasetIndex) {
						var meta = chart.getDatasetMeta(datasetIndex);
						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
							helpers$1.each(dataset.data, function(rawValue, index) {
								var value = +me.getRightValue(rawValue);
								if (isNaN(value) || meta.data[index].hidden) {
									return;
								}

								if (me.min === null) {
									me.min = value;
								} else if (value < me.min) {
									me.min = value;
								}

								if (me.max === null) {
									me.max = value;
								} else if (value > me.max) {
									me.max = value;
								}
							});
						}
					});
				}

				me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
				me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;

				// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
				this.handleTickRangeOptions();
			},
			getTickLimit: function() {
				var maxTicks;
				var me = this;
				var tickOpts = me.options.ticks;

				if (me.isHorizontal()) {
					maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
				} else {
					// The factor of 2 used to scale the font size has been experimentally determined.
					var tickFontSize = helpers$1.valueOrDefault(tickOpts.fontSize, core_defaults.global.defaultFontSize);
					maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
				}

				return maxTicks;
			},
			// Called after the ticks are built. We need
			handleDirectionalChanges: function() {
				if (!this.isHorizontal()) {
					// We are in a vertical orientation. The top value is the highest. So reverse the array
					this.ticks.reverse();
				}
			},
			getLabelForIndex: function(index, datasetIndex) {
				return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
			},
			// Utils
			getPixelForValue: function(value) {
				// This must be called after fit has been run so that
				// this.left, this.top, this.right, and this.bottom have been defined
				var me = this;
				var start = me.start;

				var rightValue = +me.getRightValue(value);
				var pixel;
				var range = me.end - start;

				if (me.isHorizontal()) {
					pixel = me.left + (me.width / range * (rightValue - start));
				} else {
					pixel = me.bottom - (me.height / range * (rightValue - start));
				}
				return pixel;
			},
			getValueForPixel: function(pixel) {
				var me = this;
				var isHorizontal = me.isHorizontal();
				var innerDimension = isHorizontal ? me.width : me.height;
				var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
				return me.start + ((me.end - me.start) * offset);
			},
			getPixelForTick: function(index) {
				return this.getPixelForValue(this.ticksAsNumbers[index]);
			}
		});
		Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);

	};

	/**
	 * Generate a set of logarithmic ticks
	 * @param generationOptions the options used to generate the ticks
	 * @param dataRange the range of the data
	 * @returns {Array<Number>} array of tick values
	 */
	function generateTicks$1(generationOptions, dataRange) {
		var ticks = [];
		var valueOrDefault = helpers$1.valueOrDefault;

		// Figure out what the max number of ticks we can support it is based on the size of
		// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
		// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
		// the graph
		var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers$1.log10(dataRange.min))));

		var endExp = Math.floor(helpers$1.log10(dataRange.max));
		var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
		var exp, significand;

		if (tickVal === 0) {
			exp = Math.floor(helpers$1.log10(dataRange.minNotZero));
			significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));

			ticks.push(tickVal);
			tickVal = significand * Math.pow(10, exp);
		} else {
			exp = Math.floor(helpers$1.log10(tickVal));
			significand = Math.floor(tickVal / Math.pow(10, exp));
		}
		var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;

		do {
			ticks.push(tickVal);

			++significand;
			if (significand === 10) {
				significand = 1;
				++exp;
				precision = exp >= 0 ? 1 : precision;
			}

			tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
		} while (exp < endExp || (exp === endExp && significand < endSignificand));

		var lastTick = valueOrDefault(generationOptions.max, tickVal);
		ticks.push(lastTick);

		return ticks;
	}


	var scale_logarithmic = function(Chart) {

		var defaultConfig = {
			position: 'left',

			// label settings
			ticks: {
				callback: core_ticks.formatters.logarithmic
			}
		};

		var LogarithmicScale = Chart.Scale.extend({
			determineDataLimits: function() {
				var me = this;
				var opts = me.options;
				var chart = me.chart;
				var data = chart.data;
				var datasets = data.datasets;
				var isHorizontal = me.isHorizontal();
				function IDMatches(meta) {
					return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
				}

				// Calculate Range
				me.min = null;
				me.max = null;
				me.minNotZero = null;

				var hasStacks = opts.stacked;
				if (hasStacks === undefined) {
					helpers$1.each(datasets, function(dataset, datasetIndex) {
						if (hasStacks) {
							return;
						}

						var meta = chart.getDatasetMeta(datasetIndex);
						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
							meta.stack !== undefined) {
							hasStacks = true;
						}
					});
				}

				if (opts.stacked || hasStacks) {
					var valuesPerStack = {};

					helpers$1.each(datasets, function(dataset, datasetIndex) {
						var meta = chart.getDatasetMeta(datasetIndex);
						var key = [
							meta.type,
							// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
							((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
							meta.stack
						].join('.');

						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
							if (valuesPerStack[key] === undefined) {
								valuesPerStack[key] = [];
							}

							helpers$1.each(dataset.data, function(rawValue, index) {
								var values = valuesPerStack[key];
								var value = +me.getRightValue(rawValue);
								// invalid, hidden and negative values are ignored
								if (isNaN(value) || meta.data[index].hidden || value < 0) {
									return;
								}
								values[index] = values[index] || 0;
								values[index] += value;
							});
						}
					});

					helpers$1.each(valuesPerStack, function(valuesForType) {
						if (valuesForType.length > 0) {
							var minVal = helpers$1.min(valuesForType);
							var maxVal = helpers$1.max(valuesForType);
							me.min = me.min === null ? minVal : Math.min(me.min, minVal);
							me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
						}
					});

				} else {
					helpers$1.each(datasets, function(dataset, datasetIndex) {
						var meta = chart.getDatasetMeta(datasetIndex);
						if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
							helpers$1.each(dataset.data, function(rawValue, index) {
								var value = +me.getRightValue(rawValue);
								// invalid, hidden and negative values are ignored
								if (isNaN(value) || meta.data[index].hidden || value < 0) {
									return;
								}

								if (me.min === null) {
									me.min = value;
								} else if (value < me.min) {
									me.min = value;
								}

								if (me.max === null) {
									me.max = value;
								} else if (value > me.max) {
									me.max = value;
								}

								if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
									me.minNotZero = value;
								}
							});
						}
					});
				}

				// Common base implementation to handle ticks.min, ticks.max
				this.handleTickRangeOptions();
			},
			handleTickRangeOptions: function() {
				var me = this;
				var opts = me.options;
				var tickOpts = opts.ticks;
				var valueOrDefault = helpers$1.valueOrDefault;
				var DEFAULT_MIN = 1;
				var DEFAULT_MAX = 10;

				me.min = valueOrDefault(tickOpts.min, me.min);
				me.max = valueOrDefault(tickOpts.max, me.max);

				if (me.min === me.max) {
					if (me.min !== 0 && me.min !== null) {
						me.min = Math.pow(10, Math.floor(helpers$1.log10(me.min)) - 1);
						me.max = Math.pow(10, Math.floor(helpers$1.log10(me.max)) + 1);
					} else {
						me.min = DEFAULT_MIN;
						me.max = DEFAULT_MAX;
					}
				}
				if (me.min === null) {
					me.min = Math.pow(10, Math.floor(helpers$1.log10(me.max)) - 1);
				}
				if (me.max === null) {
					me.max = me.min !== 0
						? Math.pow(10, Math.floor(helpers$1.log10(me.min)) + 1)
						: DEFAULT_MAX;
				}
				if (me.minNotZero === null) {
					if (me.min > 0) {
						me.minNotZero = me.min;
					} else if (me.max < 1) {
						me.minNotZero = Math.pow(10, Math.floor(helpers$1.log10(me.max)));
					} else {
						me.minNotZero = DEFAULT_MIN;
					}
				}
			},
			buildTicks: function() {
				var me = this;
				var opts = me.options;
				var tickOpts = opts.ticks;
				var reverse = !me.isHorizontal();

				var generationOptions = {
					min: tickOpts.min,
					max: tickOpts.max
				};
				var ticks = me.ticks = generateTicks$1(generationOptions, me);

				// At this point, we need to update our max and min given the tick values since we have expanded the
				// range of the scale
				me.max = helpers$1.max(ticks);
				me.min = helpers$1.min(ticks);

				if (tickOpts.reverse) {
					reverse = !reverse;
					me.start = me.max;
					me.end = me.min;
				} else {
					me.start = me.min;
					me.end = me.max;
				}
				if (reverse) {
					ticks.reverse();
				}
			},
			convertTicksToLabels: function() {
				this.tickValues = this.ticks.slice();

				Chart.Scale.prototype.convertTicksToLabels.call(this);
			},
			// Get the correct tooltip label
			getLabelForIndex: function(index, datasetIndex) {
				return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
			},
			getPixelForTick: function(index) {
				return this.getPixelForValue(this.tickValues[index]);
			},
			/**
			 * Returns the value of the first tick.
			 * @param {Number} value - The minimum not zero value.
			 * @return {Number} The first tick value.
			 * @private
			 */
			_getFirstTickValue: function(value) {
				var exp = Math.floor(helpers$1.log10(value));
				var significand = Math.floor(value / Math.pow(10, exp));

				return significand * Math.pow(10, exp);
			},
			getPixelForValue: function(value) {
				var me = this;
				var reverse = me.options.ticks.reverse;
				var log10 = helpers$1.log10;
				var firstTickValue = me._getFirstTickValue(me.minNotZero);
				var offset = 0;
				var innerDimension, pixel, start, end, sign;

				value = +me.getRightValue(value);
				if (reverse) {
					start = me.end;
					end = me.start;
					sign = -1;
				} else {
					start = me.start;
					end = me.end;
					sign = 1;
				}
				if (me.isHorizontal()) {
					innerDimension = me.width;
					pixel = reverse ? me.right : me.left;
				} else {
					innerDimension = me.height;
					sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0)
					pixel = reverse ? me.top : me.bottom;
				}
				if (value !== start) {
					if (start === 0) { // include zero tick
						offset = helpers$1.getValueOrDefault(
							me.options.ticks.fontSize,
							Chart.defaults.global.defaultFontSize
						);
						innerDimension -= offset;
						start = firstTickValue;
					}
					if (value !== 0) {
						offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start));
					}
					pixel += sign * offset;
				}
				return pixel;
			},
			getValueForPixel: function(pixel) {
				var me = this;
				var reverse = me.options.ticks.reverse;
				var log10 = helpers$1.log10;
				var firstTickValue = me._getFirstTickValue(me.minNotZero);
				var innerDimension, start, end, value;

				if (reverse) {
					start = me.end;
					end = me.start;
				} else {
					start = me.start;
					end = me.end;
				}
				if (me.isHorizontal()) {
					innerDimension = me.width;
					value = reverse ? me.right - pixel : pixel - me.left;
				} else {
					innerDimension = me.height;
					value = reverse ? pixel - me.top : me.bottom - pixel;
				}
				if (value !== start) {
					if (start === 0) { // include zero tick
						var offset = helpers$1.getValueOrDefault(
							me.options.ticks.fontSize,
							Chart.defaults.global.defaultFontSize
						);
						value -= offset;
						innerDimension -= offset;
						start = firstTickValue;
					}
					value *= log10(end) - log10(start);
					value /= innerDimension;
					value = Math.pow(10, log10(start) + value);
				}
				return value;
			}
		});
		Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);

	};

	var scale_radialLinear = function(Chart) {

		var globalDefaults = core_defaults.global;

		var defaultConfig = {
			display: true,

			// Boolean - Whether to animate scaling the chart from the centre
			animate: true,
			position: 'chartArea',

			angleLines: {
				display: true,
				color: 'rgba(0, 0, 0, 0.1)',
				lineWidth: 1
			},

			gridLines: {
				circular: false
			},

			// label settings
			ticks: {
				// Boolean - Show a backdrop to the scale label
				showLabelBackdrop: true,

				// String - The colour of the label backdrop
				backdropColor: 'rgba(255,255,255,0.75)',

				// Number - The backdrop padding above & below the label in pixels
				backdropPaddingY: 2,

				// Number - The backdrop padding to the side of the label in pixels
				backdropPaddingX: 2,

				callback: core_ticks.formatters.linear
			},

			pointLabels: {
				// Boolean - if true, show point labels
				display: true,

				// Number - Point label font size in pixels
				fontSize: 10,

				// Function - Used to convert point labels
				callback: function(label) {
					return label;
				}
			}
		};

		function getValueCount(scale) {
			var opts = scale.options;
			return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
		}

		function getPointLabelFontOptions(scale) {
			var pointLabelOptions = scale.options.pointLabels;
			var fontSize = helpers$1.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
			var fontStyle = helpers$1.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
			var fontFamily = helpers$1.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
			var font = helpers$1.fontString(fontSize, fontStyle, fontFamily);

			return {
				size: fontSize,
				style: fontStyle,
				family: fontFamily,
				font: font
			};
		}

		function measureLabelSize(ctx, fontSize, label) {
			if (helpers$1.isArray(label)) {
				return {
					w: helpers$1.longestText(ctx, ctx.font, label),
					h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
				};
			}

			return {
				w: ctx.measureText(label).width,
				h: fontSize
			};
		}

		function determineLimits(angle, pos, size, min, max) {
			if (angle === min || angle === max) {
				return {
					start: pos - (size / 2),
					end: pos + (size / 2)
				};
			} else if (angle < min || angle > max) {
				return {
					start: pos - size - 5,
					end: pos
				};
			}

			return {
				start: pos,
				end: pos + size + 5
			};
		}

		/**
		 * Helper function to fit a radial linear scale with point labels
		 */
		function fitWithPointLabels(scale) {
			/*
			 * Right, this is really confusing and there is a lot of maths going on here
			 * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
			 *
			 * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
			 *
			 * Solution:
			 *
			 * We assume the radius of the polygon is half the size of the canvas at first
			 * at each index we check if the text overlaps.
			 *
			 * Where it does, we store that angle and that index.
			 *
			 * After finding the largest index and angle we calculate how much we need to remove
			 * from the shape radius to move the point inwards by that x.
			 *
			 * We average the left and right distances to get the maximum shape radius that can fit in the box
			 * along with labels.
			 *
			 * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
			 * on each side, removing that from the size, halving it and adding the left x protrusion width.
			 *
			 * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
			 * and position it in the most space efficient manner
			 *
			 * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
			 */

			var plFont = getPointLabelFontOptions(scale);

			// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
			// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
			var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
			var furthestLimits = {
				r: scale.width,
				l: 0,
				t: scale.height,
				b: 0
			};
			var furthestAngles = {};
			var i, textSize, pointPosition;

			scale.ctx.font = plFont.font;
			scale._pointLabelSizes = [];

			var valueCount = getValueCount(scale);
			for (i = 0; i < valueCount; i++) {
				pointPosition = scale.getPointPosition(i, largestPossibleRadius);
				textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
				scale._pointLabelSizes[i] = textSize;

				// Add quarter circle to make degree 0 mean top of circle
				var angleRadians = scale.getIndexAngle(i);
				var angle = helpers$1.toDegrees(angleRadians) % 360;
				var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
				var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);

				if (hLimits.start < furthestLimits.l) {
					furthestLimits.l = hLimits.start;
					furthestAngles.l = angleRadians;
				}

				if (hLimits.end > furthestLimits.r) {
					furthestLimits.r = hLimits.end;
					furthestAngles.r = angleRadians;
				}

				if (vLimits.start < furthestLimits.t) {
					furthestLimits.t = vLimits.start;
					furthestAngles.t = angleRadians;
				}

				if (vLimits.end > furthestLimits.b) {
					furthestLimits.b = vLimits.end;
					furthestAngles.b = angleRadians;
				}
			}

			scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
		}

		/**
		 * Helper function to fit a radial linear scale with no point labels
		 */
		function fit(scale) {
			var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
			scale.drawingArea = Math.round(largestPossibleRadius);
			scale.setCenterPoint(0, 0, 0, 0);
		}

		function getTextAlignForAngle(angle) {
			if (angle === 0 || angle === 180) {
				return 'center';
			} else if (angle < 180) {
				return 'left';
			}

			return 'right';
		}

		function fillText(ctx, text, position, fontSize) {
			if (helpers$1.isArray(text)) {
				var y = position.y;
				var spacing = 1.5 * fontSize;

				for (var i = 0; i < text.length; ++i) {
					ctx.fillText(text[i], position.x, y);
					y += spacing;
				}
			} else {
				ctx.fillText(text, position.x, position.y);
			}
		}

		function adjustPointPositionForLabelHeight(angle, textSize, position) {
			if (angle === 90 || angle === 270) {
				position.y -= (textSize.h / 2);
			} else if (angle > 270 || angle < 90) {
				position.y -= textSize.h;
			}
		}

		function drawPointLabels(scale) {
			var ctx = scale.ctx;
			var opts = scale.options;
			var angleLineOpts = opts.angleLines;
			var pointLabelOpts = opts.pointLabels;

			ctx.lineWidth = angleLineOpts.lineWidth;
			ctx.strokeStyle = angleLineOpts.color;

			var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);

			// Point Label Font
			var plFont = getPointLabelFontOptions(scale);

			ctx.textBaseline = 'top';

			for (var i = getValueCount(scale) - 1; i >= 0; i--) {
				if (angleLineOpts.display) {
					var outerPosition = scale.getPointPosition(i, outerDistance);
					ctx.beginPath();
					ctx.moveTo(scale.xCenter, scale.yCenter);
					ctx.lineTo(outerPosition.x, outerPosition.y);
					ctx.stroke();
					ctx.closePath();
				}

				if (pointLabelOpts.display) {
					// Extra 3px out for some label spacing
					var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);

					// Keep this in loop since we may support array properties here
					var pointLabelFontColor = helpers$1.valueAtIndexOrDefault(pointLabelOpts.fontColor, i, globalDefaults.defaultFontColor);
					ctx.font = plFont.font;
					ctx.fillStyle = pointLabelFontColor;

					var angleRadians = scale.getIndexAngle(i);
					var angle = helpers$1.toDegrees(angleRadians);
					ctx.textAlign = getTextAlignForAngle(angle);
					adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
					fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
				}
			}
		}

		function drawRadiusLine(scale, gridLineOpts, radius, index) {
			var ctx = scale.ctx;
			ctx.strokeStyle = helpers$1.valueAtIndexOrDefault(gridLineOpts.color, index - 1);
			ctx.lineWidth = helpers$1.valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);

			if (scale.options.gridLines.circular) {
				// Draw circular arcs between the points
				ctx.beginPath();
				ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
				ctx.closePath();
				ctx.stroke();
			} else {
				// Draw straight lines connecting each index
				var valueCount = getValueCount(scale);

				if (valueCount === 0) {
					return;
				}

				ctx.beginPath();
				var pointPosition = scale.getPointPosition(0, radius);
				ctx.moveTo(pointPosition.x, pointPosition.y);

				for (var i = 1; i < valueCount; i++) {
					pointPosition = scale.getPointPosition(i, radius);
					ctx.lineTo(pointPosition.x, pointPosition.y);
				}

				ctx.closePath();
				ctx.stroke();
			}
		}

		function numberOrZero(param) {
			return helpers$1.isNumber(param) ? param : 0;
		}

		var LinearRadialScale = Chart.LinearScaleBase.extend({
			setDimensions: function() {
				var me = this;
				var opts = me.options;
				var tickOpts = opts.ticks;
				// Set the unconstrained dimension before label rotation
				me.width = me.maxWidth;
				me.height = me.maxHeight;
				me.xCenter = Math.round(me.width / 2);
				me.yCenter = Math.round(me.height / 2);

				var minSize = helpers$1.min([me.height, me.width]);
				var tickFontSize = helpers$1.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
				me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
			},
			determineDataLimits: function() {
				var me = this;
				var chart = me.chart;
				var min = Number.POSITIVE_INFINITY;
				var max = Number.NEGATIVE_INFINITY;

				helpers$1.each(chart.data.datasets, function(dataset, datasetIndex) {
					if (chart.isDatasetVisible(datasetIndex)) {
						var meta = chart.getDatasetMeta(datasetIndex);

						helpers$1.each(dataset.data, function(rawValue, index) {
							var value = +me.getRightValue(rawValue);
							if (isNaN(value) || meta.data[index].hidden) {
								return;
							}

							min = Math.min(value, min);
							max = Math.max(value, max);
						});
					}
				});

				me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
				me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);

				// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
				me.handleTickRangeOptions();
			},
			getTickLimit: function() {
				var tickOpts = this.options.ticks;
				var tickFontSize = helpers$1.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
				return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
			},
			convertTicksToLabels: function() {
				var me = this;

				Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);

				// Point labels
				me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
			},
			getLabelForIndex: function(index, datasetIndex) {
				return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
			},
			fit: function() {
				if (this.options.pointLabels.display) {
					fitWithPointLabels(this);
				} else {
					fit(this);
				}
			},
			/**
			 * Set radius reductions and determine new radius and center point
			 * @private
			 */
			setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
				var me = this;
				var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
				var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
				var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
				var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);

				radiusReductionLeft = numberOrZero(radiusReductionLeft);
				radiusReductionRight = numberOrZero(radiusReductionRight);
				radiusReductionTop = numberOrZero(radiusReductionTop);
				radiusReductionBottom = numberOrZero(radiusReductionBottom);

				me.drawingArea = Math.min(
					Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
					Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
				me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
			},
			setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
				var me = this;
				var maxRight = me.width - rightMovement - me.drawingArea;
				var maxLeft = leftMovement + me.drawingArea;
				var maxTop = topMovement + me.drawingArea;
				var maxBottom = me.height - bottomMovement - me.drawingArea;

				me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
				me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
			},

			getIndexAngle: function(index) {
				var angleMultiplier = (Math.PI * 2) / getValueCount(this);
				var startAngle = this.chart.options && this.chart.options.startAngle ?
					this.chart.options.startAngle :
					0;

				var startAngleRadians = startAngle * Math.PI * 2 / 360;

				// Start from the top instead of right, so remove a quarter of the circle
				return index * angleMultiplier + startAngleRadians;
			},
			getDistanceFromCenterForValue: function(value) {
				var me = this;

				if (value === null) {
					return 0; // null always in center
				}

				// Take into account half font size + the yPadding of the top value
				var scalingFactor = me.drawingArea / (me.max - me.min);
				if (me.options.ticks.reverse) {
					return (me.max - value) * scalingFactor;
				}
				return (value - me.min) * scalingFactor;
			},
			getPointPosition: function(index, distanceFromCenter) {
				var me = this;
				var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
				return {
					x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
					y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
				};
			},
			getPointPositionForValue: function(index, value) {
				return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
			},

			getBasePosition: function() {
				var me = this;
				var min = me.min;
				var max = me.max;

				return me.getPointPositionForValue(0,
					me.beginAtZero ? 0 :
					min < 0 && max < 0 ? max :
					min > 0 && max > 0 ? min :
					0);
			},

			draw: function() {
				var me = this;
				var opts = me.options;
				var gridLineOpts = opts.gridLines;
				var tickOpts = opts.ticks;
				var valueOrDefault = helpers$1.valueOrDefault;

				if (opts.display) {
					var ctx = me.ctx;
					var startAngle = this.getIndexAngle(0);

					// Tick Font
					var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
					var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
					var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
					var tickLabelFont = helpers$1.fontString(tickFontSize, tickFontStyle, tickFontFamily);

					helpers$1.each(me.ticks, function(label, index) {
						// Don't draw a centre value (if it is minimum)
						if (index > 0 || tickOpts.reverse) {
							var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);

							// Draw circular lines around the scale
							if (gridLineOpts.display && index !== 0) {
								drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
							}

							if (tickOpts.display) {
								var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
								ctx.font = tickLabelFont;

								ctx.save();
								ctx.translate(me.xCenter, me.yCenter);
								ctx.rotate(startAngle);

								if (tickOpts.showLabelBackdrop) {
									var labelWidth = ctx.measureText(label).width;
									ctx.fillStyle = tickOpts.backdropColor;
									ctx.fillRect(
										-labelWidth / 2 - tickOpts.backdropPaddingX,
										-yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY,
										labelWidth + tickOpts.backdropPaddingX * 2,
										tickFontSize + tickOpts.backdropPaddingY * 2
									);
								}

								ctx.textAlign = 'center';
								ctx.textBaseline = 'middle';
								ctx.fillStyle = tickFontColor;
								ctx.fillText(label, 0, -yCenterOffset);
								ctx.restore();
							}
						}
					});

					if (opts.angleLines.display || opts.pointLabels.display) {
						drawPointLabels(me);
					}
				}
			}
		});
		Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);

	};

	var moment = createCommonjsModule(function (module, exports) {
	(function (global, factory) {
	     module.exports = factory() ;
	}(commonjsGlobal, (function () {
	    var hookCallback;

	    function hooks () {
	        return hookCallback.apply(null, arguments);
	    }

	    // This is done to register the method called with moment()
	    // without creating circular dependencies.
	    function setHookCallback (callback) {
	        hookCallback = callback;
	    }

	    function isArray(input) {
	        return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
	    }

	    function isObject(input) {
	        // IE8 will treat undefined and null as object if it wasn't for
	        // input != null
	        return input != null && Object.prototype.toString.call(input) === '[object Object]';
	    }

	    function isObjectEmpty(obj) {
	        if (Object.getOwnPropertyNames) {
	            return (Object.getOwnPropertyNames(obj).length === 0);
	        } else {
	            var k;
	            for (k in obj) {
	                if (obj.hasOwnProperty(k)) {
	                    return false;
	                }
	            }
	            return true;
	        }
	    }

	    function isUndefined(input) {
	        return input === void 0;
	    }

	    function isNumber(input) {
	        return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
	    }

	    function isDate(input) {
	        return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
	    }

	    function map(arr, fn) {
	        var res = [], i;
	        for (i = 0; i < arr.length; ++i) {
	            res.push(fn(arr[i], i));
	        }
	        return res;
	    }

	    function hasOwnProp(a, b) {
	        return Object.prototype.hasOwnProperty.call(a, b);
	    }

	    function extend(a, b) {
	        for (var i in b) {
	            if (hasOwnProp(b, i)) {
	                a[i] = b[i];
	            }
	        }

	        if (hasOwnProp(b, 'toString')) {
	            a.toString = b.toString;
	        }

	        if (hasOwnProp(b, 'valueOf')) {
	            a.valueOf = b.valueOf;
	        }

	        return a;
	    }

	    function createUTC (input, format, locale, strict) {
	        return createLocalOrUTC(input, format, locale, strict, true).utc();
	    }

	    function defaultParsingFlags() {
	        // We need to deep clone this object.
	        return {
	            empty           : false,
	            unusedTokens    : [],
	            unusedInput     : [],
	            overflow        : -2,
	            charsLeftOver   : 0,
	            nullInput       : false,
	            invalidMonth    : null,
	            invalidFormat   : false,
	            userInvalidated : false,
	            iso             : false,
	            parsedDateParts : [],
	            meridiem        : null,
	            rfc2822         : false,
	            weekdayMismatch : false
	        };
	    }

	    function getParsingFlags(m) {
	        if (m._pf == null) {
	            m._pf = defaultParsingFlags();
	        }
	        return m._pf;
	    }

	    var some;
	    if (Array.prototype.some) {
	        some = Array.prototype.some;
	    } else {
	        some = function (fun) {
	            var t = Object(this);
	            var len = t.length >>> 0;

	            for (var i = 0; i < len; i++) {
	                if (i in t && fun.call(this, t[i], i, t)) {
	                    return true;
	                }
	            }

	            return false;
	        };
	    }

	    function isValid(m) {
	        if (m._isValid == null) {
	            var flags = getParsingFlags(m);
	            var parsedParts = some.call(flags.parsedDateParts, function (i) {
	                return i != null;
	            });
	            var isNowValid = !isNaN(m._d.getTime()) &&
	                flags.overflow < 0 &&
	                !flags.empty &&
	                !flags.invalidMonth &&
	                !flags.invalidWeekday &&
	                !flags.weekdayMismatch &&
	                !flags.nullInput &&
	                !flags.invalidFormat &&
	                !flags.userInvalidated &&
	                (!flags.meridiem || (flags.meridiem && parsedParts));

	            if (m._strict) {
	                isNowValid = isNowValid &&
	                    flags.charsLeftOver === 0 &&
	                    flags.unusedTokens.length === 0 &&
	                    flags.bigHour === undefined;
	            }

	            if (Object.isFrozen == null || !Object.isFrozen(m)) {
	                m._isValid = isNowValid;
	            }
	            else {
	                return isNowValid;
	            }
	        }
	        return m._isValid;
	    }

	    function createInvalid (flags) {
	        var m = createUTC(NaN);
	        if (flags != null) {
	            extend(getParsingFlags(m), flags);
	        }
	        else {
	            getParsingFlags(m).userInvalidated = true;
	        }

	        return m;
	    }

	    // Plugins that add properties should also add the key here (null value),
	    // so we can properly clone ourselves.
	    var momentProperties = hooks.momentProperties = [];

	    function copyConfig(to, from) {
	        var i, prop, val;

	        if (!isUndefined(from._isAMomentObject)) {
	            to._isAMomentObject = from._isAMomentObject;
	        }
	        if (!isUndefined(from._i)) {
	            to._i = from._i;
	        }
	        if (!isUndefined(from._f)) {
	            to._f = from._f;
	        }
	        if (!isUndefined(from._l)) {
	            to._l = from._l;
	        }
	        if (!isUndefined(from._strict)) {
	            to._strict = from._strict;
	        }
	        if (!isUndefined(from._tzm)) {
	            to._tzm = from._tzm;
	        }
	        if (!isUndefined(from._isUTC)) {
	            to._isUTC = from._isUTC;
	        }
	        if (!isUndefined(from._offset)) {
	            to._offset = from._offset;
	        }
	        if (!isUndefined(from._pf)) {
	            to._pf = getParsingFlags(from);
	        }
	        if (!isUndefined(from._locale)) {
	            to._locale = from._locale;
	        }

	        if (momentProperties.length > 0) {
	            for (i = 0; i < momentProperties.length; i++) {
	                prop = momentProperties[i];
	                val = from[prop];
	                if (!isUndefined(val)) {
	                    to[prop] = val;
	                }
	            }
	        }

	        return to;
	    }

	    var updateInProgress = false;

	    // Moment prototype object
	    function Moment(config) {
	        copyConfig(this, config);
	        this._d = new Date(config._d != null ? config._d.getTime() : NaN);
	        if (!this.isValid()) {
	            this._d = new Date(NaN);
	        }
	        // Prevent infinite loop in case updateOffset creates new moment
	        // objects.
	        if (updateInProgress === false) {
	            updateInProgress = true;
	            hooks.updateOffset(this);
	            updateInProgress = false;
	        }
	    }

	    function isMoment (obj) {
	        return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
	    }

	    function absFloor (number) {
	        if (number < 0) {
	            // -0 -> 0
	            return Math.ceil(number) || 0;
	        } else {
	            return Math.floor(number);
	        }
	    }

	    function toInt(argumentForCoercion) {
	        var coercedNumber = +argumentForCoercion,
	            value = 0;

	        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
	            value = absFloor(coercedNumber);
	        }

	        return value;
	    }

	    // compare two arrays, return the number of differences
	    function compareArrays(array1, array2, dontConvert) {
	        var len = Math.min(array1.length, array2.length),
	            lengthDiff = Math.abs(array1.length - array2.length),
	            diffs = 0,
	            i;
	        for (i = 0; i < len; i++) {
	            if ((dontConvert && array1[i] !== array2[i]) ||
	                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
	                diffs++;
	            }
	        }
	        return diffs + lengthDiff;
	    }

	    function warn(msg) {
	        if (hooks.suppressDeprecationWarnings === false &&
	                (typeof console !==  'undefined') && console.warn) {
	            console.warn('Deprecation warning: ' + msg);
	        }
	    }

	    function deprecate(msg, fn) {
	        var firstTime = true;

	        return extend(function () {
	            if (hooks.deprecationHandler != null) {
	                hooks.deprecationHandler(null, msg);
	            }
	            if (firstTime) {
	                var args = [];
	                var arg;
	                for (var i = 0; i < arguments.length; i++) {
	                    arg = '';
	                    if (typeof arguments[i] === 'object') {
	                        arg += '\n[' + i + '] ';
	                        for (var key in arguments[0]) {
	                            arg += key + ': ' + arguments[0][key] + ', ';
	                        }
	                        arg = arg.slice(0, -2); // Remove trailing comma and space
	                    } else {
	                        arg = arguments[i];
	                    }
	                    args.push(arg);
	                }
	                warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
	                firstTime = false;
	            }
	            return fn.apply(this, arguments);
	        }, fn);
	    }

	    var deprecations = {};

	    function deprecateSimple(name, msg) {
	        if (hooks.deprecationHandler != null) {
	            hooks.deprecationHandler(name, msg);
	        }
	        if (!deprecations[name]) {
	            warn(msg);
	            deprecations[name] = true;
	        }
	    }

	    hooks.suppressDeprecationWarnings = false;
	    hooks.deprecationHandler = null;

	    function isFunction(input) {
	        return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
	    }

	    function set (config) {
	        var prop, i;
	        for (i in config) {
	            prop = config[i];
	            if (isFunction(prop)) {
	                this[i] = prop;
	            } else {
	                this['_' + i] = prop;
	            }
	        }
	        this._config = config;
	        // Lenient ordinal parsing accepts just a number in addition to
	        // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
	        // TODO: Remove "ordinalParse" fallback in next major release.
	        this._dayOfMonthOrdinalParseLenient = new RegExp(
	            (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
	                '|' + (/\d{1,2}/).source);
	    }

	    function mergeConfigs(parentConfig, childConfig) {
	        var res = extend({}, parentConfig), prop;
	        for (prop in childConfig) {
	            if (hasOwnProp(childConfig, prop)) {
	                if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
	                    res[prop] = {};
	                    extend(res[prop], parentConfig[prop]);
	                    extend(res[prop], childConfig[prop]);
	                } else if (childConfig[prop] != null) {
	                    res[prop] = childConfig[prop];
	                } else {
	                    delete res[prop];
	                }
	            }
	        }
	        for (prop in parentConfig) {
	            if (hasOwnProp(parentConfig, prop) &&
	                    !hasOwnProp(childConfig, prop) &&
	                    isObject(parentConfig[prop])) {
	                // make sure changes to properties don't modify parent config
	                res[prop] = extend({}, res[prop]);
	            }
	        }
	        return res;
	    }

	    function Locale(config) {
	        if (config != null) {
	            this.set(config);
	        }
	    }

	    var keys;

	    if (Object.keys) {
	        keys = Object.keys;
	    } else {
	        keys = function (obj) {
	            var i, res = [];
	            for (i in obj) {
	                if (hasOwnProp(obj, i)) {
	                    res.push(i);
	                }
	            }
	            return res;
	        };
	    }

	    var defaultCalendar = {
	        sameDay : '[Today at] LT',
	        nextDay : '[Tomorrow at] LT',
	        nextWeek : 'dddd [at] LT',
	        lastDay : '[Yesterday at] LT',
	        lastWeek : '[Last] dddd [at] LT',
	        sameElse : 'L'
	    };

	    function calendar (key, mom, now) {
	        var output = this._calendar[key] || this._calendar['sameElse'];
	        return isFunction(output) ? output.call(mom, now) : output;
	    }

	    var defaultLongDateFormat = {
	        LTS  : 'h:mm:ss A',
	        LT   : 'h:mm A',
	        L    : 'MM/DD/YYYY',
	        LL   : 'MMMM D, YYYY',
	        LLL  : 'MMMM D, YYYY h:mm A',
	        LLLL : 'dddd, MMMM D, YYYY h:mm A'
	    };

	    function longDateFormat (key) {
	        var format = this._longDateFormat[key],
	            formatUpper = this._longDateFormat[key.toUpperCase()];

	        if (format || !formatUpper) {
	            return format;
	        }

	        this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
	            return val.slice(1);
	        });

	        return this._longDateFormat[key];
	    }

	    var defaultInvalidDate = 'Invalid date';

	    function invalidDate () {
	        return this._invalidDate;
	    }

	    var defaultOrdinal = '%d';
	    var defaultDayOfMonthOrdinalParse = /\d{1,2}/;

	    function ordinal (number) {
	        return this._ordinal.replace('%d', number);
	    }

	    var defaultRelativeTime = {
	        future : 'in %s',
	        past   : '%s ago',
	        s  : 'a few seconds',
	        ss : '%d seconds',
	        m  : 'a minute',
	        mm : '%d minutes',
	        h  : 'an hour',
	        hh : '%d hours',
	        d  : 'a day',
	        dd : '%d days',
	        M  : 'a month',
	        MM : '%d months',
	        y  : 'a year',
	        yy : '%d years'
	    };

	    function relativeTime (number, withoutSuffix, string, isFuture) {
	        var output = this._relativeTime[string];
	        return (isFunction(output)) ?
	            output(number, withoutSuffix, string, isFuture) :
	            output.replace(/%d/i, number);
	    }

	    function pastFuture (diff, output) {
	        var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
	        return isFunction(format) ? format(output) : format.replace(/%s/i, output);
	    }

	    var aliases = {};

	    function addUnitAlias (unit, shorthand) {
	        var lowerCase = unit.toLowerCase();
	        aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
	    }

	    function normalizeUnits(units) {
	        return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
	    }

	    function normalizeObjectUnits(inputObject) {
	        var normalizedInput = {},
	            normalizedProp,
	            prop;

	        for (prop in inputObject) {
	            if (hasOwnProp(inputObject, prop)) {
	                normalizedProp = normalizeUnits(prop);
	                if (normalizedProp) {
	                    normalizedInput[normalizedProp] = inputObject[prop];
	                }
	            }
	        }

	        return normalizedInput;
	    }

	    var priorities = {};

	    function addUnitPriority(unit, priority) {
	        priorities[unit] = priority;
	    }

	    function getPrioritizedUnits(unitsObj) {
	        var units = [];
	        for (var u in unitsObj) {
	            units.push({unit: u, priority: priorities[u]});
	        }
	        units.sort(function (a, b) {
	            return a.priority - b.priority;
	        });
	        return units;
	    }

	    function zeroFill(number, targetLength, forceSign) {
	        var absNumber = '' + Math.abs(number),
	            zerosToFill = targetLength - absNumber.length,
	            sign = number >= 0;
	        return (sign ? (forceSign ? '+' : '') : '-') +
	            Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
	    }

	    var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;

	    var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;

	    var formatFunctions = {};

	    var formatTokenFunctions = {};

	    // token:    'M'
	    // padded:   ['MM', 2]
	    // ordinal:  'Mo'
	    // callback: function () { this.month() + 1 }
	    function addFormatToken (token, padded, ordinal, callback) {
	        var func = callback;
	        if (typeof callback === 'string') {
	            func = function () {
	                return this[callback]();
	            };
	        }
	        if (token) {
	            formatTokenFunctions[token] = func;
	        }
	        if (padded) {
	            formatTokenFunctions[padded[0]] = function () {
	                return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
	            };
	        }
	        if (ordinal) {
	            formatTokenFunctions[ordinal] = function () {
	                return this.localeData().ordinal(func.apply(this, arguments), token);
	            };
	        }
	    }

	    function removeFormattingTokens(input) {
	        if (input.match(/\[[\s\S]/)) {
	            return input.replace(/^\[|\]$/g, '');
	        }
	        return input.replace(/\\/g, '');
	    }

	    function makeFormatFunction(format) {
	        var array = format.match(formattingTokens), i, length;

	        for (i = 0, length = array.length; i < length; i++) {
	            if (formatTokenFunctions[array[i]]) {
	                array[i] = formatTokenFunctions[array[i]];
	            } else {
	                array[i] = removeFormattingTokens(array[i]);
	            }
	        }

	        return function (mom) {
	            var output = '', i;
	            for (i = 0; i < length; i++) {
	                output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
	            }
	            return output;
	        };
	    }

	    // format date using native date object
	    function formatMoment(m, format) {
	        if (!m.isValid()) {
	            return m.localeData().invalidDate();
	        }

	        format = expandFormat(format, m.localeData());
	        formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);

	        return formatFunctions[format](m);
	    }

	    function expandFormat(format, locale) {
	        var i = 5;

	        function replaceLongDateFormatTokens(input) {
	            return locale.longDateFormat(input) || input;
	        }

	        localFormattingTokens.lastIndex = 0;
	        while (i >= 0 && localFormattingTokens.test(format)) {
	            format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
	            localFormattingTokens.lastIndex = 0;
	            i -= 1;
	        }

	        return format;
	    }

	    var match1         = /\d/;            //       0 - 9
	    var match2         = /\d\d/;          //      00 - 99
	    var match3         = /\d{3}/;         //     000 - 999
	    var match4         = /\d{4}/;         //    0000 - 9999
	    var match6         = /[+-]?\d{6}/;    // -999999 - 999999
	    var match1to2      = /\d\d?/;         //       0 - 99
	    var match3to4      = /\d\d\d\d?/;     //     999 - 9999
	    var match5to6      = /\d\d\d\d\d\d?/; //   99999 - 999999
	    var match1to3      = /\d{1,3}/;       //       0 - 999
	    var match1to4      = /\d{1,4}/;       //       0 - 9999
	    var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999

	    var matchUnsigned  = /\d+/;           //       0 - inf
	    var matchSigned    = /[+-]?\d+/;      //    -inf - inf

	    var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
	    var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z

	    var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123

	    // any word (or two) characters or numbers including two/three word month in arabic.
	    // includes scottish gaelic two word and hyphenated months
	    var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;

	    var regexes = {};

	    function addRegexToken (token, regex, strictRegex) {
	        regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
	            return (isStrict && strictRegex) ? strictRegex : regex;
	        };
	    }

	    function getParseRegexForToken (token, config) {
	        if (!hasOwnProp(regexes, token)) {
	            return new RegExp(unescapeFormat(token));
	        }

	        return regexes[token](config._strict, config._locale);
	    }

	    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
	    function unescapeFormat(s) {
	        return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
	            return p1 || p2 || p3 || p4;
	        }));
	    }

	    function regexEscape(s) {
	        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
	    }

	    var tokens = {};

	    function addParseToken (token, callback) {
	        var i, func = callback;
	        if (typeof token === 'string') {
	            token = [token];
	        }
	        if (isNumber(callback)) {
	            func = function (input, array) {
	                array[callback] = toInt(input);
	            };
	        }
	        for (i = 0; i < token.length; i++) {
	            tokens[token[i]] = func;
	        }
	    }

	    function addWeekParseToken (token, callback) {
	        addParseToken(token, function (input, array, config, token) {
	            config._w = config._w || {};
	            callback(input, config._w, config, token);
	        });
	    }

	    function addTimeToArrayFromToken(token, input, config) {
	        if (input != null && hasOwnProp(tokens, token)) {
	            tokens[token](input, config._a, config, token);
	        }
	    }

	    var YEAR = 0;
	    var MONTH = 1;
	    var DATE = 2;
	    var HOUR = 3;
	    var MINUTE = 4;
	    var SECOND = 5;
	    var MILLISECOND = 6;
	    var WEEK = 7;
	    var WEEKDAY = 8;

	    // FORMATTING

	    addFormatToken('Y', 0, 0, function () {
	        var y = this.year();
	        return y <= 9999 ? '' + y : '+' + y;
	    });

	    addFormatToken(0, ['YY', 2], 0, function () {
	        return this.year() % 100;
	    });

	    addFormatToken(0, ['YYYY',   4],       0, 'year');
	    addFormatToken(0, ['YYYYY',  5],       0, 'year');
	    addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');

	    // ALIASES

	    addUnitAlias('year', 'y');

	    // PRIORITIES

	    addUnitPriority('year', 1);

	    // PARSING

	    addRegexToken('Y',      matchSigned);
	    addRegexToken('YY',     match1to2, match2);
	    addRegexToken('YYYY',   match1to4, match4);
	    addRegexToken('YYYYY',  match1to6, match6);
	    addRegexToken('YYYYYY', match1to6, match6);

	    addParseToken(['YYYYY', 'YYYYYY'], YEAR);
	    addParseToken('YYYY', function (input, array) {
	        array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
	    });
	    addParseToken('YY', function (input, array) {
	        array[YEAR] = hooks.parseTwoDigitYear(input);
	    });
	    addParseToken('Y', function (input, array) {
	        array[YEAR] = parseInt(input, 10);
	    });

	    // HELPERS

	    function daysInYear(year) {
	        return isLeapYear(year) ? 366 : 365;
	    }

	    function isLeapYear(year) {
	        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
	    }

	    // HOOKS

	    hooks.parseTwoDigitYear = function (input) {
	        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
	    };

	    // MOMENTS

	    var getSetYear = makeGetSet('FullYear', true);

	    function getIsLeapYear () {
	        return isLeapYear(this.year());
	    }

	    function makeGetSet (unit, keepTime) {
	        return function (value) {
	            if (value != null) {
	                set$1(this, unit, value);
	                hooks.updateOffset(this, keepTime);
	                return this;
	            } else {
	                return get(this, unit);
	            }
	        };
	    }

	    function get (mom, unit) {
	        return mom.isValid() ?
	            mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
	    }

	    function set$1 (mom, unit, value) {
	        if (mom.isValid() && !isNaN(value)) {
	            if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
	                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
	            }
	            else {
	                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
	            }
	        }
	    }

	    // MOMENTS

	    function stringGet (units) {
	        units = normalizeUnits(units);
	        if (isFunction(this[units])) {
	            return this[units]();
	        }
	        return this;
	    }


	    function stringSet (units, value) {
	        if (typeof units === 'object') {
	            units = normalizeObjectUnits(units);
	            var prioritized = getPrioritizedUnits(units);
	            for (var i = 0; i < prioritized.length; i++) {
	                this[prioritized[i].unit](units[prioritized[i].unit]);
	            }
	        } else {
	            units = normalizeUnits(units);
	            if (isFunction(this[units])) {
	                return this[units](value);
	            }
	        }
	        return this;
	    }

	    function mod(n, x) {
	        return ((n % x) + x) % x;
	    }

	    var indexOf;

	    if (Array.prototype.indexOf) {
	        indexOf = Array.prototype.indexOf;
	    } else {
	        indexOf = function (o) {
	            // I know
	            var i;
	            for (i = 0; i < this.length; ++i) {
	                if (this[i] === o) {
	                    return i;
	                }
	            }
	            return -1;
	        };
	    }

	    function daysInMonth(year, month) {
	        if (isNaN(year) || isNaN(month)) {
	            return NaN;
	        }
	        var modMonth = mod(month, 12);
	        year += (month - modMonth) / 12;
	        return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
	    }

	    // FORMATTING

	    addFormatToken('M', ['MM', 2], 'Mo', function () {
	        return this.month() + 1;
	    });

	    addFormatToken('MMM', 0, 0, function (format) {
	        return this.localeData().monthsShort(this, format);
	    });

	    addFormatToken('MMMM', 0, 0, function (format) {
	        return this.localeData().months(this, format);
	    });

	    // ALIASES

	    addUnitAlias('month', 'M');

	    // PRIORITY

	    addUnitPriority('month', 8);

	    // PARSING

	    addRegexToken('M',    match1to2);
	    addRegexToken('MM',   match1to2, match2);
	    addRegexToken('MMM',  function (isStrict, locale) {
	        return locale.monthsShortRegex(isStrict);
	    });
	    addRegexToken('MMMM', function (isStrict, locale) {
	        return locale.monthsRegex(isStrict);
	    });

	    addParseToken(['M', 'MM'], function (input, array) {
	        array[MONTH] = toInt(input) - 1;
	    });

	    addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
	        var month = config._locale.monthsParse(input, token, config._strict);
	        // if we didn't find a month name, mark the date as invalid.
	        if (month != null) {
	            array[MONTH] = month;
	        } else {
	            getParsingFlags(config).invalidMonth = input;
	        }
	    });

	    // LOCALES

	    var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
	    var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
	    function localeMonths (m, format) {
	        if (!m) {
	            return isArray(this._months) ? this._months :
	                this._months['standalone'];
	        }
	        return isArray(this._months) ? this._months[m.month()] :
	            this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
	    }

	    var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
	    function localeMonthsShort (m, format) {
	        if (!m) {
	            return isArray(this._monthsShort) ? this._monthsShort :
	                this._monthsShort['standalone'];
	        }
	        return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
	            this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
	    }

	    function handleStrictParse(monthName, format, strict) {
	        var i, ii, mom, llc = monthName.toLocaleLowerCase();
	        if (!this._monthsParse) {
	            // this is not used
	            this._monthsParse = [];
	            this._longMonthsParse = [];
	            this._shortMonthsParse = [];
	            for (i = 0; i < 12; ++i) {
	                mom = createUTC([2000, i]);
	                this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
	                this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
	            }
	        }

	        if (strict) {
	            if (format === 'MMM') {
	                ii = indexOf.call(this._shortMonthsParse, llc);
	                return ii !== -1 ? ii : null;
	            } else {
	                ii = indexOf.call(this._longMonthsParse, llc);
	                return ii !== -1 ? ii : null;
	            }
	        } else {
	            if (format === 'MMM') {
	                ii = indexOf.call(this._shortMonthsParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._longMonthsParse, llc);
	                return ii !== -1 ? ii : null;
	            } else {
	                ii = indexOf.call(this._longMonthsParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._shortMonthsParse, llc);
	                return ii !== -1 ? ii : null;
	            }
	        }
	    }

	    function localeMonthsParse (monthName, format, strict) {
	        var i, mom, regex;

	        if (this._monthsParseExact) {
	            return handleStrictParse.call(this, monthName, format, strict);
	        }

	        if (!this._monthsParse) {
	            this._monthsParse = [];
	            this._longMonthsParse = [];
	            this._shortMonthsParse = [];
	        }

	        // TODO: add sorting
	        // Sorting makes sure if one month (or abbr) is a prefix of another
	        // see sorting in computeMonthsParse
	        for (i = 0; i < 12; i++) {
	            // make the regex if we don't have it already
	            mom = createUTC([2000, i]);
	            if (strict && !this._longMonthsParse[i]) {
	                this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
	                this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
	            }
	            if (!strict && !this._monthsParse[i]) {
	                regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
	                this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
	            }
	            // test the regex
	            if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
	                return i;
	            } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
	                return i;
	            } else if (!strict && this._monthsParse[i].test(monthName)) {
	                return i;
	            }
	        }
	    }

	    // MOMENTS

	    function setMonth (mom, value) {
	        var dayOfMonth;

	        if (!mom.isValid()) {
	            // No op
	            return mom;
	        }

	        if (typeof value === 'string') {
	            if (/^\d+$/.test(value)) {
	                value = toInt(value);
	            } else {
	                value = mom.localeData().monthsParse(value);
	                // TODO: Another silent failure?
	                if (!isNumber(value)) {
	                    return mom;
	                }
	            }
	        }

	        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
	        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
	        return mom;
	    }

	    function getSetMonth (value) {
	        if (value != null) {
	            setMonth(this, value);
	            hooks.updateOffset(this, true);
	            return this;
	        } else {
	            return get(this, 'Month');
	        }
	    }

	    function getDaysInMonth () {
	        return daysInMonth(this.year(), this.month());
	    }

	    var defaultMonthsShortRegex = matchWord;
	    function monthsShortRegex (isStrict) {
	        if (this._monthsParseExact) {
	            if (!hasOwnProp(this, '_monthsRegex')) {
	                computeMonthsParse.call(this);
	            }
	            if (isStrict) {
	                return this._monthsShortStrictRegex;
	            } else {
	                return this._monthsShortRegex;
	            }
	        } else {
	            if (!hasOwnProp(this, '_monthsShortRegex')) {
	                this._monthsShortRegex = defaultMonthsShortRegex;
	            }
	            return this._monthsShortStrictRegex && isStrict ?
	                this._monthsShortStrictRegex : this._monthsShortRegex;
	        }
	    }

	    var defaultMonthsRegex = matchWord;
	    function monthsRegex (isStrict) {
	        if (this._monthsParseExact) {
	            if (!hasOwnProp(this, '_monthsRegex')) {
	                computeMonthsParse.call(this);
	            }
	            if (isStrict) {
	                return this._monthsStrictRegex;
	            } else {
	                return this._monthsRegex;
	            }
	        } else {
	            if (!hasOwnProp(this, '_monthsRegex')) {
	                this._monthsRegex = defaultMonthsRegex;
	            }
	            return this._monthsStrictRegex && isStrict ?
	                this._monthsStrictRegex : this._monthsRegex;
	        }
	    }

	    function computeMonthsParse () {
	        function cmpLenRev(a, b) {
	            return b.length - a.length;
	        }

	        var shortPieces = [], longPieces = [], mixedPieces = [],
	            i, mom;
	        for (i = 0; i < 12; i++) {
	            // make the regex if we don't have it already
	            mom = createUTC([2000, i]);
	            shortPieces.push(this.monthsShort(mom, ''));
	            longPieces.push(this.months(mom, ''));
	            mixedPieces.push(this.months(mom, ''));
	            mixedPieces.push(this.monthsShort(mom, ''));
	        }
	        // Sorting makes sure if one month (or abbr) is a prefix of another it
	        // will match the longer piece.
	        shortPieces.sort(cmpLenRev);
	        longPieces.sort(cmpLenRev);
	        mixedPieces.sort(cmpLenRev);
	        for (i = 0; i < 12; i++) {
	            shortPieces[i] = regexEscape(shortPieces[i]);
	            longPieces[i] = regexEscape(longPieces[i]);
	        }
	        for (i = 0; i < 24; i++) {
	            mixedPieces[i] = regexEscape(mixedPieces[i]);
	        }

	        this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
	        this._monthsShortRegex = this._monthsRegex;
	        this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
	        this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
	    }

	    function createDate (y, m, d, h, M, s, ms) {
	        // can't just apply() to create a date:
	        // https://stackoverflow.com/q/181348
	        var date = new Date(y, m, d, h, M, s, ms);

	        // the date constructor remaps years 0-99 to 1900-1999
	        if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
	            date.setFullYear(y);
	        }
	        return date;
	    }

	    function createUTCDate (y) {
	        var date = new Date(Date.UTC.apply(null, arguments));

	        // the Date.UTC function remaps years 0-99 to 1900-1999
	        if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
	            date.setUTCFullYear(y);
	        }
	        return date;
	    }

	    // start-of-first-week - start-of-year
	    function firstWeekOffset(year, dow, doy) {
	        var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
	            fwd = 7 + dow - doy,
	            // first-week day local weekday -- which local weekday is fwd
	            fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;

	        return -fwdlw + fwd - 1;
	    }

	    // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
	    function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
	        var localWeekday = (7 + weekday - dow) % 7,
	            weekOffset = firstWeekOffset(year, dow, doy),
	            dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
	            resYear, resDayOfYear;

	        if (dayOfYear <= 0) {
	            resYear = year - 1;
	            resDayOfYear = daysInYear(resYear) + dayOfYear;
	        } else if (dayOfYear > daysInYear(year)) {
	            resYear = year + 1;
	            resDayOfYear = dayOfYear - daysInYear(year);
	        } else {
	            resYear = year;
	            resDayOfYear = dayOfYear;
	        }

	        return {
	            year: resYear,
	            dayOfYear: resDayOfYear
	        };
	    }

	    function weekOfYear(mom, dow, doy) {
	        var weekOffset = firstWeekOffset(mom.year(), dow, doy),
	            week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
	            resWeek, resYear;

	        if (week < 1) {
	            resYear = mom.year() - 1;
	            resWeek = week + weeksInYear(resYear, dow, doy);
	        } else if (week > weeksInYear(mom.year(), dow, doy)) {
	            resWeek = week - weeksInYear(mom.year(), dow, doy);
	            resYear = mom.year() + 1;
	        } else {
	            resYear = mom.year();
	            resWeek = week;
	        }

	        return {
	            week: resWeek,
	            year: resYear
	        };
	    }

	    function weeksInYear(year, dow, doy) {
	        var weekOffset = firstWeekOffset(year, dow, doy),
	            weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
	        return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
	    }

	    // FORMATTING

	    addFormatToken('w', ['ww', 2], 'wo', 'week');
	    addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');

	    // ALIASES

	    addUnitAlias('week', 'w');
	    addUnitAlias('isoWeek', 'W');

	    // PRIORITIES

	    addUnitPriority('week', 5);
	    addUnitPriority('isoWeek', 5);

	    // PARSING

	    addRegexToken('w',  match1to2);
	    addRegexToken('ww', match1to2, match2);
	    addRegexToken('W',  match1to2);
	    addRegexToken('WW', match1to2, match2);

	    addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
	        week[token.substr(0, 1)] = toInt(input);
	    });

	    // HELPERS

	    // LOCALES

	    function localeWeek (mom) {
	        return weekOfYear(mom, this._week.dow, this._week.doy).week;
	    }

	    var defaultLocaleWeek = {
	        dow : 0, // Sunday is the first day of the week.
	        doy : 6  // The week that contains Jan 1st is the first week of the year.
	    };

	    function localeFirstDayOfWeek () {
	        return this._week.dow;
	    }

	    function localeFirstDayOfYear () {
	        return this._week.doy;
	    }

	    // MOMENTS

	    function getSetWeek (input) {
	        var week = this.localeData().week(this);
	        return input == null ? week : this.add((input - week) * 7, 'd');
	    }

	    function getSetISOWeek (input) {
	        var week = weekOfYear(this, 1, 4).week;
	        return input == null ? week : this.add((input - week) * 7, 'd');
	    }

	    // FORMATTING

	    addFormatToken('d', 0, 'do', 'day');

	    addFormatToken('dd', 0, 0, function (format) {
	        return this.localeData().weekdaysMin(this, format);
	    });

	    addFormatToken('ddd', 0, 0, function (format) {
	        return this.localeData().weekdaysShort(this, format);
	    });

	    addFormatToken('dddd', 0, 0, function (format) {
	        return this.localeData().weekdays(this, format);
	    });

	    addFormatToken('e', 0, 0, 'weekday');
	    addFormatToken('E', 0, 0, 'isoWeekday');

	    // ALIASES

	    addUnitAlias('day', 'd');
	    addUnitAlias('weekday', 'e');
	    addUnitAlias('isoWeekday', 'E');

	    // PRIORITY
	    addUnitPriority('day', 11);
	    addUnitPriority('weekday', 11);
	    addUnitPriority('isoWeekday', 11);

	    // PARSING

	    addRegexToken('d',    match1to2);
	    addRegexToken('e',    match1to2);
	    addRegexToken('E',    match1to2);
	    addRegexToken('dd',   function (isStrict, locale) {
	        return locale.weekdaysMinRegex(isStrict);
	    });
	    addRegexToken('ddd',   function (isStrict, locale) {
	        return locale.weekdaysShortRegex(isStrict);
	    });
	    addRegexToken('dddd',   function (isStrict, locale) {
	        return locale.weekdaysRegex(isStrict);
	    });

	    addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
	        var weekday = config._locale.weekdaysParse(input, token, config._strict);
	        // if we didn't get a weekday name, mark the date as invalid
	        if (weekday != null) {
	            week.d = weekday;
	        } else {
	            getParsingFlags(config).invalidWeekday = input;
	        }
	    });

	    addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
	        week[token] = toInt(input);
	    });

	    // HELPERS

	    function parseWeekday(input, locale) {
	        if (typeof input !== 'string') {
	            return input;
	        }

	        if (!isNaN(input)) {
	            return parseInt(input, 10);
	        }

	        input = locale.weekdaysParse(input);
	        if (typeof input === 'number') {
	            return input;
	        }

	        return null;
	    }

	    function parseIsoWeekday(input, locale) {
	        if (typeof input === 'string') {
	            return locale.weekdaysParse(input) % 7 || 7;
	        }
	        return isNaN(input) ? null : input;
	    }

	    // LOCALES

	    var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
	    function localeWeekdays (m, format) {
	        if (!m) {
	            return isArray(this._weekdays) ? this._weekdays :
	                this._weekdays['standalone'];
	        }
	        return isArray(this._weekdays) ? this._weekdays[m.day()] :
	            this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
	    }

	    var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
	    function localeWeekdaysShort (m) {
	        return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
	    }

	    var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
	    function localeWeekdaysMin (m) {
	        return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
	    }

	    function handleStrictParse$1(weekdayName, format, strict) {
	        var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
	        if (!this._weekdaysParse) {
	            this._weekdaysParse = [];
	            this._shortWeekdaysParse = [];
	            this._minWeekdaysParse = [];

	            for (i = 0; i < 7; ++i) {
	                mom = createUTC([2000, 1]).day(i);
	                this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
	                this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
	                this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
	            }
	        }

	        if (strict) {
	            if (format === 'dddd') {
	                ii = indexOf.call(this._weekdaysParse, llc);
	                return ii !== -1 ? ii : null;
	            } else if (format === 'ddd') {
	                ii = indexOf.call(this._shortWeekdaysParse, llc);
	                return ii !== -1 ? ii : null;
	            } else {
	                ii = indexOf.call(this._minWeekdaysParse, llc);
	                return ii !== -1 ? ii : null;
	            }
	        } else {
	            if (format === 'dddd') {
	                ii = indexOf.call(this._weekdaysParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._shortWeekdaysParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._minWeekdaysParse, llc);
	                return ii !== -1 ? ii : null;
	            } else if (format === 'ddd') {
	                ii = indexOf.call(this._shortWeekdaysParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._weekdaysParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._minWeekdaysParse, llc);
	                return ii !== -1 ? ii : null;
	            } else {
	                ii = indexOf.call(this._minWeekdaysParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._weekdaysParse, llc);
	                if (ii !== -1) {
	                    return ii;
	                }
	                ii = indexOf.call(this._shortWeekdaysParse, llc);
	                return ii !== -1 ? ii : null;
	            }
	        }
	    }

	    function localeWeekdaysParse (weekdayName, format, strict) {
	        var i, mom, regex;

	        if (this._weekdaysParseExact) {
	            return handleStrictParse$1.call(this, weekdayName, format, strict);
	        }

	        if (!this._weekdaysParse) {
	            this._weekdaysParse = [];
	            this._minWeekdaysParse = [];
	            this._shortWeekdaysParse = [];
	            this._fullWeekdaysParse = [];
	        }

	        for (i = 0; i < 7; i++) {
	            // make the regex if we don't have it already

	            mom = createUTC([2000, 1]).day(i);
	            if (strict && !this._fullWeekdaysParse[i]) {
	                this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');
	                this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');
	                this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');
	            }
	            if (!this._weekdaysParse[i]) {
	                regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
	                this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
	            }
	            // test the regex
	            if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
	                return i;
	            } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
	                return i;
	            } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
	                return i;
	            } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
	                return i;
	            }
	        }
	    }

	    // MOMENTS

	    function getSetDayOfWeek (input) {
	        if (!this.isValid()) {
	            return input != null ? this : NaN;
	        }
	        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
	        if (input != null) {
	            input = parseWeekday(input, this.localeData());
	            return this.add(input - day, 'd');
	        } else {
	            return day;
	        }
	    }

	    function getSetLocaleDayOfWeek (input) {
	        if (!this.isValid()) {
	            return input != null ? this : NaN;
	        }
	        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
	        return input == null ? weekday : this.add(input - weekday, 'd');
	    }

	    function getSetISODayOfWeek (input) {
	        if (!this.isValid()) {
	            return input != null ? this : NaN;
	        }

	        // behaves the same as moment#day except
	        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
	        // as a setter, sunday should belong to the previous week.

	        if (input != null) {
	            var weekday = parseIsoWeekday(input, this.localeData());
	            return this.day(this.day() % 7 ? weekday : weekday - 7);
	        } else {
	            return this.day() || 7;
	        }
	    }

	    var defaultWeekdaysRegex = matchWord;
	    function weekdaysRegex (isStrict) {
	        if (this._weekdaysParseExact) {
	            if (!hasOwnProp(this, '_weekdaysRegex')) {
	                computeWeekdaysParse.call(this);
	            }
	            if (isStrict) {
	                return this._weekdaysStrictRegex;
	            } else {
	                return this._weekdaysRegex;
	            }
	        } else {
	            if (!hasOwnProp(this, '_weekdaysRegex')) {
	                this._weekdaysRegex = defaultWeekdaysRegex;
	            }
	            return this._weekdaysStrictRegex && isStrict ?
	                this._weekdaysStrictRegex : this._weekdaysRegex;
	        }
	    }

	    var defaultWeekdaysShortRegex = matchWord;
	    function weekdaysShortRegex (isStrict) {
	        if (this._weekdaysParseExact) {
	            if (!hasOwnProp(this, '_weekdaysRegex')) {
	                computeWeekdaysParse.call(this);
	            }
	            if (isStrict) {
	                return this._weekdaysShortStrictRegex;
	            } else {
	                return this._weekdaysShortRegex;
	            }
	        } else {
	            if (!hasOwnProp(this, '_weekdaysShortRegex')) {
	                this._weekdaysShortRegex = defaultWeekdaysShortRegex;
	            }
	            return this._weekdaysShortStrictRegex && isStrict ?
	                this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
	        }
	    }

	    var defaultWeekdaysMinRegex = matchWord;
	    function weekdaysMinRegex (isStrict) {
	        if (this._weekdaysParseExact) {
	            if (!hasOwnProp(this, '_weekdaysRegex')) {
	                computeWeekdaysParse.call(this);
	            }
	            if (isStrict) {
	                return this._weekdaysMinStrictRegex;
	            } else {
	                return this._weekdaysMinRegex;
	            }
	        } else {
	            if (!hasOwnProp(this, '_weekdaysMinRegex')) {
	                this._weekdaysMinRegex = defaultWeekdaysMinRegex;
	            }
	            return this._weekdaysMinStrictRegex && isStrict ?
	                this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
	        }
	    }


	    function computeWeekdaysParse () {
	        function cmpLenRev(a, b) {
	            return b.length - a.length;
	        }

	        var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
	            i, mom, minp, shortp, longp;
	        for (i = 0; i < 7; i++) {
	            // make the regex if we don't have it already
	            mom = createUTC([2000, 1]).day(i);
	            minp = this.weekdaysMin(mom, '');
	            shortp = this.weekdaysShort(mom, '');
	            longp = this.weekdays(mom, '');
	            minPieces.push(minp);
	            shortPieces.push(shortp);
	            longPieces.push(longp);
	            mixedPieces.push(minp);
	            mixedPieces.push(shortp);
	            mixedPieces.push(longp);
	        }
	        // Sorting makes sure if one weekday (or abbr) is a prefix of another it
	        // will match the longer piece.
	        minPieces.sort(cmpLenRev);
	        shortPieces.sort(cmpLenRev);
	        longPieces.sort(cmpLenRev);
	        mixedPieces.sort(cmpLenRev);
	        for (i = 0; i < 7; i++) {
	            shortPieces[i] = regexEscape(shortPieces[i]);
	            longPieces[i] = regexEscape(longPieces[i]);
	            mixedPieces[i] = regexEscape(mixedPieces[i]);
	        }

	        this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
	        this._weekdaysShortRegex = this._weekdaysRegex;
	        this._weekdaysMinRegex = this._weekdaysRegex;

	        this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
	        this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
	        this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
	    }

	    // FORMATTING

	    function hFormat() {
	        return this.hours() % 12 || 12;
	    }

	    function kFormat() {
	        return this.hours() || 24;
	    }

	    addFormatToken('H', ['HH', 2], 0, 'hour');
	    addFormatToken('h', ['hh', 2], 0, hFormat);
	    addFormatToken('k', ['kk', 2], 0, kFormat);

	    addFormatToken('hmm', 0, 0, function () {
	        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
	    });

	    addFormatToken('hmmss', 0, 0, function () {
	        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
	            zeroFill(this.seconds(), 2);
	    });

	    addFormatToken('Hmm', 0, 0, function () {
	        return '' + this.hours() + zeroFill(this.minutes(), 2);
	    });

	    addFormatToken('Hmmss', 0, 0, function () {
	        return '' + this.hours() + zeroFill(this.minutes(), 2) +
	            zeroFill(this.seconds(), 2);
	    });

	    function meridiem (token, lowercase) {
	        addFormatToken(token, 0, 0, function () {
	            return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
	        });
	    }

	    meridiem('a', true);
	    meridiem('A', false);

	    // ALIASES

	    addUnitAlias('hour', 'h');

	    // PRIORITY
	    addUnitPriority('hour', 13);

	    // PARSING

	    function matchMeridiem (isStrict, locale) {
	        return locale._meridiemParse;
	    }

	    addRegexToken('a',  matchMeridiem);
	    addRegexToken('A',  matchMeridiem);
	    addRegexToken('H',  match1to2);
	    addRegexToken('h',  match1to2);
	    addRegexToken('k',  match1to2);
	    addRegexToken('HH', match1to2, match2);
	    addRegexToken('hh', match1to2, match2);
	    addRegexToken('kk', match1to2, match2);

	    addRegexToken('hmm', match3to4);
	    addRegexToken('hmmss', match5to6);
	    addRegexToken('Hmm', match3to4);
	    addRegexToken('Hmmss', match5to6);

	    addParseToken(['H', 'HH'], HOUR);
	    addParseToken(['k', 'kk'], function (input, array, config) {
	        var kInput = toInt(input);
	        array[HOUR] = kInput === 24 ? 0 : kInput;
	    });
	    addParseToken(['a', 'A'], function (input, array, config) {
	        config._isPm = config._locale.isPM(input);
	        config._meridiem = input;
	    });
	    addParseToken(['h', 'hh'], function (input, array, config) {
	        array[HOUR] = toInt(input);
	        getParsingFlags(config).bigHour = true;
	    });
	    addParseToken('hmm', function (input, array, config) {
	        var pos = input.length - 2;
	        array[HOUR] = toInt(input.substr(0, pos));
	        array[MINUTE] = toInt(input.substr(pos));
	        getParsingFlags(config).bigHour = true;
	    });
	    addParseToken('hmmss', function (input, array, config) {
	        var pos1 = input.length - 4;
	        var pos2 = input.length - 2;
	        array[HOUR] = toInt(input.substr(0, pos1));
	        array[MINUTE] = toInt(input.substr(pos1, 2));
	        array[SECOND] = toInt(input.substr(pos2));
	        getParsingFlags(config).bigHour = true;
	    });
	    addParseToken('Hmm', function (input, array, config) {
	        var pos = input.length - 2;
	        array[HOUR] = toInt(input.substr(0, pos));
	        array[MINUTE] = toInt(input.substr(pos));
	    });
	    addParseToken('Hmmss', function (input, array, config) {
	        var pos1 = input.length - 4;
	        var pos2 = input.length - 2;
	        array[HOUR] = toInt(input.substr(0, pos1));
	        array[MINUTE] = toInt(input.substr(pos1, 2));
	        array[SECOND] = toInt(input.substr(pos2));
	    });

	    // LOCALES

	    function localeIsPM (input) {
	        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
	        // Using charAt should be more compatible.
	        return ((input + '').toLowerCase().charAt(0) === 'p');
	    }

	    var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
	    function localeMeridiem (hours, minutes, isLower) {
	        if (hours > 11) {
	            return isLower ? 'pm' : 'PM';
	        } else {
	            return isLower ? 'am' : 'AM';
	        }
	    }


	    // MOMENTS

	    // Setting the hour should keep the time, because the user explicitly
	    // specified which hour they want. So trying to maintain the same hour (in
	    // a new timezone) makes sense. Adding/subtracting hours does not follow
	    // this rule.
	    var getSetHour = makeGetSet('Hours', true);

	    var baseConfig = {
	        calendar: defaultCalendar,
	        longDateFormat: defaultLongDateFormat,
	        invalidDate: defaultInvalidDate,
	        ordinal: defaultOrdinal,
	        dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
	        relativeTime: defaultRelativeTime,

	        months: defaultLocaleMonths,
	        monthsShort: defaultLocaleMonthsShort,

	        week: defaultLocaleWeek,

	        weekdays: defaultLocaleWeekdays,
	        weekdaysMin: defaultLocaleWeekdaysMin,
	        weekdaysShort: defaultLocaleWeekdaysShort,

	        meridiemParse: defaultLocaleMeridiemParse
	    };

	    // internal storage for locale config files
	    var locales = {};
	    var localeFamilies = {};
	    var globalLocale;

	    function normalizeLocale(key) {
	        return key ? key.toLowerCase().replace('_', '-') : key;
	    }

	    // pick the locale from the array
	    // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
	    // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
	    function chooseLocale(names) {
	        var i = 0, j, next, locale, split;

	        while (i < names.length) {
	            split = normalizeLocale(names[i]).split('-');
	            j = split.length;
	            next = normalizeLocale(names[i + 1]);
	            next = next ? next.split('-') : null;
	            while (j > 0) {
	                locale = loadLocale(split.slice(0, j).join('-'));
	                if (locale) {
	                    return locale;
	                }
	                if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
	                    //the next array item is better than a shallower substring of this one
	                    break;
	                }
	                j--;
	            }
	            i++;
	        }
	        return globalLocale;
	    }

	    function loadLocale(name) {
	        var oldLocale = null;
	        // TODO: Find a better way to register and load all the locales in Node
	        if (!locales[name] && ('object' !== 'undefined') &&
	                module && module.exports) {
	            try {
	                oldLocale = globalLocale._abbr;
	                var aliasedRequire = commonjsRequire;
	                aliasedRequire('./locale/' + name);
	                getSetGlobalLocale(oldLocale);
	            } catch (e) {}
	        }
	        return locales[name];
	    }

	    // This function will load locale and then set the global locale.  If
	    // no arguments are passed in, it will simply return the current global
	    // locale key.
	    function getSetGlobalLocale (key, values) {
	        var data;
	        if (key) {
	            if (isUndefined(values)) {
	                data = getLocale(key);
	            }
	            else {
	                data = defineLocale(key, values);
	            }

	            if (data) {
	                // moment.duration._locale = moment._locale = data;
	                globalLocale = data;
	            }
	            else {
	                if ((typeof console !==  'undefined') && console.warn) {
	                    //warn user if arguments are passed but the locale could not be set
	                    console.warn('Locale ' + key +  ' not found. Did you forget to load it?');
	                }
	            }
	        }

	        return globalLocale._abbr;
	    }

	    function defineLocale (name, config) {
	        if (config !== null) {
	            var locale, parentConfig = baseConfig;
	            config.abbr = name;
	            if (locales[name] != null) {
	                deprecateSimple('defineLocaleOverride',
	                        'use moment.updateLocale(localeName, config) to change ' +
	                        'an existing locale. moment.defineLocale(localeName, ' +
	                        'config) should only be used for creating a new locale ' +
	                        'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
	                parentConfig = locales[name]._config;
	            } else if (config.parentLocale != null) {
	                if (locales[config.parentLocale] != null) {
	                    parentConfig = locales[config.parentLocale]._config;
	                } else {
	                    locale = loadLocale(config.parentLocale);
	                    if (locale != null) {
	                        parentConfig = locale._config;
	                    } else {
	                        if (!localeFamilies[config.parentLocale]) {
	                            localeFamilies[config.parentLocale] = [];
	                        }
	                        localeFamilies[config.parentLocale].push({
	                            name: name,
	                            config: config
	                        });
	                        return null;
	                    }
	                }
	            }
	            locales[name] = new Locale(mergeConfigs(parentConfig, config));

	            if (localeFamilies[name]) {
	                localeFamilies[name].forEach(function (x) {
	                    defineLocale(x.name, x.config);
	                });
	            }

	            // backwards compat for now: also set the locale
	            // make sure we set the locale AFTER all child locales have been
	            // created, so we won't end up with the child locale set.
	            getSetGlobalLocale(name);


	            return locales[name];
	        } else {
	            // useful for testing
	            delete locales[name];
	            return null;
	        }
	    }

	    function updateLocale(name, config) {
	        if (config != null) {
	            var locale, tmpLocale, parentConfig = baseConfig;
	            // MERGE
	            tmpLocale = loadLocale(name);
	            if (tmpLocale != null) {
	                parentConfig = tmpLocale._config;
	            }
	            config = mergeConfigs(parentConfig, config);
	            locale = new Locale(config);
	            locale.parentLocale = locales[name];
	            locales[name] = locale;

	            // backwards compat for now: also set the locale
	            getSetGlobalLocale(name);
	        } else {
	            // pass null for config to unupdate, useful for tests
	            if (locales[name] != null) {
	                if (locales[name].parentLocale != null) {
	                    locales[name] = locales[name].parentLocale;
	                } else if (locales[name] != null) {
	                    delete locales[name];
	                }
	            }
	        }
	        return locales[name];
	    }

	    // returns locale data
	    function getLocale (key) {
	        var locale;

	        if (key && key._locale && key._locale._abbr) {
	            key = key._locale._abbr;
	        }

	        if (!key) {
	            return globalLocale;
	        }

	        if (!isArray(key)) {
	            //short-circuit everything else
	            locale = loadLocale(key);
	            if (locale) {
	                return locale;
	            }
	            key = [key];
	        }

	        return chooseLocale(key);
	    }

	    function listLocales() {
	        return keys(locales);
	    }

	    function checkOverflow (m) {
	        var overflow;
	        var a = m._a;

	        if (a && getParsingFlags(m).overflow === -2) {
	            overflow =
	                a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
	                a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
	                a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
	                a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
	                a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
	                a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
	                -1;

	            if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
	                overflow = DATE;
	            }
	            if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
	                overflow = WEEK;
	            }
	            if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
	                overflow = WEEKDAY;
	            }

	            getParsingFlags(m).overflow = overflow;
	        }

	        return m;
	    }

	    // Pick the first defined of two or three arguments.
	    function defaults(a, b, c) {
	        if (a != null) {
	            return a;
	        }
	        if (b != null) {
	            return b;
	        }
	        return c;
	    }

	    function currentDateArray(config) {
	        // hooks is actually the exported moment object
	        var nowValue = new Date(hooks.now());
	        if (config._useUTC) {
	            return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
	        }
	        return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
	    }

	    // convert an array to a date.
	    // the array should mirror the parameters below
	    // note: all values past the year are optional and will default to the lowest possible value.
	    // [year, month, day , hour, minute, second, millisecond]
	    function configFromArray (config) {
	        var i, date, input = [], currentDate, expectedWeekday, yearToUse;

	        if (config._d) {
	            return;
	        }

	        currentDate = currentDateArray(config);

	        //compute day of the year from weeks and weekdays
	        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
	            dayOfYearFromWeekInfo(config);
	        }

	        //if the day of the year is set, figure out what it is
	        if (config._dayOfYear != null) {
	            yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);

	            if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
	                getParsingFlags(config)._overflowDayOfYear = true;
	            }

	            date = createUTCDate(yearToUse, 0, config._dayOfYear);
	            config._a[MONTH] = date.getUTCMonth();
	            config._a[DATE] = date.getUTCDate();
	        }

	        // Default to current date.
	        // * if no year, month, day of month are given, default to today
	        // * if day of month is given, default month and year
	        // * if month is given, default only year
	        // * if year is given, don't default anything
	        for (i = 0; i < 3 && config._a[i] == null; ++i) {
	            config._a[i] = input[i] = currentDate[i];
	        }

	        // Zero out whatever was not defaulted, including time
	        for (; i < 7; i++) {
	            config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
	        }

	        // Check for 24:00:00.000
	        if (config._a[HOUR] === 24 &&
	                config._a[MINUTE] === 0 &&
	                config._a[SECOND] === 0 &&
	                config._a[MILLISECOND] === 0) {
	            config._nextDay = true;
	            config._a[HOUR] = 0;
	        }

	        config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
	        expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();

	        // Apply timezone offset from input. The actual utcOffset can be changed
	        // with parseZone.
	        if (config._tzm != null) {
	            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
	        }

	        if (config._nextDay) {
	            config._a[HOUR] = 24;
	        }

	        // check for mismatching day of week
	        if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
	            getParsingFlags(config).weekdayMismatch = true;
	        }
	    }

	    function dayOfYearFromWeekInfo(config) {
	        var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;

	        w = config._w;
	        if (w.GG != null || w.W != null || w.E != null) {
	            dow = 1;
	            doy = 4;

	            // TODO: We need to take the current isoWeekYear, but that depends on
	            // how we interpret now (local, utc, fixed offset). So create
	            // a now version of current config (take local/utc/offset flags, and
	            // create now).
	            weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
	            week = defaults(w.W, 1);
	            weekday = defaults(w.E, 1);
	            if (weekday < 1 || weekday > 7) {
	                weekdayOverflow = true;
	            }
	        } else {
	            dow = config._locale._week.dow;
	            doy = config._locale._week.doy;

	            var curWeek = weekOfYear(createLocal(), dow, doy);

	            weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);

	            // Default to current week.
	            week = defaults(w.w, curWeek.week);

	            if (w.d != null) {
	                // weekday -- low day numbers are considered next week
	                weekday = w.d;
	                if (weekday < 0 || weekday > 6) {
	                    weekdayOverflow = true;
	                }
	            } else if (w.e != null) {
	                // local weekday -- counting starts from begining of week
	                weekday = w.e + dow;
	                if (w.e < 0 || w.e > 6) {
	                    weekdayOverflow = true;
	                }
	            } else {
	                // default to begining of week
	                weekday = dow;
	            }
	        }
	        if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
	            getParsingFlags(config)._overflowWeeks = true;
	        } else if (weekdayOverflow != null) {
	            getParsingFlags(config)._overflowWeekday = true;
	        } else {
	            temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
	            config._a[YEAR] = temp.year;
	            config._dayOfYear = temp.dayOfYear;
	        }
	    }

	    // iso 8601 regex
	    // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
	    var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
	    var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;

	    var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;

	    var isoDates = [
	        ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
	        ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
	        ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
	        ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
	        ['YYYY-DDD', /\d{4}-\d{3}/],
	        ['YYYY-MM', /\d{4}-\d\d/, false],
	        ['YYYYYYMMDD', /[+-]\d{10}/],
	        ['YYYYMMDD', /\d{8}/],
	        // YYYYMM is NOT allowed by the standard
	        ['GGGG[W]WWE', /\d{4}W\d{3}/],
	        ['GGGG[W]WW', /\d{4}W\d{2}/, false],
	        ['YYYYDDD', /\d{7}/]
	    ];

	    // iso time formats and regexes
	    var isoTimes = [
	        ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
	        ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
	        ['HH:mm:ss', /\d\d:\d\d:\d\d/],
	        ['HH:mm', /\d\d:\d\d/],
	        ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
	        ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
	        ['HHmmss', /\d\d\d\d\d\d/],
	        ['HHmm', /\d\d\d\d/],
	        ['HH', /\d\d/]
	    ];

	    var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;

	    // date from iso format
	    function configFromISO(config) {
	        var i, l,
	            string = config._i,
	            match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
	            allowTime, dateFormat, timeFormat, tzFormat;

	        if (match) {
	            getParsingFlags(config).iso = true;

	            for (i = 0, l = isoDates.length; i < l; i++) {
	                if (isoDates[i][1].exec(match[1])) {
	                    dateFormat = isoDates[i][0];
	                    allowTime = isoDates[i][2] !== false;
	                    break;
	                }
	            }
	            if (dateFormat == null) {
	                config._isValid = false;
	                return;
	            }
	            if (match[3]) {
	                for (i = 0, l = isoTimes.length; i < l; i++) {
	                    if (isoTimes[i][1].exec(match[3])) {
	                        // match[2] should be 'T' or space
	                        timeFormat = (match[2] || ' ') + isoTimes[i][0];
	                        break;
	                    }
	                }
	                if (timeFormat == null) {
	                    config._isValid = false;
	                    return;
	                }
	            }
	            if (!allowTime && timeFormat != null) {
	                config._isValid = false;
	                return;
	            }
	            if (match[4]) {
	                if (tzRegex.exec(match[4])) {
	                    tzFormat = 'Z';
	                } else {
	                    config._isValid = false;
	                    return;
	                }
	            }
	            config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
	            configFromStringAndFormat(config);
	        } else {
	            config._isValid = false;
	        }
	    }

	    // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
	    var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;

	    function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
	        var result = [
	            untruncateYear(yearStr),
	            defaultLocaleMonthsShort.indexOf(monthStr),
	            parseInt(dayStr, 10),
	            parseInt(hourStr, 10),
	            parseInt(minuteStr, 10)
	        ];

	        if (secondStr) {
	            result.push(parseInt(secondStr, 10));
	        }

	        return result;
	    }

	    function untruncateYear(yearStr) {
	        var year = parseInt(yearStr, 10);
	        if (year <= 49) {
	            return 2000 + year;
	        } else if (year <= 999) {
	            return 1900 + year;
	        }
	        return year;
	    }

	    function preprocessRFC2822(s) {
	        // Remove comments and folding whitespace and replace multiple-spaces with a single space
	        return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
	    }

	    function checkWeekday(weekdayStr, parsedInput, config) {
	        if (weekdayStr) {
	            // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
	            var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
	                weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
	            if (weekdayProvided !== weekdayActual) {
	                getParsingFlags(config).weekdayMismatch = true;
	                config._isValid = false;
	                return false;
	            }
	        }
	        return true;
	    }

	    var obsOffsets = {
	        UT: 0,
	        GMT: 0,
	        EDT: -4 * 60,
	        EST: -5 * 60,
	        CDT: -5 * 60,
	        CST: -6 * 60,
	        MDT: -6 * 60,
	        MST: -7 * 60,
	        PDT: -7 * 60,
	        PST: -8 * 60
	    };

	    function calculateOffset(obsOffset, militaryOffset, numOffset) {
	        if (obsOffset) {
	            return obsOffsets[obsOffset];
	        } else if (militaryOffset) {
	            // the only allowed military tz is Z
	            return 0;
	        } else {
	            var hm = parseInt(numOffset, 10);
	            var m = hm % 100, h = (hm - m) / 100;
	            return h * 60 + m;
	        }
	    }

	    // date and time from ref 2822 format
	    function configFromRFC2822(config) {
	        var match = rfc2822.exec(preprocessRFC2822(config._i));
	        if (match) {
	            var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
	            if (!checkWeekday(match[1], parsedArray, config)) {
	                return;
	            }

	            config._a = parsedArray;
	            config._tzm = calculateOffset(match[8], match[9], match[10]);

	            config._d = createUTCDate.apply(null, config._a);
	            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);

	            getParsingFlags(config).rfc2822 = true;
	        } else {
	            config._isValid = false;
	        }
	    }

	    // date from iso format or fallback
	    function configFromString(config) {
	        var matched = aspNetJsonRegex.exec(config._i);

	        if (matched !== null) {
	            config._d = new Date(+matched[1]);
	            return;
	        }

	        configFromISO(config);
	        if (config._isValid === false) {
	            delete config._isValid;
	        } else {
	            return;
	        }

	        configFromRFC2822(config);
	        if (config._isValid === false) {
	            delete config._isValid;
	        } else {
	            return;
	        }

	        // Final attempt, use Input Fallback
	        hooks.createFromInputFallback(config);
	    }

	    hooks.createFromInputFallback = deprecate(
	        'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
	        'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
	        'discouraged and will be removed in an upcoming major release. Please refer to ' +
	        'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
	        function (config) {
	            config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
	        }
	    );

	    // constant that refers to the ISO standard
	    hooks.ISO_8601 = function () {};

	    // constant that refers to the RFC 2822 form
	    hooks.RFC_2822 = function () {};

	    // date from string and format string
	    function configFromStringAndFormat(config) {
	        // TODO: Move this to another part of the creation flow to prevent circular deps
	        if (config._f === hooks.ISO_8601) {
	            configFromISO(config);
	            return;
	        }
	        if (config._f === hooks.RFC_2822) {
	            configFromRFC2822(config);
	            return;
	        }
	        config._a = [];
	        getParsingFlags(config).empty = true;

	        // This array is used to make a Date, either with `new Date` or `Date.UTC`
	        var string = '' + config._i,
	            i, parsedInput, tokens, token, skipped,
	            stringLength = string.length,
	            totalParsedInputLength = 0;

	        tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];

	        for (i = 0; i < tokens.length; i++) {
	            token = tokens[i];
	            parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
	            // console.log('token', token, 'parsedInput', parsedInput,
	            //         'regex', getParseRegexForToken(token, config));
	            if (parsedInput) {
	                skipped = string.substr(0, string.indexOf(parsedInput));
	                if (skipped.length > 0) {
	                    getParsingFlags(config).unusedInput.push(skipped);
	                }
	                string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
	                totalParsedInputLength += parsedInput.length;
	            }
	            // don't parse if it's not a known token
	            if (formatTokenFunctions[token]) {
	                if (parsedInput) {
	                    getParsingFlags(config).empty = false;
	                }
	                else {
	                    getParsingFlags(config).unusedTokens.push(token);
	                }
	                addTimeToArrayFromToken(token, parsedInput, config);
	            }
	            else if (config._strict && !parsedInput) {
	                getParsingFlags(config).unusedTokens.push(token);
	            }
	        }

	        // add remaining unparsed input length to the string
	        getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
	        if (string.length > 0) {
	            getParsingFlags(config).unusedInput.push(string);
	        }

	        // clear _12h flag if hour is <= 12
	        if (config._a[HOUR] <= 12 &&
	            getParsingFlags(config).bigHour === true &&
	            config._a[HOUR] > 0) {
	            getParsingFlags(config).bigHour = undefined;
	        }

	        getParsingFlags(config).parsedDateParts = config._a.slice(0);
	        getParsingFlags(config).meridiem = config._meridiem;
	        // handle meridiem
	        config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);

	        configFromArray(config);
	        checkOverflow(config);
	    }


	    function meridiemFixWrap (locale, hour, meridiem) {
	        var isPm;

	        if (meridiem == null) {
	            // nothing to do
	            return hour;
	        }
	        if (locale.meridiemHour != null) {
	            return locale.meridiemHour(hour, meridiem);
	        } else if (locale.isPM != null) {
	            // Fallback
	            isPm = locale.isPM(meridiem);
	            if (isPm && hour < 12) {
	                hour += 12;
	            }
	            if (!isPm && hour === 12) {
	                hour = 0;
	            }
	            return hour;
	        } else {
	            // this is not supposed to happen
	            return hour;
	        }
	    }

	    // date from string and array of format strings
	    function configFromStringAndArray(config) {
	        var tempConfig,
	            bestMoment,

	            scoreToBeat,
	            i,
	            currentScore;

	        if (config._f.length === 0) {
	            getParsingFlags(config).invalidFormat = true;
	            config._d = new Date(NaN);
	            return;
	        }

	        for (i = 0; i < config._f.length; i++) {
	            currentScore = 0;
	            tempConfig = copyConfig({}, config);
	            if (config._useUTC != null) {
	                tempConfig._useUTC = config._useUTC;
	            }
	            tempConfig._f = config._f[i];
	            configFromStringAndFormat(tempConfig);

	            if (!isValid(tempConfig)) {
	                continue;
	            }

	            // if there is any input that was not parsed add a penalty for that format
	            currentScore += getParsingFlags(tempConfig).charsLeftOver;

	            //or tokens
	            currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;

	            getParsingFlags(tempConfig).score = currentScore;

	            if (scoreToBeat == null || currentScore < scoreToBeat) {
	                scoreToBeat = currentScore;
	                bestMoment = tempConfig;
	            }
	        }

	        extend(config, bestMoment || tempConfig);
	    }

	    function configFromObject(config) {
	        if (config._d) {
	            return;
	        }

	        var i = normalizeObjectUnits(config._i);
	        config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
	            return obj && parseInt(obj, 10);
	        });

	        configFromArray(config);
	    }

	    function createFromConfig (config) {
	        var res = new Moment(checkOverflow(prepareConfig(config)));
	        if (res._nextDay) {
	            // Adding is smart enough around DST
	            res.add(1, 'd');
	            res._nextDay = undefined;
	        }

	        return res;
	    }

	    function prepareConfig (config) {
	        var input = config._i,
	            format = config._f;

	        config._locale = config._locale || getLocale(config._l);

	        if (input === null || (format === undefined && input === '')) {
	            return createInvalid({nullInput: true});
	        }

	        if (typeof input === 'string') {
	            config._i = input = config._locale.preparse(input);
	        }

	        if (isMoment(input)) {
	            return new Moment(checkOverflow(input));
	        } else if (isDate(input)) {
	            config._d = input;
	        } else if (isArray(format)) {
	            configFromStringAndArray(config);
	        } else if (format) {
	            configFromStringAndFormat(config);
	        }  else {
	            configFromInput(config);
	        }

	        if (!isValid(config)) {
	            config._d = null;
	        }

	        return config;
	    }

	    function configFromInput(config) {
	        var input = config._i;
	        if (isUndefined(input)) {
	            config._d = new Date(hooks.now());
	        } else if (isDate(input)) {
	            config._d = new Date(input.valueOf());
	        } else if (typeof input === 'string') {
	            configFromString(config);
	        } else if (isArray(input)) {
	            config._a = map(input.slice(0), function (obj) {
	                return parseInt(obj, 10);
	            });
	            configFromArray(config);
	        } else if (isObject(input)) {
	            configFromObject(config);
	        } else if (isNumber(input)) {
	            // from milliseconds
	            config._d = new Date(input);
	        } else {
	            hooks.createFromInputFallback(config);
	        }
	    }

	    function createLocalOrUTC (input, format, locale, strict, isUTC) {
	        var c = {};

	        if (locale === true || locale === false) {
	            strict = locale;
	            locale = undefined;
	        }

	        if ((isObject(input) && isObjectEmpty(input)) ||
	                (isArray(input) && input.length === 0)) {
	            input = undefined;
	        }
	        // object construction must be done this way.
	        // https://github.com/moment/moment/issues/1423
	        c._isAMomentObject = true;
	        c._useUTC = c._isUTC = isUTC;
	        c._l = locale;
	        c._i = input;
	        c._f = format;
	        c._strict = strict;

	        return createFromConfig(c);
	    }

	    function createLocal (input, format, locale, strict) {
	        return createLocalOrUTC(input, format, locale, strict, false);
	    }

	    var prototypeMin = deprecate(
	        'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
	        function () {
	            var other = createLocal.apply(null, arguments);
	            if (this.isValid() && other.isValid()) {
	                return other < this ? this : other;
	            } else {
	                return createInvalid();
	            }
	        }
	    );

	    var prototypeMax = deprecate(
	        'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
	        function () {
	            var other = createLocal.apply(null, arguments);
	            if (this.isValid() && other.isValid()) {
	                return other > this ? this : other;
	            } else {
	                return createInvalid();
	            }
	        }
	    );

	    // Pick a moment m from moments so that m[fn](other) is true for all
	    // other. This relies on the function fn to be transitive.
	    //
	    // moments should either be an array of moment objects or an array, whose
	    // first element is an array of moment objects.
	    function pickBy(fn, moments) {
	        var res, i;
	        if (moments.length === 1 && isArray(moments[0])) {
	            moments = moments[0];
	        }
	        if (!moments.length) {
	            return createLocal();
	        }
	        res = moments[0];
	        for (i = 1; i < moments.length; ++i) {
	            if (!moments[i].isValid() || moments[i][fn](res)) {
	                res = moments[i];
	            }
	        }
	        return res;
	    }

	    // TODO: Use [].sort instead?
	    function min () {
	        var args = [].slice.call(arguments, 0);

	        return pickBy('isBefore', args);
	    }

	    function max () {
	        var args = [].slice.call(arguments, 0);

	        return pickBy('isAfter', args);
	    }

	    var now = function () {
	        return Date.now ? Date.now() : +(new Date());
	    };

	    var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];

	    function isDurationValid(m) {
	        for (var key in m) {
	            if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
	                return false;
	            }
	        }

	        var unitHasDecimal = false;
	        for (var i = 0; i < ordering.length; ++i) {
	            if (m[ordering[i]]) {
	                if (unitHasDecimal) {
	                    return false; // only allow non-integers for smallest unit
	                }
	                if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
	                    unitHasDecimal = true;
	                }
	            }
	        }

	        return true;
	    }

	    function isValid$1() {
	        return this._isValid;
	    }

	    function createInvalid$1() {
	        return createDuration(NaN);
	    }

	    function Duration (duration) {
	        var normalizedInput = normalizeObjectUnits(duration),
	            years = normalizedInput.year || 0,
	            quarters = normalizedInput.quarter || 0,
	            months = normalizedInput.month || 0,
	            weeks = normalizedInput.week || 0,
	            days = normalizedInput.day || 0,
	            hours = normalizedInput.hour || 0,
	            minutes = normalizedInput.minute || 0,
	            seconds = normalizedInput.second || 0,
	            milliseconds = normalizedInput.millisecond || 0;

	        this._isValid = isDurationValid(normalizedInput);

	        // representation for dateAddRemove
	        this._milliseconds = +milliseconds +
	            seconds * 1e3 + // 1000
	            minutes * 6e4 + // 1000 * 60
	            hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
	        // Because of dateAddRemove treats 24 hours as different from a
	        // day when working around DST, we need to store them separately
	        this._days = +days +
	            weeks * 7;
	        // It is impossible to translate months into days without knowing
	        // which months you are are talking about, so we have to store
	        // it separately.
	        this._months = +months +
	            quarters * 3 +
	            years * 12;

	        this._data = {};

	        this._locale = getLocale();

	        this._bubble();
	    }

	    function isDuration (obj) {
	        return obj instanceof Duration;
	    }

	    function absRound (number) {
	        if (number < 0) {
	            return Math.round(-1 * number) * -1;
	        } else {
	            return Math.round(number);
	        }
	    }

	    // FORMATTING

	    function offset (token, separator) {
	        addFormatToken(token, 0, 0, function () {
	            var offset = this.utcOffset();
	            var sign = '+';
	            if (offset < 0) {
	                offset = -offset;
	                sign = '-';
	            }
	            return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
	        });
	    }

	    offset('Z', ':');
	    offset('ZZ', '');

	    // PARSING

	    addRegexToken('Z',  matchShortOffset);
	    addRegexToken('ZZ', matchShortOffset);
	    addParseToken(['Z', 'ZZ'], function (input, array, config) {
	        config._useUTC = true;
	        config._tzm = offsetFromString(matchShortOffset, input);
	    });

	    // HELPERS

	    // timezone chunker
	    // '+10:00' > ['10',  '00']
	    // '-1530'  > ['-15', '30']
	    var chunkOffset = /([\+\-]|\d\d)/gi;

	    function offsetFromString(matcher, string) {
	        var matches = (string || '').match(matcher);

	        if (matches === null) {
	            return null;
	        }

	        var chunk   = matches[matches.length - 1] || [];
	        var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];
	        var minutes = +(parts[1] * 60) + toInt(parts[2]);

	        return minutes === 0 ?
	          0 :
	          parts[0] === '+' ? minutes : -minutes;
	    }

	    // Return a moment from input, that is local/utc/zone equivalent to model.
	    function cloneWithOffset(input, model) {
	        var res, diff;
	        if (model._isUTC) {
	            res = model.clone();
	            diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
	            // Use low-level api, because this fn is low-level api.
	            res._d.setTime(res._d.valueOf() + diff);
	            hooks.updateOffset(res, false);
	            return res;
	        } else {
	            return createLocal(input).local();
	        }
	    }

	    function getDateOffset (m) {
	        // On Firefox.24 Date#getTimezoneOffset returns a floating point.
	        // https://github.com/moment/moment/pull/1871
	        return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
	    }

	    // HOOKS

	    // This function will be called whenever a moment is mutated.
	    // It is intended to keep the offset in sync with the timezone.
	    hooks.updateOffset = function () {};

	    // MOMENTS

	    // keepLocalTime = true means only change the timezone, without
	    // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
	    // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
	    // +0200, so we adjust the time as needed, to be valid.
	    //
	    // Keeping the time actually adds/subtracts (one hour)
	    // from the actual represented time. That is why we call updateOffset
	    // a second time. In case it wants us to change the offset again
	    // _changeInProgress == true case, then we have to adjust, because
	    // there is no such time in the given timezone.
	    function getSetOffset (input, keepLocalTime, keepMinutes) {
	        var offset = this._offset || 0,
	            localAdjust;
	        if (!this.isValid()) {
	            return input != null ? this : NaN;
	        }
	        if (input != null) {
	            if (typeof input === 'string') {
	                input = offsetFromString(matchShortOffset, input);
	                if (input === null) {
	                    return this;
	                }
	            } else if (Math.abs(input) < 16 && !keepMinutes) {
	                input = input * 60;
	            }
	            if (!this._isUTC && keepLocalTime) {
	                localAdjust = getDateOffset(this);
	            }
	            this._offset = input;
	            this._isUTC = true;
	            if (localAdjust != null) {
	                this.add(localAdjust, 'm');
	            }
	            if (offset !== input) {
	                if (!keepLocalTime || this._changeInProgress) {
	                    addSubtract(this, createDuration(input - offset, 'm'), 1, false);
	                } else if (!this._changeInProgress) {
	                    this._changeInProgress = true;
	                    hooks.updateOffset(this, true);
	                    this._changeInProgress = null;
	                }
	            }
	            return this;
	        } else {
	            return this._isUTC ? offset : getDateOffset(this);
	        }
	    }

	    function getSetZone (input, keepLocalTime) {
	        if (input != null) {
	            if (typeof input !== 'string') {
	                input = -input;
	            }

	            this.utcOffset(input, keepLocalTime);

	            return this;
	        } else {
	            return -this.utcOffset();
	        }
	    }

	    function setOffsetToUTC (keepLocalTime) {
	        return this.utcOffset(0, keepLocalTime);
	    }

	    function setOffsetToLocal (keepLocalTime) {
	        if (this._isUTC) {
	            this.utcOffset(0, keepLocalTime);
	            this._isUTC = false;

	            if (keepLocalTime) {
	                this.subtract(getDateOffset(this), 'm');
	            }
	        }
	        return this;
	    }

	    function setOffsetToParsedOffset () {
	        if (this._tzm != null) {
	            this.utcOffset(this._tzm, false, true);
	        } else if (typeof this._i === 'string') {
	            var tZone = offsetFromString(matchOffset, this._i);
	            if (tZone != null) {
	                this.utcOffset(tZone);
	            }
	            else {
	                this.utcOffset(0, true);
	            }
	        }
	        return this;
	    }

	    function hasAlignedHourOffset (input) {
	        if (!this.isValid()) {
	            return false;
	        }
	        input = input ? createLocal(input).utcOffset() : 0;

	        return (this.utcOffset() - input) % 60 === 0;
	    }

	    function isDaylightSavingTime () {
	        return (
	            this.utcOffset() > this.clone().month(0).utcOffset() ||
	            this.utcOffset() > this.clone().month(5).utcOffset()
	        );
	    }

	    function isDaylightSavingTimeShifted () {
	        if (!isUndefined(this._isDSTShifted)) {
	            return this._isDSTShifted;
	        }

	        var c = {};

	        copyConfig(c, this);
	        c = prepareConfig(c);

	        if (c._a) {
	            var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
	            this._isDSTShifted = this.isValid() &&
	                compareArrays(c._a, other.toArray()) > 0;
	        } else {
	            this._isDSTShifted = false;
	        }

	        return this._isDSTShifted;
	    }

	    function isLocal () {
	        return this.isValid() ? !this._isUTC : false;
	    }

	    function isUtcOffset () {
	        return this.isValid() ? this._isUTC : false;
	    }

	    function isUtc () {
	        return this.isValid() ? this._isUTC && this._offset === 0 : false;
	    }

	    // ASP.NET json date format regex
	    var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;

	    // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
	    // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
	    // and further modified to allow for strings containing both week and day
	    var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;

	    function createDuration (input, key) {
	        var duration = input,
	            // matching against regexp is expensive, do it on demand
	            match = null,
	            sign,
	            ret,
	            diffRes;

	        if (isDuration(input)) {
	            duration = {
	                ms : input._milliseconds,
	                d  : input._days,
	                M  : input._months
	            };
	        } else if (isNumber(input)) {
	            duration = {};
	            if (key) {
	                duration[key] = input;
	            } else {
	                duration.milliseconds = input;
	            }
	        } else if (!!(match = aspNetRegex.exec(input))) {
	            sign = (match[1] === '-') ? -1 : 1;
	            duration = {
	                y  : 0,
	                d  : toInt(match[DATE])                         * sign,
	                h  : toInt(match[HOUR])                         * sign,
	                m  : toInt(match[MINUTE])                       * sign,
	                s  : toInt(match[SECOND])                       * sign,
	                ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
	            };
	        } else if (!!(match = isoRegex.exec(input))) {
	            sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
	            duration = {
	                y : parseIso(match[2], sign),
	                M : parseIso(match[3], sign),
	                w : parseIso(match[4], sign),
	                d : parseIso(match[5], sign),
	                h : parseIso(match[6], sign),
	                m : parseIso(match[7], sign),
	                s : parseIso(match[8], sign)
	            };
	        } else if (duration == null) {// checks for null or undefined
	            duration = {};
	        } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
	            diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));

	            duration = {};
	            duration.ms = diffRes.milliseconds;
	            duration.M = diffRes.months;
	        }

	        ret = new Duration(duration);

	        if (isDuration(input) && hasOwnProp(input, '_locale')) {
	            ret._locale = input._locale;
	        }

	        return ret;
	    }

	    createDuration.fn = Duration.prototype;
	    createDuration.invalid = createInvalid$1;

	    function parseIso (inp, sign) {
	        // We'd normally use ~~inp for this, but unfortunately it also
	        // converts floats to ints.
	        // inp may be undefined, so careful calling replace on it.
	        var res = inp && parseFloat(inp.replace(',', '.'));
	        // apply sign while we're at it
	        return (isNaN(res) ? 0 : res) * sign;
	    }

	    function positiveMomentsDifference(base, other) {
	        var res = {milliseconds: 0, months: 0};

	        res.months = other.month() - base.month() +
	            (other.year() - base.year()) * 12;
	        if (base.clone().add(res.months, 'M').isAfter(other)) {
	            --res.months;
	        }

	        res.milliseconds = +other - +(base.clone().add(res.months, 'M'));

	        return res;
	    }

	    function momentsDifference(base, other) {
	        var res;
	        if (!(base.isValid() && other.isValid())) {
	            return {milliseconds: 0, months: 0};
	        }

	        other = cloneWithOffset(other, base);
	        if (base.isBefore(other)) {
	            res = positiveMomentsDifference(base, other);
	        } else {
	            res = positiveMomentsDifference(other, base);
	            res.milliseconds = -res.milliseconds;
	            res.months = -res.months;
	        }

	        return res;
	    }

	    // TODO: remove 'name' arg after deprecation is removed
	    function createAdder(direction, name) {
	        return function (val, period) {
	            var dur, tmp;
	            //invert the arguments, but complain about it
	            if (period !== null && !isNaN(+period)) {
	                deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
	                'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
	                tmp = val; val = period; period = tmp;
	            }

	            val = typeof val === 'string' ? +val : val;
	            dur = createDuration(val, period);
	            addSubtract(this, dur, direction);
	            return this;
	        };
	    }

	    function addSubtract (mom, duration, isAdding, updateOffset) {
	        var milliseconds = duration._milliseconds,
	            days = absRound(duration._days),
	            months = absRound(duration._months);

	        if (!mom.isValid()) {
	            // No op
	            return;
	        }

	        updateOffset = updateOffset == null ? true : updateOffset;

	        if (months) {
	            setMonth(mom, get(mom, 'Month') + months * isAdding);
	        }
	        if (days) {
	            set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
	        }
	        if (milliseconds) {
	            mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
	        }
	        if (updateOffset) {
	            hooks.updateOffset(mom, days || months);
	        }
	    }

	    var add      = createAdder(1, 'add');
	    var subtract = createAdder(-1, 'subtract');

	    function getCalendarFormat(myMoment, now) {
	        var diff = myMoment.diff(now, 'days', true);
	        return diff < -6 ? 'sameElse' :
	                diff < -1 ? 'lastWeek' :
	                diff < 0 ? 'lastDay' :
	                diff < 1 ? 'sameDay' :
	                diff < 2 ? 'nextDay' :
	                diff < 7 ? 'nextWeek' : 'sameElse';
	    }

	    function calendar$1 (time, formats) {
	        // We want to compare the start of today, vs this.
	        // Getting start-of-today depends on whether we're local/utc/offset or not.
	        var now = time || createLocal(),
	            sod = cloneWithOffset(now, this).startOf('day'),
	            format = hooks.calendarFormat(this, sod) || 'sameElse';

	        var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);

	        return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
	    }

	    function clone () {
	        return new Moment(this);
	    }

	    function isAfter (input, units) {
	        var localInput = isMoment(input) ? input : createLocal(input);
	        if (!(this.isValid() && localInput.isValid())) {
	            return false;
	        }
	        units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
	        if (units === 'millisecond') {
	            return this.valueOf() > localInput.valueOf();
	        } else {
	            return localInput.valueOf() < this.clone().startOf(units).valueOf();
	        }
	    }

	    function isBefore (input, units) {
	        var localInput = isMoment(input) ? input : createLocal(input);
	        if (!(this.isValid() && localInput.isValid())) {
	            return false;
	        }
	        units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
	        if (units === 'millisecond') {
	            return this.valueOf() < localInput.valueOf();
	        } else {
	            return this.clone().endOf(units).valueOf() < localInput.valueOf();
	        }
	    }

	    function isBetween (from, to, units, inclusivity) {
	        inclusivity = inclusivity || '()';
	        return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
	            (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
	    }

	    function isSame (input, units) {
	        var localInput = isMoment(input) ? input : createLocal(input),
	            inputMs;
	        if (!(this.isValid() && localInput.isValid())) {
	            return false;
	        }
	        units = normalizeUnits(units || 'millisecond');
	        if (units === 'millisecond') {
	            return this.valueOf() === localInput.valueOf();
	        } else {
	            inputMs = localInput.valueOf();
	            return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
	        }
	    }

	    function isSameOrAfter (input, units) {
	        return this.isSame(input, units) || this.isAfter(input,units);
	    }

	    function isSameOrBefore (input, units) {
	        return this.isSame(input, units) || this.isBefore(input,units);
	    }

	    function diff (input, units, asFloat) {
	        var that,
	            zoneDelta,
	            output;

	        if (!this.isValid()) {
	            return NaN;
	        }

	        that = cloneWithOffset(input, this);

	        if (!that.isValid()) {
	            return NaN;
	        }

	        zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;

	        units = normalizeUnits(units);

	        switch (units) {
	            case 'year': output = monthDiff(this, that) / 12; break;
	            case 'month': output = monthDiff(this, that); break;
	            case 'quarter': output = monthDiff(this, that) / 3; break;
	            case 'second': output = (this - that) / 1e3; break; // 1000
	            case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
	            case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
	            case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
	            case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
	            default: output = this - that;
	        }

	        return asFloat ? output : absFloor(output);
	    }

	    function monthDiff (a, b) {
	        // difference in months
	        var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
	            // b is in (anchor - 1 month, anchor + 1 month)
	            anchor = a.clone().add(wholeMonthDiff, 'months'),
	            anchor2, adjust;

	        if (b - anchor < 0) {
	            anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
	            // linear across the month
	            adjust = (b - anchor) / (anchor - anchor2);
	        } else {
	            anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
	            // linear across the month
	            adjust = (b - anchor) / (anchor2 - anchor);
	        }

	        //check for negative zero, return zero if negative zero
	        return -(wholeMonthDiff + adjust) || 0;
	    }

	    hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
	    hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';

	    function toString () {
	        return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
	    }

	    function toISOString(keepOffset) {
	        if (!this.isValid()) {
	            return null;
	        }
	        var utc = keepOffset !== true;
	        var m = utc ? this.clone().utc() : this;
	        if (m.year() < 0 || m.year() > 9999) {
	            return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
	        }
	        if (isFunction(Date.prototype.toISOString)) {
	            // native implementation is ~50x faster, use it when we can
	            if (utc) {
	                return this.toDate().toISOString();
	            } else {
	                return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));
	            }
	        }
	        return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
	    }

	    /**
	     * Return a human readable representation of a moment that can
	     * also be evaluated to get a new moment which is the same
	     *
	     * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
	     */
	    function inspect () {
	        if (!this.isValid()) {
	            return 'moment.invalid(/* ' + this._i + ' */)';
	        }
	        var func = 'moment';
	        var zone = '';
	        if (!this.isLocal()) {
	            func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
	            zone = 'Z';
	        }
	        var prefix = '[' + func + '("]';
	        var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
	        var datetime = '-MM-DD[T]HH:mm:ss.SSS';
	        var suffix = zone + '[")]';

	        return this.format(prefix + year + datetime + suffix);
	    }

	    function format (inputString) {
	        if (!inputString) {
	            inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
	        }
	        var output = formatMoment(this, inputString);
	        return this.localeData().postformat(output);
	    }

	    function from (time, withoutSuffix) {
	        if (this.isValid() &&
	                ((isMoment(time) && time.isValid()) ||
	                 createLocal(time).isValid())) {
	            return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
	        } else {
	            return this.localeData().invalidDate();
	        }
	    }

	    function fromNow (withoutSuffix) {
	        return this.from(createLocal(), withoutSuffix);
	    }

	    function to (time, withoutSuffix) {
	        if (this.isValid() &&
	                ((isMoment(time) && time.isValid()) ||
	                 createLocal(time).isValid())) {
	            return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
	        } else {
	            return this.localeData().invalidDate();
	        }
	    }

	    function toNow (withoutSuffix) {
	        return this.to(createLocal(), withoutSuffix);
	    }

	    // If passed a locale key, it will set the locale for this
	    // instance.  Otherwise, it will return the locale configuration
	    // variables for this instance.
	    function locale (key) {
	        var newLocaleData;

	        if (key === undefined) {
	            return this._locale._abbr;
	        } else {
	            newLocaleData = getLocale(key);
	            if (newLocaleData != null) {
	                this._locale = newLocaleData;
	            }
	            return this;
	        }
	    }

	    var lang = deprecate(
	        'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
	        function (key) {
	            if (key === undefined) {
	                return this.localeData();
	            } else {
	                return this.locale(key);
	            }
	        }
	    );

	    function localeData () {
	        return this._locale;
	    }

	    function startOf (units) {
	        units = normalizeUnits(units);
	        // the following switch intentionally omits break keywords
	        // to utilize falling through the cases.
	        switch (units) {
	            case 'year':
	                this.month(0);
	                /* falls through */
	            case 'quarter':
	            case 'month':
	                this.date(1);
	                /* falls through */
	            case 'week':
	            case 'isoWeek':
	            case 'day':
	            case 'date':
	                this.hours(0);
	                /* falls through */
	            case 'hour':
	                this.minutes(0);
	                /* falls through */
	            case 'minute':
	                this.seconds(0);
	                /* falls through */
	            case 'second':
	                this.milliseconds(0);
	        }

	        // weeks are a special case
	        if (units === 'week') {
	            this.weekday(0);
	        }
	        if (units === 'isoWeek') {
	            this.isoWeekday(1);
	        }

	        // quarters are also special
	        if (units === 'quarter') {
	            this.month(Math.floor(this.month() / 3) * 3);
	        }

	        return this;
	    }

	    function endOf (units) {
	        units = normalizeUnits(units);
	        if (units === undefined || units === 'millisecond') {
	            return this;
	        }

	        // 'date' is an alias for 'day', so it should be considered as such.
	        if (units === 'date') {
	            units = 'day';
	        }

	        return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
	    }

	    function valueOf () {
	        return this._d.valueOf() - ((this._offset || 0) * 60000);
	    }

	    function unix () {
	        return Math.floor(this.valueOf() / 1000);
	    }

	    function toDate () {
	        return new Date(this.valueOf());
	    }

	    function toArray () {
	        var m = this;
	        return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
	    }

	    function toObject () {
	        var m = this;
	        return {
	            years: m.year(),
	            months: m.month(),
	            date: m.date(),
	            hours: m.hours(),
	            minutes: m.minutes(),
	            seconds: m.seconds(),
	            milliseconds: m.milliseconds()
	        };
	    }

	    function toJSON () {
	        // new Date(NaN).toJSON() === null
	        return this.isValid() ? this.toISOString() : null;
	    }

	    function isValid$2 () {
	        return isValid(this);
	    }

	    function parsingFlags () {
	        return extend({}, getParsingFlags(this));
	    }

	    function invalidAt () {
	        return getParsingFlags(this).overflow;
	    }

	    function creationData() {
	        return {
	            input: this._i,
	            format: this._f,
	            locale: this._locale,
	            isUTC: this._isUTC,
	            strict: this._strict
	        };
	    }

	    // FORMATTING

	    addFormatToken(0, ['gg', 2], 0, function () {
	        return this.weekYear() % 100;
	    });

	    addFormatToken(0, ['GG', 2], 0, function () {
	        return this.isoWeekYear() % 100;
	    });

	    function addWeekYearFormatToken (token, getter) {
	        addFormatToken(0, [token, token.length], 0, getter);
	    }

	    addWeekYearFormatToken('gggg',     'weekYear');
	    addWeekYearFormatToken('ggggg',    'weekYear');
	    addWeekYearFormatToken('GGGG',  'isoWeekYear');
	    addWeekYearFormatToken('GGGGG', 'isoWeekYear');

	    // ALIASES

	    addUnitAlias('weekYear', 'gg');
	    addUnitAlias('isoWeekYear', 'GG');

	    // PRIORITY

	    addUnitPriority('weekYear', 1);
	    addUnitPriority('isoWeekYear', 1);


	    // PARSING

	    addRegexToken('G',      matchSigned);
	    addRegexToken('g',      matchSigned);
	    addRegexToken('GG',     match1to2, match2);
	    addRegexToken('gg',     match1to2, match2);
	    addRegexToken('GGGG',   match1to4, match4);
	    addRegexToken('gggg',   match1to4, match4);
	    addRegexToken('GGGGG',  match1to6, match6);
	    addRegexToken('ggggg',  match1to6, match6);

	    addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
	        week[token.substr(0, 2)] = toInt(input);
	    });

	    addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
	        week[token] = hooks.parseTwoDigitYear(input);
	    });

	    // MOMENTS

	    function getSetWeekYear (input) {
	        return getSetWeekYearHelper.call(this,
	                input,
	                this.week(),
	                this.weekday(),
	                this.localeData()._week.dow,
	                this.localeData()._week.doy);
	    }

	    function getSetISOWeekYear (input) {
	        return getSetWeekYearHelper.call(this,
	                input, this.isoWeek(), this.isoWeekday(), 1, 4);
	    }

	    function getISOWeeksInYear () {
	        return weeksInYear(this.year(), 1, 4);
	    }

	    function getWeeksInYear () {
	        var weekInfo = this.localeData()._week;
	        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
	    }

	    function getSetWeekYearHelper(input, week, weekday, dow, doy) {
	        var weeksTarget;
	        if (input == null) {
	            return weekOfYear(this, dow, doy).year;
	        } else {
	            weeksTarget = weeksInYear(input, dow, doy);
	            if (week > weeksTarget) {
	                week = weeksTarget;
	            }
	            return setWeekAll.call(this, input, week, weekday, dow, doy);
	        }
	    }

	    function setWeekAll(weekYear, week, weekday, dow, doy) {
	        var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
	            date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);

	        this.year(date.getUTCFullYear());
	        this.month(date.getUTCMonth());
	        this.date(date.getUTCDate());
	        return this;
	    }

	    // FORMATTING

	    addFormatToken('Q', 0, 'Qo', 'quarter');

	    // ALIASES

	    addUnitAlias('quarter', 'Q');

	    // PRIORITY

	    addUnitPriority('quarter', 7);

	    // PARSING

	    addRegexToken('Q', match1);
	    addParseToken('Q', function (input, array) {
	        array[MONTH] = (toInt(input) - 1) * 3;
	    });

	    // MOMENTS

	    function getSetQuarter (input) {
	        return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
	    }

	    // FORMATTING

	    addFormatToken('D', ['DD', 2], 'Do', 'date');

	    // ALIASES

	    addUnitAlias('date', 'D');

	    // PRIORITY
	    addUnitPriority('date', 9);

	    // PARSING

	    addRegexToken('D',  match1to2);
	    addRegexToken('DD', match1to2, match2);
	    addRegexToken('Do', function (isStrict, locale) {
	        // TODO: Remove "ordinalParse" fallback in next major release.
	        return isStrict ?
	          (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
	          locale._dayOfMonthOrdinalParseLenient;
	    });

	    addParseToken(['D', 'DD'], DATE);
	    addParseToken('Do', function (input, array) {
	        array[DATE] = toInt(input.match(match1to2)[0]);
	    });

	    // MOMENTS

	    var getSetDayOfMonth = makeGetSet('Date', true);

	    // FORMATTING

	    addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');

	    // ALIASES

	    addUnitAlias('dayOfYear', 'DDD');

	    // PRIORITY
	    addUnitPriority('dayOfYear', 4);

	    // PARSING

	    addRegexToken('DDD',  match1to3);
	    addRegexToken('DDDD', match3);
	    addParseToken(['DDD', 'DDDD'], function (input, array, config) {
	        config._dayOfYear = toInt(input);
	    });

	    // HELPERS

	    // MOMENTS

	    function getSetDayOfYear (input) {
	        var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
	        return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
	    }

	    // FORMATTING

	    addFormatToken('m', ['mm', 2], 0, 'minute');

	    // ALIASES

	    addUnitAlias('minute', 'm');

	    // PRIORITY

	    addUnitPriority('minute', 14);

	    // PARSING

	    addRegexToken('m',  match1to2);
	    addRegexToken('mm', match1to2, match2);
	    addParseToken(['m', 'mm'], MINUTE);

	    // MOMENTS

	    var getSetMinute = makeGetSet('Minutes', false);

	    // FORMATTING

	    addFormatToken('s', ['ss', 2], 0, 'second');

	    // ALIASES

	    addUnitAlias('second', 's');

	    // PRIORITY

	    addUnitPriority('second', 15);

	    // PARSING

	    addRegexToken('s',  match1to2);
	    addRegexToken('ss', match1to2, match2);
	    addParseToken(['s', 'ss'], SECOND);

	    // MOMENTS

	    var getSetSecond = makeGetSet('Seconds', false);

	    // FORMATTING

	    addFormatToken('S', 0, 0, function () {
	        return ~~(this.millisecond() / 100);
	    });

	    addFormatToken(0, ['SS', 2], 0, function () {
	        return ~~(this.millisecond() / 10);
	    });

	    addFormatToken(0, ['SSS', 3], 0, 'millisecond');
	    addFormatToken(0, ['SSSS', 4], 0, function () {
	        return this.millisecond() * 10;
	    });
	    addFormatToken(0, ['SSSSS', 5], 0, function () {
	        return this.millisecond() * 100;
	    });
	    addFormatToken(0, ['SSSSSS', 6], 0, function () {
	        return this.millisecond() * 1000;
	    });
	    addFormatToken(0, ['SSSSSSS', 7], 0, function () {
	        return this.millisecond() * 10000;
	    });
	    addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
	        return this.millisecond() * 100000;
	    });
	    addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
	        return this.millisecond() * 1000000;
	    });


	    // ALIASES

	    addUnitAlias('millisecond', 'ms');

	    // PRIORITY

	    addUnitPriority('millisecond', 16);

	    // PARSING

	    addRegexToken('S',    match1to3, match1);
	    addRegexToken('SS',   match1to3, match2);
	    addRegexToken('SSS',  match1to3, match3);

	    var token;
	    for (token = 'SSSS'; token.length <= 9; token += 'S') {
	        addRegexToken(token, matchUnsigned);
	    }

	    function parseMs(input, array) {
	        array[MILLISECOND] = toInt(('0.' + input) * 1000);
	    }

	    for (token = 'S'; token.length <= 9; token += 'S') {
	        addParseToken(token, parseMs);
	    }
	    // MOMENTS

	    var getSetMillisecond = makeGetSet('Milliseconds', false);

	    // FORMATTING

	    addFormatToken('z',  0, 0, 'zoneAbbr');
	    addFormatToken('zz', 0, 0, 'zoneName');

	    // MOMENTS

	    function getZoneAbbr () {
	        return this._isUTC ? 'UTC' : '';
	    }

	    function getZoneName () {
	        return this._isUTC ? 'Coordinated Universal Time' : '';
	    }

	    var proto = Moment.prototype;

	    proto.add               = add;
	    proto.calendar          = calendar$1;
	    proto.clone             = clone;
	    proto.diff              = diff;
	    proto.endOf             = endOf;
	    proto.format            = format;
	    proto.from              = from;
	    proto.fromNow           = fromNow;
	    proto.to                = to;
	    proto.toNow             = toNow;
	    proto.get               = stringGet;
	    proto.invalidAt         = invalidAt;
	    proto.isAfter           = isAfter;
	    proto.isBefore          = isBefore;
	    proto.isBetween         = isBetween;
	    proto.isSame            = isSame;
	    proto.isSameOrAfter     = isSameOrAfter;
	    proto.isSameOrBefore    = isSameOrBefore;
	    proto.isValid           = isValid$2;
	    proto.lang              = lang;
	    proto.locale            = locale;
	    proto.localeData        = localeData;
	    proto.max               = prototypeMax;
	    proto.min               = prototypeMin;
	    proto.parsingFlags      = parsingFlags;
	    proto.set               = stringSet;
	    proto.startOf           = startOf;
	    proto.subtract          = subtract;
	    proto.toArray           = toArray;
	    proto.toObject          = toObject;
	    proto.toDate            = toDate;
	    proto.toISOString       = toISOString;
	    proto.inspect           = inspect;
	    proto.toJSON            = toJSON;
	    proto.toString          = toString;
	    proto.unix              = unix;
	    proto.valueOf           = valueOf;
	    proto.creationData      = creationData;
	    proto.year       = getSetYear;
	    proto.isLeapYear = getIsLeapYear;
	    proto.weekYear    = getSetWeekYear;
	    proto.isoWeekYear = getSetISOWeekYear;
	    proto.quarter = proto.quarters = getSetQuarter;
	    proto.month       = getSetMonth;
	    proto.daysInMonth = getDaysInMonth;
	    proto.week           = proto.weeks        = getSetWeek;
	    proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
	    proto.weeksInYear    = getWeeksInYear;
	    proto.isoWeeksInYear = getISOWeeksInYear;
	    proto.date       = getSetDayOfMonth;
	    proto.day        = proto.days             = getSetDayOfWeek;
	    proto.weekday    = getSetLocaleDayOfWeek;
	    proto.isoWeekday = getSetISODayOfWeek;
	    proto.dayOfYear  = getSetDayOfYear;
	    proto.hour = proto.hours = getSetHour;
	    proto.minute = proto.minutes = getSetMinute;
	    proto.second = proto.seconds = getSetSecond;
	    proto.millisecond = proto.milliseconds = getSetMillisecond;
	    proto.utcOffset            = getSetOffset;
	    proto.utc                  = setOffsetToUTC;
	    proto.local                = setOffsetToLocal;
	    proto.parseZone            = setOffsetToParsedOffset;
	    proto.hasAlignedHourOffset = hasAlignedHourOffset;
	    proto.isDST                = isDaylightSavingTime;
	    proto.isLocal              = isLocal;
	    proto.isUtcOffset          = isUtcOffset;
	    proto.isUtc                = isUtc;
	    proto.isUTC                = isUtc;
	    proto.zoneAbbr = getZoneAbbr;
	    proto.zoneName = getZoneName;
	    proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
	    proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
	    proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
	    proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
	    proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);

	    function createUnix (input) {
	        return createLocal(input * 1000);
	    }

	    function createInZone () {
	        return createLocal.apply(null, arguments).parseZone();
	    }

	    function preParsePostFormat (string) {
	        return string;
	    }

	    var proto$1 = Locale.prototype;

	    proto$1.calendar        = calendar;
	    proto$1.longDateFormat  = longDateFormat;
	    proto$1.invalidDate     = invalidDate;
	    proto$1.ordinal         = ordinal;
	    proto$1.preparse        = preParsePostFormat;
	    proto$1.postformat      = preParsePostFormat;
	    proto$1.relativeTime    = relativeTime;
	    proto$1.pastFuture      = pastFuture;
	    proto$1.set             = set;

	    proto$1.months            =        localeMonths;
	    proto$1.monthsShort       =        localeMonthsShort;
	    proto$1.monthsParse       =        localeMonthsParse;
	    proto$1.monthsRegex       = monthsRegex;
	    proto$1.monthsShortRegex  = monthsShortRegex;
	    proto$1.week = localeWeek;
	    proto$1.firstDayOfYear = localeFirstDayOfYear;
	    proto$1.firstDayOfWeek = localeFirstDayOfWeek;

	    proto$1.weekdays       =        localeWeekdays;
	    proto$1.weekdaysMin    =        localeWeekdaysMin;
	    proto$1.weekdaysShort  =        localeWeekdaysShort;
	    proto$1.weekdaysParse  =        localeWeekdaysParse;

	    proto$1.weekdaysRegex       =        weekdaysRegex;
	    proto$1.weekdaysShortRegex  =        weekdaysShortRegex;
	    proto$1.weekdaysMinRegex    =        weekdaysMinRegex;

	    proto$1.isPM = localeIsPM;
	    proto$1.meridiem = localeMeridiem;

	    function get$1 (format, index, field, setter) {
	        var locale = getLocale();
	        var utc = createUTC().set(setter, index);
	        return locale[field](utc, format);
	    }

	    function listMonthsImpl (format, index, field) {
	        if (isNumber(format)) {
	            index = format;
	            format = undefined;
	        }

	        format = format || '';

	        if (index != null) {
	            return get$1(format, index, field, 'month');
	        }

	        var i;
	        var out = [];
	        for (i = 0; i < 12; i++) {
	            out[i] = get$1(format, i, field, 'month');
	        }
	        return out;
	    }

	    // ()
	    // (5)
	    // (fmt, 5)
	    // (fmt)
	    // (true)
	    // (true, 5)
	    // (true, fmt, 5)
	    // (true, fmt)
	    function listWeekdaysImpl (localeSorted, format, index, field) {
	        if (typeof localeSorted === 'boolean') {
	            if (isNumber(format)) {
	                index = format;
	                format = undefined;
	            }

	            format = format || '';
	        } else {
	            format = localeSorted;
	            index = format;
	            localeSorted = false;

	            if (isNumber(format)) {
	                index = format;
	                format = undefined;
	            }

	            format = format || '';
	        }

	        var locale = getLocale(),
	            shift = localeSorted ? locale._week.dow : 0;

	        if (index != null) {
	            return get$1(format, (index + shift) % 7, field, 'day');
	        }

	        var i;
	        var out = [];
	        for (i = 0; i < 7; i++) {
	            out[i] = get$1(format, (i + shift) % 7, field, 'day');
	        }
	        return out;
	    }

	    function listMonths (format, index) {
	        return listMonthsImpl(format, index, 'months');
	    }

	    function listMonthsShort (format, index) {
	        return listMonthsImpl(format, index, 'monthsShort');
	    }

	    function listWeekdays (localeSorted, format, index) {
	        return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
	    }

	    function listWeekdaysShort (localeSorted, format, index) {
	        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
	    }

	    function listWeekdaysMin (localeSorted, format, index) {
	        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
	    }

	    getSetGlobalLocale('en', {
	        dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
	        ordinal : function (number) {
	            var b = number % 10,
	                output = (toInt(number % 100 / 10) === 1) ? 'th' :
	                (b === 1) ? 'st' :
	                (b === 2) ? 'nd' :
	                (b === 3) ? 'rd' : 'th';
	            return number + output;
	        }
	    });

	    // Side effect imports

	    hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
	    hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);

	    var mathAbs = Math.abs;

	    function abs () {
	        var data           = this._data;

	        this._milliseconds = mathAbs(this._milliseconds);
	        this._days         = mathAbs(this._days);
	        this._months       = mathAbs(this._months);

	        data.milliseconds  = mathAbs(data.milliseconds);
	        data.seconds       = mathAbs(data.seconds);
	        data.minutes       = mathAbs(data.minutes);
	        data.hours         = mathAbs(data.hours);
	        data.months        = mathAbs(data.months);
	        data.years         = mathAbs(data.years);

	        return this;
	    }

	    function addSubtract$1 (duration, input, value, direction) {
	        var other = createDuration(input, value);

	        duration._milliseconds += direction * other._milliseconds;
	        duration._days         += direction * other._days;
	        duration._months       += direction * other._months;

	        return duration._bubble();
	    }

	    // supports only 2.0-style add(1, 's') or add(duration)
	    function add$1 (input, value) {
	        return addSubtract$1(this, input, value, 1);
	    }

	    // supports only 2.0-style subtract(1, 's') or subtract(duration)
	    function subtract$1 (input, value) {
	        return addSubtract$1(this, input, value, -1);
	    }

	    function absCeil (number) {
	        if (number < 0) {
	            return Math.floor(number);
	        } else {
	            return Math.ceil(number);
	        }
	    }

	    function bubble () {
	        var milliseconds = this._milliseconds;
	        var days         = this._days;
	        var months       = this._months;
	        var data         = this._data;
	        var seconds, minutes, hours, years, monthsFromDays;

	        // if we have a mix of positive and negative values, bubble down first
	        // check: https://github.com/moment/moment/issues/2166
	        if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
	                (milliseconds <= 0 && days <= 0 && months <= 0))) {
	            milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
	            days = 0;
	            months = 0;
	        }

	        // The following code bubbles up values, see the tests for
	        // examples of what that means.
	        data.milliseconds = milliseconds % 1000;

	        seconds           = absFloor(milliseconds / 1000);
	        data.seconds      = seconds % 60;

	        minutes           = absFloor(seconds / 60);
	        data.minutes      = minutes % 60;

	        hours             = absFloor(minutes / 60);
	        data.hours        = hours % 24;

	        days += absFloor(hours / 24);

	        // convert days to months
	        monthsFromDays = absFloor(daysToMonths(days));
	        months += monthsFromDays;
	        days -= absCeil(monthsToDays(monthsFromDays));

	        // 12 months -> 1 year
	        years = absFloor(months / 12);
	        months %= 12;

	        data.days   = days;
	        data.months = months;
	        data.years  = years;

	        return this;
	    }

	    function daysToMonths (days) {
	        // 400 years have 146097 days (taking into account leap year rules)
	        // 400 years have 12 months === 4800
	        return days * 4800 / 146097;
	    }

	    function monthsToDays (months) {
	        // the reverse of daysToMonths
	        return months * 146097 / 4800;
	    }

	    function as (units) {
	        if (!this.isValid()) {
	            return NaN;
	        }
	        var days;
	        var months;
	        var milliseconds = this._milliseconds;

	        units = normalizeUnits(units);

	        if (units === 'month' || units === 'year') {
	            days   = this._days   + milliseconds / 864e5;
	            months = this._months + daysToMonths(days);
	            return units === 'month' ? months : months / 12;
	        } else {
	            // handle milliseconds separately because of floating point math errors (issue #1867)
	            days = this._days + Math.round(monthsToDays(this._months));
	            switch (units) {
	                case 'week'   : return days / 7     + milliseconds / 6048e5;
	                case 'day'    : return days         + milliseconds / 864e5;
	                case 'hour'   : return days * 24    + milliseconds / 36e5;
	                case 'minute' : return days * 1440  + milliseconds / 6e4;
	                case 'second' : return days * 86400 + milliseconds / 1000;
	                // Math.floor prevents floating point math errors here
	                case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
	                default: throw new Error('Unknown unit ' + units);
	            }
	        }
	    }

	    // TODO: Use this.as('ms')?
	    function valueOf$1 () {
	        if (!this.isValid()) {
	            return NaN;
	        }
	        return (
	            this._milliseconds +
	            this._days * 864e5 +
	            (this._months % 12) * 2592e6 +
	            toInt(this._months / 12) * 31536e6
	        );
	    }

	    function makeAs (alias) {
	        return function () {
	            return this.as(alias);
	        };
	    }

	    var asMilliseconds = makeAs('ms');
	    var asSeconds      = makeAs('s');
	    var asMinutes      = makeAs('m');
	    var asHours        = makeAs('h');
	    var asDays         = makeAs('d');
	    var asWeeks        = makeAs('w');
	    var asMonths       = makeAs('M');
	    var asYears        = makeAs('y');

	    function clone$1 () {
	        return createDuration(this);
	    }

	    function get$2 (units) {
	        units = normalizeUnits(units);
	        return this.isValid() ? this[units + 's']() : NaN;
	    }

	    function makeGetter(name) {
	        return function () {
	            return this.isValid() ? this._data[name] : NaN;
	        };
	    }

	    var milliseconds = makeGetter('milliseconds');
	    var seconds      = makeGetter('seconds');
	    var minutes      = makeGetter('minutes');
	    var hours        = makeGetter('hours');
	    var days         = makeGetter('days');
	    var months       = makeGetter('months');
	    var years        = makeGetter('years');

	    function weeks () {
	        return absFloor(this.days() / 7);
	    }

	    var round = Math.round;
	    var thresholds = {
	        ss: 44,         // a few seconds to seconds
	        s : 45,         // seconds to minute
	        m : 45,         // minutes to hour
	        h : 22,         // hours to day
	        d : 26,         // days to month
	        M : 11          // months to year
	    };

	    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
	    function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
	        return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
	    }

	    function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
	        var duration = createDuration(posNegDuration).abs();
	        var seconds  = round(duration.as('s'));
	        var minutes  = round(duration.as('m'));
	        var hours    = round(duration.as('h'));
	        var days     = round(duration.as('d'));
	        var months   = round(duration.as('M'));
	        var years    = round(duration.as('y'));

	        var a = seconds <= thresholds.ss && ['s', seconds]  ||
	                seconds < thresholds.s   && ['ss', seconds] ||
	                minutes <= 1             && ['m']           ||
	                minutes < thresholds.m   && ['mm', minutes] ||
	                hours   <= 1             && ['h']           ||
	                hours   < thresholds.h   && ['hh', hours]   ||
	                days    <= 1             && ['d']           ||
	                days    < thresholds.d   && ['dd', days]    ||
	                months  <= 1             && ['M']           ||
	                months  < thresholds.M   && ['MM', months]  ||
	                years   <= 1             && ['y']           || ['yy', years];

	        a[2] = withoutSuffix;
	        a[3] = +posNegDuration > 0;
	        a[4] = locale;
	        return substituteTimeAgo.apply(null, a);
	    }

	    // This function allows you to set the rounding function for relative time strings
	    function getSetRelativeTimeRounding (roundingFunction) {
	        if (roundingFunction === undefined) {
	            return round;
	        }
	        if (typeof(roundingFunction) === 'function') {
	            round = roundingFunction;
	            return true;
	        }
	        return false;
	    }

	    // This function allows you to set a threshold for relative time strings
	    function getSetRelativeTimeThreshold (threshold, limit) {
	        if (thresholds[threshold] === undefined) {
	            return false;
	        }
	        if (limit === undefined) {
	            return thresholds[threshold];
	        }
	        thresholds[threshold] = limit;
	        if (threshold === 's') {
	            thresholds.ss = limit - 1;
	        }
	        return true;
	    }

	    function humanize (withSuffix) {
	        if (!this.isValid()) {
	            return this.localeData().invalidDate();
	        }

	        var locale = this.localeData();
	        var output = relativeTime$1(this, !withSuffix, locale);

	        if (withSuffix) {
	            output = locale.pastFuture(+this, output);
	        }

	        return locale.postformat(output);
	    }

	    var abs$1 = Math.abs;

	    function sign(x) {
	        return ((x > 0) - (x < 0)) || +x;
	    }

	    function toISOString$1() {
	        // for ISO strings we do not use the normal bubbling rules:
	        //  * milliseconds bubble up until they become hours
	        //  * days do not bubble at all
	        //  * months bubble up until they become years
	        // This is because there is no context-free conversion between hours and days
	        // (think of clock changes)
	        // and also not between days and months (28-31 days per month)
	        if (!this.isValid()) {
	            return this.localeData().invalidDate();
	        }

	        var seconds = abs$1(this._milliseconds) / 1000;
	        var days         = abs$1(this._days);
	        var months       = abs$1(this._months);
	        var minutes, hours, years;

	        // 3600 seconds -> 60 minutes -> 1 hour
	        minutes           = absFloor(seconds / 60);
	        hours             = absFloor(minutes / 60);
	        seconds %= 60;
	        minutes %= 60;

	        // 12 months -> 1 year
	        years  = absFloor(months / 12);
	        months %= 12;


	        // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
	        var Y = years;
	        var M = months;
	        var D = days;
	        var h = hours;
	        var m = minutes;
	        var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
	        var total = this.asSeconds();

	        if (!total) {
	            // this is the same as C#'s (Noda) and python (isodate)...
	            // but not other JS (goog.date)
	            return 'P0D';
	        }

	        var totalSign = total < 0 ? '-' : '';
	        var ymSign = sign(this._months) !== sign(total) ? '-' : '';
	        var daysSign = sign(this._days) !== sign(total) ? '-' : '';
	        var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';

	        return totalSign + 'P' +
	            (Y ? ymSign + Y + 'Y' : '') +
	            (M ? ymSign + M + 'M' : '') +
	            (D ? daysSign + D + 'D' : '') +
	            ((h || m || s) ? 'T' : '') +
	            (h ? hmsSign + h + 'H' : '') +
	            (m ? hmsSign + m + 'M' : '') +
	            (s ? hmsSign + s + 'S' : '');
	    }

	    var proto$2 = Duration.prototype;

	    proto$2.isValid        = isValid$1;
	    proto$2.abs            = abs;
	    proto$2.add            = add$1;
	    proto$2.subtract       = subtract$1;
	    proto$2.as             = as;
	    proto$2.asMilliseconds = asMilliseconds;
	    proto$2.asSeconds      = asSeconds;
	    proto$2.asMinutes      = asMinutes;
	    proto$2.asHours        = asHours;
	    proto$2.asDays         = asDays;
	    proto$2.asWeeks        = asWeeks;
	    proto$2.asMonths       = asMonths;
	    proto$2.asYears        = asYears;
	    proto$2.valueOf        = valueOf$1;
	    proto$2._bubble        = bubble;
	    proto$2.clone          = clone$1;
	    proto$2.get            = get$2;
	    proto$2.milliseconds   = milliseconds;
	    proto$2.seconds        = seconds;
	    proto$2.minutes        = minutes;
	    proto$2.hours          = hours;
	    proto$2.days           = days;
	    proto$2.weeks          = weeks;
	    proto$2.months         = months;
	    proto$2.years          = years;
	    proto$2.humanize       = humanize;
	    proto$2.toISOString    = toISOString$1;
	    proto$2.toString       = toISOString$1;
	    proto$2.toJSON         = toISOString$1;
	    proto$2.locale         = locale;
	    proto$2.localeData     = localeData;

	    proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
	    proto$2.lang = lang;

	    // Side effect imports

	    // FORMATTING

	    addFormatToken('X', 0, 0, 'unix');
	    addFormatToken('x', 0, 0, 'valueOf');

	    // PARSING

	    addRegexToken('x', matchSigned);
	    addRegexToken('X', matchTimestamp);
	    addParseToken('X', function (input, array, config) {
	        config._d = new Date(parseFloat(input, 10) * 1000);
	    });
	    addParseToken('x', function (input, array, config) {
	        config._d = new Date(toInt(input));
	    });

	    // Side effect imports


	    hooks.version = '2.22.2';

	    setHookCallback(createLocal);

	    hooks.fn                    = proto;
	    hooks.min                   = min;
	    hooks.max                   = max;
	    hooks.now                   = now;
	    hooks.utc                   = createUTC;
	    hooks.unix                  = createUnix;
	    hooks.months                = listMonths;
	    hooks.isDate                = isDate;
	    hooks.locale                = getSetGlobalLocale;
	    hooks.invalid               = createInvalid;
	    hooks.duration              = createDuration;
	    hooks.isMoment              = isMoment;
	    hooks.weekdays              = listWeekdays;
	    hooks.parseZone             = createInZone;
	    hooks.localeData            = getLocale;
	    hooks.isDuration            = isDuration;
	    hooks.monthsShort           = listMonthsShort;
	    hooks.weekdaysMin           = listWeekdaysMin;
	    hooks.defineLocale          = defineLocale;
	    hooks.updateLocale          = updateLocale;
	    hooks.locales               = listLocales;
	    hooks.weekdaysShort         = listWeekdaysShort;
	    hooks.normalizeUnits        = normalizeUnits;
	    hooks.relativeTimeRounding  = getSetRelativeTimeRounding;
	    hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
	    hooks.calendarFormat        = getCalendarFormat;
	    hooks.prototype             = proto;

	    // currently HTML5 input type only supports 24-hour formats
	    hooks.HTML5_FMT = {
	        DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',             // <input type="datetime-local" />
	        DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',  // <input type="datetime-local" step="1" />
	        DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',   // <input type="datetime-local" step="0.001" />
	        DATE: 'YYYY-MM-DD',                             // <input type="date" />
	        TIME: 'HH:mm',                                  // <input type="time" />
	        TIME_SECONDS: 'HH:mm:ss',                       // <input type="time" step="1" />
	        TIME_MS: 'HH:mm:ss.SSS',                        // <input type="time" step="0.001" />
	        WEEK: 'YYYY-[W]WW',                             // <input type="week" />
	        MONTH: 'YYYY-MM'                                // <input type="month" />
	    };

	    return hooks;

	})));
	});

	var moment$1 = moment;
	moment$1 = typeof moment$1 === 'function' ? moment$1 : window.moment;




	// Integer constants are from the ES6 spec.
	var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
	var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;

	var INTERVALS = {
		millisecond: {
			common: true,
			size: 1,
			steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
		},
		second: {
			common: true,
			size: 1000,
			steps: [1, 2, 5, 10, 30]
		},
		minute: {
			common: true,
			size: 60000,
			steps: [1, 2, 5, 10, 30]
		},
		hour: {
			common: true,
			size: 3600000,
			steps: [1, 2, 3, 6, 12]
		},
		day: {
			common: true,
			size: 86400000,
			steps: [1, 2, 5]
		},
		week: {
			common: false,
			size: 604800000,
			steps: [1, 2, 3, 4]
		},
		month: {
			common: true,
			size: 2.628e9,
			steps: [1, 2, 3]
		},
		quarter: {
			common: false,
			size: 7.884e9,
			steps: [1, 2, 3, 4]
		},
		year: {
			common: true,
			size: 3.154e10
		}
	};

	var UNITS = Object.keys(INTERVALS);

	function sorter(a, b) {
		return a - b;
	}

	function arrayUnique(items) {
		var hash = {};
		var out = [];
		var i, ilen, item;

		for (i = 0, ilen = items.length; i < ilen; ++i) {
			item = items[i];
			if (!hash[item]) {
				hash[item] = true;
				out.push(item);
			}
		}

		return out;
	}

	/**
	 * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
	 * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
	 * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
	 * extremity (left + width or top + height). Note that it would be more optimized to directly
	 * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
	 * to create the lookup table. The table ALWAYS contains at least two items: min and max.
	 *
	 * @param {Number[]} timestamps - timestamps sorted from lowest to highest.
	 * @param {String} distribution - If 'linear', timestamps will be spread linearly along the min
	 * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
	 * If 'series', timestamps will be positioned at the same distance from each other. In this
	 * case, only timestamps that break the time linearity are registered, meaning that in the
	 * best case, all timestamps are linear, the table contains only min and max.
	 */
	function buildLookupTable(timestamps, min, max, distribution) {
		if (distribution === 'linear' || !timestamps.length) {
			return [
				{time: min, pos: 0},
				{time: max, pos: 1}
			];
		}

		var table = [];
		var items = [min];
		var i, ilen, prev, curr, next;

		for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
			curr = timestamps[i];
			if (curr > min && curr < max) {
				items.push(curr);
			}
		}

		items.push(max);

		for (i = 0, ilen = items.length; i < ilen; ++i) {
			next = items[i + 1];
			prev = items[i - 1];
			curr = items[i];

			// only add points that breaks the scale linearity
			if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
				table.push({time: curr, pos: i / (ilen - 1)});
			}
		}

		return table;
	}

	// @see adapted from http://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
	function lookup(table, key, value) {
		var lo = 0;
		var hi = table.length - 1;
		var mid, i0, i1;

		while (lo >= 0 && lo <= hi) {
			mid = (lo + hi) >> 1;
			i0 = table[mid - 1] || null;
			i1 = table[mid];

			if (!i0) {
				// given value is outside table (before first item)
				return {lo: null, hi: i1};
			} else if (i1[key] < value) {
				lo = mid + 1;
			} else if (i0[key] > value) {
				hi = mid - 1;
			} else {
				return {lo: i0, hi: i1};
			}
		}

		// given value is outside table (after last item)
		return {lo: i1, hi: null};
	}

	/**
	 * Linearly interpolates the given source `value` using the table items `skey` values and
	 * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
	 * returns the position for a timestamp equal to 42. If value is out of bounds, values at
	 * index [0, 1] or [n - 1, n] are used for the interpolation.
	 */
	function interpolate$1(table, skey, sval, tkey) {
		var range = lookup(table, skey, sval);

		// Note: the lookup table ALWAYS contains at least 2 items (min and max)
		var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
		var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;

		var span = next[skey] - prev[skey];
		var ratio = span ? (sval - prev[skey]) / span : 0;
		var offset = (next[tkey] - prev[tkey]) * ratio;

		return prev[tkey] + offset;
	}

	/**
	 * Convert the given value to a moment object using the given time options.
	 * @see http://momentjs.com/docs/#/parsing/
	 */
	function momentify(value, options) {
		var parser = options.parser;
		var format = options.parser || options.format;

		if (typeof parser === 'function') {
			return parser(value);
		}

		if (typeof value === 'string' && typeof format === 'string') {
			return moment$1(value, format);
		}

		if (!(value instanceof moment$1)) {
			value = moment$1(value);
		}

		if (value.isValid()) {
			return value;
		}

		// Labels are in an incompatible moment format and no `parser` has been provided.
		// The user might still use the deprecated `format` option to convert his inputs.
		if (typeof format === 'function') {
			return format(value);
		}

		return value;
	}

	function parse(input, scale) {
		if (helpers$1.isNullOrUndef(input)) {
			return null;
		}

		var options = scale.options.time;
		var value = momentify(scale.getRightValue(input), options);
		if (!value.isValid()) {
			return null;
		}

		if (options.round) {
			value.startOf(options.round);
		}

		return value.valueOf();
	}

	/**
	 * Returns the number of unit to skip to be able to display up to `capacity` number of ticks
	 * in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
	 */
	function determineStepSize(min, max, unit, capacity) {
		var range = max - min;
		var interval = INTERVALS[unit];
		var milliseconds = interval.size;
		var steps = interval.steps;
		var i, ilen, factor;

		if (!steps) {
			return Math.ceil(range / (capacity * milliseconds));
		}

		for (i = 0, ilen = steps.length; i < ilen; ++i) {
			factor = steps[i];
			if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
				break;
			}
		}

		return factor;
	}

	/**
	 * Figures out what unit results in an appropriate number of auto-generated ticks
	 */
	function determineUnitForAutoTicks(minUnit, min, max, capacity) {
		var ilen = UNITS.length;
		var i, interval, factor;

		for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
			interval = INTERVALS[UNITS[i]];
			factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;

			if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
				return UNITS[i];
			}
		}

		return UNITS[ilen - 1];
	}

	/**
	 * Figures out what unit to format a set of ticks with
	 */
	function determineUnitForFormatting(ticks, minUnit, min, max) {
		var duration = moment$1.duration(moment$1(max).diff(moment$1(min)));
		var ilen = UNITS.length;
		var i, unit;

		for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
			unit = UNITS[i];
			if (INTERVALS[unit].common && duration.as(unit) >= ticks.length) {
				return unit;
			}
		}

		return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
	}

	function determineMajorUnit(unit) {
		for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
			if (INTERVALS[UNITS[i]].common) {
				return UNITS[i];
			}
		}
	}

	/**
	 * Generates a maximum of `capacity` timestamps between min and max, rounded to the
	 * `minor` unit, aligned on the `major` unit and using the given scale time `options`.
	 * Important: this method can return ticks outside the min and max range, it's the
	 * responsibility of the calling code to clamp values if needed.
	 */
	function generate(min, max, capacity, options) {
		var timeOpts = options.time;
		var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
		var major = determineMajorUnit(minor);
		var stepSize = helpers$1.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize);
		var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
		var majorTicksEnabled = options.ticks.major.enabled;
		var interval = INTERVALS[minor];
		var first = moment$1(min);
		var last = moment$1(max);
		var ticks = [];
		var time;

		if (!stepSize) {
			stepSize = determineStepSize(min, max, minor, capacity);
		}

		// For 'week' unit, handle the first day of week option
		if (weekday) {
			first = first.isoWeekday(weekday);
			last = last.isoWeekday(weekday);
		}

		// Align first/last ticks on unit
		first = first.startOf(weekday ? 'day' : minor);
		last = last.startOf(weekday ? 'day' : minor);

		// Make sure that the last tick include max
		if (last < max) {
			last.add(1, minor);
		}

		time = moment$1(first);

		if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
			// Align the first tick on the previous `minor` unit aligned on the `major` unit:
			// we first aligned time on the previous `major` unit then add the number of full
			// stepSize there is between first and the previous major time.
			time.startOf(major);
			time.add(~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
		}

		for (; time < last; time.add(stepSize, minor)) {
			ticks.push(+time);
		}

		ticks.push(+time);

		return ticks;
	}

	/**
	 * Returns the right and left offsets from edges in the form of {left, right}.
	 * Offsets are added when the `offset` option is true.
	 */
	function computeOffsets(table, ticks, min, max, options) {
		var left = 0;
		var right = 0;
		var upper, lower;

		if (options.offset && ticks.length) {
			if (!options.time.min) {
				upper = ticks.length > 1 ? ticks[1] : max;
				lower = ticks[0];
				left = (
					interpolate$1(table, 'time', upper, 'pos') -
					interpolate$1(table, 'time', lower, 'pos')
				) / 2;
			}
			if (!options.time.max) {
				upper = ticks[ticks.length - 1];
				lower = ticks.length > 1 ? ticks[ticks.length - 2] : min;
				right = (
					interpolate$1(table, 'time', upper, 'pos') -
					interpolate$1(table, 'time', lower, 'pos')
				) / 2;
			}
		}

		return {left: left, right: right};
	}

	function ticksFromTimestamps(values, majorUnit) {
		var ticks = [];
		var i, ilen, value, major;

		for (i = 0, ilen = values.length; i < ilen; ++i) {
			value = values[i];
			major = majorUnit ? value === +moment$1(value).startOf(majorUnit) : false;

			ticks.push({
				value: value,
				major: major
			});
		}

		return ticks;
	}

	function determineLabelFormat(data, timeOpts) {
		var i, momentDate, hasTime;
		var ilen = data.length;

		// find the label with the most parts (milliseconds, minutes, etc.)
		// format all labels with the same level of detail as the most specific label
		for (i = 0; i < ilen; i++) {
			momentDate = momentify(data[i], timeOpts);
			if (momentDate.millisecond() !== 0) {
				return 'MMM D, YYYY h:mm:ss.SSS a';
			}
			if (momentDate.second() !== 0 || momentDate.minute() !== 0 || momentDate.hour() !== 0) {
				hasTime = true;
			}
		}
		if (hasTime) {
			return 'MMM D, YYYY h:mm:ss a';
		}
		return 'MMM D, YYYY';
	}

	var scale_time = function(Chart) {

		var defaultConfig = {
			position: 'bottom',

			/**
			 * Data distribution along the scale:
			 * - 'linear': data are spread according to their time (distances can vary),
			 * - 'series': data are spread at the same distance from each other.
			 * @see https://github.com/chartjs/Chart.js/pull/4507
			 * @since 2.7.0
			 */
			distribution: 'linear',

			/**
			 * Scale boundary strategy (bypassed by min/max time options)
			 * - `data`: make sure data are fully visible, ticks outside are removed
			 * - `ticks`: make sure ticks are fully visible, data outside are truncated
			 * @see https://github.com/chartjs/Chart.js/pull/4556
			 * @since 2.7.0
			 */
			bounds: 'data',

			time: {
				parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
				format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
				unit: false, // false == automatic or override with week, month, year, etc.
				round: false, // none, or override with week, month, year, etc.
				displayFormat: false, // DEPRECATED
				isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
				minUnit: 'millisecond',

				// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
				displayFormats: {
					millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
					second: 'h:mm:ss a', // 11:20:01 AM
					minute: 'h:mm a', // 11:20 AM
					hour: 'hA', // 5PM
					day: 'MMM D', // Sep 4
					week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
					month: 'MMM YYYY', // Sept 2015
					quarter: '[Q]Q - YYYY', // Q3
					year: 'YYYY' // 2015
				},
			},
			ticks: {
				autoSkip: false,

				/**
				 * Ticks generation input values:
				 * - 'auto': generates "optimal" ticks based on scale size and time options.
				 * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
				 * - 'labels': generates ticks from user given `data.labels` values ONLY.
				 * @see https://github.com/chartjs/Chart.js/pull/4507
				 * @since 2.7.0
				 */
				source: 'auto',

				major: {
					enabled: false
				}
			}
		};

		var TimeScale = Chart.Scale.extend({
			initialize: function() {
				if (!moment$1) {
					throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
				}

				this.mergeTicksOptions();

				Chart.Scale.prototype.initialize.call(this);
			},

			update: function() {
				var me = this;
				var options = me.options;

				// DEPRECATIONS: output a message only one time per update
				if (options.time && options.time.format) {
					console.warn('options.time.format is deprecated and replaced by options.time.parser.');
				}

				return Chart.Scale.prototype.update.apply(me, arguments);
			},

			/**
			 * Allows data to be referenced via 't' attribute
			 */
			getRightValue: function(rawValue) {
				if (rawValue && rawValue.t !== undefined) {
					rawValue = rawValue.t;
				}
				return Chart.Scale.prototype.getRightValue.call(this, rawValue);
			},

			determineDataLimits: function() {
				var me = this;
				var chart = me.chart;
				var timeOpts = me.options.time;
				var unit = timeOpts.unit || 'day';
				var min = MAX_INTEGER;
				var max = MIN_INTEGER;
				var timestamps = [];
				var datasets = [];
				var labels = [];
				var i, j, ilen, jlen, data, timestamp;

				// Convert labels to timestamps
				for (i = 0, ilen = chart.data.labels.length; i < ilen; ++i) {
					labels.push(parse(chart.data.labels[i], me));
				}

				// Convert data to timestamps
				for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
					if (chart.isDatasetVisible(i)) {
						data = chart.data.datasets[i].data;

						// Let's consider that all data have the same format.
						if (helpers$1.isObject(data[0])) {
							datasets[i] = [];

							for (j = 0, jlen = data.length; j < jlen; ++j) {
								timestamp = parse(data[j], me);
								timestamps.push(timestamp);
								datasets[i][j] = timestamp;
							}
						} else {
							timestamps.push.apply(timestamps, labels);
							datasets[i] = labels.slice(0);
						}
					} else {
						datasets[i] = [];
					}
				}

				if (labels.length) {
					// Sort labels **after** data have been converted
					labels = arrayUnique(labels).sort(sorter);
					min = Math.min(min, labels[0]);
					max = Math.max(max, labels[labels.length - 1]);
				}

				if (timestamps.length) {
					timestamps = arrayUnique(timestamps).sort(sorter);
					min = Math.min(min, timestamps[0]);
					max = Math.max(max, timestamps[timestamps.length - 1]);
				}

				min = parse(timeOpts.min, me) || min;
				max = parse(timeOpts.max, me) || max;

				// In case there is no valid min/max, set limits based on unit time option
				min = min === MAX_INTEGER ? +moment$1().startOf(unit) : min;
				max = max === MIN_INTEGER ? +moment$1().endOf(unit) + 1 : max;

				// Make sure that max is strictly higher than min (required by the lookup table)
				me.min = Math.min(min, max);
				me.max = Math.max(min + 1, max);

				// PRIVATE
				me._horizontal = me.isHorizontal();
				me._table = [];
				me._timestamps = {
					data: timestamps,
					datasets: datasets,
					labels: labels
				};
			},

			buildTicks: function() {
				var me = this;
				var min = me.min;
				var max = me.max;
				var options = me.options;
				var timeOpts = options.time;
				var timestamps = [];
				var ticks = [];
				var i, ilen, timestamp;

				switch (options.ticks.source) {
				case 'data':
					timestamps = me._timestamps.data;
					break;
				case 'labels':
					timestamps = me._timestamps.labels;
					break;
				case 'auto':
				default:
					timestamps = generate(min, max, me.getLabelCapacity(min), options);
				}

				if (options.bounds === 'ticks' && timestamps.length) {
					min = timestamps[0];
					max = timestamps[timestamps.length - 1];
				}

				// Enforce limits with user min/max options
				min = parse(timeOpts.min, me) || min;
				max = parse(timeOpts.max, me) || max;

				// Remove ticks outside the min/max range
				for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
					timestamp = timestamps[i];
					if (timestamp >= min && timestamp <= max) {
						ticks.push(timestamp);
					}
				}

				me.min = min;
				me.max = max;

				// PRIVATE
				me._unit = timeOpts.unit || determineUnitForFormatting(ticks, timeOpts.minUnit, me.min, me.max);
				me._majorUnit = determineMajorUnit(me._unit);
				me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
				me._offsets = computeOffsets(me._table, ticks, min, max, options);
				me._labelFormat = determineLabelFormat(me._timestamps.data, timeOpts);

				return ticksFromTimestamps(ticks, me._majorUnit);
			},

			getLabelForIndex: function(index, datasetIndex) {
				var me = this;
				var data = me.chart.data;
				var timeOpts = me.options.time;
				var label = data.labels && index < data.labels.length ? data.labels[index] : '';
				var value = data.datasets[datasetIndex].data[index];

				if (helpers$1.isObject(value)) {
					label = me.getRightValue(value);
				}
				if (timeOpts.tooltipFormat) {
					return momentify(label, timeOpts).format(timeOpts.tooltipFormat);
				}
				if (typeof label === 'string') {
					return label;
				}

				return momentify(label, timeOpts).format(me._labelFormat);
			},

			/**
			 * Function to format an individual tick mark
			 * @private
			 */
			tickFormatFunction: function(tick, index, ticks, formatOverride) {
				var me = this;
				var options = me.options;
				var time = tick.valueOf();
				var formats = options.time.displayFormats;
				var minorFormat = formats[me._unit];
				var majorUnit = me._majorUnit;
				var majorFormat = formats[majorUnit];
				var majorTime = tick.clone().startOf(majorUnit).valueOf();
				var majorTickOpts = options.ticks.major;
				var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
				var label = tick.format(formatOverride ? formatOverride : major ? majorFormat : minorFormat);
				var tickOpts = major ? majorTickOpts : options.ticks.minor;
				var formatter = helpers$1.valueOrDefault(tickOpts.callback, tickOpts.userCallback);

				return formatter ? formatter(label, index, ticks) : label;
			},

			convertTicksToLabels: function(ticks) {
				var labels = [];
				var i, ilen;

				for (i = 0, ilen = ticks.length; i < ilen; ++i) {
					labels.push(this.tickFormatFunction(moment$1(ticks[i].value), i, ticks));
				}

				return labels;
			},

			/**
			 * @private
			 */
			getPixelForOffset: function(time) {
				var me = this;
				var size = me._horizontal ? me.width : me.height;
				var start = me._horizontal ? me.left : me.top;
				var pos = interpolate$1(me._table, 'time', time, 'pos');

				return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right);
			},

			getPixelForValue: function(value, index, datasetIndex) {
				var me = this;
				var time = null;

				if (index !== undefined && datasetIndex !== undefined) {
					time = me._timestamps.datasets[datasetIndex][index];
				}

				if (time === null) {
					time = parse(value, me);
				}

				if (time !== null) {
					return me.getPixelForOffset(time);
				}
			},

			getPixelForTick: function(index) {
				var ticks = this.getTicks();
				return index >= 0 && index < ticks.length ?
					this.getPixelForOffset(ticks[index].value) :
					null;
			},

			getValueForPixel: function(pixel) {
				var me = this;
				var size = me._horizontal ? me.width : me.height;
				var start = me._horizontal ? me.left : me.top;
				var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right;
				var time = interpolate$1(me._table, 'pos', pos, 'time');

				return moment$1(time);
			},

			/**
			 * Crude approximation of what the label width might be
			 * @private
			 */
			getLabelWidth: function(label) {
				var me = this;
				var ticksOpts = me.options.ticks;
				var tickLabelWidth = me.ctx.measureText(label).width;
				var angle = helpers$1.toRadians(ticksOpts.maxRotation);
				var cosRotation = Math.cos(angle);
				var sinRotation = Math.sin(angle);
				var tickFontSize = helpers$1.valueOrDefault(ticksOpts.fontSize, core_defaults.global.defaultFontSize);

				return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
			},

			/**
			 * @private
			 */
			getLabelCapacity: function(exampleTime) {
				var me = this;

				var formatOverride = me.options.time.displayFormats.millisecond;	// Pick the longest format for guestimation

				var exampleLabel = me.tickFormatFunction(moment$1(exampleTime), 0, [], formatOverride);
				var tickLabelWidth = me.getLabelWidth(exampleLabel);
				var innerWidth = me.isHorizontal() ? me.width : me.height;

				var capacity = Math.floor(innerWidth / tickLabelWidth);
				return capacity > 0 ? capacity : 1;
			}
		});

		Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);
	};

	core_defaults._set('bar', {
		hover: {
			mode: 'label'
		},

		scales: {
			xAxes: [{
				type: 'category',

				// Specific to Bar Controller
				categoryPercentage: 0.8,
				barPercentage: 0.9,

				// offset settings
				offset: true,

				// grid line settings
				gridLines: {
					offsetGridLines: true
				}
			}],

			yAxes: [{
				type: 'linear'
			}]
		}
	});

	core_defaults._set('horizontalBar', {
		hover: {
			mode: 'index',
			axis: 'y'
		},

		scales: {
			xAxes: [{
				type: 'linear',
				position: 'bottom'
			}],

			yAxes: [{
				position: 'left',
				type: 'category',

				// Specific to Horizontal Bar Controller
				categoryPercentage: 0.8,
				barPercentage: 0.9,

				// offset settings
				offset: true,

				// grid line settings
				gridLines: {
					offsetGridLines: true
				}
			}]
		},

		elements: {
			rectangle: {
				borderSkipped: 'left'
			}
		},

		tooltips: {
			callbacks: {
				title: function(item, data) {
					// Pick first xLabel for now
					var title = '';

					if (item.length > 0) {
						if (item[0].yLabel) {
							title = item[0].yLabel;
						} else if (data.labels.length > 0 && item[0].index < data.labels.length) {
							title = data.labels[item[0].index];
						}
					}

					return title;
				},

				label: function(item, data) {
					var datasetLabel = data.datasets[item.datasetIndex].label || '';
					return datasetLabel + ': ' + item.xLabel;
				}
			},
			mode: 'index',
			axis: 'y'
		}
	});

	/**
	 * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
	 * @private
	 */
	function computeMinSampleSize(scale, pixels) {
		var min = scale.isHorizontal() ? scale.width : scale.height;
		var ticks = scale.getTicks();
		var prev, curr, i, ilen;

		for (i = 1, ilen = pixels.length; i < ilen; ++i) {
			min = Math.min(min, pixels[i] - pixels[i - 1]);
		}

		for (i = 0, ilen = ticks.length; i < ilen; ++i) {
			curr = scale.getPixelForTick(i);
			min = i > 0 ? Math.min(min, curr - prev) : min;
			prev = curr;
		}

		return min;
	}

	/**
	 * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,
	 * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This
	 * mode currently always generates bars equally sized (until we introduce scriptable options?).
	 * @private
	 */
	function computeFitCategoryTraits(index, ruler, options) {
		var thickness = options.barThickness;
		var count = ruler.stackCount;
		var curr = ruler.pixels[index];
		var size, ratio;

		if (helpers$1.isNullOrUndef(thickness)) {
			size = ruler.min * options.categoryPercentage;
			ratio = options.barPercentage;
		} else {
			// When bar thickness is enforced, category and bar percentages are ignored.
			// Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
			// and deprecate barPercentage since this value is ignored when thickness is absolute.
			size = thickness * count;
			ratio = 1;
		}

		return {
			chunk: size / count,
			ratio: ratio,
			start: curr - (size / 2)
		};
	}

	/**
	 * Computes an "optimal" category that globally arranges bars side by side (no gap when
	 * percentage options are 1), based on the previous and following categories. This mode
	 * generates bars with different widths when data are not evenly spaced.
	 * @private
	 */
	function computeFlexCategoryTraits(index, ruler, options) {
		var pixels = ruler.pixels;
		var curr = pixels[index];
		var prev = index > 0 ? pixels[index - 1] : null;
		var next = index < pixels.length - 1 ? pixels[index + 1] : null;
		var percent = options.categoryPercentage;
		var start, size;

		if (prev === null) {
			// first data: its size is double based on the next point or,
			// if it's also the last data, we use the scale end extremity.
			prev = curr - (next === null ? ruler.end - curr : next - curr);
		}

		if (next === null) {
			// last data: its size is also double based on the previous point.
			next = curr + curr - prev;
		}

		start = curr - ((curr - prev) / 2) * percent;
		size = ((next - prev) / 2) * percent;

		return {
			chunk: size / ruler.stackCount,
			ratio: options.barPercentage,
			start: start
		};
	}

	var controller_bar = function(Chart) {

		Chart.controllers.bar = Chart.DatasetController.extend({

			dataElementType: elements.Rectangle,

			initialize: function() {
				var me = this;
				var meta;

				Chart.DatasetController.prototype.initialize.apply(me, arguments);

				meta = me.getMeta();
				meta.stack = me.getDataset().stack;
				meta.bar = true;
			},

			update: function(reset) {
				var me = this;
				var rects = me.getMeta().data;
				var i, ilen;

				me._ruler = me.getRuler();

				for (i = 0, ilen = rects.length; i < ilen; ++i) {
					me.updateElement(rects[i], i, reset);
				}
			},

			updateElement: function(rectangle, index, reset) {
				var me = this;
				var chart = me.chart;
				var meta = me.getMeta();
				var dataset = me.getDataset();
				var custom = rectangle.custom || {};
				var rectangleOptions = chart.options.elements.rectangle;

				rectangle._xScale = me.getScaleForId(meta.xAxisID);
				rectangle._yScale = me.getScaleForId(meta.yAxisID);
				rectangle._datasetIndex = me.index;
				rectangle._index = index;

				rectangle._model = {
					datasetLabel: dataset.label,
					label: chart.data.labels[index],
					borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
					backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers$1.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
					borderColor: custom.borderColor ? custom.borderColor : helpers$1.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
					borderWidth: custom.borderWidth ? custom.borderWidth : helpers$1.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
				};

				me.updateElementGeometry(rectangle, index, reset);

				rectangle.pivot();
			},

			/**
			 * @private
			 */
			updateElementGeometry: function(rectangle, index, reset) {
				var me = this;
				var model = rectangle._model;
				var vscale = me.getValueScale();
				var base = vscale.getBasePixel();
				var horizontal = vscale.isHorizontal();
				var ruler = me._ruler || me.getRuler();
				var vpixels = me.calculateBarValuePixels(me.index, index);
				var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);

				model.horizontal = horizontal;
				model.base = reset ? base : vpixels.base;
				model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
				model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
				model.height = horizontal ? ipixels.size : undefined;
				model.width = horizontal ? undefined : ipixels.size;
			},

			/**
			 * @private
			 */
			getValueScaleId: function() {
				return this.getMeta().yAxisID;
			},

			/**
			 * @private
			 */
			getIndexScaleId: function() {
				return this.getMeta().xAxisID;
			},

			/**
			 * @private
			 */
			getValueScale: function() {
				return this.getScaleForId(this.getValueScaleId());
			},

			/**
			 * @private
			 */
			getIndexScale: function() {
				return this.getScaleForId(this.getIndexScaleId());
			},

			/**
			 * Returns the stacks based on groups and bar visibility.
			 * @param {Number} [last] - The dataset index
			 * @returns {Array} The stack list
			 * @private
			 */
			_getStacks: function(last) {
				var me = this;
				var chart = me.chart;
				var scale = me.getIndexScale();
				var stacked = scale.options.stacked;
				var ilen = last === undefined ? chart.data.datasets.length : last + 1;
				var stacks = [];
				var i, meta;

				for (i = 0; i < ilen; ++i) {
					meta = chart.getDatasetMeta(i);
					if (meta.bar && chart.isDatasetVisible(i) &&
						(stacked === false ||
						(stacked === true && stacks.indexOf(meta.stack) === -1) ||
						(stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
						stacks.push(meta.stack);
					}
				}

				return stacks;
			},

			/**
			 * Returns the effective number of stacks based on groups and bar visibility.
			 * @private
			 */
			getStackCount: function() {
				return this._getStacks().length;
			},

			/**
			 * Returns the stack index for the given dataset based on groups and bar visibility.
			 * @param {Number} [datasetIndex] - The dataset index
			 * @param {String} [name] - The stack name to find
			 * @returns {Number} The stack index
			 * @private
			 */
			getStackIndex: function(datasetIndex, name) {
				var stacks = this._getStacks(datasetIndex);
				var index = (name !== undefined)
					? stacks.indexOf(name)
					: -1; // indexOf returns -1 if element is not present

				return (index === -1)
					? stacks.length - 1
					: index;
			},

			/**
			 * @private
			 */
			getRuler: function() {
				var me = this;
				var scale = me.getIndexScale();
				var stackCount = me.getStackCount();
				var datasetIndex = me.index;
				var isHorizontal = scale.isHorizontal();
				var start = isHorizontal ? scale.left : scale.top;
				var end = start + (isHorizontal ? scale.width : scale.height);
				var pixels = [];
				var i, ilen, min;

				for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
					pixels.push(scale.getPixelForValue(null, i, datasetIndex));
				}

				min = helpers$1.isNullOrUndef(scale.options.barThickness)
					? computeMinSampleSize(scale, pixels)
					: -1;

				return {
					min: min,
					pixels: pixels,
					start: start,
					end: end,
					stackCount: stackCount,
					scale: scale
				};
			},

			/**
			 * Note: pixel values are not clamped to the scale area.
			 * @private
			 */
			calculateBarValuePixels: function(datasetIndex, index) {
				var me = this;
				var chart = me.chart;
				var meta = me.getMeta();
				var scale = me.getValueScale();
				var datasets = chart.data.datasets;
				var value = scale.getRightValue(datasets[datasetIndex].data[index]);
				var stacked = scale.options.stacked;
				var stack = meta.stack;
				var start = 0;
				var i, imeta, ivalue, base, head, size;

				if (stacked || (stacked === undefined && stack !== undefined)) {
					for (i = 0; i < datasetIndex; ++i) {
						imeta = chart.getDatasetMeta(i);

						if (imeta.bar &&
							imeta.stack === stack &&
							imeta.controller.getValueScaleId() === scale.id &&
							chart.isDatasetVisible(i)) {

							ivalue = scale.getRightValue(datasets[i].data[index]);
							if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
								start += ivalue;
							}
						}
					}
				}

				base = scale.getPixelForValue(start);
				head = scale.getPixelForValue(start + value);
				size = (head - base) / 2;

				return {
					size: size,
					base: base,
					head: head,
					center: head + size / 2
				};
			},

			/**
			 * @private
			 */
			calculateBarIndexPixels: function(datasetIndex, index, ruler) {
				var me = this;
				var options = ruler.scale.options;
				var range = options.barThickness === 'flex'
					? computeFlexCategoryTraits(index, ruler, options)
					: computeFitCategoryTraits(index, ruler, options);

				var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
				var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
				var size = Math.min(
					helpers$1.valueOrDefault(options.maxBarThickness, Infinity),
					range.chunk * range.ratio);

				return {
					base: center - size / 2,
					head: center + size / 2,
					center: center,
					size: size
				};
			},

			draw: function() {
				var me = this;
				var chart = me.chart;
				var scale = me.getValueScale();
				var rects = me.getMeta().data;
				var dataset = me.getDataset();
				var ilen = rects.length;
				var i = 0;

				helpers$1.canvas.clipArea(chart.ctx, chart.chartArea);

				for (; i < ilen; ++i) {
					if (!isNaN(scale.getRightValue(dataset.data[i]))) {
						rects[i].draw();
					}
				}

				helpers$1.canvas.unclipArea(chart.ctx);
			},

			setHoverStyle: function(rectangle) {
				var dataset = this.chart.data.datasets[rectangle._datasetIndex];
				var index = rectangle._index;
				var custom = rectangle.custom || {};
				var model = rectangle._model;

				model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers$1.valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers$1.getHoverColor(model.backgroundColor));
				model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers$1.valueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers$1.getHoverColor(model.borderColor));
				model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers$1.valueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
			},

			removeHoverStyle: function(rectangle) {
				var dataset = this.chart.data.datasets[rectangle._datasetIndex];
				var index = rectangle._index;
				var custom = rectangle.custom || {};
				var model = rectangle._model;
				var rectangleElementOptions = this.chart.options.elements.rectangle;

				model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers$1.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
				model.borderColor = custom.borderColor ? custom.borderColor : helpers$1.valueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
				model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers$1.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
			}
		});

		Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
			/**
			 * @private
			 */
			getValueScaleId: function() {
				return this.getMeta().xAxisID;
			},

			/**
			 * @private
			 */
			getIndexScaleId: function() {
				return this.getMeta().yAxisID;
			}
		});
	};

	core_defaults._set('bubble', {
		hover: {
			mode: 'single'
		},

		scales: {
			xAxes: [{
				type: 'linear', // bubble should probably use a linear scale by default
				position: 'bottom',
				id: 'x-axis-0' // need an ID so datasets can reference the scale
			}],
			yAxes: [{
				type: 'linear',
				position: 'left',
				id: 'y-axis-0'
			}]
		},

		tooltips: {
			callbacks: {
				title: function() {
					// Title doesn't make sense for scatter since we format the data as a point
					return '';
				},
				label: function(item, data) {
					var datasetLabel = data.datasets[item.datasetIndex].label || '';
					var dataPoint = data.datasets[item.datasetIndex].data[item.index];
					return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
				}
			}
		}
	});


	var controller_bubble = function(Chart) {

		Chart.controllers.bubble = Chart.DatasetController.extend({
			/**
			 * @protected
			 */
			dataElementType: elements.Point,

			/**
			 * @protected
			 */
			update: function(reset) {
				var me = this;
				var meta = me.getMeta();
				var points = meta.data;

				// Update Points
				helpers$1.each(points, function(point, index) {
					me.updateElement(point, index, reset);
				});
			},

			/**
			 * @protected
			 */
			updateElement: function(point, index, reset) {
				var me = this;
				var meta = me.getMeta();
				var custom = point.custom || {};
				var xScale = me.getScaleForId(meta.xAxisID);
				var yScale = me.getScaleForId(meta.yAxisID);
				var options = me._resolveElementOptions(point, index);
				var data = me.getDataset().data[index];
				var dsIndex = me.index;

				var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
				var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);

				point._xScale = xScale;
				point._yScale = yScale;
				point._options = options;
				point._datasetIndex = dsIndex;
				point._index = index;
				point._model = {
					backgroundColor: options.backgroundColor,
					borderColor: options.borderColor,
					borderWidth: options.borderWidth,
					hitRadius: options.hitRadius,
					pointStyle: options.pointStyle,
					radius: reset ? 0 : options.radius,
					skip: custom.skip || isNaN(x) || isNaN(y),
					x: x,
					y: y,
				};

				point.pivot();
			},

			/**
			 * @protected
			 */
			setHoverStyle: function(point) {
				var model = point._model;
				var options = point._options;

				model.backgroundColor = helpers$1.valueOrDefault(options.hoverBackgroundColor, helpers$1.getHoverColor(options.backgroundColor));
				model.borderColor = helpers$1.valueOrDefault(options.hoverBorderColor, helpers$1.getHoverColor(options.borderColor));
				model.borderWidth = helpers$1.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
				model.radius = options.radius + options.hoverRadius;
			},

			/**
			 * @protected
			 */
			removeHoverStyle: function(point) {
				var model = point._model;
				var options = point._options;

				model.backgroundColor = options.backgroundColor;
				model.borderColor = options.borderColor;
				model.borderWidth = options.borderWidth;
				model.radius = options.radius;
			},

			/**
			 * @private
			 */
			_resolveElementOptions: function(point, index) {
				var me = this;
				var chart = me.chart;
				var datasets = chart.data.datasets;
				var dataset = datasets[me.index];
				var custom = point.custom || {};
				var options = chart.options.elements.point;
				var resolve = helpers$1.options.resolve;
				var data = dataset.data[index];
				var values = {};
				var i, ilen, key;

				// Scriptable options
				var context = {
					chart: chart,
					dataIndex: index,
					dataset: dataset,
					datasetIndex: me.index
				};

				var keys = [
					'backgroundColor',
					'borderColor',
					'borderWidth',
					'hoverBackgroundColor',
					'hoverBorderColor',
					'hoverBorderWidth',
					'hoverRadius',
					'hitRadius',
					'pointStyle'
				];

				for (i = 0, ilen = keys.length; i < ilen; ++i) {
					key = keys[i];
					values[key] = resolve([
						custom[key],
						dataset[key],
						options[key]
					], context, index);
				}

				// Custom radius resolution
				values.radius = resolve([
					custom.radius,
					data ? data.r : undefined,
					dataset.radius,
					options.radius
				], context, index);

				return values;
			}
		});
	};

	core_defaults._set('doughnut', {
		animation: {
			// Boolean - Whether we animate the rotation of the Doughnut
			animateRotate: true,
			// Boolean - Whether we animate scaling the Doughnut from the centre
			animateScale: false
		},
		hover: {
			mode: 'single'
		},
		legendCallback: function(chart) {
			var text = [];
			text.push('<ul class="' + chart.id + '-legend">');

			var data = chart.data;
			var datasets = data.datasets;
			var labels = data.labels;

			if (datasets.length) {
				for (var i = 0; i < datasets[0].data.length; ++i) {
					text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
					if (labels[i]) {
						text.push(labels[i]);
					}
					text.push('</li>');
				}
			}

			text.push('</ul>');
			return text.join('');
		},
		legend: {
			labels: {
				generateLabels: function(chart) {
					var data = chart.data;
					if (data.labels.length && data.datasets.length) {
						return data.labels.map(function(label, i) {
							var meta = chart.getDatasetMeta(0);
							var ds = data.datasets[0];
							var arc = meta.data[i];
							var custom = arc && arc.custom || {};
							var valueAtIndexOrDefault = helpers$1.valueAtIndexOrDefault;
							var arcOpts = chart.options.elements.arc;
							var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
							var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
							var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);

							return {
								text: label,
								fillStyle: fill,
								strokeStyle: stroke,
								lineWidth: bw,
								hidden: isNaN(ds.data[i]) || meta.data[i].hidden,

								// Extra data used for toggling the correct item
								index: i
							};
						});
					}
					return [];
				}
			},

			onClick: function(e, legendItem) {
				var index = legendItem.index;
				var chart = this.chart;
				var i, ilen, meta;

				for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
					meta = chart.getDatasetMeta(i);
					// toggle visibility of index if exists
					if (meta.data[index]) {
						meta.data[index].hidden = !meta.data[index].hidden;
					}
				}

				chart.update();
			}
		},

		// The percentage of the chart that we cut out of the middle.
		cutoutPercentage: 50,

		// The rotation of the chart, where the first data arc begins.
		rotation: Math.PI * -0.5,

		// The total circumference of the chart.
		circumference: Math.PI * 2.0,

		// Need to override these to give a nice default
		tooltips: {
			callbacks: {
				title: function() {
					return '';
				},
				label: function(tooltipItem, data) {
					var dataLabel = data.labels[tooltipItem.index];
					var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];

					if (helpers$1.isArray(dataLabel)) {
						// show value on first line of multiline label
						// need to clone because we are changing the value
						dataLabel = dataLabel.slice();
						dataLabel[0] += value;
					} else {
						dataLabel += value;
					}

					return dataLabel;
				}
			}
		}
	});

	core_defaults._set('pie', helpers$1.clone(core_defaults.doughnut));
	core_defaults._set('pie', {
		cutoutPercentage: 0
	});

	var controller_doughnut = function(Chart) {

		Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({

			dataElementType: elements.Arc,

			linkScales: helpers$1.noop,

			// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
			getRingIndex: function(datasetIndex) {
				var ringIndex = 0;

				for (var j = 0; j < datasetIndex; ++j) {
					if (this.chart.isDatasetVisible(j)) {
						++ringIndex;
					}
				}

				return ringIndex;
			},

			update: function(reset) {
				var me = this;
				var chart = me.chart;
				var chartArea = chart.chartArea;
				var opts = chart.options;
				var arcOpts = opts.elements.arc;
				var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
				var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
				var minSize = Math.min(availableWidth, availableHeight);
				var offset = {x: 0, y: 0};
				var meta = me.getMeta();
				var cutoutPercentage = opts.cutoutPercentage;
				var circumference = opts.circumference;

				// If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
				if (circumference < Math.PI * 2.0) {
					var startAngle = opts.rotation % (Math.PI * 2.0);
					startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
					var endAngle = startAngle + circumference;
					var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
					var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
					var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
					var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
					var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
					var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
					var cutout = cutoutPercentage / 100.0;
					var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
					var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
					var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
					minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
					offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
				}

				chart.borderWidth = me.getMaxBorderWidth(meta.data);
				chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
				chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
				chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
				chart.offsetX = offset.x * chart.outerRadius;
				chart.offsetY = offset.y * chart.outerRadius;

				meta.total = me.calculateTotal();

				me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
				me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);

				helpers$1.each(meta.data, function(arc, index) {
					me.updateElement(arc, index, reset);
				});
			},

			updateElement: function(arc, index, reset) {
				var me = this;
				var chart = me.chart;
				var chartArea = chart.chartArea;
				var opts = chart.options;
				var animationOpts = opts.animation;
				var centerX = (chartArea.left + chartArea.right) / 2;
				var centerY = (chartArea.top + chartArea.bottom) / 2;
				var startAngle = opts.rotation; // non reset case handled later
				var endAngle = opts.rotation; // non reset case handled later
				var dataset = me.getDataset();
				var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
				var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
				var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
				var valueAtIndexOrDefault = helpers$1.valueAtIndexOrDefault;

				helpers$1.extend(arc, {
					// Utility
					_datasetIndex: me.index,
					_index: index,

					// Desired view properties
					_model: {
						x: centerX + chart.offsetX,
						y: centerY + chart.offsetY,
						startAngle: startAngle,
						endAngle: endAngle,
						circumference: circumference,
						outerRadius: outerRadius,
						innerRadius: innerRadius,
						label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
					}
				});

				var model = arc._model;
				// Resets the visual styles
				this.removeHoverStyle(arc);

				// Set correct angles if not resetting
				if (!reset || !animationOpts.animateRotate) {
					if (index === 0) {
						model.startAngle = opts.rotation;
					} else {
						model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
					}

					model.endAngle = model.startAngle + model.circumference;
				}

				arc.pivot();
			},

			removeHoverStyle: function(arc) {
				Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
			},

			calculateTotal: function() {
				var dataset = this.getDataset();
				var meta = this.getMeta();
				var total = 0;
				var value;

				helpers$1.each(meta.data, function(element, index) {
					value = dataset.data[index];
					if (!isNaN(value) && !element.hidden) {
						total += Math.abs(value);
					}
				});

				/* if (total === 0) {
					total = NaN;
				}*/

				return total;
			},

			calculateCircumference: function(value) {
				var total = this.getMeta().total;
				if (total > 0 && !isNaN(value)) {
					return (Math.PI * 2.0) * (Math.abs(value) / total);
				}
				return 0;
			},

			// gets the max border or hover width to properly scale pie charts
			getMaxBorderWidth: function(arcs) {
				var max = 0;
				var index = this.index;
				var length = arcs.length;
				var borderWidth;
				var hoverWidth;

				for (var i = 0; i < length; i++) {
					borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
					hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;

					max = borderWidth > max ? borderWidth : max;
					max = hoverWidth > max ? hoverWidth : max;
				}
				return max;
			}
		});
	};

	core_defaults._set('line', {
		showLines: true,
		spanGaps: false,

		hover: {
			mode: 'label'
		},

		scales: {
			xAxes: [{
				type: 'category',
				id: 'x-axis-0'
			}],
			yAxes: [{
				type: 'linear',
				id: 'y-axis-0'
			}]
		}
	});

	var controller_line = function(Chart) {

		function lineEnabled(dataset, options) {
			return helpers$1.valueOrDefault(dataset.showLine, options.showLines);
		}

		Chart.controllers.line = Chart.DatasetController.extend({

			datasetElementType: elements.Line,

			dataElementType: elements.Point,

			update: function(reset) {
				var me = this;
				var meta = me.getMeta();
				var line = meta.dataset;
				var points = meta.data || [];
				var options = me.chart.options;
				var lineElementOptions = options.elements.line;
				var scale = me.getScaleForId(meta.yAxisID);
				var i, ilen, custom;
				var dataset = me.getDataset();
				var showLine = lineEnabled(dataset, options);

				// Update Line
				if (showLine) {
					custom = line.custom || {};

					// Compatibility: If the properties are defined with only the old name, use those values
					if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
						dataset.lineTension = dataset.tension;
					}

					// Utility
					line._scale = scale;
					line._datasetIndex = me.index;
					// Data
					line._children = points;
					// Model
					line._model = {
						// Appearance
						// The default behavior of lines is to break at null values, according
						// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
						// This option gives lines the ability to span gaps
						spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
						tension: custom.tension ? custom.tension : helpers$1.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
						backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
						borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
						borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
						borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
						borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
						borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
						borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
						fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
						steppedLine: custom.steppedLine ? custom.steppedLine : helpers$1.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
						cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers$1.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
					};

					line.pivot();
				}

				// Update Points
				for (i = 0, ilen = points.length; i < ilen; ++i) {
					me.updateElement(points[i], i, reset);
				}

				if (showLine && line._model.tension !== 0) {
					me.updateBezierControlPoints();
				}

				// Now pivot the point for animation
				for (i = 0, ilen = points.length; i < ilen; ++i) {
					points[i].pivot();
				}
			},

			getPointBackgroundColor: function(point, index) {
				var backgroundColor = this.chart.options.elements.point.backgroundColor;
				var dataset = this.getDataset();
				var custom = point.custom || {};

				if (custom.backgroundColor) {
					backgroundColor = custom.backgroundColor;
				} else if (dataset.pointBackgroundColor) {
					backgroundColor = helpers$1.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
				} else if (dataset.backgroundColor) {
					backgroundColor = dataset.backgroundColor;
				}

				return backgroundColor;
			},

			getPointBorderColor: function(point, index) {
				var borderColor = this.chart.options.elements.point.borderColor;
				var dataset = this.getDataset();
				var custom = point.custom || {};

				if (custom.borderColor) {
					borderColor = custom.borderColor;
				} else if (dataset.pointBorderColor) {
					borderColor = helpers$1.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
				} else if (dataset.borderColor) {
					borderColor = dataset.borderColor;
				}

				return borderColor;
			},

			getPointBorderWidth: function(point, index) {
				var borderWidth = this.chart.options.elements.point.borderWidth;
				var dataset = this.getDataset();
				var custom = point.custom || {};

				if (!isNaN(custom.borderWidth)) {
					borderWidth = custom.borderWidth;
				} else if (!isNaN(dataset.pointBorderWidth) || helpers$1.isArray(dataset.pointBorderWidth)) {
					borderWidth = helpers$1.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
				} else if (!isNaN(dataset.borderWidth)) {
					borderWidth = dataset.borderWidth;
				}

				return borderWidth;
			},

			updateElement: function(point, index, reset) {
				var me = this;
				var meta = me.getMeta();
				var custom = point.custom || {};
				var dataset = me.getDataset();
				var datasetIndex = me.index;
				var value = dataset.data[index];
				var yScale = me.getScaleForId(meta.yAxisID);
				var xScale = me.getScaleForId(meta.xAxisID);
				var pointOptions = me.chart.options.elements.point;
				var x, y;

				// Compatibility: If the properties are defined with only the old name, use those values
				if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
					dataset.pointRadius = dataset.radius;
				}
				if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
					dataset.pointHitRadius = dataset.hitRadius;
				}

				x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
				y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);

				// Utility
				point._xScale = xScale;
				point._yScale = yScale;
				point._datasetIndex = datasetIndex;
				point._index = index;

				// Desired view properties
				point._model = {
					x: x,
					y: y,
					skip: custom.skip || isNaN(x) || isNaN(y),
					// Appearance
					radius: custom.radius || helpers$1.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
					pointStyle: custom.pointStyle || helpers$1.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
					backgroundColor: me.getPointBackgroundColor(point, index),
					borderColor: me.getPointBorderColor(point, index),
					borderWidth: me.getPointBorderWidth(point, index),
					tension: meta.dataset._model ? meta.dataset._model.tension : 0,
					steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
					// Tooltip
					hitRadius: custom.hitRadius || helpers$1.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
				};
			},

			calculatePointY: function(value, index, datasetIndex) {
				var me = this;
				var chart = me.chart;
				var meta = me.getMeta();
				var yScale = me.getScaleForId(meta.yAxisID);
				var sumPos = 0;
				var sumNeg = 0;
				var i, ds, dsMeta;

				if (yScale.options.stacked) {
					for (i = 0; i < datasetIndex; i++) {
						ds = chart.data.datasets[i];
						dsMeta = chart.getDatasetMeta(i);
						if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
							var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
							if (stackedRightValue < 0) {
								sumNeg += stackedRightValue || 0;
							} else {
								sumPos += stackedRightValue || 0;
							}
						}
					}

					var rightValue = Number(yScale.getRightValue(value));
					if (rightValue < 0) {
						return yScale.getPixelForValue(sumNeg + rightValue);
					}
					return yScale.getPixelForValue(sumPos + rightValue);
				}

				return yScale.getPixelForValue(value);
			},

			updateBezierControlPoints: function() {
				var me = this;
				var meta = me.getMeta();
				var area = me.chart.chartArea;
				var points = (meta.data || []);
				var i, ilen, point, model, controlPoints;

				// Only consider points that are drawn in case the spanGaps option is used
				if (meta.dataset._model.spanGaps) {
					points = points.filter(function(pt) {
						return !pt._model.skip;
					});
				}

				function capControlPoint(pt, min, max) {
					return Math.max(Math.min(pt, max), min);
				}

				if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
					helpers$1.splineCurveMonotone(points);
				} else {
					for (i = 0, ilen = points.length; i < ilen; ++i) {
						point = points[i];
						model = point._model;
						controlPoints = helpers$1.splineCurve(
							helpers$1.previousItem(points, i)._model,
							model,
							helpers$1.nextItem(points, i)._model,
							meta.dataset._model.tension
						);
						model.controlPointPreviousX = controlPoints.previous.x;
						model.controlPointPreviousY = controlPoints.previous.y;
						model.controlPointNextX = controlPoints.next.x;
						model.controlPointNextY = controlPoints.next.y;
					}
				}

				if (me.chart.options.elements.line.capBezierPoints) {
					for (i = 0, ilen = points.length; i < ilen; ++i) {
						model = points[i]._model;
						model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
						model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
						model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
						model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
					}
				}
			},

			draw: function() {
				var me = this;
				var chart = me.chart;
				var meta = me.getMeta();
				var points = meta.data || [];
				var area = chart.chartArea;
				var ilen = points.length;
				var i = 0;

				helpers$1.canvas.clipArea(chart.ctx, area);

				if (lineEnabled(me.getDataset(), chart.options)) {
					meta.dataset.draw();
				}

				helpers$1.canvas.unclipArea(chart.ctx);

				// Draw the points
				for (; i < ilen; ++i) {
					points[i].draw(area);
				}
			},

			setHoverStyle: function(point) {
				// Point
				var dataset = this.chart.data.datasets[point._datasetIndex];
				var index = point._index;
				var custom = point.custom || {};
				var model = point._model;

				model.radius = custom.hoverRadius || helpers$1.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
				model.backgroundColor = custom.hoverBackgroundColor || helpers$1.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers$1.getHoverColor(model.backgroundColor));
				model.borderColor = custom.hoverBorderColor || helpers$1.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers$1.getHoverColor(model.borderColor));
				model.borderWidth = custom.hoverBorderWidth || helpers$1.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
			},

			removeHoverStyle: function(point) {
				var me = this;
				var dataset = me.chart.data.datasets[point._datasetIndex];
				var index = point._index;
				var custom = point.custom || {};
				var model = point._model;

				// Compatibility: If the properties are defined with only the old name, use those values
				if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
					dataset.pointRadius = dataset.radius;
				}

				model.radius = custom.radius || helpers$1.valueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
				model.backgroundColor = me.getPointBackgroundColor(point, index);
				model.borderColor = me.getPointBorderColor(point, index);
				model.borderWidth = me.getPointBorderWidth(point, index);
			}
		});
	};

	core_defaults._set('polarArea', {
		scale: {
			type: 'radialLinear',
			angleLines: {
				display: false
			},
			gridLines: {
				circular: true
			},
			pointLabels: {
				display: false
			},
			ticks: {
				beginAtZero: true
			}
		},

		// Boolean - Whether to animate the rotation of the chart
		animation: {
			animateRotate: true,
			animateScale: true
		},

		startAngle: -0.5 * Math.PI,
		legendCallback: function(chart) {
			var text = [];
			text.push('<ul class="' + chart.id + '-legend">');

			var data = chart.data;
			var datasets = data.datasets;
			var labels = data.labels;

			if (datasets.length) {
				for (var i = 0; i < datasets[0].data.length; ++i) {
					text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
					if (labels[i]) {
						text.push(labels[i]);
					}
					text.push('</li>');
				}
			}

			text.push('</ul>');
			return text.join('');
		},
		legend: {
			labels: {
				generateLabels: function(chart) {
					var data = chart.data;
					if (data.labels.length && data.datasets.length) {
						return data.labels.map(function(label, i) {
							var meta = chart.getDatasetMeta(0);
							var ds = data.datasets[0];
							var arc = meta.data[i];
							var custom = arc.custom || {};
							var valueAtIndexOrDefault = helpers$1.valueAtIndexOrDefault;
							var arcOpts = chart.options.elements.arc;
							var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
							var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
							var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);

							return {
								text: label,
								fillStyle: fill,
								strokeStyle: stroke,
								lineWidth: bw,
								hidden: isNaN(ds.data[i]) || meta.data[i].hidden,

								// Extra data used for toggling the correct item
								index: i
							};
						});
					}
					return [];
				}
			},

			onClick: function(e, legendItem) {
				var index = legendItem.index;
				var chart = this.chart;
				var i, ilen, meta;

				for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
					meta = chart.getDatasetMeta(i);
					meta.data[index].hidden = !meta.data[index].hidden;
				}

				chart.update();
			}
		},

		// Need to override these to give a nice default
		tooltips: {
			callbacks: {
				title: function() {
					return '';
				},
				label: function(item, data) {
					return data.labels[item.index] + ': ' + item.yLabel;
				}
			}
		}
	});

	var controller_polarArea = function(Chart) {

		Chart.controllers.polarArea = Chart.DatasetController.extend({

			dataElementType: elements.Arc,

			linkScales: helpers$1.noop,

			update: function(reset) {
				var me = this;
				var chart = me.chart;
				var chartArea = chart.chartArea;
				var meta = me.getMeta();
				var opts = chart.options;
				var arcOpts = opts.elements.arc;
				var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
				chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
				chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
				chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();

				me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
				me.innerRadius = me.outerRadius - chart.radiusLength;

				meta.count = me.countVisibleElements();

				helpers$1.each(meta.data, function(arc, index) {
					me.updateElement(arc, index, reset);
				});
			},

			updateElement: function(arc, index, reset) {
				var me = this;
				var chart = me.chart;
				var dataset = me.getDataset();
				var opts = chart.options;
				var animationOpts = opts.animation;
				var scale = chart.scale;
				var labels = chart.data.labels;

				var circumference = me.calculateCircumference(dataset.data[index]);
				var centerX = scale.xCenter;
				var centerY = scale.yCenter;

				// If there is NaN data before us, we need to calculate the starting angle correctly.
				// We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
				var visibleCount = 0;
				var meta = me.getMeta();
				for (var i = 0; i < index; ++i) {
					if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
						++visibleCount;
					}
				}

				// var negHalfPI = -0.5 * Math.PI;
				var datasetStartAngle = opts.startAngle;
				var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
				var startAngle = datasetStartAngle + (circumference * visibleCount);
				var endAngle = startAngle + (arc.hidden ? 0 : circumference);

				var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);

				helpers$1.extend(arc, {
					// Utility
					_datasetIndex: me.index,
					_index: index,
					_scale: scale,

					// Desired view properties
					_model: {
						x: centerX,
						y: centerY,
						innerRadius: 0,
						outerRadius: reset ? resetRadius : distance,
						startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
						endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
						label: helpers$1.valueAtIndexOrDefault(labels, index, labels[index])
					}
				});

				// Apply border and fill style
				me.removeHoverStyle(arc);

				arc.pivot();
			},

			removeHoverStyle: function(arc) {
				Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
			},

			countVisibleElements: function() {
				var dataset = this.getDataset();
				var meta = this.getMeta();
				var count = 0;

				helpers$1.each(meta.data, function(element, index) {
					if (!isNaN(dataset.data[index]) && !element.hidden) {
						count++;
					}
				});

				return count;
			},

			calculateCircumference: function(value) {
				var count = this.getMeta().count;
				if (count > 0 && !isNaN(value)) {
					return (2 * Math.PI) / count;
				}
				return 0;
			}
		});
	};

	core_defaults._set('radar', {
		scale: {
			type: 'radialLinear'
		},
		elements: {
			line: {
				tension: 0 // no bezier in radar
			}
		}
	});

	var controller_radar = function(Chart) {

		Chart.controllers.radar = Chart.DatasetController.extend({

			datasetElementType: elements.Line,

			dataElementType: elements.Point,

			linkScales: helpers$1.noop,

			update: function(reset) {
				var me = this;
				var meta = me.getMeta();
				var line = meta.dataset;
				var points = meta.data;
				var custom = line.custom || {};
				var dataset = me.getDataset();
				var lineElementOptions = me.chart.options.elements.line;
				var scale = me.chart.scale;

				// Compatibility: If the properties are defined with only the old name, use those values
				if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
					dataset.lineTension = dataset.tension;
				}

				helpers$1.extend(meta.dataset, {
					// Utility
					_datasetIndex: me.index,
					_scale: scale,
					// Data
					_children: points,
					_loop: true,
					// Model
					_model: {
						// Appearance
						tension: custom.tension ? custom.tension : helpers$1.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
						backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
						borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
						borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
						fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
						borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
						borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
						borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
						borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
					}
				});

				meta.dataset.pivot();

				// Update Points
				helpers$1.each(points, function(point, index) {
					me.updateElement(point, index, reset);
				}, me);

				// Update bezier control points
				me.updateBezierControlPoints();
			},
			updateElement: function(point, index, reset) {
				var me = this;
				var custom = point.custom || {};
				var dataset = me.getDataset();
				var scale = me.chart.scale;
				var pointElementOptions = me.chart.options.elements.point;
				var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);

				// Compatibility: If the properties are defined with only the old name, use those values
				if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
					dataset.pointRadius = dataset.radius;
				}
				if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
					dataset.pointHitRadius = dataset.hitRadius;
				}

				helpers$1.extend(point, {
					// Utility
					_datasetIndex: me.index,
					_index: index,
					_scale: scale,

					// Desired view properties
					_model: {
						x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
						y: reset ? scale.yCenter : pointPosition.y,

						// Appearance
						tension: custom.tension ? custom.tension : helpers$1.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
						radius: custom.radius ? custom.radius : helpers$1.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
						backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers$1.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
						borderColor: custom.borderColor ? custom.borderColor : helpers$1.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
						borderWidth: custom.borderWidth ? custom.borderWidth : helpers$1.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
						pointStyle: custom.pointStyle ? custom.pointStyle : helpers$1.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),

						// Tooltip
						hitRadius: custom.hitRadius ? custom.hitRadius : helpers$1.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
					}
				});

				point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
			},
			updateBezierControlPoints: function() {
				var chartArea = this.chart.chartArea;
				var meta = this.getMeta();

				helpers$1.each(meta.data, function(point, index) {
					var model = point._model;
					var controlPoints = helpers$1.splineCurve(
						helpers$1.previousItem(meta.data, index, true)._model,
						model,
						helpers$1.nextItem(meta.data, index, true)._model,
						model.tension
					);

					// Prevent the bezier going outside of the bounds of the graph
					model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
					model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);

					model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
					model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);

					// Now pivot the point for animation
					point.pivot();
				});
			},

			setHoverStyle: function(point) {
				// Point
				var dataset = this.chart.data.datasets[point._datasetIndex];
				var custom = point.custom || {};
				var index = point._index;
				var model = point._model;

				model.radius = custom.hoverRadius ? custom.hoverRadius : helpers$1.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
				model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers$1.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers$1.getHoverColor(model.backgroundColor));
				model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers$1.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers$1.getHoverColor(model.borderColor));
				model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers$1.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
			},

			removeHoverStyle: function(point) {
				var dataset = this.chart.data.datasets[point._datasetIndex];
				var custom = point.custom || {};
				var index = point._index;
				var model = point._model;
				var pointElementOptions = this.chart.options.elements.point;

				model.radius = custom.radius ? custom.radius : helpers$1.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius);
				model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers$1.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor);
				model.borderColor = custom.borderColor ? custom.borderColor : helpers$1.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
				model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers$1.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
			}
		});
	};

	core_defaults._set('scatter', {
		hover: {
			mode: 'single'
		},

		scales: {
			xAxes: [{
				id: 'x-axis-1',    // need an ID so datasets can reference the scale
				type: 'linear',    // scatter should not use a category axis
				position: 'bottom'
			}],
			yAxes: [{
				id: 'y-axis-1',
				type: 'linear',
				position: 'left'
			}]
		},

		showLines: false,

		tooltips: {
			callbacks: {
				title: function() {
					return '';     // doesn't make sense for scatter since data are formatted as a point
				},
				label: function(item) {
					return '(' + item.xLabel + ', ' + item.yLabel + ')';
				}
			}
		}
	});

	var controller_scatter = function(Chart) {

		// Scatter charts use line controllers
		Chart.controllers.scatter = Chart.controllers.line;

	};

	var Chart_Bar = function(Chart) {

		Chart.Bar = function(context, config) {
			config.type = 'bar';

			return new Chart(context, config);
		};

	};

	var Chart_Bubble = function(Chart) {

		Chart.Bubble = function(context, config) {
			config.type = 'bubble';
			return new Chart(context, config);
		};

	};

	var Chart_Doughnut = function(Chart) {

		Chart.Doughnut = function(context, config) {
			config.type = 'doughnut';

			return new Chart(context, config);
		};

	};

	var Chart_Line = function(Chart) {

		Chart.Line = function(context, config) {
			config.type = 'line';

			return new Chart(context, config);
		};

	};

	var Chart_PolarArea = function(Chart) {

		Chart.PolarArea = function(context, config) {
			config.type = 'polarArea';

			return new Chart(context, config);
		};

	};

	var Chart_Radar = function(Chart) {

		Chart.Radar = function(context, config) {
			config.type = 'radar';

			return new Chart(context, config);
		};

	};

	var Chart_Scatter = function(Chart) {
		Chart.Scatter = function(context, config) {
			config.type = 'scatter';
			return new Chart(context, config);
		};
	};

	core_defaults._set('global', {
		plugins: {
			filler: {
				propagate: true
			}
		}
	});

	var mappers = {
		dataset: function(source) {
			var index = source.fill;
			var chart = source.chart;
			var meta = chart.getDatasetMeta(index);
			var visible = meta && chart.isDatasetVisible(index);
			var points = (visible && meta.dataset._children) || [];
			var length = points.length || 0;

			return !length ? null : function(point, i) {
				return (i < length && points[i]._view) || null;
			};
		},

		boundary: function(source) {
			var boundary = source.boundary;
			var x = boundary ? boundary.x : null;
			var y = boundary ? boundary.y : null;

			return function(point) {
				return {
					x: x === null ? point.x : x,
					y: y === null ? point.y : y,
				};
			};
		}
	};

	// @todo if (fill[0] === '#')
	function decodeFill(el, index, count) {
		var model = el._model || {};
		var fill = model.fill;
		var target;

		if (fill === undefined) {
			fill = !!model.backgroundColor;
		}

		if (fill === false || fill === null) {
			return false;
		}

		if (fill === true) {
			return 'origin';
		}

		target = parseFloat(fill, 10);
		if (isFinite(target) && Math.floor(target) === target) {
			if (fill[0] === '-' || fill[0] === '+') {
				target = index + target;
			}

			if (target === index || target < 0 || target >= count) {
				return false;
			}

			return target;
		}

		switch (fill) {
		// compatibility
		case 'bottom':
			return 'start';
		case 'top':
			return 'end';
		case 'zero':
			return 'origin';
		// supported boundaries
		case 'origin':
		case 'start':
		case 'end':
			return fill;
		// invalid fill values
		default:
			return false;
		}
	}

	function computeBoundary(source) {
		var model = source.el._model || {};
		var scale = source.el._scale || {};
		var fill = source.fill;
		var target = null;
		var horizontal;

		if (isFinite(fill)) {
			return null;
		}

		// Backward compatibility: until v3, we still need to support boundary values set on
		// the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
		// controllers might still use it (e.g. the Smith chart).

		if (fill === 'start') {
			target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
		} else if (fill === 'end') {
			target = model.scaleTop === undefined ? scale.top : model.scaleTop;
		} else if (model.scaleZero !== undefined) {
			target = model.scaleZero;
		} else if (scale.getBasePosition) {
			target = scale.getBasePosition();
		} else if (scale.getBasePixel) {
			target = scale.getBasePixel();
		}

		if (target !== undefined && target !== null) {
			if (target.x !== undefined && target.y !== undefined) {
				return target;
			}

			if (typeof target === 'number' && isFinite(target)) {
				horizontal = scale.isHorizontal();
				return {
					x: horizontal ? target : null,
					y: horizontal ? null : target
				};
			}
		}

		return null;
	}

	function resolveTarget(sources, index, propagate) {
		var source = sources[index];
		var fill = source.fill;
		var visited = [index];
		var target;

		if (!propagate) {
			return fill;
		}

		while (fill !== false && visited.indexOf(fill) === -1) {
			if (!isFinite(fill)) {
				return fill;
			}

			target = sources[fill];
			if (!target) {
				return false;
			}

			if (target.visible) {
				return fill;
			}

			visited.push(fill);
			fill = target.fill;
		}

		return false;
	}

	function createMapper(source) {
		var fill = source.fill;
		var type = 'dataset';

		if (fill === false) {
			return null;
		}

		if (!isFinite(fill)) {
			type = 'boundary';
		}

		return mappers[type](source);
	}

	function isDrawable(point) {
		return point && !point.skip;
	}

	function drawArea(ctx, curve0, curve1, len0, len1) {
		var i;

		if (!len0 || !len1) {
			return;
		}

		// building first area curve (normal)
		ctx.moveTo(curve0[0].x, curve0[0].y);
		for (i = 1; i < len0; ++i) {
			helpers$1.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
		}

		// joining the two area curves
		ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);

		// building opposite area curve (reverse)
		for (i = len1 - 1; i > 0; --i) {
			helpers$1.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
		}
	}

	function doFill(ctx, points, mapper, view, color, loop) {
		var count = points.length;
		var span = view.spanGaps;
		var curve0 = [];
		var curve1 = [];
		var len0 = 0;
		var len1 = 0;
		var i, ilen, index, p0, p1, d0, d1;

		ctx.beginPath();

		for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
			index = i % count;
			p0 = points[index]._view;
			p1 = mapper(p0, index, view);
			d0 = isDrawable(p0);
			d1 = isDrawable(p1);

			if (d0 && d1) {
				len0 = curve0.push(p0);
				len1 = curve1.push(p1);
			} else if (len0 && len1) {
				if (!span) {
					drawArea(ctx, curve0, curve1, len0, len1);
					len0 = len1 = 0;
					curve0 = [];
					curve1 = [];
				} else {
					if (d0) {
						curve0.push(p0);
					}
					if (d1) {
						curve1.push(p1);
					}
				}
			}
		}

		drawArea(ctx, curve0, curve1, len0, len1);

		ctx.closePath();
		ctx.fillStyle = color;
		ctx.fill();
	}

	var plugin_filler = {
		id: 'filler',

		afterDatasetsUpdate: function(chart, options) {
			var count = (chart.data.datasets || []).length;
			var propagate = options.propagate;
			var sources = [];
			var meta, i, el, source;

			for (i = 0; i < count; ++i) {
				meta = chart.getDatasetMeta(i);
				el = meta.dataset;
				source = null;

				if (el && el._model && el instanceof elements.Line) {
					source = {
						visible: chart.isDatasetVisible(i),
						fill: decodeFill(el, i, count),
						chart: chart,
						el: el
					};
				}

				meta.$filler = source;
				sources.push(source);
			}

			for (i = 0; i < count; ++i) {
				source = sources[i];
				if (!source) {
					continue;
				}

				source.fill = resolveTarget(sources, i, propagate);
				source.boundary = computeBoundary(source);
				source.mapper = createMapper(source);
			}
		},

		beforeDatasetDraw: function(chart, args) {
			var meta = args.meta.$filler;
			if (!meta) {
				return;
			}

			var ctx = chart.ctx;
			var el = meta.el;
			var view = el._view;
			var points = el._children || [];
			var mapper = meta.mapper;
			var color = view.backgroundColor || core_defaults.global.defaultColor;

			if (mapper && color && points.length) {
				helpers$1.canvas.clipArea(ctx, chart.chartArea);
				doFill(ctx, points, mapper, view, color, el._loop);
				helpers$1.canvas.unclipArea(ctx);
			}
		}
	};

	var noop = helpers$1.noop;

	core_defaults._set('global', {
		legend: {
			display: true,
			position: 'top',
			fullWidth: true,
			reverse: false,
			weight: 1000,

			// a callback that will handle
			onClick: function(e, legendItem) {
				var index = legendItem.datasetIndex;
				var ci = this.chart;
				var meta = ci.getDatasetMeta(index);

				// See controller.isDatasetVisible comment
				meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;

				// We hid a dataset ... rerender the chart
				ci.update();
			},

			onHover: null,

			labels: {
				boxWidth: 40,
				padding: 10,
				// Generates labels shown in the legend
				// Valid properties to return:
				// text : text to display
				// fillStyle : fill of coloured box
				// strokeStyle: stroke of coloured box
				// hidden : if this legend item refers to a hidden item
				// lineCap : cap style for line
				// lineDash
				// lineDashOffset :
				// lineJoin :
				// lineWidth :
				generateLabels: function(chart) {
					var data = chart.data;
					return helpers$1.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
						return {
							text: dataset.label,
							fillStyle: (!helpers$1.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
							hidden: !chart.isDatasetVisible(i),
							lineCap: dataset.borderCapStyle,
							lineDash: dataset.borderDash,
							lineDashOffset: dataset.borderDashOffset,
							lineJoin: dataset.borderJoinStyle,
							lineWidth: dataset.borderWidth,
							strokeStyle: dataset.borderColor,
							pointStyle: dataset.pointStyle,

							// Below is extra data used for toggling the datasets
							datasetIndex: i
						};
					}, this) : [];
				}
			}
		},

		legendCallback: function(chart) {
			var text = [];
			text.push('<ul class="' + chart.id + '-legend">');
			for (var i = 0; i < chart.data.datasets.length; i++) {
				text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
				if (chart.data.datasets[i].label) {
					text.push(chart.data.datasets[i].label);
				}
				text.push('</li>');
			}
			text.push('</ul>');
			return text.join('');
		}
	});

	/**
	 * Helper function to get the box width based on the usePointStyle option
	 * @param labelopts {Object} the label options on the legend
	 * @param fontSize {Number} the label font size
	 * @return {Number} width of the color box area
	 */
	function getBoxWidth(labelOpts, fontSize) {
		return labelOpts.usePointStyle ?
			fontSize * Math.SQRT2 :
			labelOpts.boxWidth;
	}

	/**
	 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
	 */
	var Legend = core_element.extend({

		initialize: function(config) {
			helpers$1.extend(this, config);

			// Contains hit boxes for each dataset (in dataset order)
			this.legendHitBoxes = [];

			// Are we in doughnut mode which has a different data type
			this.doughnutMode = false;
		},

		// These methods are ordered by lifecycle. Utilities then follow.
		// Any function defined here is inherited by all legend types.
		// Any function can be extended by the legend type

		beforeUpdate: noop,
		update: function(maxWidth, maxHeight, margins) {
			var me = this;

			// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
			me.beforeUpdate();

			// Absorb the master measurements
			me.maxWidth = maxWidth;
			me.maxHeight = maxHeight;
			me.margins = margins;

			// Dimensions
			me.beforeSetDimensions();
			me.setDimensions();
			me.afterSetDimensions();
			// Labels
			me.beforeBuildLabels();
			me.buildLabels();
			me.afterBuildLabels();

			// Fit
			me.beforeFit();
			me.fit();
			me.afterFit();
			//
			me.afterUpdate();

			return me.minSize;
		},
		afterUpdate: noop,

		//

		beforeSetDimensions: noop,
		setDimensions: function() {
			var me = this;
			// Set the unconstrained dimension before label rotation
			if (me.isHorizontal()) {
				// Reset position before calculating rotation
				me.width = me.maxWidth;
				me.left = 0;
				me.right = me.width;
			} else {
				me.height = me.maxHeight;

				// Reset position before calculating rotation
				me.top = 0;
				me.bottom = me.height;
			}

			// Reset padding
			me.paddingLeft = 0;
			me.paddingTop = 0;
			me.paddingRight = 0;
			me.paddingBottom = 0;

			// Reset minSize
			me.minSize = {
				width: 0,
				height: 0
			};
		},
		afterSetDimensions: noop,

		//

		beforeBuildLabels: noop,
		buildLabels: function() {
			var me = this;
			var labelOpts = me.options.labels || {};
			var legendItems = helpers$1.callback(labelOpts.generateLabels, [me.chart], me) || [];

			if (labelOpts.filter) {
				legendItems = legendItems.filter(function(item) {
					return labelOpts.filter(item, me.chart.data);
				});
			}

			if (me.options.reverse) {
				legendItems.reverse();
			}

			me.legendItems = legendItems;
		},
		afterBuildLabels: noop,

		//

		beforeFit: noop,
		fit: function() {
			var me = this;
			var opts = me.options;
			var labelOpts = opts.labels;
			var display = opts.display;

			var ctx = me.ctx;

			var globalDefault = core_defaults.global;
			var valueOrDefault = helpers$1.valueOrDefault;
			var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
			var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
			var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
			var labelFont = helpers$1.fontString(fontSize, fontStyle, fontFamily);

			// Reset hit boxes
			var hitboxes = me.legendHitBoxes = [];

			var minSize = me.minSize;
			var isHorizontal = me.isHorizontal();

			if (isHorizontal) {
				minSize.width = me.maxWidth; // fill all the width
				minSize.height = display ? 10 : 0;
			} else {
				minSize.width = display ? 10 : 0;
				minSize.height = me.maxHeight; // fill all the height
			}

			// Increase sizes here
			if (display) {
				ctx.font = labelFont;

				if (isHorizontal) {
					// Labels

					// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
					var lineWidths = me.lineWidths = [0];
					var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;

					ctx.textAlign = 'left';
					ctx.textBaseline = 'top';

					helpers$1.each(me.legendItems, function(legendItem, i) {
						var boxWidth = getBoxWidth(labelOpts, fontSize);
						var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;

						if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
							totalHeight += fontSize + (labelOpts.padding);
							lineWidths[lineWidths.length] = me.left;
						}

						// Store the hitbox width and height here. Final position will be updated in `draw`
						hitboxes[i] = {
							left: 0,
							top: 0,
							width: width,
							height: fontSize
						};

						lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
					});

					minSize.height += totalHeight;

				} else {
					var vPadding = labelOpts.padding;
					var columnWidths = me.columnWidths = [];
					var totalWidth = labelOpts.padding;
					var currentColWidth = 0;
					var currentColHeight = 0;
					var itemHeight = fontSize + vPadding;

					helpers$1.each(me.legendItems, function(legendItem, i) {
						var boxWidth = getBoxWidth(labelOpts, fontSize);
						var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;

						// If too tall, go to new column
						if (currentColHeight + itemHeight > minSize.height) {
							totalWidth += currentColWidth + labelOpts.padding;
							columnWidths.push(currentColWidth); // previous column width

							currentColWidth = 0;
							currentColHeight = 0;
						}

						// Get max width
						currentColWidth = Math.max(currentColWidth, itemWidth);
						currentColHeight += itemHeight;

						// Store the hitbox width and height here. Final position will be updated in `draw`
						hitboxes[i] = {
							left: 0,
							top: 0,
							width: itemWidth,
							height: fontSize
						};
					});

					totalWidth += currentColWidth;
					columnWidths.push(currentColWidth);
					minSize.width += totalWidth;
				}
			}

			me.width = minSize.width;
			me.height = minSize.height;
		},
		afterFit: noop,

		// Shared Methods
		isHorizontal: function() {
			return this.options.position === 'top' || this.options.position === 'bottom';
		},

		// Actually draw the legend on the canvas
		draw: function() {
			var me = this;
			var opts = me.options;
			var labelOpts = opts.labels;
			var globalDefault = core_defaults.global;
			var lineDefault = globalDefault.elements.line;
			var legendWidth = me.width;
			var lineWidths = me.lineWidths;

			if (opts.display) {
				var ctx = me.ctx;
				var valueOrDefault = helpers$1.valueOrDefault;
				var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor);
				var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
				var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
				var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
				var labelFont = helpers$1.fontString(fontSize, fontStyle, fontFamily);
				var cursor;

				// Canvas setup
				ctx.textAlign = 'left';
				ctx.textBaseline = 'middle';
				ctx.lineWidth = 0.5;
				ctx.strokeStyle = fontColor; // for strikethrough effect
				ctx.fillStyle = fontColor; // render in correct colour
				ctx.font = labelFont;

				var boxWidth = getBoxWidth(labelOpts, fontSize);
				var hitboxes = me.legendHitBoxes;

				// current position
				var drawLegendBox = function(x, y, legendItem) {
					if (isNaN(boxWidth) || boxWidth <= 0) {
						return;
					}

					// Set the ctx for the box
					ctx.save();

					ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
					ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
					ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
					ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
					ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
					ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
					var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);

					if (ctx.setLineDash) {
						// IE 9 and 10 do not support line dash
						ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash));
					}

					if (opts.labels && opts.labels.usePointStyle) {
						// Recalculate x and y for drawPoint() because its expecting
						// x and y to be center of figure (instead of top left)
						var radius = fontSize * Math.SQRT2 / 2;
						var offSet = radius / Math.SQRT2;
						var centerX = x + offSet;
						var centerY = y + offSet;

						// Draw pointStyle as legend symbol
						helpers$1.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
					} else {
						// Draw box as legend symbol
						if (!isLineWidthZero) {
							ctx.strokeRect(x, y, boxWidth, fontSize);
						}
						ctx.fillRect(x, y, boxWidth, fontSize);
					}

					ctx.restore();
				};
				var fillText = function(x, y, legendItem, textWidth) {
					var halfFontSize = fontSize / 2;
					var xLeft = boxWidth + halfFontSize + x;
					var yMiddle = y + halfFontSize;

					ctx.fillText(legendItem.text, xLeft, yMiddle);

					if (legendItem.hidden) {
						// Strikethrough the text if hidden
						ctx.beginPath();
						ctx.lineWidth = 2;
						ctx.moveTo(xLeft, yMiddle);
						ctx.lineTo(xLeft + textWidth, yMiddle);
						ctx.stroke();
					}
				};

				// Horizontal
				var isHorizontal = me.isHorizontal();
				if (isHorizontal) {
					cursor = {
						x: me.left + ((legendWidth - lineWidths[0]) / 2),
						y: me.top + labelOpts.padding,
						line: 0
					};
				} else {
					cursor = {
						x: me.left + labelOpts.padding,
						y: me.top + labelOpts.padding,
						line: 0
					};
				}

				var itemHeight = fontSize + labelOpts.padding;
				helpers$1.each(me.legendItems, function(legendItem, i) {
					var textWidth = ctx.measureText(legendItem.text).width;
					var width = boxWidth + (fontSize / 2) + textWidth;
					var x = cursor.x;
					var y = cursor.y;

					if (isHorizontal) {
						if (x + width >= legendWidth) {
							y = cursor.y += itemHeight;
							cursor.line++;
							x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
						}
					} else if (y + itemHeight > me.bottom) {
						x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
						y = cursor.y = me.top + labelOpts.padding;
						cursor.line++;
					}

					drawLegendBox(x, y, legendItem);

					hitboxes[i].left = x;
					hitboxes[i].top = y;

					// Fill the actual label
					fillText(x, y, legendItem, textWidth);

					if (isHorizontal) {
						cursor.x += width + (labelOpts.padding);
					} else {
						cursor.y += itemHeight;
					}

				});
			}
		},

		/**
		 * Handle an event
		 * @private
		 * @param {IEvent} event - The event to handle
		 * @return {Boolean} true if a change occured
		 */
		handleEvent: function(e) {
			var me = this;
			var opts = me.options;
			var type = e.type === 'mouseup' ? 'click' : e.type;
			var changed = false;

			if (type === 'mousemove') {
				if (!opts.onHover) {
					return;
				}
			} else if (type === 'click') {
				if (!opts.onClick) {
					return;
				}
			} else {
				return;
			}

			// Chart event already has relative position in it
			var x = e.x;
			var y = e.y;

			if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
				// See if we are touching one of the dataset boxes
				var lh = me.legendHitBoxes;
				for (var i = 0; i < lh.length; ++i) {
					var hitBox = lh[i];

					if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
						// Touching an element
						if (type === 'click') {
							// use e.native for backwards compatibility
							opts.onClick.call(me, e.native, me.legendItems[i]);
							changed = true;
							break;
						} else if (type === 'mousemove') {
							// use e.native for backwards compatibility
							opts.onHover.call(me, e.native, me.legendItems[i]);
							changed = true;
							break;
						}
					}
				}
			}

			return changed;
		}
	});

	function createNewLegendAndAttach(chart, legendOpts) {
		var legend = new Legend({
			ctx: chart.ctx,
			options: legendOpts,
			chart: chart
		});

		core_layouts.configure(chart, legend, legendOpts);
		core_layouts.addBox(chart, legend);
		chart.legend = legend;
	}

	var plugin_legend = {
		id: 'legend',

		/**
		 * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making
		 * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of
		 * the plugin, which one will be re-exposed in the chart.js file.
		 * https://github.com/chartjs/Chart.js/pull/2640
		 * @private
		 */
		_element: Legend,

		beforeInit: function(chart) {
			var legendOpts = chart.options.legend;

			if (legendOpts) {
				createNewLegendAndAttach(chart, legendOpts);
			}
		},

		beforeUpdate: function(chart) {
			var legendOpts = chart.options.legend;
			var legend = chart.legend;

			if (legendOpts) {
				helpers$1.mergeIf(legendOpts, core_defaults.global.legend);

				if (legend) {
					core_layouts.configure(chart, legend, legendOpts);
					legend.options = legendOpts;
				} else {
					createNewLegendAndAttach(chart, legendOpts);
				}
			} else if (legend) {
				core_layouts.removeBox(chart, legend);
				delete chart.legend;
			}
		},

		afterEvent: function(chart, e) {
			var legend = chart.legend;
			if (legend) {
				legend.handleEvent(e);
			}
		}
	};

	var noop$1 = helpers$1.noop;

	core_defaults._set('global', {
		title: {
			display: false,
			fontStyle: 'bold',
			fullWidth: true,
			lineHeight: 1.2,
			padding: 10,
			position: 'top',
			text: '',
			weight: 2000         // by default greater than legend (1000) to be above
		}
	});

	/**
	 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
	 */
	var Title = core_element.extend({
		initialize: function(config) {
			var me = this;
			helpers$1.extend(me, config);

			// Contains hit boxes for each dataset (in dataset order)
			me.legendHitBoxes = [];
		},

		// These methods are ordered by lifecycle. Utilities then follow.

		beforeUpdate: noop$1,
		update: function(maxWidth, maxHeight, margins) {
			var me = this;

			// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
			me.beforeUpdate();

			// Absorb the master measurements
			me.maxWidth = maxWidth;
			me.maxHeight = maxHeight;
			me.margins = margins;

			// Dimensions
			me.beforeSetDimensions();
			me.setDimensions();
			me.afterSetDimensions();
			// Labels
			me.beforeBuildLabels();
			me.buildLabels();
			me.afterBuildLabels();

			// Fit
			me.beforeFit();
			me.fit();
			me.afterFit();
			//
			me.afterUpdate();

			return me.minSize;

		},
		afterUpdate: noop$1,

		//

		beforeSetDimensions: noop$1,
		setDimensions: function() {
			var me = this;
			// Set the unconstrained dimension before label rotation
			if (me.isHorizontal()) {
				// Reset position before calculating rotation
				me.width = me.maxWidth;
				me.left = 0;
				me.right = me.width;
			} else {
				me.height = me.maxHeight;

				// Reset position before calculating rotation
				me.top = 0;
				me.bottom = me.height;
			}

			// Reset padding
			me.paddingLeft = 0;
			me.paddingTop = 0;
			me.paddingRight = 0;
			me.paddingBottom = 0;

			// Reset minSize
			me.minSize = {
				width: 0,
				height: 0
			};
		},
		afterSetDimensions: noop$1,

		//

		beforeBuildLabels: noop$1,
		buildLabels: noop$1,
		afterBuildLabels: noop$1,

		//

		beforeFit: noop$1,
		fit: function() {
			var me = this;
			var valueOrDefault = helpers$1.valueOrDefault;
			var opts = me.options;
			var display = opts.display;
			var fontSize = valueOrDefault(opts.fontSize, core_defaults.global.defaultFontSize);
			var minSize = me.minSize;
			var lineCount = helpers$1.isArray(opts.text) ? opts.text.length : 1;
			var lineHeight = helpers$1.options.toLineHeight(opts.lineHeight, fontSize);
			var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0;

			if (me.isHorizontal()) {
				minSize.width = me.maxWidth; // fill all the width
				minSize.height = textSize;
			} else {
				minSize.width = textSize;
				minSize.height = me.maxHeight; // fill all the height
			}

			me.width = minSize.width;
			me.height = minSize.height;

		},
		afterFit: noop$1,

		// Shared Methods
		isHorizontal: function() {
			var pos = this.options.position;
			return pos === 'top' || pos === 'bottom';
		},

		// Actually draw the title block on the canvas
		draw: function() {
			var me = this;
			var ctx = me.ctx;
			var valueOrDefault = helpers$1.valueOrDefault;
			var opts = me.options;
			var globalDefaults = core_defaults.global;

			if (opts.display) {
				var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize);
				var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle);
				var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily);
				var titleFont = helpers$1.fontString(fontSize, fontStyle, fontFamily);
				var lineHeight = helpers$1.options.toLineHeight(opts.lineHeight, fontSize);
				var offset = lineHeight / 2 + opts.padding;
				var rotation = 0;
				var top = me.top;
				var left = me.left;
				var bottom = me.bottom;
				var right = me.right;
				var maxWidth, titleX, titleY;

				ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
				ctx.font = titleFont;

				// Horizontal
				if (me.isHorizontal()) {
					titleX = left + ((right - left) / 2); // midpoint of the width
					titleY = top + offset;
					maxWidth = right - left;
				} else {
					titleX = opts.position === 'left' ? left + offset : right - offset;
					titleY = top + ((bottom - top) / 2);
					maxWidth = bottom - top;
					rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
				}

				ctx.save();
				ctx.translate(titleX, titleY);
				ctx.rotate(rotation);
				ctx.textAlign = 'center';
				ctx.textBaseline = 'middle';

				var text = opts.text;
				if (helpers$1.isArray(text)) {
					var y = 0;
					for (var i = 0; i < text.length; ++i) {
						ctx.fillText(text[i], 0, y, maxWidth);
						y += lineHeight;
					}
				} else {
					ctx.fillText(text, 0, 0, maxWidth);
				}

				ctx.restore();
			}
		}
	});

	function createNewTitleBlockAndAttach(chart, titleOpts) {
		var title = new Title({
			ctx: chart.ctx,
			options: titleOpts,
			chart: chart
		});

		core_layouts.configure(chart, title, titleOpts);
		core_layouts.addBox(chart, title);
		chart.titleBlock = title;
	}

	var plugin_title = {
		id: 'title',

		/**
		 * Backward compatibility: since 2.1.5, the title is registered as a plugin, making
		 * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
		 * the plugin, which one will be re-exposed in the chart.js file.
		 * https://github.com/chartjs/Chart.js/pull/2640
		 * @private
		 */
		_element: Title,

		beforeInit: function(chart) {
			var titleOpts = chart.options.title;

			if (titleOpts) {
				createNewTitleBlockAndAttach(chart, titleOpts);
			}
		},

		beforeUpdate: function(chart) {
			var titleOpts = chart.options.title;
			var titleBlock = chart.titleBlock;

			if (titleOpts) {
				helpers$1.mergeIf(titleOpts, core_defaults.global.title);

				if (titleBlock) {
					core_layouts.configure(chart, titleBlock, titleOpts);
					titleBlock.options = titleOpts;
				} else {
					createNewTitleBlockAndAttach(chart, titleOpts);
				}
			} else if (titleBlock) {
				core_layouts.removeBox(chart, titleBlock);
				delete chart.titleBlock;
			}
		}
	};

	var plugins = {};
	var filler = plugin_filler;
	var legend = plugin_legend;
	var title = plugin_title;
	plugins.filler = filler;
	plugins.legend = legend;
	plugins.title = title;

	/**
	 * @namespace Chart
	 */
	var Chart = core();

	Chart.helpers = helpers$1;

	// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
	core_helpers(Chart);

	Chart.defaults = core_defaults;
	Chart.Element = core_element;
	Chart.elements = elements;
	Chart.Interaction = core_interaction;
	Chart.layouts = core_layouts;
	Chart.platform = platform;
	Chart.plugins = core_plugins;
	Chart.Ticks = core_ticks;

	core_animation(Chart);
	core_controller(Chart);
	core_datasetController(Chart);
	core_scaleService(Chart);
	core_scale(Chart);
	core_tooltip(Chart);

	scale_linearbase(Chart);
	scale_category(Chart);
	scale_linear(Chart);
	scale_logarithmic(Chart);
	scale_radialLinear(Chart);
	scale_time(Chart);

	// Controllers must be loaded after elements
	// See Chart.core.datasetController.dataElementType
	controller_bar(Chart);
	controller_bubble(Chart);
	controller_doughnut(Chart);
	controller_line(Chart);
	controller_polarArea(Chart);
	controller_radar(Chart);
	controller_scatter(Chart);

	Chart_Bar(Chart);
	Chart_Bubble(Chart);
	Chart_Doughnut(Chart);
	Chart_Line(Chart);
	Chart_PolarArea(Chart);
	Chart_Radar(Chart);
	Chart_Scatter(Chart);

	// Loading built-it plugins

	for (var k in plugins) {
		if (plugins.hasOwnProperty(k)) {
			Chart.plugins.register(plugins[k]);
		}
	}

	Chart.platform.initialize();

	var chart = Chart;
	if (typeof window !== 'undefined') {
		window.Chart = Chart;
	}

	// DEPRECATIONS

	/**
	 * Provided for backward compatibility, not available anymore
	 * @namespace Chart.Legend
	 * @deprecated since version 2.1.5
	 * @todo remove at version 3
	 * @private
	 */
	Chart.Legend = plugins.legend._element;

	/**
	 * Provided for backward compatibility, not available anymore
	 * @namespace Chart.Title
	 * @deprecated since version 2.1.5
	 * @todo remove at version 3
	 * @private
	 */
	Chart.Title = plugins.title._element;

	/**
	 * Provided for backward compatibility, use Chart.plugins instead
	 * @namespace Chart.pluginService
	 * @deprecated since version 2.1.5
	 * @todo remove at version 3
	 * @private
	 */
	Chart.pluginService = Chart.plugins;

	/**
	 * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
	 * effect, instead simply create/register plugins via plain JavaScript objects.
	 * @interface Chart.PluginBase
	 * @deprecated since version 2.5.0
	 * @todo remove at version 3
	 * @private
	 */
	Chart.PluginBase = Chart.Element.extend({});

	/**
	 * Provided for backward compatibility, use Chart.helpers.canvas instead.
	 * @namespace Chart.canvasHelpers
	 * @deprecated since version 2.6.0
	 * @todo remove at version 3
	 * @private
	 */
	Chart.canvasHelpers = Chart.helpers.canvas;

	/**
	 * Provided for backward compatibility, use Chart.layouts instead.
	 * @namespace Chart.layoutService
	 * @deprecated since version 2.8.0
	 * @todo remove at version 3
	 * @private
	 */
	Chart.layoutService = Chart.layouts;

	function dataHandler(newData, oldData) {
	  if (oldData) {
	    var chart = this.$data._chart;
	    var newDatasetLabels = newData.datasets.map(function (dataset) {
	      return dataset.label;
	    });
	    var oldDatasetLabels = oldData.datasets.map(function (dataset) {
	      return dataset.label;
	    });
	    var oldLabels = JSON.stringify(oldDatasetLabels);
	    var newLabels = JSON.stringify(newDatasetLabels);

	    if (newLabels === oldLabels && oldData.datasets.length === newData.datasets.length) {
	      newData.datasets.forEach(function (dataset, i) {
	        var oldDatasetKeys = Object.keys(oldData.datasets[i]);
	        var newDatasetKeys = Object.keys(dataset);
	        var deletionKeys = oldDatasetKeys.filter(function (key) {
	          return key !== '_meta' && newDatasetKeys.indexOf(key) === -1;
	        });
	        deletionKeys.forEach(function (deletionKey) {
	          delete chart.data.datasets[i][deletionKey];
	        });

	        for (var attribute in dataset) {
	          if (dataset.hasOwnProperty(attribute)) {
	            chart.data.datasets[i][attribute] = dataset[attribute];
	          }
	        }
	      });

	      if (newData.hasOwnProperty('labels')) {
	        chart.data.labels = newData.labels;
	        this.$emit('labels:update');
	      }

	      if (newData.hasOwnProperty('xLabels')) {
	        chart.data.xLabels = newData.xLabels;
	        this.$emit('xlabels:update');
	      }

	      if (newData.hasOwnProperty('yLabels')) {
	        chart.data.yLabels = newData.yLabels;
	        this.$emit('ylabels:update');
	      }

	      chart.update();
	      this.$emit('chart:update');
	    } else {
	      if (chart) {
	        chart.destroy();
	        this.$emit('chart:destroy');
	      }

	      this.renderChart(this.chartData, this.options);
	      this.$emit('chart:render');
	    }
	  } else {
	    if (this.$data._chart) {
	      this.$data._chart.destroy();

	      this.$emit('chart:destroy');
	    }

	    this.renderChart(this.chartData, this.options);
	    this.$emit('chart:render');
	  }
	}

	var reactiveData = {
	  data: function data() {
	    return {
	      chartData: null
	    };
	  },
	  watch: {
	    'chartData': dataHandler
	  }
	};
	var reactiveProp = {
	  props: {
	    chartData: {
	      type: Object,
	      required: true,
	      default: function _default() {}
	    }
	  },
	  watch: {
	    'chartData': dataHandler
	  }
	};
	var mixins = {
	  reactiveData: reactiveData,
	  reactiveProp: reactiveProp
	};

	function generateChart(chartId, chartType) {
	  return {
	    render: function render(createElement) {
	      return createElement('div', {
	        style: this.styles,
	        class: this.cssClasses
	      }, [createElement('canvas', {
	        attrs: {
	          id: this.chartId,
	          width: this.width,
	          height: this.height
	        },
	        ref: 'canvas'
	      })]);
	    },
	    props: {
	      chartId: {
	        default: chartId,
	        type: String
	      },
	      width: {
	        default: 400,
	        type: Number
	      },
	      height: {
	        default: 400,
	        type: Number
	      },
	      cssClasses: {
	        type: String,
	        default: ''
	      },
	      styles: {
	        type: Object
	      },
	      plugins: {
	        type: Array,
	        default: function _default() {
	          return [];
	        }
	      }
	    },
	    data: function data() {
	      return {
	        _chart: null,
	        _plugins: this.plugins
	      };
	    },
	    methods: {
	      addPlugin: function addPlugin(plugin) {
	        this.$data._plugins.push(plugin);
	      },
	      generateLegend: function generateLegend() {
	        if (this.$data._chart) {
	          return this.$data._chart.generateLegend();
	        }
	      },
	      renderChart: function renderChart(data, options) {
	        if (this.$data._chart) this.$data._chart.destroy();
	        if (!this.$refs.canvas) throw new Error('Please remove the <template></template> tags from your chart component. See https://vue-chartjs.org/guide/#vue-single-file-components');
	        this.$data._chart = new chart(this.$refs.canvas.getContext('2d'), {
	          type: chartType,
	          data: data,
	          options: options,
	          plugins: this.$data._plugins
	        });
	      }
	    },
	    beforeDestroy: function beforeDestroy() {
	      if (this.$data._chart) {
	        this.$data._chart.destroy();
	      }
	    }
	  };
	}
	var HorizontalBar = generateChart('horizontalbar-chart', 'horizontalBar');
	var Doughnut = generateChart('doughnut-chart', 'doughnut');
	var Line$1 = generateChart('line-chart', 'line');

	chart.NewLegend = chart.Legend.extend({
		afterFit: function() {
			this.height = this.height + 20;
		},
	});

	let createNewLegendAndAttach$1 = function(chartInstance, legendOpts) {
		if ('line'!==chartInstance.config.type) {
			return;
		}

		var legend = new chart.NewLegend({
			ctx: chartInstance.chart.ctx,
			options: legendOpts,
			chart: chartInstance
		});

		if (chartInstance.legend) {
			chart.layoutService.removeBox(chartInstance, chartInstance.legend);
			delete chartInstance.newLegend;
		}

		chartInstance.newLegend = legend;
		chart.layoutService.addBox(chartInstance, legend);
	};

	// Register the legend plugin
	chart.plugins.register({
		beforeInit: function(chartInstance) {
			if ('line'!==chartInstance.config.type) {
				return;
			}

			var legendOpts = chartInstance.options.legend;

			if (legendOpts) {
				createNewLegendAndAttach$1(chartInstance, legendOpts);
			}
		},
		beforeUpdate: function(chartInstance) {
			if ('line'!==chartInstance.config.type) {
				return;
			}

			var legendOpts = chartInstance.options.legend;

			if (legendOpts) {
				legendOpts = chart.helpers.configMerge(chart.defaults.global.legend, legendOpts);

				if (chartInstance.newLegend) {
					chartInstance.newLegend.options = legendOpts;
				} else {
					createNewLegendAndAttach$1(chartInstance, legendOpts);
				}
		  	} else {
				chart.layoutService.removeBox(chartInstance, chartInstance.newLegend);
				delete chartInstance.newLegend;
			}
		},
		afterEvent: function(chartInstance, e) {
			if ('line'!==chartInstance.config.type) {
				return;
			}

			var legend = chartInstance.newLegend;
			if (legend) {
				legend.handleEvent(e);
			}
		}
	});
	const { reactiveProp: reactiveProp$1 } = mixins;

	var LineChart = {
		extends: Line$1,
		mixins: [reactiveProp$1],
		props: ['options'],
		mounted () {
			if(this.chartData){
				this.renderChart(this.chartData, this.options);
			}
		}
	};

	//

		var script$3 = {
		components: {
			LineChart
		},
		props: {
			datacollection: Object,
			options: {
				type: Object,
				default: {}
			}
		}
	};

	/* script */
	const __vue_script__$3 = script$3;
	/* template */
	var __vue_render__$3 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"searchwp-metrics-chart searchwp-metrics-chart--line"},[_c('line-chart',{attrs:{"chart-data":_vm.datacollection,"options":_vm.options}})],1)};
	var __vue_staticRenderFns__$3 = [];

	  /* style */
	  const __vue_inject_styles__$3 = undefined;
	  /* scoped */
	  const __vue_scope_id__$3 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$3 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$3 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$3 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$3, staticRenderFns: __vue_staticRenderFns__$3 },
	    __vue_inject_styles__$3,
	    __vue_script__$3,
	    __vue_scope_id__$3,
	    __vue_is_functional_template__$3,
	    __vue_module_identifier__$3,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	//

	var script$4 = {
		methods: {
			onclick: function() {
				this.$emit('onclick');
			}
		},
		data () {
			return {
				i18n: {
					remove: _SEARCHWP_METRICS_VARS.i18n.remove
				}
			}
		}
	};

	/* script */
	const __vue_script__$4 = script$4;
	/* template */
	var __vue_render__$4 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('button',{staticClass:"searchwp-delete dashicons dashicons-dismiss",attrs:{"title":_vm.i18n.remove},on:{"click":_vm.onclick}})};
	var __vue_staticRenderFns__$4 = [];

	  /* style */
	  const __vue_inject_styles__$4 = undefined;
	  /* scoped */
	  const __vue_scope_id__$4 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$4 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$4 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$4 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$4, staticRenderFns: __vue_staticRenderFns__$4 },
	    __vue_inject_styles__$4,
	    __vue_script__$4,
	    __vue_scope_id__$4,
	    __vue_is_functional_template__$4,
	    __vue_module_identifier__$4,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	const { reactiveProp: reactiveProp$2 } = mixins;

	var DoughnutChart = {
		extends: Doughnut,
		mixins: [reactiveProp$2],
		props: ['options'],
		mounted () {
			this.renderChart(this.chartData, this.options);
		}
	};

	//

		var script$5 = {
		components: {
			DoughnutChart
		},
		props: {
			datacollection: Object,
			options: {
				type: Object,
				default: {}
			}
		}
	};

	/* script */
	const __vue_script__$5 = script$5;
	/* template */
	var __vue_render__$5 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"searchwp-metrics-chart searchwp-metrics-chart--doughnut"},[_c('doughnut-chart',{attrs:{"chart-data":_vm.datacollection,"options":_vm.options}})],1)};
	var __vue_staticRenderFns__$5 = [];

	  /* style */
	  const __vue_inject_styles__$5 = undefined;
	  /* scoped */
	  const __vue_scope_id__$5 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$5 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$5 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$5 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$5, staticRenderFns: __vue_staticRenderFns__$5 },
	    __vue_inject_styles__$5,
	    __vue_script__$5,
	    __vue_scope_id__$5,
	    __vue_is_functional_template__$5,
	    __vue_module_identifier__$5,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	const { reactiveProp: reactiveProp$3 } = mixins;

	var BarChart = {
		extends: HorizontalBar,
		mixins: [reactiveProp$3],
		props: ['options'],
		mounted () {
			this.renderChart(this.chartData, this.options);
		}
	};

	//

		var script$6 = {
		components: {
			BarChart
		},
		props: {
			datacollection: Object,
			options: {
				type: Object,
				default: {}
			}
		}
	};

	/* script */
	const __vue_script__$6 = script$6;
	/* template */
	var __vue_render__$6 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"searchwp-metrics-chart searchwp-metrics-chart--bar"},[_c('bar-chart',{attrs:{"chart-data":_vm.datacollection,"options":_vm.options}})],1)};
	var __vue_staticRenderFns__$6 = [];

	  /* style */
	  const __vue_inject_styles__$6 = undefined;
	  /* scoped */
	  const __vue_scope_id__$6 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$6 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$6 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$6 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
	    __vue_inject_styles__$6,
	    __vue_script__$6,
	    __vue_scope_id__$6,
	    __vue_is_functional_template__$6,
	    __vue_module_identifier__$6,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	//

	var script$7 = {
		props: {
			index: Number,
			text: String
		},
		mounted () {
			this.color = Vue$1.SearchwpMetricsGetColor(this.index);
		},
		data () {
			return {
				color: '#ffffff'
			}
		}
	};

	/* script */
	const __vue_script__$7 = script$7;
	/* template */
	var __vue_render__$7 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('span',{staticClass:"searchwp-metrics-legend-item"},[_c('span',{staticClass:"searchwp-metrics-legend-indicator",style:({ backgroundColor: _vm.color }),attrs:{"title":_vm.text}}),_vm._v(" "),_c('span',{staticClass:"searchwp-metrics-legend-label",attrs:{"title":_vm.text},on:{"click":function($event){return _vm.$emit('onclick')}}},[_c('span',[_vm._v(_vm._s(_vm.text))])])])};
	var __vue_staticRenderFns__$7 = [];

	  /* style */
	  const __vue_inject_styles__$7 = undefined;
	  /* scoped */
	  const __vue_scope_id__$7 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$7 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$7 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$7 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
	    __vue_inject_styles__$7,
	    __vue_script__$7,
	    __vue_scope_id__$7,
	    __vue_is_functional_template__$7,
	    __vue_module_identifier__$7,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	//

	var script$8 = {
		props: {
			query: String,
			clickCount: Number,
			postCount: Number,
			icon: {
				type: String,
				default: 'arrow-right'
			},
			buttonText: {
				type: String,
				default: _SEARCHWP_METRICS_VARS.i18n.details
			}
		},
		computed: {
			translatedCopy() {
				return {
					template: '<span>' + this.i18n.insightAnalysis + '</span>',
					props: this.$options.props
				}
			}
		},
		data () {
			return {
				i18n: {
					insightAnalysis: _SEARCHWP_METRICS_VARS.i18n.insight_analysis
				}
			}
		}
	};

	/* script */
	const __vue_script__$8 = script$8;
	/* template */
	var __vue_render__$8 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"searchwp-metrics__insight"},[(_vm.icon)?_c('span',{class:'dashicons dashicons-' + _vm.icon}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-suggestions-insight-content"},[_c('p',[_c(_vm.translatedCopy,_vm._b({tag:"component"},'component',_vm.$props,false)),_vm._v(" "),(_vm.buttonText)?_c('button',{staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){return _vm.$emit('onclick')}}},[_vm._v("\n\t\t\t\t"+_vm._s(_vm.buttonText)+"\n\t\t\t")]):_vm._e()],1)])])};
	var __vue_staticRenderFns__$8 = [];

	  /* style */
	  const __vue_inject_styles__$8 = undefined;
	  /* scoped */
	  const __vue_scope_id__$8 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$8 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$8 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$8 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
	    __vue_inject_styles__$8,
	    __vue_script__$8,
	    __vue_scope_id__$8,
	    __vue_is_functional_template__$8,
	    __vue_module_identifier__$8,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	//

	var script$9 = {
		props: {
			postCount: Number,
			icon: {
				type: String,
				default: 'awards'
			},
			buttonText: {
				type: String,
				default: _SEARCHWP_METRICS_VARS.i18n.details
			}
		},
		computed: {
			translatedCopySingular() {
				return {
					template: '<span>' + this.i18n.insightPopularSingular + '</span>'
				}
			},
			translatedCopyPlural() {
				return {
					template: '<span>' + this.i18n.insightPopularPlural + '</span>',
					props: this.$options.props
				}
			}
		},
		data () {
			return {
				i18n: {
					insightPopularPlural: _SEARCHWP_METRICS_VARS.i18n.insight_popular_plural,
					insightPopularSingular: _SEARCHWP_METRICS_VARS.i18n.insight_popular_singular
				}
			}
		}
	};

	/* script */
	const __vue_script__$9 = script$9;
	/* template */
	var __vue_render__$9 = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"searchwp-metrics__insight"},[(_vm.icon)?_c('span',{class:'dashicons dashicons-' + _vm.icon}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-suggestions-insight-content"},[_c('p',[(1 === _vm.postCount)?_c(_vm.translatedCopySingular,{tag:"component"}):_c(_vm.translatedCopyPlural,_vm._b({tag:"component"},'component',_vm.$props,false)),_vm._v(" "),(_vm.buttonText)?_c('button',{staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){return _vm.$emit('onclick')}}},[_vm._v("\n\t\t\t\t"+_vm._s(_vm.buttonText)+"\n\t\t\t")]):_vm._e()],1)])])};
	var __vue_staticRenderFns__$9 = [];

	  /* style */
	  const __vue_inject_styles__$9 = undefined;
	  /* scoped */
	  const __vue_scope_id__$9 = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$9 = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$9 = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$9 = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
	    __vue_inject_styles__$9,
	    __vue_script__$9,
	    __vue_scope_id__$9,
	    __vue_is_functional_template__$9,
	    __vue_module_identifier__$9,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	//

	var script$a = {
		props: {
			postCount: Number,
			icon: {
				type: String,
				default: 'sos'
			},
			buttonText: {
				type: String,
				default: _SEARCHWP_METRICS_VARS.i18n.details
			}
		},
		computed: {
			translatedCopySingular() {
				return {
					template: '<span>' + this.i18n.insightUnderdogSingular + '</span>'
				}
			},
			translatedCopyPlural() {
				return {
					template: '<span>' + this.i18n.insightUnderdogPlural + '</span>',
					props: this.$options.props
				}
			}
		},
		data () {
			return {
				i18n: {
					insightUnderdogPlural: _SEARCHWP_METRICS_VARS.i18n.insight_underdog_plural,
					insightUnderdogSingular: _SEARCHWP_METRICS_VARS.i18n.insight_underdog_singular,
				}
			}
		}
	};

	/* script */
	const __vue_script__$a = script$a;
	/* template */
	var __vue_render__$a = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"searchwp-metrics__insight"},[(_vm.icon)?_c('span',{class:'dashicons dashicons-' + _vm.icon}):_vm._e(),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-suggestions-insight-content"},[_c('p',[(1 === _vm.postCount)?_c(_vm.translatedCopySingular,{tag:"component"}):_c(_vm.translatedCopyPlural,_vm._b({tag:"component"},'component',_vm.$props,false)),_vm._v(" "),(_vm.buttonText)?_c('button',{staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){return _vm.$emit('onclick')}}},[_vm._v("\n\t\t\t\t"+_vm._s(_vm.buttonText)+"\n\t\t\t")]):_vm._e()],1)])])};
	var __vue_staticRenderFns__$a = [];

	  /* style */
	  const __vue_inject_styles__$a = undefined;
	  /* scoped */
	  const __vue_scope_id__$a = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$a = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$a = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$a = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$a, staticRenderFns: __vue_staticRenderFns__$a },
	    __vue_inject_styles__$a,
	    __vue_script__$a,
	    __vue_scope_id__$a,
	    __vue_is_functional_template__$a,
	    __vue_module_identifier__$a,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	var vueSimpleSpinner = createCommonjsModule(function (module, exports) {
	/*!
	 * vue-simple-spinner v1.2.8 (https://github.com/dzwillia/vue-simple-spinner)
	 * (c) 2017 David Z. Williams
	 * Released under the MIT License.
	 */
	(function webpackUniversalModuleDefinition(root, factory) {
		module.exports = factory();
	})(commonjsGlobal, function() {
	return /******/ (function(modules) { // webpackBootstrap
	/******/ 	// The module cache
	/******/ 	var installedModules = {};
	/******/
	/******/ 	// The require function
	/******/ 	function __webpack_require__(moduleId) {
	/******/
	/******/ 		// Check if module is in cache
	/******/ 		if(installedModules[moduleId]) {
	/******/ 			return installedModules[moduleId].exports;
	/******/ 		}
	/******/ 		// Create a new module (and put it into the cache)
	/******/ 		var module = installedModules[moduleId] = {
	/******/ 			i: moduleId,
	/******/ 			l: false,
	/******/ 			exports: {}
	/******/ 		};
	/******/
	/******/ 		// Execute the module function
	/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
	/******/
	/******/ 		// Flag the module as loaded
	/******/ 		module.l = true;
	/******/
	/******/ 		// Return the exports of the module
	/******/ 		return module.exports;
	/******/ 	}
	/******/
	/******/
	/******/ 	// expose the modules object (__webpack_modules__)
	/******/ 	__webpack_require__.m = modules;
	/******/
	/******/ 	// expose the module cache
	/******/ 	__webpack_require__.c = installedModules;
	/******/
	/******/ 	// define getter function for harmony exports
	/******/ 	__webpack_require__.d = function(exports, name, getter) {
	/******/ 		if(!__webpack_require__.o(exports, name)) {
	/******/ 			Object.defineProperty(exports, name, {
	/******/ 				configurable: false,
	/******/ 				enumerable: true,
	/******/ 				get: getter
	/******/ 			});
	/******/ 		}
	/******/ 	};
	/******/
	/******/ 	// getDefaultExport function for compatibility with non-harmony modules
	/******/ 	__webpack_require__.n = function(module) {
	/******/ 		var getter = module && module.__esModule ?
	/******/ 			function getDefault() { return module['default']; } :
	/******/ 			function getModuleExports() { return module; };
	/******/ 		__webpack_require__.d(getter, 'a', getter);
	/******/ 		return getter;
	/******/ 	};
	/******/
	/******/ 	// Object.prototype.hasOwnProperty.call
	/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
	/******/
	/******/ 	// __webpack_public_path__
	/******/ 	__webpack_require__.p = "";
	/******/
	/******/ 	// Load entry module and return exports
	/******/ 	return __webpack_require__(__webpack_require__.s = 0);
	/******/ })
	/************************************************************************/
	/******/ ([
	/* 0 */
	/***/ (function(module, exports, __webpack_require__) {


	Object.defineProperty(exports, "__esModule", {
	  value: true
	});
	exports.VueSimpleSpinner = undefined;

	var _Spinner = __webpack_require__(1);

	var _Spinner2 = _interopRequireDefault(_Spinner);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	if (typeof window !== 'undefined' && window.Vue) {
	  Vue.component('vue-simple-spinner', _Spinner2.default);
	}

	exports.VueSimpleSpinner = _Spinner2.default;
	exports.default = _Spinner2.default;

	/***/ }),
	/* 1 */
	/***/ (function(module, exports, __webpack_require__) {


	/* styles */
	__webpack_require__(2);

	var Component = __webpack_require__(7)(
	  /* script */
	  __webpack_require__(8),
	  /* template */
	  __webpack_require__(9),
	  /* scopeId */
	  null,
	  /* cssModules */
	  null
	);

	module.exports = Component.exports;


	/***/ }),
	/* 2 */
	/***/ (function(module, exports, __webpack_require__) {

	// style-loader: Adds some css to the DOM by adding a <style> tag

	// load the styles
	var content = __webpack_require__(3);
	if(typeof content === 'string') content = [[module.i, content, '']];
	if(content.locals) module.exports = content.locals;
	// add the styles to the DOM
	var update = __webpack_require__(5)("d89557e4", content, true);

	/***/ }),
	/* 3 */
	/***/ (function(module, exports, __webpack_require__) {

	exports = module.exports = __webpack_require__(4)();
	// imports


	// module
	exports.push([module.i, ".vue-simple-spinner{transition:all .3s linear}@keyframes vue-simple-spinner-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}", ""]);

	// exports


	/***/ }),
	/* 4 */
	/***/ (function(module, exports) {

	/*
		MIT License http://www.opensource.org/licenses/mit-license.php
		Author Tobias Koppers @sokra
	*/
	// css base code, injected by the css-loader
	module.exports = function() {
		var list = [];

		// return the list of modules as css string
		list.toString = function toString() {
			var result = [];
			for(var i = 0; i < this.length; i++) {
				var item = this[i];
				if(item[2]) {
					result.push("@media " + item[2] + "{" + item[1] + "}");
				} else {
					result.push(item[1]);
				}
			}
			return result.join("");
		};

		// import a list of modules into the list
		list.i = function(modules, mediaQuery) {
			if(typeof modules === "string")
				modules = [[null, modules, ""]];
			var alreadyImportedModules = {};
			for(var i = 0; i < this.length; i++) {
				var id = this[i][0];
				if(typeof id === "number")
					alreadyImportedModules[id] = true;
			}
			for(i = 0; i < modules.length; i++) {
				var item = modules[i];
				// skip already imported module
				// this implementation is not 100% perfect for weird media query combinations
				//  when a module is imported multiple times with different media queries.
				//  I hope this will never occur (Hey this way we have smaller bundles)
				if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
					if(mediaQuery && !item[2]) {
						item[2] = mediaQuery;
					} else if(mediaQuery) {
						item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
					}
					list.push(item);
				}
			}
		};
		return list;
	};


	/***/ }),
	/* 5 */
	/***/ (function(module, exports, __webpack_require__) {

	/*
	  MIT License http://www.opensource.org/licenses/mit-license.php
	  Author Tobias Koppers @sokra
	  Modified by Evan You @yyx990803
	*/

	var hasDocument = typeof document !== 'undefined';

	if (typeof DEBUG !== 'undefined' && DEBUG) {
	  if (!hasDocument) {
	    throw new Error(
	    'vue-style-loader cannot be used in a non-browser environment. ' +
	    "Use { target: 'node' } in your Webpack config to indicate a server-rendering environment."
	  ) }
	}

	var listToStyles = __webpack_require__(6);

	/*
	type StyleObject = {
	  id: number;
	  parts: Array<StyleObjectPart>
	}

	type StyleObjectPart = {
	  css: string;
	  media: string;
	  sourceMap: ?string
	}
	*/

	var stylesInDom = {/*
	  [id: number]: {
	    id: number,
	    refs: number,
	    parts: Array<(obj?: StyleObjectPart) => void>
	  }
	*/};

	var head = hasDocument && (document.head || document.getElementsByTagName('head')[0]);
	var singletonElement = null;
	var singletonCounter = 0;
	var isProduction = false;
	var noop = function () {};

	// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
	// tags it will allow on a page
	var isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\b/.test(navigator.userAgent.toLowerCase());

	module.exports = function (parentId, list, _isProduction) {
	  isProduction = _isProduction;

	  var styles = listToStyles(parentId, list);
	  addStylesToDom(styles);

	  return function update (newList) {
	    var mayRemove = [];
	    for (var i = 0; i < styles.length; i++) {
	      var item = styles[i];
	      var domStyle = stylesInDom[item.id];
	      domStyle.refs--;
	      mayRemove.push(domStyle);
	    }
	    if (newList) {
	      styles = listToStyles(parentId, newList);
	      addStylesToDom(styles);
	    } else {
	      styles = [];
	    }
	    for (var i = 0; i < mayRemove.length; i++) {
	      var domStyle = mayRemove[i];
	      if (domStyle.refs === 0) {
	        for (var j = 0; j < domStyle.parts.length; j++) {
	          domStyle.parts[j]();
	        }
	        delete stylesInDom[domStyle.id];
	      }
	    }
	  }
	};

	function addStylesToDom (styles /* Array<StyleObject> */) {
	  for (var i = 0; i < styles.length; i++) {
	    var item = styles[i];
	    var domStyle = stylesInDom[item.id];
	    if (domStyle) {
	      domStyle.refs++;
	      for (var j = 0; j < domStyle.parts.length; j++) {
	        domStyle.parts[j](item.parts[j]);
	      }
	      for (; j < item.parts.length; j++) {
	        domStyle.parts.push(addStyle(item.parts[j]));
	      }
	      if (domStyle.parts.length > item.parts.length) {
	        domStyle.parts.length = item.parts.length;
	      }
	    } else {
	      var parts = [];
	      for (var j = 0; j < item.parts.length; j++) {
	        parts.push(addStyle(item.parts[j]));
	      }
	      stylesInDom[item.id] = { id: item.id, refs: 1, parts: parts };
	    }
	  }
	}

	function createStyleElement () {
	  var styleElement = document.createElement('style');
	  styleElement.type = 'text/css';
	  head.appendChild(styleElement);
	  return styleElement
	}

	function addStyle (obj /* StyleObjectPart */) {
	  var update, remove;
	  var styleElement = document.querySelector('style[data-vue-ssr-id~="' + obj.id + '"]');

	  if (styleElement) {
	    if (isProduction) {
	      // has SSR styles and in production mode.
	      // simply do nothing.
	      return noop
	    } else {
	      // has SSR styles but in dev mode.
	      // for some reason Chrome can't handle source map in server-rendered
	      // style tags - source maps in <style> only works if the style tag is
	      // created and inserted dynamically. So we remove the server rendered
	      // styles and inject new ones.
	      styleElement.parentNode.removeChild(styleElement);
	    }
	  }

	  if (isOldIE) {
	    // use singleton mode for IE9.
	    var styleIndex = singletonCounter++;
	    styleElement = singletonElement || (singletonElement = createStyleElement());
	    update = applyToSingletonTag.bind(null, styleElement, styleIndex, false);
	    remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);
	  } else {
	    // use multi-style-tag mode in all other cases
	    styleElement = createStyleElement();
	    update = applyToTag.bind(null, styleElement);
	    remove = function () {
	      styleElement.parentNode.removeChild(styleElement);
	    };
	  }

	  update(obj);

	  return function updateStyle (newObj /* StyleObjectPart */) {
	    if (newObj) {
	      if (newObj.css === obj.css &&
	          newObj.media === obj.media &&
	          newObj.sourceMap === obj.sourceMap) {
	        return
	      }
	      update(obj = newObj);
	    } else {
	      remove();
	    }
	  }
	}

	var replaceText = (function () {
	  var textStore = [];

	  return function (index, replacement) {
	    textStore[index] = replacement;
	    return textStore.filter(Boolean).join('\n')
	  }
	})();

	function applyToSingletonTag (styleElement, index, remove, obj) {
	  var css = remove ? '' : obj.css;

	  if (styleElement.styleSheet) {
	    styleElement.styleSheet.cssText = replaceText(index, css);
	  } else {
	    var cssNode = document.createTextNode(css);
	    var childNodes = styleElement.childNodes;
	    if (childNodes[index]) styleElement.removeChild(childNodes[index]);
	    if (childNodes.length) {
	      styleElement.insertBefore(cssNode, childNodes[index]);
	    } else {
	      styleElement.appendChild(cssNode);
	    }
	  }
	}

	function applyToTag (styleElement, obj) {
	  var css = obj.css;
	  var media = obj.media;
	  var sourceMap = obj.sourceMap;

	  if (media) {
	    styleElement.setAttribute('media', media);
	  }

	  if (sourceMap) {
	    // https://developer.chrome.com/devtools/docs/javascript-debugging
	    // this makes source maps inside style tags work properly in Chrome
	    css += '\n/*# sourceURL=' + sourceMap.sources[0] + ' */';
	    // http://stackoverflow.com/a/26603875
	    css += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + ' */';
	  }

	  if (styleElement.styleSheet) {
	    styleElement.styleSheet.cssText = css;
	  } else {
	    while (styleElement.firstChild) {
	      styleElement.removeChild(styleElement.firstChild);
	    }
	    styleElement.appendChild(document.createTextNode(css));
	  }
	}


	/***/ }),
	/* 6 */
	/***/ (function(module, exports) {

	/**
	 * Translates the list format produced by css-loader into something
	 * easier to manipulate.
	 */
	module.exports = function listToStyles (parentId, list) {
	  var styles = [];
	  var newStyles = {};
	  for (var i = 0; i < list.length; i++) {
	    var item = list[i];
	    var id = item[0];
	    var css = item[1];
	    var media = item[2];
	    var sourceMap = item[3];
	    var part = {
	      id: parentId + ':' + i,
	      css: css,
	      media: media,
	      sourceMap: sourceMap
	    };
	    if (!newStyles[id]) {
	      styles.push(newStyles[id] = { id: id, parts: [part] });
	    } else {
	      newStyles[id].parts.push(part);
	    }
	  }
	  return styles
	};


	/***/ }),
	/* 7 */
	/***/ (function(module, exports) {

	// this module is a runtime utility for cleaner component module output and will
	// be included in the final webpack user bundle

	module.exports = function normalizeComponent (
	  rawScriptExports,
	  compiledTemplate,
	  scopeId,
	  cssModules
	) {
	  var esModule;
	  var scriptExports = rawScriptExports = rawScriptExports || {};

	  // ES6 modules interop
	  var type = typeof rawScriptExports.default;
	  if (type === 'object' || type === 'function') {
	    esModule = rawScriptExports;
	    scriptExports = rawScriptExports.default;
	  }

	  // Vue.extend constructor export interop
	  var options = typeof scriptExports === 'function'
	    ? scriptExports.options
	    : scriptExports;

	  // render functions
	  if (compiledTemplate) {
	    options.render = compiledTemplate.render;
	    options.staticRenderFns = compiledTemplate.staticRenderFns;
	  }

	  // scopedId
	  if (scopeId) {
	    options._scopeId = scopeId;
	  }

	  // inject cssModules
	  if (cssModules) {
	    var computed = Object.create(options.computed || null);
	    Object.keys(cssModules).forEach(function (key) {
	      var module = cssModules[key];
	      computed[key] = function () { return module };
	    });
	    options.computed = computed;
	  }

	  return {
	    esModule: esModule,
	    exports: scriptExports,
	    options: options
	  }
	};


	/***/ }),
	/* 8 */
	/***/ (function(module, exports, __webpack_require__) {


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


	var isNumber = function isNumber(n) {
	  return !isNaN(parseFloat(n)) && isFinite(n);
	};

	exports.default = {
	  name: 'vue-simple-spinner',
	  props: {
	    'size': {
	      default: 32
	    },
	    'line-size': {
	      type: Number,
	      default: 3
	    },
	    'line-bg-color': {
	      type: String,
	      default: '#eee'
	    },
	    'line-fg-color': {
	      type: String,
	      default: '#2196f3' },
	    'speed': {
	      type: Number,
	      default: 0.8
	    },
	    'spacing': {
	      type: Number,
	      default: 4
	    },
	    'message': {
	      type: String,
	      default: ''
	    },
	    'font-size': {
	      type: Number,
	      default: 13
	    },
	    'text-fg-color': {
	      type: String,
	      default: '#555'
	    }
	  },
	  computed: {
	    size_px: function size_px() {
	      switch (this.size) {
	        case 'tiny':
	          return 12;
	        case 'small':
	          return 16;
	        case 'medium':
	          return 32;
	        case 'large':
	          return 48;
	        case 'big':
	          return 64;
	        case 'huge':
	          return 96;
	        case 'massive':
	          return 128;
	      }

	      return isNumber(this.size) ? this.size : 32;
	    },
	    line_size_px: function line_size_px() {
	      switch (this.size) {
	        case 'tiny':
	          return 1;
	        case 'small':
	          return 2;
	        case 'medium':
	          return 3;
	        case 'large':
	          return 3;
	        case 'big':
	          return 4;
	        case 'huge':
	          return 4;
	        case 'massive':
	          return 5;
	      }

	      return isNumber(this.lineSize) ? this.lineSize : 4;
	    },
	    text_margin_top: function text_margin_top() {
	      switch (this.size) {
	        case 'tiny':
	        case 'small':
	        case 'medium':
	        case 'large':
	        case 'big':
	        case 'huge':
	        case 'massive':
	          return Math.min(Math.max(Math.ceil(this.size_px / 8), 3), 12);
	      }

	      return isNumber(this.spacing) ? this.spacing : 4;
	    },
	    text_font_size: function text_font_size() {
	      switch (this.size) {
	        case 'tiny':
	        case 'small':
	        case 'medium':
	        case 'large':
	        case 'big':
	        case 'huge':
	        case 'massive':
	          return Math.min(Math.max(Math.ceil(this.size_px * 0.4), 11), 32);
	      }

	      return isNumber(this.fontSize) ? this.fontSize : 13;
	    },
	    spinner_style: function spinner_style() {
	      return {
	        'margin': '0 auto',
	        'border-radius': '100%',
	        'border': this.line_size_px + 'px solid ' + this.lineBgColor,
	        'border-top': this.line_size_px + 'px solid ' + this.lineFgColor,
	        'width': this.size_px + 'px',
	        'height': this.size_px + 'px',
	        'animation': 'vue-simple-spinner-spin ' + this.speed + 's linear infinite'
	      };
	    },
	    text_style: function text_style() {
	      return {
	        'margin-top': this.text_margin_top + 'px',
	        'color': this.textFgColor,
	        'font-size': this.text_font_size + 'px',
	        'text-align': 'center'
	      };
	    }
	  }
	};

	/***/ }),
	/* 9 */
	/***/ (function(module, exports) {

	module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
	  return _c('div', [_c('div', {
	    staticClass: "vue-simple-spinner",
	    style: (_vm.spinner_style)
	  }), _vm._v(" "), (_vm.message.length > 0) ? _c('div', {
	    staticClass: "vue-simple-spinner-text",
	    style: (_vm.text_style)
	  }, [_vm._v(_vm._s(_vm.message))]) : _vm._e()])
	},staticRenderFns: []};

	/***/ })
	/******/ ])["default"];
	});
	});

	var Spinner = unwrapExports(vueSimpleSpinner);

	var download = createCommonjsModule(function (module, exports) {
	//download.js v4.2, by dandavis; 2008-2016. [MIT] see http://danml.com/download.html for tests/usage
	// v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
	// v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs
	// v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support. 3.1 improved safari handling.
	// v4 adds AMD/UMD, commonJS, and plain browser support
	// v4.1 adds url download capability via solo URL argument (same domain/CORS only)
	// v4.2 adds semantic variable names, long (over 2MB) dataURL support, and hidden by default temp anchors
	// https://github.com/rndme/download

	(function (root, factory) {
		{
			// Node. Does not work with strict CommonJS, but
			// only CommonJS-like environments that support module.exports,
			// like Node.
			module.exports = factory();
		}
	}(commonjsGlobal, function () {

		return function download(data, strFileName, strMimeType) {

			var self = window, // this script is only for browsers anyway...
				defaultMime = "application/octet-stream", // this default mime also triggers iframe downloads
				mimeType = strMimeType || defaultMime,
				payload = data,
				url = !strFileName && !strMimeType && payload,
				anchor = document.createElement("a"),
				toString = function(a){return String(a);},
				myBlob = (self.Blob || self.MozBlob || self.WebKitBlob || toString),
				fileName = strFileName || "download",
				blob,
				reader;
				myBlob= myBlob.call ? myBlob.bind(self) : Blob ;
		  
			if(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback
				payload=[payload, mimeType];
				mimeType=payload[0];
				payload=payload[1];
			}


			if(url && url.length< 2048){ // if no filename and no mime, assume a url was passed as the only argument
				fileName = url.split("/").pop().split("?")[0];
				anchor.href = url; // assign href prop to temp anchor
			  	if(anchor.href.indexOf(url) !== -1){ // if the browser determines that it's a potentially valid url path:
	        		var ajax=new XMLHttpRequest();
	        		ajax.open( "GET", url, true);
	        		ajax.responseType = 'blob';
	        		ajax.onload= function(e){ 
					  download(e.target.response, fileName, defaultMime);
					};
	        		setTimeout(function(){ ajax.send();}, 0); // allows setting custom ajax headers using the return:
				    return ajax;
				} // end if valid url?
			} // end if url?


			//go ahead and download dataURLs right away
			if(/^data:([\w+-]+\/[\w+.-]+)?[,;]/.test(payload)){
			
				if(payload.length > (1024*1024*1.999) && myBlob !== toString ){
					payload=dataUrlToBlob(payload);
					mimeType=payload.type || defaultMime;
				}else {			
					return navigator.msSaveBlob ?  // IE10 can't do a[download], only Blobs:
						navigator.msSaveBlob(dataUrlToBlob(payload), fileName) :
						saver(payload) ; // everyone else can save dataURLs un-processed
				}
				
			}else {//not data url, is it a string with special needs?
				if(/([\x80-\xff])/.test(payload)){			  
					var i=0, tempUiArr= new Uint8Array(payload.length), mx=tempUiArr.length;
					for(i;i<mx;++i) tempUiArr[i]= payload.charCodeAt(i);
				 	payload=new myBlob([tempUiArr], {type: mimeType});
				}		  
			}
			blob = payload instanceof myBlob ?
				payload :
				new myBlob([payload], {type: mimeType}) ;


			function dataUrlToBlob(strUrl) {
				var parts= strUrl.split(/[:;,]/),
				type= parts[1],
				decoder= parts[2] == "base64" ? atob : decodeURIComponent,
				binData= decoder( parts.pop() ),
				mx= binData.length,
				i= 0,
				uiArr= new Uint8Array(mx);

				for(i;i<mx;++i) uiArr[i]= binData.charCodeAt(i);

				return new myBlob([uiArr], {type: type});
			 }

			function saver(url, winMode){

				if ('download' in anchor) { //html5 A[download]
					anchor.href = url;
					anchor.setAttribute("download", fileName);
					anchor.className = "download-js-link";
					anchor.innerHTML = "downloading...";
					anchor.style.display = "none";
					document.body.appendChild(anchor);
					setTimeout(function() {
						anchor.click();
						document.body.removeChild(anchor);
						if(winMode===true){setTimeout(function(){ self.URL.revokeObjectURL(anchor.href);}, 250 );}
					}, 66);
					return true;
				}

				// handle non-a[download] safari as best we can:
				if(/(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test(navigator.userAgent)) {
					if(/^data:/.test(url))	url="data:"+url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
					if(!window.open(url)){ // popup blocked, offer direct download:
						if(confirm("Displaying New Document\n\nUse Save As... to download, then click back to return to this page.")){ location.href=url; }
					}
					return true;
				}

				//do iframe dataURL download (old ch+FF):
				var f = document.createElement("iframe");
				document.body.appendChild(f);

				if(!winMode && /^data:/.test(url)){ // force a mime that will download:
					url="data:"+url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
				}
				f.src=url;
				setTimeout(function(){ document.body.removeChild(f); }, 333);

			}//end saver




			if (navigator.msSaveBlob) { // IE10+ : (has Blob, but not a[download] or URL)
				return navigator.msSaveBlob(blob, fileName);
			}

			if(self.URL){ // simple fast and modern way using Blob and URL:
				saver(self.URL.createObjectURL(blob), true);
			}else {
				// handle non-Blob()+non-URL browsers:
				if(typeof blob === "string" || blob.constructor===toString ){
					try{
						return saver( "data:" +  mimeType   + ";base64,"  +  self.btoa(blob)  );
					}catch(y){
						return saver( "data:" +  mimeType   + "," + encodeURIComponent(blob)  );
					}
				}

				// Blob but not URL support:
				reader=new FileReader();
				reader.onload=function(e){
					saver(this.result);
				};
				reader.readAsDataURL(blob);
			}
			return true;
		}; /* end download() */
	}));
	});

	//

	var script$b = {
	  props: {
	    // mime type [xls, csv]
	    type: {
	      type: String,
	      default: "xls"
	    },
	    // Json to download
	    data: {
	      type: Array,
	      required: false,
	      default: null
	    },
	    // fields inside the Json Object that you want to export
	    // if no given, all the properties in the Json are exported
	    fields: {
	      type: Object,
	      required: false
	    },
	    // this prop is used to fix the problem with other components that use the
	    // variable fields, like vee-validate. exportFields works exactly like fields
	    exportFields: {
	      type: Object,
	      required: false
	    },
	    // Use as fallback when the row has no field values
	    defaultValue: {
	      type: String,
	      required: false,
	      default: ""
	    },
	    // Title(s) for the data, could be a string or an array of strings (multiple titles)
	    title: {
	      default: null
	    },
	    // Footer(s) for the data, could be a string or an array of strings (multiple footers)
	    footer: {
	      default: null
	    },
	    // filename to export
	    name: {
	      type: String,
	      default: "data.xls"
	    },
	    fetch: {
	      type: Function,
	    },
	    meta: {
	      type: Array,
	      default: () => []
	    }, 
	    worksheet: {
	      type: String, 
	      default: "Sheet1"
	    },
	    //event before generate was called
	    beforeGenerate:{
	      type: Function,
	    },
	    //event before download pops up
	    beforeFinish:{
	      type: Function,
	    },
	  },
	  computed: {
	    // unique identifier
	    idName() {
	      var now = new Date().getTime();
	      return "export_" + now;
	    },

	    downloadFields() {
	      if (this.fields !== undefined) return this.fields;

	      if (this.exportFields !== undefined) return this.exportFields;
	    }
	  },
	  methods: {
	    async generate() {
	      if(typeof this.beforeGenerate === 'function'){
	        await this.beforeGenerate();
	      }
	      let data = this.data;
	      if(typeof this.fetch === 'function' || !data)
	         data = await this.fetch();

	      if (!data || !data.length) {
	        return;
	      }

	      let json = this.getProcessedJson(data, this.downloadFields);
	      if (this.type === "html") {
	        // this is mainly for testing
	        return this.export(
	          this.jsonToXLS(json),
	          this.name.replace(".xls", ".html"),
	          "text/html"
	        );
	      } else if (this.type === "csv") {
	        return this.export(
	          this.jsonToCSV(json),
	          this.name.replace(".xls", ".csv"),
	          "application/csv"
	        );
	      }
	      return this.export(
	        this.jsonToXLS(json),
	        this.name,
	        "application/vnd.ms-excel"
	      );
	    },
	    /*
			Use downloadjs to generate the download link
			*/
	    export:async function(data, filename, mime) {
	      let blob = this.base64ToBlob(data, mime);
	      if(typeof this.beforeFinish === 'function')
	        await this.beforeFinish();
	      download(blob, filename, mime);
	    },
	    /*
			jsonToXLS
			---------------
			Transform json data into an xml document with MS Excel format, sadly
			it shows a prompt when it opens, that is a default behavior for
			Microsoft office and cannot be avoided. It's recommended to use CSV format instead.
			*/
	    jsonToXLS(data) {
	      let xlsTemp =
	        '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>${worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--><style>br {mso-data-placement: same-cell;}</style></head><body><table>${table}</table></body></html>';
	      let xlsData = "<thead>";
	      const colspan = Object.keys(data[0]).length;
	      let _self = this;

	      //Header
	      if (this.title != null) {
	        xlsData += this.parseExtraData(
	          this.title,
	          '<tr><th colspan="' + colspan + '">${data}</th></tr>'
	        );
	      }

	      //Fields
	      xlsData += "<tr>";
	      for (let key in data[0]) {
	        xlsData += "<th>" + key + "</th>";
	      }
	      xlsData += "</tr>";
	      xlsData += "</thead>";

	      //Data
	      xlsData += "<tbody>";
	      data.map(function(item, index) {
	        xlsData += "<tr>";
	        for (let key in item) {
	          xlsData += "<td>" + _self.valueReformattedForMultilines(item[key]) + "</td>";
	        }
	        xlsData += "</tr>";
	      });
	      xlsData += "</tbody>";

	      //Footer
	      if (this.footer != null) {
	        xlsData += "<tfoot>";
	        xlsData += this.parseExtraData(
	          this.footer,
	          '<tr><td colspan="' + colspan + '">${data}</td></tr>'
	        );
	        xlsData += "</tfoot>";
	      }

	      return xlsTemp.replace("${table}", xlsData).replace("${worksheet}", this.worksheet);
	    },
	    /*
			jsonToCSV
			---------------
			Transform json data into an CSV file.
			*/
	    jsonToCSV(data) {
	      var csvData = [];
	      //Header
	      if (this.title != null) {
	        csvData.push(this.parseExtraData(this.title, "${data}\r\n"));
	      }
	      //Fields
	      for (let key in data[0]) {
	        csvData.push(key);
	        csvData.push(",");
	      }
	      csvData.pop();
	      csvData.push("\r\n");
	      //Data
	      data.map(function(item) {
	        for (let key in item) {
	          let escapedCSV = '=\"' + item[key] + '\"'; // cast Numbers to string
	          if (escapedCSV.match(/[,"\n]/)) {
	            escapedCSV = '"' + escapedCSV.replace(/\"/g, '""') + '"';
	          }
	          csvData.push(escapedCSV);
	          csvData.push(",");
	        }
	        csvData.pop();
	        csvData.push("\r\n");
	      });
	      //Footer
	      if (this.footer != null) {
	        csvData.push(this.parseExtraData(this.footer, "${data}\r\n"));
	      }
	      return csvData.join("");
	    },
	    /*
			getProcessedJson
			---------------
			Get only the data to export, if no fields are set return all the data
			*/
	    getProcessedJson(data, header) {
	      let keys = this.getKeys(data, header);
	      let newData = [];
	      let _self = this;
	      data.map(function(item, index) {
	        let newItem = {};
	        for (let label in keys) {
	          let property = keys[label];
	          newItem[label] = _self.getValue(property, item);
	        }
	        newData.push(newItem);
	      });

	      return newData;
	    },
	    getKeys(data, header) {
	      if (header) {
	        return header;
	      }

	      let keys = {};
	      for (let key in data[0]) {
	        keys[key] = key;
	      }
	      return keys;
	    },
	    /*
			parseExtraData
			---------------
			Parse title and footer attribute to the csv format
			*/
	    parseExtraData(extraData, format) {
	      let parseData = "";
	      if (Array.isArray(extraData)) {
	        for (var i = 0; i < extraData.length; i++) {
	          parseData += format.replace("${data}", extraData[i]);
	        }
	      } else {
	        parseData += format.replace("${data}", extraData);
	      }
	      return parseData;
	    },

	    getValue(key, item) {
	      const field = typeof key   !== "object" ? key : key.field;
	      let indexes = typeof field !== "string" ? []  : field.split(".");
	      let value   = this.defaultValue;
	    
	      if (!field)
		      value = item;
	      else if( indexes.length > 1 )
	        value = this.getValueFromNestedItem(item, indexes);
	      else
	        value = this.parseValue(item[field]);
	      
	      if( key.hasOwnProperty('callback'))
	        value = this.getValueFromCallback(value, key.callback);
	      
	      return value;
	    },

	    /*
	    convert values with newline \n characters into <br/>
	    */
	    valueReformattedForMultilines(value) {
	      if (typeof(value)=="string") return(value.replace(/\n/ig,"<br/>"));
	      else return(value);
	    },

	    getValueFromNestedItem(item, indexes){
	      let nestedItem = item;
	      for (let index of indexes) {
	        if(nestedItem)
	          nestedItem = nestedItem[index];
	      }
	      return this.parseValue(nestedItem);
	    },

	    getValueFromCallback(item, callback){
	      if(typeof callback !== "function")
	        return this.defaultValue
	      const value = callback(item);
	      return this.parseValue(value);
	    },
	    parseValue(value){
	      return value || value === 0 || typeof value === 'boolean'
	          ? value
	          : this.defaultValue;
	    },
	    base64ToBlob(data, mime) {
	      let base64 = window.btoa(window.unescape(encodeURIComponent(data)));
	      let bstr = atob(base64);
	      let n = bstr.length;
	      let u8arr = new Uint8ClampedArray(n);
	      while (n--) {
	        u8arr[n] = bstr.charCodeAt(n);
	      }
	      return new Blob([u8arr], { type: mime });
	    }
	  } // end methods
	};

	/* script */
	const __vue_script__$b = script$b;

	/* template */
	var __vue_render__$b = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{attrs:{"id":_vm.idName},on:{"click":_vm.generate}},[_vm._t("default",[_vm._v("\n\t\tDownload "+_vm._s(_vm.name)+"\n\t")])],2)};
	var __vue_staticRenderFns__$b = [];

	  /* style */
	  const __vue_inject_styles__$b = undefined;
	  /* scoped */
	  const __vue_scope_id__$b = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$b = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$b = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$b = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$b, staticRenderFns: __vue_staticRenderFns__$b },
	    __vue_inject_styles__$b,
	    __vue_script__$b,
	    __vue_scope_id__$b,
	    __vue_is_functional_template__$b,
	    __vue_module_identifier__$b,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	//

	var script$c = {
		name: 'SearchwpMetrics',
		components: {
			Multiselect,
			VueDatepickerLocal: __vue_component__$1,
			LineChart: __vue_component__$3,
			Tooltip: __vue_component__$2,
			DoughnutChart: __vue_component__$5,
			BarChart: __vue_component__$6,
			Delete: __vue_component__$4,
			LegendIndicator: __vue_component__$7,
			InsightAnalysis: __vue_component__$8,
			InsightPopular: __vue_component__$9,
			InsightUnderdog: __vue_component__$a,
			Spinner,
			JsonCsv: __vue_component__$b
		},
		methods: {
			addNewIgnoredSearch: function() {
				let newIgnoredSearch = prompt('Enter search to ignore');

				newIgnoredSearch = newIgnoredSearch.trim();

				if(newIgnoredSearch){
					this.showingIgnoredSearches = false;
					this.ignoreSearch(newIgnoredSearch,true);
				}
			},
			clearMetricsData: function() {
				let self = this;
				let payload = {
					action: 'searchwp_metrics_clear_metrics_data',
				};

				// We want the loading state to be triggered right away
				this.loading = true;
				this.hideClearMetricsData();

				// Request the deletion and then update when it's done
				self.apiRequest(payload).then((response) => {
					this.update();
				});
			},
			hideClearMetricsData: function(){
				this.showingClearMetricsData = false;
			},
			clearIgnoredQueries: function() {
				let self = this;
				let payload = {
					action: 'searchwp_metrics_clear_ignored_queries',
				};

				// We want the loading state to be triggered right away
				this.loading = true;
				this.hideClearIgnoredQueries();

				// Request the deletion and then update when it's done
				self.apiRequest(payload).then((response) => {
					this.update();
				});
			},
			hideClearIgnoredQueries: function() {
				this.showingClearIgnoredQueries = false;
			},
			hideModifyLoggingRules: function() {
				this.showingModifyLoggingRules = false;

				let self = this;
				let payload = {
					action: 'searchwp_metrics_update_logging_rules',
					ips: this.ignoredIps,
					roles: this.ignoredRoles
				};

				self.apiRequest(payload).then((response) => {});
			},
			hideSettings: function() {
				this.showingSettings = false;

				let self = this;
				let payload = {
					action: 'searchwp_metrics_update_settings',
					clear_data_on_uninstall: this.clearDataOnUninstall,
					click_tracking_buoy: this.clickTrackingBuoy
				};

				self.apiRequest(payload).then((response) => {});
			},
			formattedPopularSearchesForCsv: function(engineIndex){
				if (!this.popularSearches || !this.popularSearches[ engineIndex ]) {
					return [];
				}
				let data = this.popularSearches[ engineIndex ].datasets[0].data;
				let labels = this.popularSearches[ engineIndex ].labels;

				let formatted = [];

				for (let i = 0; i < labels.length; i++) {
					// The output will be nested in a query object so as to utilize the existing Popular Search Details format
					formatted.push({
						query: {
							query: labels[i],
							searchcount: data[i],
						}
					});
				}

				return formatted;
			},
			formattedSearchesOverTimeForCsv: function(engineIndex){
				if (!this.searchesOverTime || !this.searchesOverTime.datasets[ engineIndex ]) {
					return [];
				}
				let data = this.searchesOverTime.datasets[ engineIndex ].data;
				let labels = this.searchesOverTime.labels;

				let formatted = [];

				for (let i = 0; i < labels.length; i++) {
					formatted.push({
						label: labels[i],
						searches: data[i],
					});
				}

				return formatted;
			},
			formattedEngineStatisticForCsv: function(engineIndex, engine = 'default') {
				return [
					{ statistic: 'Total Searches', value: this.getTotalSearchesCount( engineIndex ) },
					{ statistic: 'No Results Searches', value: this.getFailedSearchesCount( engineIndex ) },
					{ statistic: 'Total Results Viewed', value: this.outputMetric( this.totalClicks[ engine.name ].statistic ) },
					{ statistic: 'Searches Per User', value: this.outputMetric( this.averageSearchesPerUser[ engine.name ].statistic ) },
					{ statistic: 'Clicks Per Search', value: this.outputMetric( this.averageClicksPerSearch[ engine.name ].statistic ) },
					{ statistic: 'Average Click Rank', value: this.outputMetric( this.averageClickRank[ engine.name ].statistic ) }
				];
			},
			appendTimestamp: function(string = 'export'){
				return string + '_' + this.formatDate(this.dateRange[0]) + '_' + this.formatDate(this.dateRange[1]);
			},
			// TODO: the params here are terrible
			showPopularSearchDetails: function(engine = 'default', query = ''){
				this.showingPopularSearchDetails = { engine: engine, query: query };
				this.updatePopularSearchDetails(engine.name);
			},
			// TODO: the params here are terrible
			showInsightDetails: function(engine = 'default', insightIndex = -1){
				this.showingInsights = { engine: engine, insightIndex: insightIndex };
			},
			buildChartDataset: function(data, total = 0){
				let labels = ['Clicks'];
				let datasets = [];

				// This is kind of wacky because it's being used for Popular Searches and Insights and the data
				// structure is a bit different; Analysis Insights already know the total number of clicks
				// so in those cases that param is populated, otherwise this figures it out
				let totalClicks = total === 0 ? lib(data,'clicks').reduce((a, b) => a + b, 0) : total;

				for (let i = 0; i < data.length; i++) {
					let value = (( data[i].clicks * 100 ) / totalClicks).toFixed(2);
					datasets.push({
						type: 'horizontalBar',
						backgroundColor: Vue$1.SearchwpMetricsGetColor(i),
						label: data[i].post_title,
						data: [ value ]
					});
				}

				return {
					labels: labels,
					datasets: datasets
				}
			},
			updatePopularSearchDetails: function(engine) {
				let self = this;
				self.loadingPopularSearchDetails = true;

				let payload = {
					action: 'searchwp_metrics_popular_search_details',
					engine: engine,
					limit: this.popularSearchesCount,
				};

				self.apiRequest(payload).then((response) => {
					// We need to 'reset' the rules of any inline ignores
					if (this.inlineIgnores.length) {
						this.inlineIgnores.forEach(function(index){
							document.getElementById('searchwp-metrics--hook-popular-' + index).removeAttribute('style');
						});

						// Empty out the array
						this.inlineIgnores = [];
					}

					self.popularSearchesDetails = response.data;
					self.loadingPopularSearchDetails = false;
				});
			},
			unIgnoreQuery: function(hash) {
				// Remove from display (we're not refreshing until modal is closed)
				let newIgnoredQueries = this.ignoredQueries;
				for (let i = 0; i < this.ignoredQueries.length; i++) {
					if (hash === this.ignoredQueries[i].hash) {
						Vue$1.set(this.ignoredQueries[i], 'unignored', true);
						break;
					}
				}

				this.unIgnoreSearch(hash, false);
				this.needsRefresh = true;
			},
			unIgnoreSearch: function(hash, refresh = true) {
				let self = this;
				let payload = {
					action: 'searchwp_metrics_unignore_query',
					hash: hash
				};
				self.apiRequest(payload).then((response) => {
					if (refresh) {
						self.update();
					}
				});
			},
			hideInsights: function(){
				this.showingInsights = false;
			},
			searchSearchQueries: debounce$1(function(query) {
				let self = this;

				if (query.length<3) {
					return;
				}

				self.isLoadingSearchSearches = true;

				let payload = {
					action: 'searchwp_metrics_search_queries',
					searchquery: query
				};
				self.apiRequest(payload).then((response) => {
					self.searchQueries = response.data;
					self.isLoadingSearchSearches = false;
				});
			}, 500),
			addSelectedSearchQuery: function(query){
				// In this case we've added a partial match so we're going to use the query as the ID
				// and the server will consider it for a partial match
				let tag = {
					id: query,
					query: query
				};

				this.searchQueries.push(tag);
				this.selectedSearchQueries.push(tag);
				this.update();
			},
			limit: function(data, limit = 10) {
				// As it stands this causes a Vue Warning about a potential infinite render loop, but
				// I'm not sure why yet, so we're going to hide the data with CSS while other tests are run
				let limited;

				// Is it an object?
				if (data.length === undefined) {
					limited = {};
					for (let property in data) {
						if (data.hasOwnProperty(property)) {
							limited[property] = data[property];

							if (Object.keys(limited).length >= limit) {
								break;
							}
						}
					}
				} else {
					limited = data.splice(0,limit);
				}

				return limited;
			},
			engineHasNoTracking: function(engine) {
				return this.outputMetric( this.totalClicks[ engine ].statistic ) === '--' || this.outputMetric( this.averageClicksPerSearch[ engine ].statistic ) === '--' || this.outputMetric( this.averageClickRank[ engine ].statistic ) === '--';
			},
			outputMetric: function(n) {
				if ('0' === n.toString() || '0.000' === n.toString()) {
					return '--';
				} else {
					return n;
				}
			},
			hidePopularSearchDetails: function() {
				this.showingPopularSearchDetails = false;

				// We only need to update stats on close if new ignored searches were added
				if (this.needsRefresh) {
					this.update();
					this.needsRefresh = false;
				}
			},
			hideFailedSearches: function() {
				this.showingFailedSearches = false;

				// We need to 'reset' the rules of any inline ignores
				if (this.inlineIgnores.length) {
					let self = this;
					// Persist the ignore in the data model
					self.inlineIgnores.forEach(function(ignore){
						for (let i = 0; i < self.failedSearches.length; i++) {
							if (self.failedSearches[i].engine === ignore.engine) {
								for (let y = 0; y < self.failedSearches[i].data.length; y++) {
									if (ignore.ignoredSearch === self.failedSearches[i].data[y].query) {
										Vue$1.delete(self.failedSearches[i].data, y);
										break;
									}
								}
								break;
							}
						}
					});

					// Remove the inline style in case of reload
					this.inlineIgnores.forEach(function(ignore){
						document.getElementById('searchwp-metrics--hook-failed-' + ignore.index).removeAttribute('style');
					});

					// Empty out the array
					this.inlineIgnores = [];
				}

				// We only need to update stats on close if new ignored searches were added
				if (this.needsRefresh) {
					this.update();
					this.needsRefresh = false;
				}
			},
			hideIgnoredSearches: function() {
				this.showingIgnoredSearches = false;

				// We only need to update stats on close if ignored searches were removed
				if (this.needsRefresh) {
					this.update();
					this.needsRefresh = false;
				}
			},
			getTotalSearchesCount: function( engineIndex ) {
				if (!this.searchesOverTime || !this.searchesOverTime.datasets[ engineIndex ]) {
					return 0;
				}
				let data = this.searchesOverTime.datasets[ engineIndex ].data;
				return data.reduce((a, b) => a + b, 0);
			},
			getFailedSearchesCount: function( engineIndex ) {
				if (!this.failedSearches || !this.failedSearches[ engineIndex ]) {
					return 0;
				}
				let data = this.failedSearches[ engineIndex ].data;
				return data.reduce((a, b) => a + b.count, 0);
			},
			ignoreSearch: function(ignoredSearch, refresh = true) {
				let self = this;
				let payload = {
					action: 'searchwp_metrics_ignore_query',
					query: ignoredSearch
				};
				self.apiRequest(payload).then((response) => {
					if (refresh) {
						self.update();
					}
				});
			},
			ignorePopularSearch: function(ignoredSearch, index) {
				// Remove from display right away because there's a delay when there's a lot of data
				document.getElementById('searchwp-metrics--hook-popular-' + index).style.display = 'none';

				// We are also going to persist the ID so we can un-hide it later (because the whole point of
				// this is to avoid mutation and in doing so avoid the perf hit)
				this.inlineIgnores.push(index);

				// Also remove from the model in the 'background' because we can export from here without refresh
				for (let i = 0; i < this.popularSearchesDetails.length; i++) {
					if (ignoredSearch === this.popularSearchesDetails[i].query.query) {
						Vue$1.delete(this.popularSearchesDetails, i);
						break;
					}
				}

				// Persist the ignore
				this.ignoreSearch(ignoredSearch, false);
				this.needsRefresh = true;
			},
			ignoreFailedSearch: function(ignoredSearch, engine, index) {
				// Remove from display right away because there's a delay when there's a lot of data
				document.getElementById('searchwp-metrics--hook-failed-' + index).style.display = 'none';

				// We are also going to persist the ID so we can un-hide it later (because the whole point of
				// this is to avoid mutation and in doing so avoid the perf hit)
				this.inlineIgnores.push({
					engine: engine,
					ignoredSearch: ignoredSearch,
					index: index
				});

				// The data removal will be offloaded to the hideFailedSearches()

				// Persist the ignore
				this.ignoreSearch(ignoredSearch, false);
				this.needsRefresh = true;
			},
			getFailedSearches: function(engine) {
				for (let i = 0; i < this.failedSearches.length; i++) {
					if (this.failedSearches[i].engine === engine) {
						return this.failedSearches[i].data;
					}
				}

				return [];
			},
			getPopularSearches: function(engine) {
				for (let i = 0; i < this.popularSearches.length; i++) {
					if (this.popularSearches[i].engine === engine) {
						return this.popularSearches[i];
					}
				}

				return [];
			},
			getPopularSearchesPercentage: function(engine, engineIndex) {
				let totalSearches = this.getTotalSearchesCount( engineIndex );
				let totalPopularSearches = this.getPopularSearches(engine).datasets[0].data.reduce((a, b) => a + b, 0);

				return Math.round(( totalPopularSearches * 100 ) / totalSearches);
			},
			getPopularClicks: function(engine) {
				for (let i = 0; i < this.popularClicks.length; i++) {
					if (this.popularClicks[i].engine === engine) {
						return this.popularClicks[i];
					}
				}

				return [];
			},
			shuffle: function(a){
				for (let i = a.length - 1; i > 0; i--) {
					const j = Math.floor(Math.random() * (i + 1));
					[a[i], a[j]] = [a[j], a[i]];
				}

				return a;
			},
			getInsightsCount: function(engine) {
				if (!this.getPopularClicks(engine)){
					return 0;
				}

				if (!this.getPopularClicks(engine).insights){
					return 0;
				}

				let popular = this.getPopularClicks(engine).insights.popular;
				let underdogs = this.getPopularClicks(engine).insights.underdogs;
				let analysis = this.getPopularClicks(engine).insights.analysis;

				let total = 0;

				if (underdogs && underdogs.length) {
					total++;
				}

				if (popular && popular.length) {
					total++;
				}

				total += Object.keys(analysis).length;

				return total;
			},
			getInsights: function(engine, limit = 3){
				if (!this.getPopularClicks(engine)){
					return [];
				}

				if (!this.getPopularClicks(engine).insights){
					return [];
				}

				let insights = [];
				let popular = this.getPopularClicks(engine).insights.popular;
				let underdogs = this.getPopularClicks(engine).insights.underdogs;
				let analysis = this.getPopularClicks(engine).insights.analysis;

				if (underdogs && underdogs.length) {
					insights.push({
						type: 'underdog',
						postCount: underdogs.length,
						posts: underdogs
					});
				}

				if (popular && popular.length) {
					insights.push({
						type: 'popular',
						postCount: popular.length,
						posts: popular
					});
				}

				for (let insight in analysis) {
					if (analysis.hasOwnProperty(insight)) {
						insights.push({
							type: 'analysis',
							query: analysis[insight].query,
							clickCount: analysis[insight].clicks,
							postCount: analysis[insight].posts.length,
							posts: analysis[insight].posts
						});
					}

					// We only want a maximum of 3 entries in Insights just so the UI is balanced
					if (limit > 0 && insights.length > (limit - 1)) {
						break;
					}
				}

				return insights;
			},
			formatDate: function(date) {
				let year = date.getFullYear().toString();

				let month = date.getMonth() + 1; // getMonth() is zero based ¯\_(ツ)_/¯
				month = month < 10 ? '0' + month.toString() : month.toString();

				let day = date.getDate() < 10 ? '0' + date.getDate().toString() : date.getDate().toString();

				return year + '-' + month + '-' + day;
			},
			updateSearchesOverTime: function(data) {
				this.searchesOverTime = Vue$1.SearchwpMetricsFormatForChart(data, {
					type: 'line',
					borderWidth: 2,
					fill: true
				});
			},
			updatePopularQueriesOverTime: function(data) {
				let popularSearches = [];
				if (data) {
					data.forEach(function(dataset){
						popularSearches.push({
							engine: dataset.engine,
							engineLabel: dataset.engineLabel,
							labels: dataset.labels,
							datasets: [{
								type: 'doughnut',
								data: dataset.dataset,
								backgroundColor: dataset.dataset.map((el, index) =>{
									return Vue$1.SearchwpMetricsGetColor(index);
								})
							}]
						});
					});
				}

				this.popularSearches = popularSearches;
			},
			updatePopularClicksOverTime: function(data) {
				let popularClicks = [];

				if (data) {
					data.forEach(function(dataset){

						popularClicks.push({
							engine: dataset.engine,
							engineLabel: dataset.engineLabel,
							type: 'bar',
							insights: dataset.insights,
							datasets: dataset.dataset,
							labels: dataset.labels
						});
					});
				}

				this.popularClicks = popularClicks;
			},
			updateFailedSearchesOverTime: function(data) {
				let failedSearches = [];

				if (data) {
					data.forEach(function(dataset){
						let engineFailedSearches = [];

						for (let i = 0; i < dataset.labels.length; i++) {
							engineFailedSearches.push({
								query: dataset.labels[i],
								count: dataset.dataset[i]
							});
						}

						failedSearches.push({
							engine: dataset.engine,
							engineLabel: dataset.engineLabel,
							data: engineFailedSearches
						});
					});
				}

				this.failedSearches = failedSearches;
			},
			apiRequest: function(data = {}) {

				// Requests for metrics share a lot of properties
				if (!Object.keys(data).length) {
					data.action = 'searchwp_metrics';
					data.limit = 10;
					data.searches = lib(this.selectedSearchQueries, 'id');
				}

				data.engines = [];
				if (this.multiselect.engines.value.length) {
					this.multiselect.engines.value.forEach(function(engine){
						data.engines.push(engine.name);
					});
				}

				data.after = this.formatDate(this.dateRange[0]);
				data.before = this.formatDate(this.dateRange[1]);

				data._ajax_nonce = _SEARCHWP_METRICS_VARS.nonce;

				return new Promise(function(resolve, reject) {
					jQuery.post(ajaxurl, data, function(response) {
						if (response.success) {
							resolve(response);
						} else {
							reject(response);
						}
					});
				});
			},
			update: function() {
				this.loading = true;
				this.apiRequest().then((response) => {
					this.updateSearchesOverTime(response.data.searches_over_time);
					this.updatePopularQueriesOverTime(response.data.popular_queries_over_time);
					this.updatePopularClicksOverTime(response.data.popular_clicks_over_time);
					this.updateFailedSearchesOverTime(response.data.failed_searches_over_time);
					this.ignoredQueries = response.data.ignored_queries;
					this.averageSearchesPerUser = response.data.average_searches_per_user;
					this.averageClicksPerSearch = response.data.average_clicks_per_search;
					this.averageClickRank = response.data.average_click_rank;
					this.totalClicks = response.data.total_clicks;

					let engines = [];

					for (let i = 0; i < this.multiselect.engines.value.length; i++) {
						engines.push({
							name: this.multiselect.engines.value[i].name,
							label: this.multiselect.engines.value[i].label,
							color: Vue$1.SearchwpMetricsGetColor(i)
						});
					}

					this.sameDate = this.formatDate(this.dateRange[0]) === this.formatDate(this.dateRange[1]);
					this.engines = engines;
					this.loading = false;
				});
			},
			updateLoaderPosition: function() {
				let topEl = document.getElementById('wpadminbar');
				let leftEl = document.getElementById('adminmenuback');
				this.loaderPositionTop = topEl ? topEl.offsetHeight : 0;
				this.loaderPositionLeft = leftEl ? leftEl.offsetWidth : 0;
			}
		},
		mounted () {
			this.updateLoaderPosition();

			window.addEventListener('resize', this.updateLoaderPosition);

			this.update();
		},
		computed: {
			noResultsDetailsForExport() {
				return this.getFailedSearches(this.showingFailedSearches);
			},
			popularSearchesDetailsForExport() {
				// To effectively populate a CSV-compatible display of popular searches, we need to
				// enforce the data structure to accommodate the display of click data.
				const source = this.popularSearchesDetails;
				let formatted = [];

				if (!source.length) {
					return formatted;
				}

				source.forEach(function(popularSearch) {
					// Add a row in the spreadsheet for the search, acting as a heading.
					formatted.push({
						query: popularSearch.query.query,
						searches: popularSearch.query.searchcount,
						clickId: '',
						clickTitle: '',
						clickCount: '',
					});

					// For each click, we need to make space in the spreadsheet, so we
					// blank out the search query info and instead fill in click details.
					if (popularSearch.clicks.length) {
						popularSearch.clicks.forEach(function(click) {
							formatted.push({
								query: '',
								searches: '',
								clickId: click.post_id,
								clickTitle: click.post_title,
								clickCount: click.clicks,
							});
						});
					}
				});

				return formatted;
			},
			translatedEngineDetailsHeading() {
				return {
					template: '<span>' + this.i18n.engineDetailsForTimeline + '</span>',
					props: ['props'],
					data () {
						return {
							engine: this.props
						}
					}
				}
			},
			translatedNoResultsSearchesEngineHeading() {
				return {
					template: '<h4>' + this.i18n.noResultsSearchesEngine + '</h4>',
					props: ['props'],
					data () {
						return {
							engine: this.props
						}
					}
				}
			},
			translatedNoResultsSearchesEngineNote() {
				return {
					template: '<p>' + this.i18n.noResultsSearchesEngineNote + '</p>'
				}
			},
			translatedClickTrackingNote() {
				return {
					template: '<p>' + this.i18n.clickTrackingNote + '</p>'
				}
			},
			translatedPopularSearchDetailsHeading() {
				return {
					template: '<h4>' + this.i18n.popularSearchDetailsEngine + '</h4>',
					props: ['props'],
					data () {
						return {
							engine: this.props
						}
					}
				}
			},
			translatedInsightsEngineHeading() {
				return {
					template: '<h4>' + this.i18n.insightsEngine + '</h4>',
					props: ['props'],
					data () {
						return {
							engine: this.props
						}
					}
				}
			},
			translatedClearMetricsDataNote() {
				return {
					template: '<p>' + this.i18n.clearMetricsDataNote + '</p>'
				}
			},
			translatedClearIgnoredQueriesNote() {
				return {
					template: '<p>' + this.i18n.clearIgnoredQueriesNote + '</p>'
				}
			},
			translatedLoggingRulesNoteDetails() {
				return {
					template: '<span>' + this.i18n.loggingRulesNoteDetails + '</span>'
				}
			}
		},
		data () {

			return {
				canEditSettings: _SEARCHWP_METRICS_VARS.can_edit_settings,
				clearDataOnUninstall: _SEARCHWP_METRICS_VARS.settings.clear_data_on_uninstall,
				clickTrackingBuoy: _SEARCHWP_METRICS_VARS.settings.click_tracking_buoy,
				clickTrackingBuoyApplicable: _SEARCHWP_METRICS_VARS.settings.click_tracking_buoy_applicable,
				inlineIgnores: [],
				ignoredIps: _SEARCHWP_METRICS_VARS.settings.blocklists.ips,
				ignoredRoles: _SEARCHWP_METRICS_VARS.settings.blocklists.roles,
				sameDate: false,
				showingSettings: false,
				showingClearMetricsData: false,
				showingClearIgnoredQueries: false,
				showingModifyLoggingRules: false,
				noResultsDetailsJsonFields: {
					'Query': 'query',
					'No Results Search Count': 'count'
				},
				searchesOverTimeJsonFields: {
					'Date': 'label',
					'Searches': 'searches'
				},
				engineStatisticsJsonFields: {
					'Statistic': 'statistic',
					'Value': 'value'
				},
				popularSearchesJsonFields: {
					'Search Query': 'query.query',
					'Searches': 'query.searchcount'
				},
				popularSearchesDetailsJsonFields: {
					'Search Query': 'query',
					'Searches': 'searches',
					'Clicked Title': {
						callback: function(value) {
							return !value.clickId ? '' : value.clickTitle + ' (' + value.clickId + ')';
						}
					},
					'Clicks': 'clickCount'
				},
				popularSearchesCount: 10,
				popularSearchesDetails: [],
				loading: true,
				loaderPositionTop: 0,
				loaderPositionLeft: 0,
				showingInsights: false,
				showingIgnoredSearches: false,
				showingFailedSearches: false,
				showingPopularSearchDetails: false,
				loadingPopularSearchDetails: true,
				needsRefresh: false,
				engines: [],
				ignoredQueries: [],
				isLoadingSearchSearches: false,
				searchQueries: [],
				selectedSearchQueries: [],
				multiselect: {
					engines: {
						value: _SEARCHWP_METRICS_VARS.engine_default,
						options: _SEARCHWP_METRICS_VARS.engines,
					}
				},
				averageSearchesPerUser: [],
				averageClicksPerSearch: [],
				averageClickRank: [],
				totalClicks: [],
				// Metrics are grouped by chart type because some will combine engines while others will not
				searchesOverTime: null,
				searchesOverTimeOptions: {
					maintainAspectRatio: false,
					legend: {},
					tooltips: {
						cornerRadius: 2,
						titleMarginBottom: 10,
						xPadding: 16,
						yPadding: 9,
						displayColors: false // We want the fill color to be semi-transparent but that doesn't translate well here
					}
				},
				popularSearchDetailsClicksOptions: {
					maintainAspectRatio: false,
					height: '40px',
					legend: {
						display: false
					},
					tooltips: {
						enabled: false
					},
					hover: {
						mode: null
					},
					scales: {
						xAxes: [{
							stacked: true,
							display: false,
							ticks: {
								max: 100
							}
						}],
						yAxes: [{
							stacked: true,
							display: false
						}]
					}
				},
				popularSearches: [],
				popularSearchesOptions: {
					maintainAspectRatio: true,
					legend: {
						display: false
					},
					tooltips: {
						cornerRadius: 2,
						titleMarginBottom: 10,
						xPadding: 11,
						yPadding: 9,
					}// ,
					// onClick: function(e,i){
					// 	that.showPopularSearchDetails('default', i[0]['_index']); // In progress, needs to pass engine
					// }
				},
				popularClicks: [],
				popularClicksOptions: {
					maintainAspectRatio: false,
					legend: {
						display: false,
						position: 'bottom'
					},
					tooltips: {
						cornerRadius: 2,
						titleMarginBottom: 10,
						xPadding: 11,
						yPadding: 9,
					},
					scales: {
						xAxes: [{
							stacked: true,
						}],
						yAxes: [{
							stacked: true
						}]
					}
				},
				failedSearches: [],
				dateRange: [
					new Date(_SEARCHWP_METRICS_VARS.options.default_start),
					new Date(_SEARCHWP_METRICS_VARS.options.default_end)
				],
				i18n: {
					addAsPartialMatch: _SEARCHWP_METRICS_VARS.i18n.add_as_partial_match,
					areYouSure: _SEARCHWP_METRICS_VARS.i18n.are_you_sure,
					averageClickRank: _SEARCHWP_METRICS_VARS.i18n.average_click_rank,
					averageRank: _SEARCHWP_METRICS_VARS.i18n.average_rank,
					cancel: _SEARCHWP_METRICS_VARS.i18n.cancel,
					chooseEngine: _SEARCHWP_METRICS_VARS.i18n.choose_engine,
					clearData: _SEARCHWP_METRICS_VARS.i18n.clear_data,
					clearIgnoredQueriesNote: _SEARCHWP_METRICS_VARS.i18n.clear_ignored_queries_note,
					clearMetricsData: _SEARCHWP_METRICS_VARS.i18n.clear_metrics_data,
					clearMetricsDataNote: _SEARCHWP_METRICS_VARS.i18n.clear_metrics_data_note,
					clickedResult: _SEARCHWP_METRICS_VARS.i18n.clicked_result,
					clicks: _SEARCHWP_METRICS_VARS.i18n.clicks,
					clicksPerSearch: _SEARCHWP_METRICS_VARS.i18n.clicks_per_search,
					clickTrackingNote: _SEARCHWP_METRICS_VARS.i18n.click_tracking_note,
					clickTrackingBuoy: _SEARCHWP_METRICS_VARS.i18n.click_tracking_buoy,
					clickTrackingBuoyLabelNote: _SEARCHWP_METRICS_VARS.i18n.click_tracking_buoy_label_note,
					clickTrackingBuoyUnavailable: _SEARCHWP_METRICS_VARS.i18n.click_tracking_buoy_unavailable,
					conversionRate: _SEARCHWP_METRICS_VARS.i18n.conversion_rate,
					datePicker: {
						dow: _SEARCHWP_METRICS_VARS.options.first_day_of_week,
						hourTip: _SEARCHWP_METRICS_VARS.i18n.select_hour,
						minuteTip: _SEARCHWP_METRICS_VARS.i18n.select_minute,
						secondTip: _SEARCHWP_METRICS_VARS.i18n.select_second,
						yearSuffix: _SEARCHWP_METRICS_VARS.options.year_suffix,
						monthsHead: _SEARCHWP_METRICS_VARS.i18n.months.split('_'),
						months: _SEARCHWP_METRICS_VARS.i18n.months_abbr.split('_'),
						weeks: _SEARCHWP_METRICS_VARS.i18n.days_abbr.split('_'),
						cancelTip: _SEARCHWP_METRICS_VARS.i18n.close,
						submitTip: _SEARCHWP_METRICS_VARS.i18n.update
					},
					dateRange: _SEARCHWP_METRICS_VARS.i18n.date_range,
					engineDetailsForTimeline: _SEARCHWP_METRICS_VARS.i18n.engine_details_for_timeline,
					engineStatistics: _SEARCHWP_METRICS_VARS.i18n.engine_statistics,
					enginesToDisplay: _SEARCHWP_METRICS_VARS.i18n.engines_to_display,
					entry: _SEARCHWP_METRICS_VARS.i18n.entry,
					exportEngineStatistics: _SEARCHWP_METRICS_VARS.i18n.export_engine_statistics,
					exportPopularSearches: _SEARCHWP_METRICS_VARS.i18n.export_popular_searches,
					exportSearchesOverTime: _SEARCHWP_METRICS_VARS.i18n.export_searches_over_time,
					ignored: _SEARCHWP_METRICS_VARS.i18n.ignored,
					ignoredSearches: _SEARCHWP_METRICS_VARS.i18n.ignored_searches,
					ignoredSearchQuery: _SEARCHWP_METRICS_VARS.i18n.ignored_search_query,
					ignoredMessage: _SEARCHWP_METRICS_VARS.i18n.ignored_message,
					insights: _SEARCHWP_METRICS_VARS.i18n.insights,
					insightsEngine: _SEARCHWP_METRICS_VARS.i18n.insights_engine,
					ipBlocklist: _SEARCHWP_METRICS_VARS.i18n.ip_blocklist,
					ipBlocklistNote: _SEARCHWP_METRICS_VARS.i18n.ip_blocklist_note,
					limitMetricsToQueries: _SEARCHWP_METRICS_VARS.i18n.limit_metrics_to_queries,
					loggingRules: _SEARCHWP_METRICS_VARS.i18n.logging_rules,
					loggingRulesNote: _SEARCHWP_METRICS_VARS.i18n.logging_rules_note,
					loggingRulesNoteDetails: _SEARCHWP_METRICS_VARS.i18n.logging_rules_note_details,
					modifyLoggingRules: _SEARCHWP_METRICS_VARS.i18n.modify_logging_rules,
					noClicks: _SEARCHWP_METRICS_VARS.i18n.no_clicks,
					noFailedSearches: _SEARCHWP_METRICS_VARS.i18n.no_failed_searches,
					noIgnoredQueries: _SEARCHWP_METRICS_VARS.i18n.no_ignored_queries,
					noInsights: _SEARCHWP_METRICS_VARS.i18n.no_insights,
					noResultsSearches: _SEARCHWP_METRICS_VARS.i18n.no_results_searches,
					noResultsSearchesEngine: _SEARCHWP_METRICS_VARS.i18n.no_results_searches_engine,
					noResultsSearchesEngineNote: _SEARCHWP_METRICS_VARS.i18n.no_results_searches_engine_note,
					notEnoughData: _SEARCHWP_METRICS_VARS.i18n.not_enough_data,
					ofAllSearches: _SEARCHWP_METRICS_VARS.i18n.of_all_searches,
					popularSearchDetailsEngine: _SEARCHWP_METRICS_VARS.i18n.popular_search_details_engine,
					popularSearchDetailsNote: _SEARCHWP_METRICS_VARS.i18n.popular_search_details_note,
					popularSearches: _SEARCHWP_METRICS_VARS.i18n.popular_searches,
					removeAllIgnoredQueries: _SEARCHWP_METRICS_VARS.i18n.remove_all_ignored_queries,
					removeOnUninstallation: _SEARCHWP_METRICS_VARS.i18n.remove_on_uninstallation,
					removeOnUninstallationLabelNote: _SEARCHWP_METRICS_VARS.i18n.remove_on_uninstallation_label_note,
					saveClose: _SEARCHWP_METRICS_VARS.i18n.save_close,
					searches: _SEARCHWP_METRICS_VARS.i18n.searches,
					searchesPerUser: _SEARCHWP_METRICS_VARS.i18n.searches_per_user,
					searchesPerUserNote: _SEARCHWP_METRICS_VARS.i18n.searches_per_user_note,
					// searchMetrics: _SEARCHWP_METRICS_VARS.i18n.search_metrics,
					searchQuery: _SEARCHWP_METRICS_VARS.i18n.search_query,
					searchQueryControls: _SEARCHWP_METRICS_VARS.i18n.search_query_controls,
					settings: _SEARCHWP_METRICS_VARS.i18n.settings,
					stopIgnoringQuery: _SEARCHWP_METRICS_VARS.i18n.stop_ignoring_query,
					to: _SEARCHWP_METRICS_VARS.i18n.to,
					totalResultsViewed: _SEARCHWP_METRICS_VARS.i18n.total_results_viewed,
					totalSearches: _SEARCHWP_METRICS_VARS.i18n.total_searches,
					userIdRoleBlocklist: _SEARCHWP_METRICS_VARS.i18n.user_id_role_blocklist,
					userIdRoleBlocklistNote: _SEARCHWP_METRICS_VARS.i18n.user_id_role_blocklist_note,
					viewAll: _SEARCHWP_METRICS_VARS.i18n.view_all,
					viewMore: _SEARCHWP_METRICS_VARS.i18n.view_more,
					viewNoResultsSearches: _SEARCHWP_METRICS_VARS.i18n.view_no_results_searches
				}
			}
		}
	};

	/* script */
	const __vue_script__$c = script$c;
	/* template */
	var __vue_render__$c = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"searchwp-metrics wrap"},[_c('div',{staticClass:"searchwp-metrics__title"},[_c('h1',[_vm._v("SearchWP Metrics")]),_vm._v(" "),('1' === _vm.canEditSettings)?_c('v-popover',{attrs:{"popover-wrapper-class":'searchwp-metrics-popover',"placement":'bottom'}},[_c('button',{staticClass:"button"},[_c('span',{staticClass:"dashicons dashicons-menu"})]),_vm._v(" "),_c('template',{slot:"popover"},[_c('ul',[_c('li',[_c('button',{directives:[{name:"close-popover",rawName:"v-close-popover"}],staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){$event.preventDefault();_vm.showingClearMetricsData = true;}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.clearMetricsData)+"\n\t\t\t\t\t\t")])]),_vm._v(" "),(_vm.ignoredQueries && _vm.ignoredQueries.length)?_c('li',[_c('button',{directives:[{name:"close-popover",rawName:"v-close-popover"}],staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){$event.preventDefault();_vm.showingClearIgnoredQueries = true;}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.removeAllIgnoredQueries)+"\n\t\t\t\t\t\t")])]):_vm._e(),_vm._v(" "),_c('li',[_c('button',{directives:[{name:"close-popover",rawName:"v-close-popover"}],staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){$event.preventDefault();_vm.showingModifyLoggingRules = true;}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.modifyLoggingRules)+"\n\t\t\t\t\t\t")])]),_vm._v(" "),_c('li',[_c('button',{directives:[{name:"close-popover",rawName:"v-close-popover"}],staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){$event.preventDefault();_vm.showingSettings = true;}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.settings)+"\n\t\t\t\t\t\t")])])])])],2):_vm._e(),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingClearMetricsData,"default-width":'300px'},on:{"hide":_vm.hideClearMetricsData}},[_c('div',{staticClass:"searchwp-metrics__modal searchwp-metrics__modal-confirmation"},[_c('h4',[_c('span',{staticClass:"dashicons dashicons-arrow-right"}),_vm._v(" "+_vm._s(_vm.i18n.areYouSure)+" "),_c('span',{staticClass:"dashicons dashicons-arrow-left"})]),_vm._v(" "),_c(_vm.translatedClearMetricsDataNote,{tag:"component"}),_vm._v(" "),_c('ul',{staticClass:"searchwp-metrics__modal-confirmation--actions"},[_c('li',[_c('button',{staticClass:"button",on:{"click":function($event){$event.preventDefault();return _vm.clearMetricsData($event)}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.clearData)+"\n\t\t\t\t\t\t")])]),_vm._v(" "),_c('li',[_c('button',{staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){$event.preventDefault();return _vm.hideClearMetricsData($event)}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.cancel)+"\n\t\t\t\t\t\t")])])])],1)]),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingClearIgnoredQueries,"default-width":'300px'},on:{"hide":_vm.hideClearIgnoredQueries}},[_c('div',{staticClass:"searchwp-metrics__modal searchwp-metrics__modal-confirmation"},[_c('h4',[_c('span',{staticClass:"dashicons dashicons-arrow-right"}),_vm._v(" "+_vm._s(_vm.i18n.areYouSure)+" "),_c('span',{staticClass:"dashicons dashicons-arrow-left"})]),_vm._v(" "),_c(_vm.translatedClearIgnoredQueriesNote,{tag:"component"}),_vm._v(" "),_c('ul',{staticClass:"searchwp-metrics__modal-confirmation--actions"},[_c('li',[_c('button',{staticClass:"button",on:{"click":function($event){$event.preventDefault();return _vm.clearIgnoredQueries($event)}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.clearData)+"\n\t\t\t\t\t\t")])]),_vm._v(" "),_c('li',[_c('button',{staticClass:"searchwp-metrics-nonbutton",on:{"click":function($event){$event.preventDefault();return _vm.hideClearIgnoredQueries($event)}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.cancel)+"\n\t\t\t\t\t\t")])])])],1)]),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingModifyLoggingRules,"default-width":'400px'},on:{"hide":_vm.hideModifyLoggingRules}},[_c('div',{staticClass:"searchwp-metrics__modal searchwp-metrics__modal-logging"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.loggingRules))]),_vm._v(" "),_c('p',[_vm._v(_vm._s(_vm.i18n.loggingRulesNote))]),_vm._v(" "),_c('p',[_c('span',{staticClass:"dashicons dashicons-info"}),_vm._v(" "),_c(_vm.translatedLoggingRulesNoteDetails,{tag:"component"})],1),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__textarea"},[_c('label',{attrs:{"for":"searchwp_metrics_ip_blocklist"}},[_vm._v(_vm._s(_vm.i18n.userIdRoleBlocklist))]),_vm._v(" "),_c('textarea',{directives:[{name:"model",rawName:"v-model",value:(_vm.ignoredRoles),expression:"ignoredRoles"}],attrs:{"name":"searchwp_metrics_role_blocklist","id":"searchwp_metrics_role_blocklist","cols":"30","rows":"10"},domProps:{"value":(_vm.ignoredRoles)},on:{"input":function($event){if($event.target.composing){ return; }_vm.ignoredRoles=$event.target.value;}}}),_vm._v(" "),_c('p',{staticClass:"description"},[_vm._v(_vm._s(_vm.i18n.userIdRoleBlocklistNote))])]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__textarea"},[_c('label',{attrs:{"for":"searchwp_metrics_ip_blocklist"}},[_vm._v(_vm._s(_vm.i18n.ipBlocklist))]),_vm._v(" "),_c('textarea',{directives:[{name:"model",rawName:"v-model",value:(_vm.ignoredIps),expression:"ignoredIps"}],attrs:{"name":"searchwp_metrics_ip_blocklist","id":"searchwp_metrics_ip_blocklist","cols":"30","rows":"10"},domProps:{"value":(_vm.ignoredIps)},on:{"input":function($event){if($event.target.composing){ return; }_vm.ignoredIps=$event.target.value;}}}),_vm._v(" "),_c('p',{staticClass:"description"},[_vm._v(_vm._s(_vm.i18n.ipBlocklistNote))])]),_vm._v(" "),_c('ul',{staticClass:"searchwp-metrics__modal-confirmation--actions"},[_c('li',[_c('button',{staticClass:"button",on:{"click":function($event){$event.preventDefault();return _vm.hideModifyLoggingRules($event)}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.saveClose)+"\n\t\t\t\t\t\t")])])])])]),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingSettings,"default-width":'400px'},on:{"hide":_vm.hideSettings}},[_c('div',{staticClass:"searchwp-metrics__modal searchwp-metrics__modal-settings"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.settings))]),_vm._v(" "),(_vm.clickTrackingBuoyApplicable)?_c('div',{staticClass:"searchwp-metrics__checkbox"},[_c('input',{directives:[{name:"model",rawName:"v-model",value:(_vm.clickTrackingBuoy),expression:"clickTrackingBuoy"}],attrs:{"type":"checkbox","name":"searchwp_metrics_click_track_buoy","id":"searchwp_metrics_click_track_buoy"},domProps:{"checked":Array.isArray(_vm.clickTrackingBuoy)?_vm._i(_vm.clickTrackingBuoy,null)>-1:(_vm.clickTrackingBuoy)},on:{"change":function($event){var $$a=_vm.clickTrackingBuoy,$$el=$event.target,$$c=$$el.checked?(true):(false);if(Array.isArray($$a)){var $$v=null,$$i=_vm._i($$a,$$v);if($$el.checked){$$i<0&&(_vm.clickTrackingBuoy=$$a.concat([$$v]));}else {$$i>-1&&(_vm.clickTrackingBuoy=$$a.slice(0,$$i).concat($$a.slice($$i+1)));}}else {_vm.clickTrackingBuoy=$$c;}}}}),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__checkbox-label"},[_c('label',{attrs:{"for":"searchwp_metrics_click_track_buoy"}},[_vm._v(_vm._s(_vm.i18n.clickTrackingBuoy))]),_vm._v(" "),_c('p',{staticClass:"description"},[_vm._v(_vm._s(_vm.i18n.clickTrackingBuoyLabelNote))])])]):_c('div',{staticClass:"searchwp-metrics__note"},[_c('span',{staticClass:"dashicons dashicons-info"}),_vm._v(" "),_c('div',[_c('p',[_vm._v(_vm._s(_vm.i18n.clickTrackingBuoyUnavailable))])])]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__checkbox"},[_c('input',{directives:[{name:"model",rawName:"v-model",value:(_vm.clearDataOnUninstall),expression:"clearDataOnUninstall"}],attrs:{"type":"checkbox","name":"searchwp_metrics_clear_data_on_uninstall","id":"searchwp_metrics_clear_data_on_uninstall"},domProps:{"checked":Array.isArray(_vm.clearDataOnUninstall)?_vm._i(_vm.clearDataOnUninstall,null)>-1:(_vm.clearDataOnUninstall)},on:{"change":function($event){var $$a=_vm.clearDataOnUninstall,$$el=$event.target,$$c=$$el.checked?(true):(false);if(Array.isArray($$a)){var $$v=null,$$i=_vm._i($$a,$$v);if($$el.checked){$$i<0&&(_vm.clearDataOnUninstall=$$a.concat([$$v]));}else {$$i>-1&&(_vm.clearDataOnUninstall=$$a.slice(0,$$i).concat($$a.slice($$i+1)));}}else {_vm.clearDataOnUninstall=$$c;}}}}),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__checkbox-label"},[_c('label',{attrs:{"for":"searchwp_metrics_clear_data_on_uninstall"}},[_vm._v(_vm._s(_vm.i18n.removeOnUninstallation))]),_vm._v(" "),_c('p',{staticClass:"description"},[_vm._v(_vm._s(_vm.i18n.removeOnUninstallationLabelNote))])])]),_vm._v(" "),_c('ul',{staticClass:"searchwp-metrics__modal-confirmation--actions"},[_c('li',[_c('button',{staticClass:"button",on:{"click":function($event){$event.preventDefault();return _vm.hideSettings($event)}}},[_vm._v("\n\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.saveClose)+"\n\t\t\t\t\t\t")])])])])])],1),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__controls"},[_c('div',{staticClass:"searchwp-metrics__control"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.dateRange))]),_vm._v(" "),_c('vue-datepicker-local',{attrs:{"range-separator":_vm.i18n.to,"local":_vm.i18n.datePicker,"show-buttons":""},on:{"confirm":_vm.update},model:{value:(_vm.dateRange),callback:function ($$v) {_vm.dateRange=$$v;},expression:"dateRange"}})],1),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__control"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.searchQueryControls))]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__control-queries"},[_c('multiselect',{attrs:{"id":"searchwp-metrics-query-limiter","label":"query","track-by":"id","placeholder":_vm.i18n.limitMetricsToQueries,"open-direction":"bottom","options":_vm.searchQueries,"multiple":true,"searchable":true,"loading":_vm.isLoadingSearchSearches,"internal-search":false,"clear-on-select":false,"close-on-select":false,"options-limit":300,"limit":3,"max-height":300,"show-no-results":false,"hide-selected":true,"taggable":true,"tag-placeholder":_vm.i18n.addAsPartialMatch},on:{"search-change":_vm.searchSearchQueries,"tag":_vm.addSelectedSearchQuery,"input":_vm.update},model:{value:(_vm.selectedSearchQueries),callback:function ($$v) {_vm.selectedSearchQueries=$$v;},expression:"selectedSearchQueries"}}),_vm._v(" "),_c('button',{staticClass:"button",on:{"click":function($event){_vm.showingIgnoredSearches = true;}}},[_vm._v(_vm._s(_vm.i18n.ignored)+": "+_vm._s(Object.keys(_vm.ignoredQueries).length))]),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingIgnoredSearches,"default-width":'600px'},on:{"hide":_vm.hideIgnoredSearches}},[_c('div',{staticClass:"searchwp-metrics__modal searchwp-metrics__ignored-searches-details"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.ignoredSearches))]),_vm._v(" "),_c('p',[_vm._v(_vm._s(_vm.i18n.ignoredMessage))]),_vm._v(" "),_c('p',[_c('button',{staticClass:"button",on:{"click":_vm.addNewIgnoredSearch}},[_vm._v("Add")])]),_vm._v(" "),(_vm.ignoredQueries && _vm.ignoredQueries.length)?_c('table',[_c('thead',[_c('tr',[_c('th',[_vm._v(_vm._s(_vm.i18n.ignoredSearchQuery))])])]),_vm._v(" "),_c('tbody',_vm._l((_vm.ignoredQueries),function(ignoredQuery,ignoredQueryIndex){return (!ignoredQuery.unignored)?_c('tr',{key:'ignored' + ignoredQueryIndex},[_c('td',[_c('delete',{attrs:{"title":_vm.i18n.stopIgnoringQuery},on:{"onclick":function($event){return _vm.unIgnoreQuery(ignoredQuery.hash)}}}),_vm._v("\n\t\t\t\t\t\t\t\t\t\t"+_vm._s(ignoredQuery.query)+"\n\t\t\t\t\t\t\t\t\t")],1)]):_vm._e()}),0)]):_c('div',{staticClass:"searchwp-metrics__note"},[_c('span',{staticClass:"dashicons dashicons-info"}),_vm._v(" "),_c('div',[_c('p',[_vm._v(_vm._s(_vm.i18n.noIgnoredQueries))])])])])])],1)]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__control"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.enginesToDisplay))]),_vm._v(" "),_c('multiselect',{attrs:{"options":_vm.multiselect.engines.options,"multiple":true,"close-on-select":true,"hide-selected":true,"placeholder":_vm.i18n.chooseEngine,"label":"label","track-by":"name","searchable":false,"allow-empty":false},on:{"input":_vm.update},model:{value:(_vm.multiselect.engines.value),callback:function ($$v) {_vm.$set(_vm.multiselect.engines, "value", $$v);},expression:"multiselect.engines.value"}})],1)]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__details"},[(!_vm.sameDate)?_c('div',{class:['searchwp-metrics__searches-over-time', _vm.searchesOverTime ? '' : 'searchwp-metrics__is-loading']},[_c('line-chart',{attrs:{"datacollection":_vm.searchesOverTime,"options":_vm.searchesOverTimeOptions,"height":'300px'}})],1):_vm._e(),_vm._v(" "),_vm._l((_vm.engines),function(engine,engineIndex){return (_vm.engines && !_vm.loading)?_c('div',{key:engine.name,staticClass:"searchwp-metrics__engine-details"},[_c('div',{staticClass:"searchwp-metrics__engine-details-heading-group"},[_c('h3',{staticClass:"searchwp-metrics__engine-details-heading"},[_c('span',{staticClass:"searchwp-metrics__engine-details-legend",style:({ backgroundColor: engine.color })}),_vm._v(" "),_c(_vm.translatedEngineDetailsHeading,{tag:"component",attrs:{"props":engine}})],1),_vm._v(" "),_c('v-popover',{attrs:{"popover-wrapper-class":'searchwp-metrics-popover',"placement":'left'}},[_c('button',{staticClass:"button"},[_c('span',{staticClass:"dashicons dashicons-menu"})]),_vm._v(" "),_c('template',{slot:"popover"},[_c('ul',[_c('li',[_c('json-csv',{attrs:{"data":_vm.formattedSearchesOverTimeForCsv(engineIndex),"fields":_vm.searchesOverTimeJsonFields,"type":"csv","name":_vm.appendTimestamp('SearchesOverTime_' + engine.name) + '.csv'}},[_vm._v("\n\t\t\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.exportSearchesOverTime)+"\n\t\t\t\t\t\t\t\t")])],1),_vm._v(" "),_c('li',[_c('json-csv',{attrs:{"data":_vm.formattedEngineStatisticForCsv(engineIndex, engine),"fields":_vm.engineStatisticsJsonFields,"type":"csv","name":_vm.appendTimestamp('EngineStatistics_' + engine.name) + '.csv'}},[_vm._v("\n\t\t\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.exportEngineStatistics)+"\n\t\t\t\t\t\t\t\t")])],1),_vm._v(" "),_c('li',[_c('json-csv',{attrs:{"data":_vm.formattedPopularSearchesForCsv(engineIndex),"fields":_vm.popularSearchesJsonFields,"type":"csv","name":_vm.appendTimestamp('PopularSearches') + '.csv'}},[_vm._v("\n\t\t\t\t\t\t\t\t\t"+_vm._s(_vm.i18n.exportPopularSearches)+"\n\t\t\t\t\t\t\t\t")])],1)])])],2)],1),_vm._v(" "),(0 == _vm.getTotalSearchesCount( engineIndex ))?_c('div',{staticClass:"searchwp-metrics__no-data"},[_c('p',[_vm._v(_vm._s(_vm.i18n.notEnoughData))])]):_c('div',{staticClass:"searchwp-metrics__engine-details-hook"},[_c('div',{staticClass:"searchwp-metrics__engine-details-alpha"},[_c('div',{staticClass:"searchwp-metrics__engine-details--heading"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.engineStatistics))])]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__stats-grid"},[_c('div',[_c('dl',[_c('dt',[_vm._v(_vm._s(_vm.i18n.totalSearches))]),_vm._v(" "),_c('dd',[_vm._v(_vm._s(_vm.getTotalSearchesCount( engineIndex )))])])]),_vm._v(" "),_c('div',[_c('dl',[_c('dt',[_vm._v(_vm._s(_vm.i18n.noResultsSearches))]),_vm._v(" "),_c('dd',[_c('div',{staticClass:"searchwp-metrics__flex"},[_c('div',[_vm._v(_vm._s(_vm.getFailedSearchesCount( engineIndex )))]),_vm._v(" "),_c('div',[_c('button',{staticClass:"searchwp-trigger__external",on:{"click":function($event){_vm.showingFailedSearches = engine.name;}}},[_c('span',{staticClass:"dashicons dashicons-external"}),_vm._v(" "),_c('span',{staticClass:"screen-reader-text"},[_vm._v(_vm._s(_vm.i18n.viewNoResultsSearches))])])])])])]),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingFailedSearches === engine.name,"default-width":'600px'},on:{"hide":_vm.hideFailedSearches}},[_c('div',{staticClass:"searchwp-metrics__modal searchwp-metrics__failed-searches-details"},[_c(_vm.translatedNoResultsSearchesEngineHeading,{tag:"component",attrs:{"props":engine}}),_vm._v(" "),(_vm.getFailedSearches(engine.name) && _vm.getFailedSearches(engine.name).length)?_c('div',{staticClass:"searchwp-metrics__engine-details--heading"},[_c(_vm.translatedNoResultsSearchesEngineNote,{tag:"component"}),_vm._v(" "),_c('json-csv',{staticClass:"button",attrs:{"data":_vm.noResultsDetailsForExport,"fields":_vm.noResultsDetailsJsonFields,"type":"csv","name":_vm.appendTimestamp('NoResultsSearches') + '.csv'}},[_c('span',{staticClass:"dashicons dashicons-download"})])],1):_vm._e(),_vm._v(" "),(_vm.getFailedSearches(engine.name) && _vm.getFailedSearches(engine.name).length)?_c('table',[_c('thead',[_c('tr',[_c('th',[_vm._v(_vm._s(_vm.i18n.searchQuery))]),_vm._v(" "),_c('th',[_vm._v(_vm._s(_vm.i18n.searches))])])]),_vm._v(" "),_c('tbody',_vm._l((_vm.getFailedSearches(engine.name)),function(failedSearch,failedSearchIndex){return _c('tr',{key:'failed' + failedSearchIndex + engine.name,attrs:{"id":'searchwp-metrics--hook-failed-' + failedSearchIndex}},[_c('td',[_c('delete',{attrs:{"title":"Ignore this query"},on:{"onclick":function($event){return _vm.ignoreFailedSearch(failedSearch.query, engine.name, failedSearchIndex)}}}),_vm._v("\n\t\t\t\t\t\t\t\t\t\t\t\t\t"+_vm._s(failedSearch.query)+"\n\t\t\t\t\t\t\t\t\t\t\t\t")],1),_vm._v(" "),_c('td',[_vm._v(_vm._s(failedSearch.count))])])}),0)]):_c('div',{staticClass:"searchwp-metrics__note"},[_c('span',{staticClass:"dashicons dashicons-info"}),_vm._v(" "),_c('div',[_c('p',[_vm._v(_vm._s(_vm.i18n.noFailedSearches))])])])],1)])],1),_vm._v(" "),_c('div',[_c('dl',[_c('dt',[_vm._v(_vm._s(_vm.i18n.totalResultsViewed))]),_vm._v(" "),_c('dd',[_vm._v(_vm._s(_vm.outputMetric( _vm.totalClicks[ engine.name ].statistic )))])])]),_vm._v(" "),_c('div',[_c('dl',[_c('dt',[_c('tooltip',{attrs:{"content":_vm.i18n.searchesPerUserNote}},[_vm._v(_vm._s(_vm.i18n.searchesPerUser))])],1),_vm._v(" "),_c('dd',[_vm._v(_vm._s(_vm.outputMetric( _vm.averageSearchesPerUser[ engine.name ].statistic )))])])]),_vm._v(" "),_c('div',[_c('dl',[_c('dt',[_vm._v(_vm._s(_vm.i18n.clicksPerSearch))]),_vm._v(" "),_c('dd',[_vm._v(_vm._s(_vm.outputMetric( _vm.averageClicksPerSearch[ engine.name ].statistic )))])])]),_vm._v(" "),_c('div',[_c('dl',[_c('dt',[_vm._v(_vm._s(_vm.i18n.averageClickRank))]),_vm._v(" "),_c('dd',[_vm._v(_vm._s(_vm.outputMetric( _vm.averageClickRank[ engine.name ].statistic )))])])])]),_vm._v(" "),(_vm.engineHasNoTracking( engine.name ))?_c('div',{staticClass:"searchwp-metrics__note"},[_c('span',{staticClass:"dashicons dashicons-info"}),_vm._v(" "),_c('div',[_c(_vm.translatedClickTrackingNote,{tag:"component"})],1)]):_vm._e()]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-details-beta searchwp-metrics__engine-popular-searches"},[_c('div',{staticClass:"searchwp-metrics__engine-details--heading"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.popularSearches))]),_vm._v(" "),_c('div',[_c('button',{staticClass:"button",on:{"click":function($event){$event.preventDefault();return _vm.showPopularSearchDetails(engine)}}},[_vm._v(_vm._s(_vm.i18n.viewMore))])])]),_vm._v(" "),(_vm.getPopularSearches(engine.name))?_c('div',{staticClass:"searchwp-metrics__chart-donut-wrapper"},[_c('div',[_c('table',{staticClass:"searchwp-metrics-table"},[_c('tbody',_vm._l((_vm.getPopularSearches(engine.name).labels),function(popularSearch,popularSearchIndex){return _c('tr',{key:'popularSearch' + engine.name + popularSearchIndex},[_c('td',[_c('legend-indicator',{attrs:{"index":popularSearchIndex,"text":popularSearch},on:{"onclick":function($event){return _vm.showPopularSearchDetails(engine, popularSearch)}}})],1),_vm._v(" "),_c('td',[_c('delete',{on:{"onclick":function($event){return _vm.ignoreSearch(popularSearch)}}})],1),_vm._v(" "),_c('td',[_vm._v(_vm._s(_vm.getPopularSearches(engine.name).datasets[0].data[ popularSearchIndex ]))])])}),0)]),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingPopularSearchDetails && _vm.showingPopularSearchDetails.engine.name === engine.name,"default-width":'800px'},on:{"hide":_vm.hidePopularSearchDetails}},[(_vm.showingPopularSearchDetails)?_c('div',{class:['searchwp-metrics__modal searchwp-metrics__popular-search-details', _vm.loadingPopularSearchDetails ? 'searchwp-metrics__is-loading-details' : '']},[_c('div',{staticClass:"searchwp-metrics__loading-details-container"},[_c(_vm.translatedPopularSearchDetailsHeading,{tag:"component",attrs:{"props":engine}}),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-details--heading"},[_c('p',[_vm._v(_vm._s(_vm.i18n.popularSearchDetailsNote))]),_vm._v(" "),_c('div',[_c('input',{directives:[{name:"model",rawName:"v-model.number",value:(_vm.popularSearchesCount),expression:"popularSearchesCount",modifiers:{"number":true}}],attrs:{"type":"text"},domProps:{"value":(_vm.popularSearchesCount)},on:{"keyup":function($event){if(!$event.type.indexOf('key')&&_vm._k($event.keyCode,"enter",13,$event.key,"Enter")){ return null; }return _vm.updatePopularSearchDetails(_vm.showingPopularSearchDetails.engine.name)},"input":function($event){if($event.target.composing){ return; }_vm.popularSearchesCount=_vm._n($event.target.value);},"blur":function($event){return _vm.$forceUpdate()}}}),_vm._v(" "),_c('button',{staticClass:"button",on:{"click":function($event){$event.preventDefault();return _vm.updatePopularSearchDetails(_vm.showingPopularSearchDetails.engine.name)}}},[_c('span',{staticClass:"dashicons dashicons-update"})]),_vm._v(" "),_c('json-csv',{staticClass:"button",attrs:{"data":_vm.popularSearchesDetailsForExport,"fields":_vm.popularSearchesDetailsJsonFields,"type":"csv","name":_vm.appendTimestamp('PopularSearchesDetails') + '.csv'}},[_c('span',{staticClass:"dashicons dashicons-download"})])],1)]),_vm._v(" "),_c('v-collapse-group',[_c('div',{staticClass:"searchwp-metrics__split"},[_c('p',{staticClass:"searchwp-metrics__guide"},[_vm._v(_vm._s(_vm.i18n.searchQuery))]),_vm._v(" "),_c('p',{staticClass:"searchwp-metrics__guide"},[_vm._v(_vm._s(_vm.i18n.searches))])]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__popular-search-details searchwp-metrics__accordion"},_vm._l((_vm.popularSearchesDetails),function(popularSearchDetail,popularSearchDetailIndex){return _c('v-collapse-wrapper',{key:'popularSearchDetail' + _vm.showingPopularSearchDetails.engine.name + popularSearchDetailIndex,attrs:{"active":popularSearchDetail.query.query === _vm.showingPopularSearchDetails.query,"id":'searchwp-metrics--hook-popular-' + popularSearchDetailIndex}},[_c('div',{staticClass:"searchwp-metrics__accordion--header"},[_c('div',{directives:[{name:"collapse-toggle",rawName:"v-collapse-toggle"}],staticClass:"searchwp-metrics__accordion--trigger"},[_c('div',{staticClass:"searchwp-metrics__accordion--header-icon"},[_c('span',{staticClass:"dashicons dashicons-arrow-right"})]),_vm._v(" "),_c('h5',{staticClass:"searchwp-metrics__accordion--header-title"},[_vm._v("\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"+_vm._s(popularSearchDetail.query.query)+"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__accordion--header-figure"},[_vm._v("\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"+_vm._s(popularSearchDetail.query.searchcount)+"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")])]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__accordion--actions"},[_c('delete',{on:{"onclick":function($event){return _vm.ignorePopularSearch(popularSearchDetail.query.query, popularSearchDetailIndex)}}})],1)]),_vm._v(" "),_c('div',{directives:[{name:"collapse-content",rawName:"v-collapse-content"}],staticClass:"searchwp-metrics__accordion--content"},[_c('div',{staticClass:"searchwp-metrics__inner"},[(popularSearchDetail.clicks.length)?_c('div',[_c('bar-chart',{attrs:{"datacollection":_vm.buildChartDataset(popularSearchDetail.clicks),"options":_vm.popularSearchDetailsClicksOptions,"height":'30px'}}),_vm._v(" "),_c('table',[_c('thead',[_c('tr',[_c('th',{staticClass:"searchwp-metrics--primary-col"},[_vm._v(_vm._s(_vm.i18n.clickedResult))]),_vm._v(" "),_c('th',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(_vm.i18n.clicks))]),_vm._v(" "),_c('th',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(_vm.i18n.conversionRate))])])]),_vm._v(" "),_c('tbody',_vm._l((popularSearchDetail.clicks),function(popularSearchDetailClicks,popularSearchDetailClicksIndex){return _c('tr',{key:'popularSearchDetailClicks' + _vm.showingPopularSearchDetails.engine.name + popularSearchDetailClicksIndex},[_c('td',{staticClass:"searchwp-metrics--primary-col"},[_c('a',{attrs:{"href":popularSearchDetailClicks.permalink,"target":"_blank"}},[_c('legend-indicator',{attrs:{"index":popularSearchDetailClicksIndex,"text":popularSearchDetailClicks.post_title}})],1)]),_vm._v(" "),_c('td',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(popularSearchDetailClicks.clicks))]),_vm._v(" "),_c('td',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s((( popularSearchDetailClicks.clicks * 100 ) / popularSearchDetail.query.searchcount).toFixed(2))+"%")])])}),0)])],1):_c('div',{staticClass:"searchwp-metrics__no-data"},[_c('p',[_vm._v(_vm._s(_vm.i18n.noClicks))])])])])])}),1)])],1),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__loading-details-loader"},[_c('spinner',{attrs:{"size":55,"line-size":6}})],1)]):_vm._e()])],1),_vm._v(" "),_c('div',[_c('doughnut-chart',{attrs:{"datacollection":_vm.getPopularSearches(engine.name),"options":_vm.popularSearchesOptions}}),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-popular-searches-coverage"},[_c('span',[_vm._v(_vm._s(_vm.getPopularSearchesPercentage(engine.name, engineIndex))+"%")]),_vm._v(" "+_vm._s(_vm.i18n.ofAllSearches)+"\n\t\t\t\t\t\t\t")])],1)]):_vm._e()]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-details-omega searchwp-metrics__engine-suggestions"},[(_vm.getPopularClicks(engine.name))?_c('div',[_c('div',{staticClass:"searchwp-metrics__engine-details--heading"},[_c('h4',[_vm._v(_vm._s(_vm.i18n.insights))])]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__engine-suggestions-insights"},[(_vm.getInsights(engine.name) && _vm.getInsights(engine.name).length)?_c('div',[_c('ul',_vm._l((_vm.getInsights(engine.name)),function(insight,insightIndex){return _c('li',{key:'insight' + engine.name + insightIndex,staticClass:"searchwp-metrics__engine-suggestions-insight"},[(insight.type === 'underdog')?_c('insight-underdog',{attrs:{"post-count":insight.postCount},on:{"onclick":function($event){return _vm.showInsightDetails(engine, insightIndex)}}}):_vm._e(),_vm._v(" "),(insight.type === 'popular')?_c('insight-popular',{attrs:{"post-count":insight.postCount},on:{"onclick":function($event){return _vm.showInsightDetails(engine, insightIndex)}}}):_vm._e(),_vm._v(" "),(insight.type === 'analysis')?_c('insight-analysis',{attrs:{"query":insight.query,"click-count":insight.clickCount,"post-count":insight.postCount},on:{"onclick":function($event){return _vm.showInsightDetails(engine, insightIndex)}}}):_vm._e()],1)}),0),_vm._v(" "),(_vm.getInsightsCount(engine.name) > 5)?_c('div',{staticClass:"searchwp-metrics__engine-suggestions-insights-actions"},[_c('button',{staticClass:"button",on:{"click":function($event){$event.preventDefault();return _vm.showInsightDetails(engine)}}},[_vm._v(_vm._s(_vm.i18n.viewAll)+" ("+_vm._s(_vm.getInsightsCount(engine.name))+")")])]):_vm._e()]):_c('div',{staticClass:"searchwp-metrics__note"},[_c('span',{staticClass:"dashicons dashicons-info"}),_vm._v(" "),_c('div',[_c('p',[_vm._v(_vm._s(_vm.i18n.noInsights))])])])]),_vm._v(" "),_c('vue-modaltor',{attrs:{"visible":_vm.showingInsights && _vm.showingInsights.engine.name === engine.name,"default-width":'600px'},on:{"hide":_vm.hideInsights}},[(_vm.showingInsights && _vm.showingInsights.engine.name === engine.name)?_c('div',{staticClass:"searchwp-metrics__modal searchwp-metrics__engine-suggestions-insights-details"},[_c(_vm.translatedInsightsEngineHeading,{tag:"component",attrs:{"props":engine}}),_vm._v(" "),_c('v-collapse-group',[_c('div',{staticClass:"searchwp-metrics__accordion"},_vm._l((_vm.getInsights(engine.name, -1)),function(insightDetail,insightDetailIndex){return _c('v-collapse-wrapper',{key:'insightDetail' + engine.name + insightDetailIndex,attrs:{"active":insightDetailIndex === _vm.showingInsights.insightIndex}},[_c('div',{staticClass:"searchwp-metrics__accordion--header"},[_c('div',{directives:[{name:"collapse-toggle",rawName:"v-collapse-toggle"}],staticClass:"searchwp-metrics__accordion--trigger"},[_c('div',{staticClass:"searchwp-metrics__accordion--header-icon"},[(insightDetail.type === 'underdog')?_c('span',{staticClass:"dashicons dashicons-sos"}):_vm._e(),_vm._v(" "),(insightDetail.type === 'popular')?_c('span',{staticClass:"dashicons dashicons-awards"}):_vm._e(),_vm._v(" "),(insightDetail.type === 'analysis')?_c('span',{staticClass:"dashicons dashicons-arrow-right"}):_vm._e()]),_vm._v(" "),_c('div',{staticClass:"searchwp-metrics__accordion--header-title"},[(insightDetail.type === 'underdog')?_c('insight-underdog',{attrs:{"post-count":insightDetail.postCount,"icon":''}}):_vm._e(),_vm._v(" "),(insightDetail.type === 'popular')?_c('insight-popular',{attrs:{"post-count":insightDetail.postCount,"icon":''}}):_vm._e(),_vm._v(" "),(insightDetail.type === 'analysis')?_c('insight-analysis',{attrs:{"query":insightDetail.query,"click-count":insightDetail.clickCount,"post-count":insightDetail.postCount,"icon":''}}):_vm._e()],1)])]),_vm._v(" "),_c('div',{directives:[{name:"collapse-content",rawName:"v-collapse-content"}],staticClass:"searchwp-metrics__accordion--content"},[_c('div',{staticClass:"searchwp-metrics__inner"},[(insightDetail.type === 'underdog')?_c('div',[_c('table',[_c('thead',[_c('tr',[_c('th',{staticClass:"searchwp-metrics--primary-col"},[_vm._v(_vm._s(_vm.i18n.entry))]),_vm._v(" "),_c('th',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(_vm.i18n.clicks))]),_vm._v(" "),_c('th',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(_vm.i18n.averageRank))])])]),_vm._v(" "),_c('tbody',_vm._l((insightDetail.posts),function(insightPost,insightPostIndex){return _c('tr',{key:'insightPost' + engine.name + insightPostIndex},[_c('td',{staticClass:"searchwp-metrics--primary-col"},[_c('a',{attrs:{"href":insightPost.permalink,"target":"_blank"}},[_vm._v("\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"+_vm._s(insightPost.post_title)+"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")])]),_vm._v(" "),_c('td',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(insightPost.click_count))]),_vm._v(" "),_c('td',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(insightPost.avg_rank))])])}),0)])]):_vm._e(),_vm._v(" "),(insightDetail.type === 'popular')?_c('div',[_c('table',[_c('thead',[_c('tr',[_c('th',{staticClass:"searchwp-metrics--primary-col"},[_vm._v(_vm._s(_vm.i18n.entry))]),_vm._v(" "),_c('th',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(_vm.i18n.clicks))])])]),_vm._v(" "),_c('tbody',_vm._l((insightDetail.posts),function(insightPost,insightPostIndex){return _c('tr',{key:'insightPost' + engine.name + insightPostIndex},[_c('td',{staticClass:"searchwp-metrics--primary-col"},[_c('a',{attrs:{"href":insightPost.permalink,"target":"_blank"}},[_vm._v("\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"+_vm._s(insightPost.post_title)+"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")])]),_vm._v(" "),_c('td',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(insightPost.clicks))])])}),0)])]):_vm._e(),_vm._v(" "),(insightDetail.type === 'analysis')?_c('div',[_c('bar-chart',{attrs:{"datacollection":_vm.buildChartDataset(insightDetail.posts, insightDetail.clickCount),"options":_vm.popularSearchDetailsClicksOptions,"height":'30px'}}),_vm._v(" "),_c('table',[_c('thead',[_c('tr',[_c('th',{staticClass:"searchwp-metrics--primary-col"},[_vm._v(_vm._s(_vm.i18n.entry))]),_vm._v(" "),_c('th',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(_vm.i18n.clicks))])])]),_vm._v(" "),_c('tbody',_vm._l((insightDetail.posts),function(insightDetailInfo,insightDetailIndex){return _c('tr',{key:'insightDetail' + engine.name + insightDetailIndex},[_c('td',{staticClass:"searchwp-metrics--primary-col"},[_c('a',{attrs:{"href":insightDetailInfo.permalink,"target":"_blank"}},[_c('legend-indicator',{attrs:{"index":insightDetailIndex,"text":insightDetailInfo.post_title}})],1)]),_vm._v(" "),_c('td',{staticClass:"searchwp-metrics--secondary-col"},[_vm._v(_vm._s(insightDetailInfo.clicks))])])}),0)])],1):_vm._e()])])])}),1)])],1):_vm._e()])],1):_vm._e()])])]):_vm._e()})],2),_vm._v(" "),_c('transition',{attrs:{"name":"fade"}},[(_vm.loading)?_c('div',{staticClass:"searchwp-metrics__loading",style:({ top: _vm.loaderPositionTop + 'px', left: _vm.loaderPositionLeft + 'px' })},[_c('spinner',{attrs:{"size":55,"line-size":6}})],1):_vm._e()])],1)};
	var __vue_staticRenderFns__$c = [];

	  /* style */
	  const __vue_inject_styles__$c = undefined;
	  /* scoped */
	  const __vue_scope_id__$c = undefined;
	  /* module identifier */
	  const __vue_module_identifier__$c = undefined;
	  /* functional template */
	  const __vue_is_functional_template__$c = false;
	  /* style inject */
	  
	  /* style inject SSR */
	  
	  /* style inject shadow dom */
	  

	  
	  const __vue_component__$c = /*#__PURE__*/normalizeComponent(
	    { render: __vue_render__$c, staticRenderFns: __vue_staticRenderFns__$c },
	    __vue_inject_styles__$c,
	    __vue_script__$c,
	    __vue_scope_id__$c,
	    __vue_is_functional_template__$c,
	    __vue_module_identifier__$c,
	    false,
	    undefined,
	    undefined,
	    undefined
	  );

	Vue$1.use(VueModalTor);
	Vue$1.use(plugin);
	Vue$1.use(VueCollapse);
	Vue$1.use(SearchwpMetricsColors);
	Vue$1.use(SearchwpMetricsFormatFor);

	new Vue$1({
	  el: '#searchwp-metrics',
	  render: h => h(__vue_component__$c)
	});

}());

Zerion Mini Shell 1.0