/*!
 * jQuery JavaScript Library v3.7.1
 * https://jquery.com/
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license
 * https://jquery.org/license
 *
 * Date: 2023-08-28T13:37Z
 */
( function( global, factory ) {

	"use strict";

	if ( typeof module === "object" && typeof module.exports === "object" ) {

		// For CommonJS and CommonJS-like environments where a proper `window`
		// is present, execute the factory and get jQuery.
		// For environments that do not have a `window` with a `document`
		// (such as Node.js), expose a factory as module.exports.
		// This accentuates the need for the creation of a real `window`.
		// e.g. var jQuery = require("jquery")(window);
		// See ticket trac-14549 for more info.
		module.exports = global.document ?
			factory( global, true ) :
			function( w ) {
				if ( !w.document ) {
					throw new Error( "jQuery requires a window with a document" );
				}
				return factory( w );
			};
	} else {
		factory( global );
	}

// Pass this if window is not defined yet
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {

// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
// enough that all such attempts are guarded in a try block.
"use strict";

var arr = [];

var getProto = Object.getPrototypeOf;

var slice = arr.slice;

var flat = arr.flat ? function( array ) {
	return arr.flat.call( array );
} : function( array ) {
	return arr.concat.apply( [], array );
};


var push = arr.push;

var indexOf = arr.indexOf;

var class2type = {};

var toString = class2type.toString;

var hasOwn = class2type.hasOwnProperty;

var fnToString = hasOwn.toString;

var ObjectFunctionString = fnToString.call( Object );

var support = {};

var isFunction = function isFunction( obj ) {

		// Support: Chrome <=57, Firefox <=52
		// In some browsers, typeof returns "function" for HTML <object> elements
		// (i.e., `typeof document.createElement( "object" ) === "function"`).
		// We don't want to classify *any* DOM node as a function.
		// Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5
		// Plus for old WebKit, typeof returns "function" for HTML collections
		// (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756)
		return typeof obj === "function" && typeof obj.nodeType !== "number" &&
			typeof obj.item !== "function";
	};


var isWindow = function isWindow( obj ) {
		return obj != null && obj === obj.window;
	};


var document = window.document;



	var preservedScriptAttributes = {
		type: true,
		src: true,
		nonce: true,
		noModule: true
	};

	function DOMEval( code, node, doc ) {
		doc = doc || document;

		var i, val,
			script = doc.createElement( "script" );

		script.text = code;
		if ( node ) {
			for ( i in preservedScriptAttributes ) {

				// Support: Firefox 64+, Edge 18+
				// Some browsers don't support the "nonce" property on scripts.
				// On the other hand, just using `getAttribute` is not enough as
				// the `nonce` attribute is reset to an empty string whenever it
				// becomes browsing-context connected.
				// See https://github.com/whatwg/html/issues/2369
				// See https://html.spec.whatwg.org/#nonce-attributes
				// The `node.getAttribute` check was added for the sake of
				// `jQuery.globalEval` so that it can fake a nonce-containing node
				// via an object.
				val = node[ i ] || node.getAttribute && node.getAttribute( i );
				if ( val ) {
					script.setAttribute( i, val );
				}
			}
		}
		doc.head.appendChild( script ).parentNode.removeChild( script );
	}


function toType( obj ) {
	if ( obj == null ) {
		return obj + "";
	}

	// Support: Android <=2.3 only (functionish RegExp)
	return typeof obj === "object" || typeof obj === "function" ?
		class2type[ toString.call( obj ) ] || "object" :
		typeof obj;
}
/* global Symbol */
// Defining this global in .eslintrc.json would create a danger of using the global
// unguarded in another place, it seems safer to define global only for this module



var version = "3.7.1",

	rhtmlSuffix = /HTML$/i,

	// Define a local copy of jQuery
	jQuery = function( selector, context ) {

		// The jQuery object is actually just the init constructor 'enhanced'
		// Need init if jQuery is called (just allow error to be thrown if not included)
		return new jQuery.fn.init( selector, context );
	};

jQuery.fn = jQuery.prototype = {

	// The current version of jQuery being used
	jquery: version,

	constructor: jQuery,

	// The default length of a jQuery object is 0
	length: 0,

	toArray: function() {
		return slice.call( this );
	},

	// Get the Nth element in the matched element set OR
	// Get the whole matched element set as a clean array
	get: function( num ) {

		// Return all the elements in a clean array
		if ( num == null ) {
			return slice.call( this );
		}

		// Return just the one element from the set
		return num < 0 ? this[ num + this.length ] : this[ num ];
	},

	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems ) {

		// Build a new jQuery matched element set
		var ret = jQuery.merge( this.constructor(), elems );

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;

		// Return the newly-formed element set
		return ret;
	},

	// Execute a callback for every element in the matched set.
	each: function( callback ) {
		return jQuery.each( this, callback );
	},

	map: function( callback ) {
		return this.pushStack( jQuery.map( this, function( elem, i ) {
			return callback.call( elem, i, elem );
		} ) );
	},

	slice: function() {
		return this.pushStack( slice.apply( this, arguments ) );
	},

	first: function() {
		return this.eq( 0 );
	},

	last: function() {
		return this.eq( -1 );
	},

	even: function() {
		return this.pushStack( jQuery.grep( this, function( _elem, i ) {
			return ( i + 1 ) % 2;
		} ) );
	},

	odd: function() {
		return this.pushStack( jQuery.grep( this, function( _elem, i ) {
			return i % 2;
		} ) );
	},

	eq: function( i ) {
		var len = this.length,
			j = +i + ( i < 0 ? len : 0 );
		return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
	},

	end: function() {
		return this.prevObject || this.constructor();
	},

	// For internal use only.
	// Behaves like an Array's method, not like a jQuery method.
	push: push,
	sort: arr.sort,
	splice: arr.splice
};

jQuery.extend = jQuery.fn.extend = function() {
	var options, name, src, copy, copyIsArray, clone,
		target = arguments[ 0 ] || {},
		i = 1,
		length = arguments.length,
		deep = false;

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;

		// Skip the boolean and the target
		target = arguments[ i ] || {};
		i++;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !isFunction( target ) ) {
		target = {};
	}

	// Extend jQuery itself if only one argument is passed
	if ( i === length ) {
		target = this;
		i--;
	}

	for ( ; i < length; i++ ) {

		// Only deal with non-null/undefined values
		if ( ( options = arguments[ i ] ) != null ) {

			// Extend the base object
			for ( name in options ) {
				copy = options[ name ];

				// Prevent Object.prototype pollution
				// Prevent never-ending loop
				if ( name === "__proto__" || target === copy ) {
					continue;
				}

				// Recurse if we're merging plain objects or arrays
				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
					( copyIsArray = Array.isArray( copy ) ) ) ) {
					src = target[ name ];

					// Ensure proper type for the source value
					if ( copyIsArray && !Array.isArray( src ) ) {
						clone = [];
					} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
						clone = {};
					} else {
						clone = src;
					}
					copyIsArray = false;

					// Never move original objects, clone them
					target[ name ] = jQuery.extend( deep, clone, copy );

				// Don't bring in undefined values
				} else if ( copy !== undefined ) {
					target[ name ] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};

jQuery.extend( {

	// Unique for each copy of jQuery on the page
	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),

	// Assume jQuery is ready without the ready module
	isReady: true,

	error: function( msg ) {
		throw new Error( msg );
	},

	noop: function() {},

	isPlainObject: function( obj ) {
		var proto, Ctor;

		// Detect obvious negatives
		// Use toString instead of jQuery.type to catch host objects
		if ( !obj || toString.call( obj ) !== "[object Object]" ) {
			return false;
		}

		proto = getProto( obj );

		// Objects with no prototype (e.g., `Object.create( null )`) are plain
		if ( !proto ) {
			return true;
		}

		// Objects with prototype are plain iff they were constructed by a global Object function
		Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
		return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
	},

	isEmptyObject: function( obj ) {
		var name;

		for ( name in obj ) {
			return false;
		}
		return true;
	},

	// Evaluates a script in a provided context; falls back to the global one
	// if not specified.
	globalEval: function( code, options, doc ) {
		DOMEval( code, { nonce: options && options.nonce }, doc );
	},

	each: function( obj, callback ) {
		var length, i = 0;

		if ( isArrayLike( obj ) ) {
			length = obj.length;
			for ( ; i < length; i++ ) {
				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
					break;
				}
			}
		} else {
			for ( i in obj ) {
				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
					break;
				}
			}
		}

		return obj;
	},


	// Retrieve the text value of an array of DOM nodes
	text: function( elem ) {
		var node,
			ret = "",
			i = 0,
			nodeType = elem.nodeType;

		if ( !nodeType ) {

			// If no nodeType, this is expected to be an array
			while ( ( node = elem[ i++ ] ) ) {

				// Do not traverse comment nodes
				ret += jQuery.text( node );
			}
		}
		if ( nodeType === 1 || nodeType === 11 ) {
			return elem.textContent;
		}
		if ( nodeType === 9 ) {
			return elem.documentElement.textContent;
		}
		if ( nodeType === 3 || nodeType === 4 ) {
			return elem.nodeValue;
		}

		// Do not include comment or processing instruction nodes

		return ret;
	},

	// results is for internal usage only
	makeArray: function( arr, results ) {
		var ret = results || [];

		if ( arr != null ) {
			if ( isArrayLike( Object( arr ) ) ) {
				jQuery.merge( ret,
					typeof arr === "string" ?
						[ arr ] : arr
				);
			} else {
				push.call( ret, arr );
			}
		}

		return ret;
	},

	inArray: function( elem, arr, i ) {
		return arr == null ? -1 : indexOf.call( arr, elem, i );
	},

	isXMLDoc: function( elem ) {
		var namespace = elem && elem.namespaceURI,
			docElem = elem && ( elem.ownerDocument || elem ).documentElement;

		// Assume HTML when documentElement doesn't yet exist, such as inside
		// document fragments.
		return !rhtmlSuffix.test( namespace || docElem && docElem.nodeName || "HTML" );
	},

	// Support: Android <=4.0 only, PhantomJS 1 only
	// push.apply(_, arraylike) throws on ancient WebKit
	merge: function( first, second ) {
		var len = +second.length,
			j = 0,
			i = first.length;

		for ( ; j < len; j++ ) {
			first[ i++ ] = second[ j ];
		}

		first.length = i;

		return first;
	},

	grep: function( elems, callback, invert ) {
		var callbackInverse,
			matches = [],
			i = 0,
			length = elems.length,
			callbackExpect = !invert;

		// Go through the array, only saving the items
		// that pass the validator function
		for ( ; i < length; i++ ) {
			callbackInverse = !callback( elems[ i ], i );
			if ( callbackInverse !== callbackExpect ) {
				matches.push( elems[ i ] );
			}
		}

		return matches;
	},

	// arg is for internal usage only
	map: function( elems, callback, arg ) {
		var length, value,
			i = 0,
			ret = [];

		// Go through the array, translating each of the items to their new values
		if ( isArrayLike( elems ) ) {
			length = elems.length;
			for ( ; i < length; i++ ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret.push( value );
				}
			}

		// Go through every key on the object,
		} else {
			for ( i in elems ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret.push( value );
				}
			}
		}

		// Flatten any nested arrays
		return flat( ret );
	},

	// A global GUID counter for objects
	guid: 1,

	// jQuery.support is not used in Core but other projects attach their
	// properties to it so it needs to exist.
	support: support
} );

if ( typeof Symbol === "function" ) {
	jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
}

// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
	function( _i, name ) {
		class2type[ "[object " + name + "]" ] = name.toLowerCase();
	} );

function isArrayLike( obj ) {

	// Support: real iOS 8.2 only (not reproducible in simulator)
	// `in` check used to prevent JIT error (gh-2145)
	// hasOwn isn't used here due to false negatives
	// regarding Nodelist length in IE
	var length = !!obj && "length" in obj && obj.length,
		type = toType( obj );

	if ( isFunction( obj ) || isWindow( obj ) ) {
		return false;
	}

	return type === "array" || length === 0 ||
		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}


function nodeName( elem, name ) {

	return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();

}
var pop = arr.pop;


var sort = arr.sort;


var splice = arr.splice;


var whitespace = "[\\x20\\t\\r\\n\\f]";


var rtrimCSS = new RegExp(
	"^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$",
	"g"
);




// Note: an element does not contain itself
jQuery.contains = function( a, b ) {
	var bup = b && b.parentNode;

	return a === bup || !!( bup && bup.nodeType === 1 && (

		// Support: IE 9 - 11+
		// IE doesn't have `contains` on SVG.
		a.contains ?
			a.contains( bup ) :
			a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
	) );
};




// CSS string/identifier serialization
// https://drafts.csswg.org/cssom/#common-serializing-idioms
var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;

function fcssescape( ch, asCodePoint ) {
	if ( asCodePoint ) {

		// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
		if ( ch === "\0" ) {
			return "\uFFFD";
		}

		// Control characters and (dependent upon position) numbers get escaped as code points
		return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
	}

	// Other potentially-special ASCII characters get backslash-escaped
	return "\\" + ch;
}

jQuery.escapeSelector = function( sel ) {
	return ( sel + "" ).replace( rcssescape, fcssescape );
};




var preferredDoc = document,
	pushNative = push;

( function() {

var i,
	Expr,
	outermostContext,
	sortInput,
	hasDuplicate,
	push = pushNative,

	// Local document vars
	document,
	documentElement,
	documentIsHTML,
	rbuggyQSA,
	matches,

	// Instance-specific data
	expando = jQuery.expando,
	dirruns = 0,
	done = 0,
	classCache = createCache(),
	tokenCache = createCache(),
	compilerCache = createCache(),
	nonnativeSelectorCache = createCache(),
	sortOrder = function( a, b ) {
		if ( a === b ) {
			hasDuplicate = true;
		}
		return 0;
	},

	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|" +
		"loop|multiple|open|readonly|required|scoped",

	// Regular expressions

	// https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
	identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
		"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",

	// Attribute selectors: https://www.w3.org/TR/selectors/#attribute-selectors
	attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +

		// Operator (capture 2)
		"*([*^$|!~]?=)" + whitespace +

		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
		whitespace + "*\\]",

	pseudos = ":(" + identifier + ")(?:\\((" +

		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
		// 1. quoted (capture 3; capture 4 or capture 5)
		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +

		// 2. simple (capture 6)
		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +

		// 3. anything else (capture 2)
		".*" +
		")\\)|)",

	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
	rwhitespace = new RegExp( whitespace + "+", "g" ),

	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
	rleadingCombinator = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" +
		whitespace + "*" ),
	rdescend = new RegExp( whitespace + "|>" ),

	rpseudo = new RegExp( pseudos ),
	ridentifier = new RegExp( "^" + identifier + "$" ),

	matchExpr = {
		ID: new RegExp( "^#(" + identifier + ")" ),
		CLASS: new RegExp( "^\\.(" + identifier + ")" ),
		TAG: new RegExp( "^(" + identifier + "|[*])" ),
		ATTR: new RegExp( "^" + attributes ),
		PSEUDO: new RegExp( "^" + pseudos ),
		CHILD: new RegExp(
			"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
				whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
				whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
		bool: new RegExp( "^(?:" + booleans + ")$", "i" ),

		// For use in libraries implementing .is()
		// We use this for POS matching in `select`
		needsContext: new RegExp( "^" + whitespace +
			"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
			"*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
	},

	rinputs = /^(?:input|select|textarea|button)$/i,
	rheader = /^h\d$/i,

	// Easily-parseable/retrievable ID or TAG or CLASS selectors
	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,

	rsibling = /[+~]/,

	// CSS escapes
	// https://www.w3.org/TR/CSS21/syndata.html#escaped-characters
	runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace +
		"?|\\\\([^\\r\\n\\f])", "g" ),
	funescape = function( escape, nonHex ) {
		var high = "0x" + escape.slice( 1 ) - 0x10000;

		if ( nonHex ) {

			// Strip the backslash prefix from a non-hex escape sequence
			return nonHex;
		}

		// Replace a hexadecimal escape sequence with the encoded Unicode code point
		// Support: IE <=11+
		// For values outside the Basic Multilingual Plane (BMP), manually construct a
		// surrogate pair
		return high < 0 ?
			String.fromCharCode( high + 0x10000 ) :
			String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
	},

	// Used for iframes; see `setDocument`.
	// Support: IE 9 - 11+, Edge 12 - 18+
	// Removing the function wrapper causes a "Permission Denied"
	// error in IE/Edge.
	unloadHandler = function() {
		setDocument();
	},

	inDisabledFieldset = addCombinator(
		function( elem ) {
			return elem.disabled === true && nodeName( elem, "fieldset" );
		},
		{ dir: "parentNode", next: "legend" }
	);

// Support: IE <=9 only
// Accessing document.activeElement can throw unexpectedly
// https://bugs.jquery.com/ticket/13393
function safeActiveElement() {
	try {
		return document.activeElement;
	} catch ( err ) { }
}

// Optimize for push.apply( _, NodeList )
try {
	push.apply(
		( arr = slice.call( preferredDoc.childNodes ) ),
		preferredDoc.childNodes
	);

	// Support: Android <=4.0
	// Detect silently failing push.apply
	// eslint-disable-next-line no-unused-expressions
	arr[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
	push = {
		apply: function( target, els ) {
			pushNative.apply( target, slice.call( els ) );
		},
		call: function( target ) {
			pushNative.apply( target, slice.call( arguments, 1 ) );
		}
	};
}

function find( selector, context, results, seed ) {
	var m, i, elem, nid, match, groups, newSelector,
		newContext = context && context.ownerDocument,

		// nodeType defaults to 9, since context defaults to document
		nodeType = context ? context.nodeType : 9;

	results = results || [];

	// Return early from calls with invalid selector or context
	if ( typeof selector !== "string" || !selector ||
		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {

		return results;
	}

	// Try to shortcut find operations (as opposed to filters) in HTML documents
	if ( !seed ) {
		setDocument( context );
		context = context || document;

		if ( documentIsHTML ) {

			// If the selector is sufficiently simple, try using a "get*By*" DOM method
			// (excepting DocumentFragment context, where the methods don't exist)
			if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {

				// ID selector
				if ( ( m = match[ 1 ] ) ) {

					// Document context
					if ( nodeType === 9 ) {
						if ( ( elem = context.getElementById( m ) ) ) {

							// Support: IE 9 only
							// getElementById can match elements by name instead of ID
							if ( elem.id === m ) {
								push.call( results, elem );
								return results;
							}
						} else {
							return results;
						}

					// Element context
					} else {

						// Support: IE 9 only
						// getElementById can match elements by name instead of ID
						if ( newContext && ( elem = newContext.getElementById( m ) ) &&
							find.contains( context, elem ) &&
							elem.id === m ) {

							push.call( results, elem );
							return results;
						}
					}

				// Type selector
				} else if ( match[ 2 ] ) {
					push.apply( results, context.getElementsByTagName( selector ) );
					return results;

				// Class selector
				} else if ( ( m = match[ 3 ] ) && context.getElementsByClassName ) {
					push.apply( results, context.getElementsByClassName( m ) );
					return results;
				}
			}

			// Take advantage of querySelectorAll
			if ( !nonnativeSelectorCache[ selector + " " ] &&
				( !rbuggyQSA || !rbuggyQSA.test( selector ) ) ) {

				newSelector = selector;
				newContext = context;

				// qSA considers elements outside a scoping root when evaluating child or
				// descendant combinators, which is not what we want.
				// In such cases, we work around the behavior by prefixing every selector in the
				// list with an ID selector referencing the scope context.
				// The technique has to be used as well when a leading combinator is used
				// as such selectors are not recognized by querySelectorAll.
				// Thanks to Andrew Dupont for this technique.
				if ( nodeType === 1 &&
					( rdescend.test( selector ) || rleadingCombinator.test( selector ) ) ) {

					// Expand context for sibling selectors
					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
						context;

					// We can use :scope instead of the ID hack if the browser
					// supports it & if we're not changing the context.
					// Support: IE 11+, Edge 17 - 18+
					// IE/Edge sometimes throw a "Permission denied" error when
					// strict-comparing two documents; shallow comparisons work.
					// eslint-disable-next-line eqeqeq
					if ( newContext != context || !support.scope ) {

						// Capture the context ID, setting it first if necessary
						if ( ( nid = context.getAttribute( "id" ) ) ) {
							nid = jQuery.escapeSelector( nid );
						} else {
							context.setAttribute( "id", ( nid = expando ) );
						}
					}

					// Prefix every selector in the list
					groups = tokenize( selector );
					i = groups.length;
					while ( i-- ) {
						groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
							toSelector( groups[ i ] );
					}
					newSelector = groups.join( "," );
				}

				try {
					push.apply( results,
						newContext.querySelectorAll( newSelector )
					);
					return results;
				} catch ( qsaError ) {
					nonnativeSelectorCache( selector, true );
				} finally {
					if ( nid === expando ) {
						context.removeAttribute( "id" );
					}
				}
			}
		}
	}

	// All others
	return select( selector.replace( rtrimCSS, "$1" ), context, results, seed );
}

/**
 * Create key-value caches of limited size
 * @returns {function(string, object)} Returns the Object data after storing it on itself with
 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
 *	deleting the oldest entry
 */
function createCache() {
	var keys = [];

	function cache( key, value ) {

		// Use (key + " ") to avoid collision with native prototype properties
		// (see https://github.com/jquery/sizzle/issues/157)
		if ( keys.push( key + " " ) > Expr.cacheLength ) {

			// Only keep the most recent entries
			delete cache[ keys.shift() ];
		}
		return ( cache[ key + " " ] = value );
	}
	return cache;
}

/**
 * Mark a function for special use by jQuery selector module
 * @param {Function} fn The function to mark
 */
function markFunction( fn ) {
	fn[ expando ] = true;
	return fn;
}

/**
 * Support testing using an element
 * @param {Function} fn Passed the created element and returns a boolean result
 */
function assert( fn ) {
	var el = document.createElement( "fieldset" );

	try {
		return !!fn( el );
	} catch ( e ) {
		return false;
	} finally {

		// Remove from its parent by default
		if ( el.parentNode ) {
			el.parentNode.removeChild( el );
		}

		// release memory in IE
		el = null;
	}
}

/**
 * Returns a function to use in pseudos for input types
 * @param {String} type
 */
function createInputPseudo( type ) {
	return function( elem ) {
		return nodeName( elem, "input" ) && elem.type === type;
	};
}

/**
 * Returns a function to use in pseudos for buttons
 * @param {String} type
 */
function createButtonPseudo( type ) {
	return function( elem ) {
		return ( nodeName( elem, "input" ) || nodeName( elem, "button" ) ) &&
			elem.type === type;
	};
}

/**
 * Returns a function to use in pseudos for :enabled/:disabled
 * @param {Boolean} disabled true for :disabled; false for :enabled
 */
function createDisabledPseudo( disabled ) {

	// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
	return function( elem ) {

		// Only certain elements can match :enabled or :disabled
		// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
		// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
		if ( "form" in elem ) {

			// Check for inherited disabledness on relevant non-disabled elements:
			// * listed form-associated elements in a disabled fieldset
			//   https://html.spec.whatwg.org/multipage/forms.html#category-listed
			//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
			// * option elements in a disabled optgroup
			//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
			// All such elements have a "form" property.
			if ( elem.parentNode && elem.disabled === false ) {

				// Option elements defer to a parent optgroup if present
				if ( "label" in elem ) {
					if ( "label" in elem.parentNode ) {
						return elem.parentNode.disabled === disabled;
					} else {
						return elem.disabled === disabled;
					}
				}

				// Support: IE 6 - 11+
				// Use the isDisabled shortcut property to check for disabled fieldset ancestors
				return elem.isDisabled === disabled ||

					// Where there is no isDisabled, check manually
					elem.isDisabled !== !disabled &&
						inDisabledFieldset( elem ) === disabled;
			}

			return elem.disabled === disabled;

		// Try to winnow out elements that can't be disabled before trusting the disabled property.
		// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
		// even exist on them, let alone have a boolean value.
		} else if ( "label" in elem ) {
			return elem.disabled === disabled;
		}

		// Remaining elements are neither :enabled nor :disabled
		return false;
	};
}

/**
 * Returns a function to use in pseudos for positionals
 * @param {Function} fn
 */
function createPositionalPseudo( fn ) {
	return markFunction( function( argument ) {
		argument = +argument;
		return markFunction( function( seed, matches ) {
			var j,
				matchIndexes = fn( [], seed.length, argument ),
				i = matchIndexes.length;

			// Match elements found at the specified indexes
			while ( i-- ) {
				if ( seed[ ( j = matchIndexes[ i ] ) ] ) {
					seed[ j ] = !( matches[ j ] = seed[ j ] );
				}
			}
		} );
	} );
}

/**
 * Checks a node for validity as a jQuery selector context
 * @param {Element|Object=} context
 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
 */
function testContext( context ) {
	return context && typeof context.getElementsByTagName !== "undefined" && context;
}

/**
 * Sets document-related variables once based on the current document
 * @param {Element|Object} [node] An element or document object to use to set the document
 * @returns {Object} Returns the current document
 */
function setDocument( node ) {
	var subWindow,
		doc = node ? node.ownerDocument || node : preferredDoc;

	// Return early if doc is invalid or already selected
	// Support: IE 11+, Edge 17 - 18+
	// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
	// two documents; shallow comparisons work.
	// eslint-disable-next-line eqeqeq
	if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {
		return document;
	}

	// Update global variables
	document = doc;
	documentElement = document.documentElement;
	documentIsHTML = !jQuery.isXMLDoc( document );

	// Support: iOS 7 only, IE 9 - 11+
	// Older browsers didn't support unprefixed `matches`.
	matches = documentElement.matches ||
		documentElement.webkitMatchesSelector ||
		documentElement.msMatchesSelector;

	// Support: IE 9 - 11+, Edge 12 - 18+
	// Accessing iframe documents after unload throws "permission denied" errors
	// (see trac-13936).
	// Limit the fix to IE & Edge Legacy; despite Edge 15+ implementing `matches`,
	// all IE 9+ and Edge Legacy versions implement `msMatchesSelector` as well.
	if ( documentElement.msMatchesSelector &&

		// Support: IE 11+, Edge 17 - 18+
		// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
		// two documents; shallow comparisons work.
		// eslint-disable-next-line eqeqeq
		preferredDoc != document &&
		( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {

		// Support: IE 9 - 11+, Edge 12 - 18+
		subWindow.addEventListener( "unload", unloadHandler );
	}

	// Support: IE <10
	// Check if getElementById returns elements by name
	// The broken getElementById methods don't pick up programmatically-set names,
	// so use a roundabout getElementsByName test
	support.getById = assert( function( el ) {
		documentElement.appendChild( el ).id = jQuery.expando;
		return !document.getElementsByName ||
			!document.getElementsByName( jQuery.expando ).length;
	} );

	// Support: IE 9 only
	// Check to see if it's possible to do matchesSelector
	// on a disconnected node.
	support.disconnectedMatch = assert( function( el ) {
		return matches.call( el, "*" );
	} );

	// Support: IE 9 - 11+, Edge 12 - 18+
	// IE/Edge don't support the :scope pseudo-class.
	support.scope = assert( function() {
		return document.querySelectorAll( ":scope" );
	} );

	// Support: Chrome 105 - 111 only, Safari 15.4 - 16.3 only
	// Make sure the `:has()` argument is parsed unforgivingly.
	// We include `*` in the test to detect buggy implementations that are
	// _selectively_ forgiving (specifically when the list includes at least
	// one valid selector).
	// Note that we treat complete lack of support for `:has()` as if it were
	// spec-compliant support, which is fine because use of `:has()` in such
	// environments will fail in the qSA path and fall back to jQuery traversal
	// anyway.
	support.cssHas = assert( function() {
		try {
			document.querySelector( ":has(*,:jqfake)" );
			return false;
		} catch ( e ) {
			return true;
		}
	} );

	// ID filter and find
	if ( support.getById ) {
		Expr.filter.ID = function( id ) {
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				return elem.getAttribute( "id" ) === attrId;
			};
		};
		Expr.find.ID = function( id, context ) {
			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
				var elem = context.getElementById( id );
				return elem ? [ elem ] : [];
			}
		};
	} else {
		Expr.filter.ID =  function( id ) {
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				var node = typeof elem.getAttributeNode !== "undefined" &&
					elem.getAttributeNode( "id" );
				return node && node.value === attrId;
			};
		};

		// Support: IE 6 - 7 only
		// getElementById is not reliable as a find shortcut
		Expr.find.ID = function( id, context ) {
			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
				var node, i, elems,
					elem = context.getElementById( id );

				if ( elem ) {

					// Verify the id attribute
					node = elem.getAttributeNode( "id" );
					if ( node && node.value === id ) {
						return [ elem ];
					}

					// Fall back on getElementsByName
					elems = context.getElementsByName( id );
					i = 0;
					while ( ( elem = elems[ i++ ] ) ) {
						node = elem.getAttributeNode( "id" );
						if ( node && node.value === id ) {
							return [ elem ];
						}
					}
				}

				return [];
			}
		};
	}

	// Tag
	Expr.find.TAG = function( tag, context ) {
		if ( typeof context.getElementsByTagName !== "undefined" ) {
			return context.getElementsByTagName( tag );

		// DocumentFragment nodes don't have gEBTN
		} else {
			return context.querySelectorAll( tag );
		}
	};

	// Class
	Expr.find.CLASS = function( className, context ) {
		if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
			return context.getElementsByClassName( className );
		}
	};

	/* QSA/matchesSelector
	---------------------------------------------------------------------- */

	// QSA and matchesSelector support

	rbuggyQSA = [];

	// Build QSA regex
	// Regex strategy adopted from Diego Perini
	assert( function( el ) {

		var input;

		documentElement.appendChild( el ).innerHTML =
			"<a id='" + expando + "' href='' disabled='disabled'></a>" +
			"<select id='" + expando + "-\r\\' disabled='disabled'>" +
			"<option selected=''></option></select>";

		// Support: iOS <=7 - 8 only
		// Boolean attributes and "value" are not treated correctly in some XML documents
		if ( !el.querySelectorAll( "[selected]" ).length ) {
			rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
		}

		// Support: iOS <=7 - 8 only
		if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
			rbuggyQSA.push( "~=" );
		}

		// Support: iOS 8 only
		// https://bugs.webkit.org/show_bug.cgi?id=136851
		// In-page `selector#id sibling-combinator selector` fails
		if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
			rbuggyQSA.push( ".#.+[+~]" );
		}

		// Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+
		// In some of the document kinds, these selectors wouldn't work natively.
		// This is probably OK but for backwards compatibility we want to maintain
		// handling them through jQuery traversal in jQuery 3.x.
		if ( !el.querySelectorAll( ":checked" ).length ) {
			rbuggyQSA.push( ":checked" );
		}

		// Support: Windows 8 Native Apps
		// The type and name attributes are restricted during .innerHTML assignment
		input = document.createElement( "input" );
		input.setAttribute( "type", "hidden" );
		el.appendChild( input ).setAttribute( "name", "D" );

		// Support: IE 9 - 11+
		// IE's :disabled selector does not pick up the children of disabled fieldsets
		// Support: Chrome <=105+, Firefox <=104+, Safari <=15.4+
		// In some of the document kinds, these selectors wouldn't work natively.
		// This is probably OK but for backwards compatibility we want to maintain
		// handling them through jQuery traversal in jQuery 3.x.
		documentElement.appendChild( el ).disabled = true;
		if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
			rbuggyQSA.push( ":enabled", ":disabled" );
		}

		// Support: IE 11+, Edge 15 - 18+
		// IE 11/Edge don't find elements on a `[name='']` query in some cases.
		// Adding a temporary attribute to the document before the selection works
		// around the issue.
		// Interestingly, IE 10 & older don't seem to have the issue.
		input = document.createElement( "input" );
		input.setAttribute( "name", "" );
		el.appendChild( input );
		if ( !el.querySelectorAll( "[name='']" ).length ) {
			rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
				whitespace + "*(?:''|\"\")" );
		}
	} );

	if ( !support.cssHas ) {

		// Support: Chrome 105 - 110+, Safari 15.4 - 16.3+
		// Our regular `try-catch` mechanism fails to detect natively-unsupported
		// pseudo-classes inside `:has()` (such as `:has(:contains("Foo"))`)
		// in browsers that parse the `:has()` argument as a forgiving selector list.
		// https://drafts.csswg.org/selectors/#relational now requires the argument
		// to be parsed unforgivingly, but browsers have not yet fully adjusted.
		rbuggyQSA.push( ":has" );
	}

	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );

	/* Sorting
	---------------------------------------------------------------------- */

	// Document order sorting
	sortOrder = function( a, b ) {

		// Flag for duplicate removal
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		// Sort on method existence if only one input has compareDocumentPosition
		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
		if ( compare ) {
			return compare;
		}

		// Calculate position if both inputs belong to the same document
		// Support: IE 11+, Edge 17 - 18+
		// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
		// two documents; shallow comparisons work.
		// eslint-disable-next-line eqeqeq
		compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?
			a.compareDocumentPosition( b ) :

			// Otherwise we know they are disconnected
			1;

		// Disconnected nodes
		if ( compare & 1 ||
			( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {

			// Choose the first element that is related to our preferred document
			// Support: IE 11+, Edge 17 - 18+
			// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
			// two documents; shallow comparisons work.
			// eslint-disable-next-line eqeqeq
			if ( a === document || a.ownerDocument == preferredDoc &&
				find.contains( preferredDoc, a ) ) {
				return -1;
			}

			// Support: IE 11+, Edge 17 - 18+
			// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
			// two documents; shallow comparisons work.
			// eslint-disable-next-line eqeqeq
			if ( b === document || b.ownerDocument == preferredDoc &&
				find.contains( preferredDoc, b ) ) {
				return 1;
			}

			// Maintain original order
			return sortInput ?
				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
				0;
		}

		return compare & 4 ? -1 : 1;
	};

	return document;
}

find.matches = function( expr, elements ) {
	return find( expr, null, null, elements );
};

find.matchesSelector = function( elem, expr ) {
	setDocument( elem );

	if ( documentIsHTML &&
		!nonnativeSelectorCache[ expr + " " ] &&
		( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {

		try {
			var ret = matches.call( elem, expr );

			// IE 9's matchesSelector returns false on disconnected nodes
			if ( ret || support.disconnectedMatch ||

					// As well, disconnected nodes are said to be in a document
					// fragment in IE 9
					elem.document && elem.document.nodeType !== 11 ) {
				return ret;
			}
		} catch ( e ) {
			nonnativeSelectorCache( expr, true );
		}
	}

	return find( expr, document, null, [ elem ] ).length > 0;
};

find.contains = function( context, elem ) {

	// Set document vars if needed
	// Support: IE 11+, Edge 17 - 18+
	// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
	// two documents; shallow comparisons work.
	// eslint-disable-next-line eqeqeq
	if ( ( context.ownerDocument || context ) != document ) {
		setDocument( context );
	}
	return jQuery.contains( context, elem );
};


find.attr = function( elem, name ) {

	// Set document vars if needed
	// Support: IE 11+, Edge 17 - 18+
	// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
	// two documents; shallow comparisons work.
	// eslint-disable-next-line eqeqeq
	if ( ( elem.ownerDocument || elem ) != document ) {
		setDocument( elem );
	}

	var fn = Expr.attrHandle[ name.toLowerCase() ],

		// Don't get fooled by Object.prototype properties (see trac-13807)
		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
			fn( elem, name, !documentIsHTML ) :
			undefined;

	if ( val !== undefined ) {
		return val;
	}

	return elem.getAttribute( name );
};

find.error = function( msg ) {
	throw new Error( "Syntax error, unrecognized expression: " + msg );
};

/**
 * Document sorting and removing duplicates
 * @param {ArrayLike} results
 */
jQuery.uniqueSort = function( results ) {
	var elem,
		duplicates = [],
		j = 0,
		i = 0;

	// Unless we *know* we can detect duplicates, assume their presence
	//
	// Support: Android <=4.0+
	// Testing for detecting duplicates is unpredictable so instead assume we can't
	// depend on duplicate detection in all browsers without a stable sort.
	hasDuplicate = !support.sortStable;
	sortInput = !support.sortStable && slice.call( results, 0 );
	sort.call( results, sortOrder );

	if ( hasDuplicate ) {
		while ( ( elem = results[ i++ ] ) ) {
			if ( elem === results[ i ] ) {
				j = duplicates.push( i );
			}
		}
		while ( j-- ) {
			splice.call( results, duplicates[ j ], 1 );
		}
	}

	// Clear input after sorting to release objects
	// See https://github.com/jquery/sizzle/pull/225
	sortInput = null;

	return results;
};

jQuery.fn.uniqueSort = function() {
	return this.pushStack( jQuery.uniqueSort( slice.apply( this ) ) );
};

Expr = jQuery.expr = {

	// Can be adjusted by the user
	cacheLength: 50,

	createPseudo: markFunction,

	match: matchExpr,

	attrHandle: {},

	find: {},

	relative: {
		">": { dir: "parentNode", first: true },
		" ": { dir: "parentNode" },
		"+": { dir: "previousSibling", first: true },
		"~": { dir: "previousSibling" }
	},

	preFilter: {
		ATTR: function( match ) {
			match[ 1 ] = match[ 1 ].replace( runescape, funescape );

			// Move the given value to match[3] whether quoted or unquoted
			match[ 3 ] = ( match[ 3 ] || match[ 4 ] || match[ 5 ] || "" )
				.replace( runescape, funescape );

			if ( match[ 2 ] === "~=" ) {
				match[ 3 ] = " " + match[ 3 ] + " ";
			}

			return match.slice( 0, 4 );
		},

		CHILD: function( match ) {

			/* matches from matchExpr["CHILD"]
				1 type (only|nth|...)
				2 what (child|of-type)
				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
				4 xn-component of xn+y argument ([+-]?\d*n|)
				5 sign of xn-component
				6 x of xn-component
				7 sign of y-component
				8 y of y-component
			*/
			match[ 1 ] = match[ 1 ].toLowerCase();

			if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {

				// nth-* requires argument
				if ( !match[ 3 ] ) {
					find.error( match[ 0 ] );
				}

				// numeric x and y parameters for Expr.filter.CHILD
				// remember that false/true cast respectively to 0/1
				match[ 4 ] = +( match[ 4 ] ?
					match[ 5 ] + ( match[ 6 ] || 1 ) :
					2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" )
				);
				match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );

			// other types prohibit arguments
			} else if ( match[ 3 ] ) {
				find.error( match[ 0 ] );
			}

			return match;
		},

		PSEUDO: function( match ) {
			var excess,
				unquoted = !match[ 6 ] && match[ 2 ];

			if ( matchExpr.CHILD.test( match[ 0 ] ) ) {
				return null;
			}

			// Accept quoted arguments as-is
			if ( match[ 3 ] ) {
				match[ 2 ] = match[ 4 ] || match[ 5 ] || "";

			// Strip excess characters from unquoted arguments
			} else if ( unquoted && rpseudo.test( unquoted ) &&

				// Get excess from tokenize (recursively)
				( excess = tokenize( unquoted, true ) ) &&

				// advance to the next closing parenthesis
				( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) {

				// excess is a negative index
				match[ 0 ] = match[ 0 ].slice( 0, excess );
				match[ 2 ] = unquoted.slice( 0, excess );
			}

			// Return only captures needed by the pseudo filter method (type and argument)
			return match.slice( 0, 3 );
		}
	},

	filter: {

		TAG: function( nodeNameSelector ) {
			var expectedNodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
			return nodeNameSelector === "*" ?
				function() {
					return true;
				} :
				function( elem ) {
					return nodeName( elem, expectedNodeName );
				};
		},

		CLASS: function( className ) {
			var pattern = classCache[ className + " " ];

			return pattern ||
				( pattern = new RegExp( "(^|" + whitespace + ")" + className +
					"(" + whitespace + "|$)" ) ) &&
				classCache( className, function( elem ) {
					return pattern.test(
						typeof elem.className === "string" && elem.className ||
							typeof elem.getAttribute !== "undefined" &&
								elem.getAttribute( "class" ) ||
							""
					);
				} );
		},

		ATTR: function( name, operator, check ) {
			return function( elem ) {
				var result = find.attr( elem, name );

				if ( result == null ) {
					return operator === "!=";
				}
				if ( !operator ) {
					return true;
				}

				result += "";

				if ( operator === "=" ) {
					return result === check;
				}
				if ( operator === "!=" ) {
					return result !== check;
				}
				if ( operator === "^=" ) {
					return check && result.indexOf( check ) === 0;
				}
				if ( operator === "*=" ) {
					return check && result.indexOf( check ) > -1;
				}
				if ( operator === "$=" ) {
					return check && result.slice( -check.length ) === check;
				}
				if ( operator === "~=" ) {
					return ( " " + result.replace( rwhitespace, " " ) + " " )
						.indexOf( check ) > -1;
				}
				if ( operator === "|=" ) {
					return result === check || result.slice( 0, check.length + 1 ) === check + "-";
				}

				return false;
			};
		},

		CHILD: function( type, what, _argument, first, last ) {
			var simple = type.slice( 0, 3 ) !== "nth",
				forward = type.slice( -4 ) !== "last",
				ofType = what === "of-type";

			return first === 1 && last === 0 ?

				// Shortcut for :nth-*(n)
				function( elem ) {
					return !!elem.parentNode;
				} :

				function( elem, _context, xml ) {
					var cache, outerCache, node, nodeIndex, start,
						dir = simple !== forward ? "nextSibling" : "previousSibling",
						parent = elem.parentNode,
						name = ofType && elem.nodeName.toLowerCase(),
						useCache = !xml && !ofType,
						diff = false;

					if ( parent ) {

						// :(first|last|only)-(child|of-type)
						if ( simple ) {
							while ( dir ) {
								node = elem;
								while ( ( node = node[ dir ] ) ) {
									if ( ofType ?
										nodeName( node, name ) :
										node.nodeType === 1 ) {

										return false;
									}
								}

								// Reverse direction for :only-* (if we haven't yet done so)
								start = dir = type === "only" && !start && "nextSibling";
							}
							return true;
						}

						start = [ forward ? parent.firstChild : parent.lastChild ];

						// non-xml :nth-child(...) stores cache data on `parent`
						if ( forward && useCache ) {

							// Seek `elem` from a previously-cached index
							outerCache = parent[ expando ] || ( parent[ expando ] = {} );
							cache = outerCache[ type ] || [];
							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
							diff = nodeIndex && cache[ 2 ];
							node = nodeIndex && parent.childNodes[ nodeIndex ];

							while ( ( node = ++nodeIndex && node && node[ dir ] ||

								// Fallback to seeking `elem` from the start
								( diff = nodeIndex = 0 ) || start.pop() ) ) {

								// When found, cache indexes on `parent` and break
								if ( node.nodeType === 1 && ++diff && node === elem ) {
									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
									break;
								}
							}

						} else {

							// Use previously-cached element index if available
							if ( useCache ) {
								outerCache = elem[ expando ] || ( elem[ expando ] = {} );
								cache = outerCache[ type ] || [];
								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
								diff = nodeIndex;
							}

							// xml :nth-child(...)
							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
							if ( diff === false ) {

								// Use the same loop as above to seek `elem` from the start
								while ( ( node = ++nodeIndex && node && node[ dir ] ||
									( diff = nodeIndex = 0 ) || start.pop() ) ) {

									if ( ( ofType ?
										nodeName( node, name ) :
										node.nodeType === 1 ) &&
										++diff ) {

										// Cache the index of each encountered element
										if ( useCache ) {
											outerCache = node[ expando ] ||
												( node[ expando ] = {} );
											outerCache[ type ] = [ dirruns, diff ];
										}

										if ( node === elem ) {
											break;
										}
									}
								}
							}
						}

						// Incorporate the offset, then check against cycle size
						diff -= last;
						return diff === first || ( diff % first === 0 && diff / first >= 0 );
					}
				};
		},

		PSEUDO: function( pseudo, argument ) {

			// pseudo-class names are case-insensitive
			// https://www.w3.org/TR/selectors/#pseudo-classes
			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
			// Remember that setFilters inherits from pseudos
			var args,
				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
					find.error( "unsupported pseudo: " + pseudo );

			// The user may use createPseudo to indicate that
			// arguments are needed to create the filter function
			// just as jQuery does
			if ( fn[ expando ] ) {
				return fn( argument );
			}

			// But maintain support for old signatures
			if ( fn.length > 1 ) {
				args = [ pseudo, pseudo, "", argument ];
				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
					markFunction( function( seed, matches ) {
						var idx,
							matched = fn( seed, argument ),
							i = matched.length;
						while ( i-- ) {
							idx = indexOf.call( seed, matched[ i ] );
							seed[ idx ] = !( matches[ idx ] = matched[ i ] );
						}
					} ) :
					function( elem ) {
						return fn( elem, 0, args );
					};
			}

			return fn;
		}
	},

	pseudos: {

		// Potentially complex pseudos
		not: markFunction( function( selector ) {

			// Trim the selector passed to compile
			// to avoid treating leading and trailing
			// spaces as combinators
			var input = [],
				results = [],
				matcher = compile( selector.replace( rtrimCSS, "$1" ) );

			return matcher[ expando ] ?
				markFunction( function( seed, matches, _context, xml ) {
					var elem,
						unmatched = matcher( seed, null, xml, [] ),
						i = seed.length;

					// Match elements unmatched by `matcher`
					while ( i-- ) {
						if ( ( elem = unmatched[ i ] ) ) {
							seed[ i ] = !( matches[ i ] = elem );
						}
					}
				} ) :
				function( elem, _context, xml ) {
					input[ 0 ] = elem;
					matcher( input, null, xml, results );

					// Don't keep the element
					// (see https://github.com/jquery/sizzle/issues/299)
					input[ 0 ] = null;
					return !results.pop();
				};
		} ),

		has: markFunction( function( selector ) {
			return function( elem ) {
				return find( selector, elem ).length > 0;
			};
		} ),

		contains: markFunction( function( text ) {
			text = text.replace( runescape, funescape );
			return function( elem ) {
				return ( elem.textContent || jQuery.text( elem ) ).indexOf( text ) > -1;
			};
		} ),

		// "Whether an element is represented by a :lang() selector
		// is based solely on the element's language value
		// being equal to the identifier C,
		// or beginning with the identifier C immediately followed by "-".
		// The matching of C against the element's language value is performed case-insensitively.
		// The identifier C does not have to be a valid language name."
		// https://www.w3.org/TR/selectors/#lang-pseudo
		lang: markFunction( function( lang ) {

			// lang value must be a valid identifier
			if ( !ridentifier.test( lang || "" ) ) {
				find.error( "unsupported lang: " + lang );
			}
			lang = lang.replace( runescape, funescape ).toLowerCase();
			return function( elem ) {
				var elemLang;
				do {
					if ( ( elemLang = documentIsHTML ?
						elem.lang :
						elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {

						elemLang = elemLang.toLowerCase();
						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
					}
				} while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
				return false;
			};
		} ),

		// Miscellaneous
		target: function( elem ) {
			var hash = window.location && window.location.hash;
			return hash && hash.slice( 1 ) === elem.id;
		},

		root: function( elem ) {
			return elem === documentElement;
		},

		focus: function( elem ) {
			return elem === safeActiveElement() &&
				document.hasFocus() &&
				!!( elem.type || elem.href || ~elem.tabIndex );
		},

		// Boolean properties
		enabled: createDisabledPseudo( false ),
		disabled: createDisabledPseudo( true ),

		checked: function( elem ) {

			// In CSS3, :checked should return both checked and selected elements
			// https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
			return ( nodeName( elem, "input" ) && !!elem.checked ) ||
				( nodeName( elem, "option" ) && !!elem.selected );
		},

		selected: function( elem ) {

			// Support: IE <=11+
			// Accessing the selectedIndex property
			// forces the browser to treat the default option as
			// selected when in an optgroup.
			if ( elem.parentNode ) {
				// eslint-disable-next-line no-unused-expressions
				elem.parentNode.selectedIndex;
			}

			return elem.selected === true;
		},

		// Contents
		empty: function( elem ) {

			// https://www.w3.org/TR/selectors/#empty-pseudo
			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
			//   but not by others (comment: 8; processing instruction: 7; etc.)
			// nodeType < 6 works because attributes (2) do not appear as children
			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
				if ( elem.nodeType < 6 ) {
					return false;
				}
			}
			return true;
		},

		parent: function( elem ) {
			return !Expr.pseudos.empty( elem );
		},

		// Element/input types
		header: function( elem ) {
			return rheader.test( elem.nodeName );
		},

		input: function( elem ) {
			return rinputs.test( elem.nodeName );
		},

		button: function( elem ) {
			return nodeName( elem, "input" ) && elem.type === "button" ||
				nodeName( elem, "button" );
		},

		text: function( elem ) {
			var attr;
			return nodeName( elem, "input" ) && elem.type === "text" &&

				// Support: IE <10 only
				// New HTML5 attribute values (e.g., "search") appear
				// with elem.type === "text"
				( ( attr = elem.getAttribute( "type" ) ) == null ||
					attr.toLowerCase() === "text" );
		},

		// Position-in-collection
		first: createPositionalPseudo( function() {
			return [ 0 ];
		} ),

		last: createPositionalPseudo( function( _matchIndexes, length ) {
			return [ length - 1 ];
		} ),

		eq: createPositionalPseudo( function( _matchIndexes, length, argument ) {
			return [ argument < 0 ? argument + length : argument ];
		} ),

		even: createPositionalPseudo( function( matchIndexes, length ) {
			var i = 0;
			for ( ; i < length; i += 2 ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		} ),

		odd: createPositionalPseudo( function( matchIndexes, length ) {
			var i = 1;
			for ( ; i < length; i += 2 ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		} ),

		lt: createPositionalPseudo( function( matchIndexes, length, argument ) {
			var i;

			if ( argument < 0 ) {
				i = argument + length;
			} else if ( argument > length ) {
				i = length;
			} else {
				i = argument;
			}

			for ( ; --i >= 0; ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		} ),

		gt: createPositionalPseudo( function( matchIndexes, length, argument ) {
			var i = argument < 0 ? argument + length : argument;
			for ( ; ++i < length; ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		} )
	}
};

Expr.pseudos.nth = Expr.pseudos.eq;

// Add button/input type pseudos
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
	Expr.pseudos[ i ] = createInputPseudo( i );
}
for ( i in { submit: true, reset: true } ) {
	Expr.pseudos[ i ] = createButtonPseudo( i );
}

// Easy API for creating new setFilters
function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();

function tokenize( selector, parseOnly ) {
	var matched, match, tokens, type,
		soFar, groups, preFilters,
		cached = tokenCache[ selector + " " ];

	if ( cached ) {
		return parseOnly ? 0 : cached.slice( 0 );
	}

	soFar = selector;
	groups = [];
	preFilters = Expr.preFilter;

	while ( soFar ) {

		// Comma and first run
		if ( !matched || ( match = rcomma.exec( soFar ) ) ) {
			if ( match ) {

				// Don't consume trailing commas as valid
				soFar = soFar.slice( match[ 0 ].length ) || soFar;
			}
			groups.push( ( tokens = [] ) );
		}

		matched = false;

		// Combinators
		if ( ( match = rleadingCombinator.exec( soFar ) ) ) {
			matched = match.shift();
			tokens.push( {
				value: matched,

				// Cast descendant combinators to space
				type: match[ 0 ].replace( rtrimCSS, " " )
			} );
			soFar = soFar.slice( matched.length );
		}

		// Filters
		for ( type in Expr.filter ) {
			if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||
				( match = preFilters[ type ]( match ) ) ) ) {
				matched = match.shift();
				tokens.push( {
					value: matched,
					type: type,
					matches: match
				} );
				soFar = soFar.slice( matched.length );
			}
		}

		if ( !matched ) {
			break;
		}
	}

	// Return the length of the invalid excess
	// if we're just parsing
	// Otherwise, throw an error or return tokens
	if ( parseOnly ) {
		return soFar.length;
	}

	return soFar ?
		find.error( selector ) :

		// Cache the tokens
		tokenCache( selector, groups ).slice( 0 );
}

function toSelector( tokens ) {
	var i = 0,
		len = tokens.length,
		selector = "";
	for ( ; i < len; i++ ) {
		selector += tokens[ i ].value;
	}
	return selector;
}

function addCombinator( matcher, combinator, base ) {
	var dir = combinator.dir,
		skip = combinator.next,
		key = skip || dir,
		checkNonElements = base && key === "parentNode",
		doneName = done++;

	return combinator.first ?

		// Check against closest ancestor/preceding element
		function( elem, context, xml ) {
			while ( ( elem = elem[ dir ] ) ) {
				if ( elem.nodeType === 1 || checkNonElements ) {
					return matcher( elem, context, xml );
				}
			}
			return false;
		} :

		// Check against all ancestor/preceding elements
		function( elem, context, xml ) {
			var oldCache, outerCache,
				newCache = [ dirruns, doneName ];

			// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
			if ( xml ) {
				while ( ( elem = elem[ dir ] ) ) {
					if ( elem.nodeType === 1 || checkNonElements ) {
						if ( matcher( elem, context, xml ) ) {
							return true;
						}
					}
				}
			} else {
				while ( ( elem = elem[ dir ] ) ) {
					if ( elem.nodeType === 1 || checkNonElements ) {
						outerCache = elem[ expando ] || ( elem[ expando ] = {} );

						if ( skip && nodeName( elem, skip ) ) {
							elem = elem[ dir ] || elem;
						} else if ( ( oldCache = outerCache[ key ] ) &&
							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {

							// Assign to newCache so results back-propagate to previous elements
							return ( newCache[ 2 ] = oldCache[ 2 ] );
						} else {

							// Reuse newcache so results back-propagate to previous elements
							outerCache[ key ] = newCache;

							// A match means we're done; a fail means we have to keep checking
							if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
								return true;
							}
						}
					}
				}
			}
			return false;
		};
}

function elementMatcher( matchers ) {
	return matchers.length > 1 ?
		function( elem, context, xml ) {
			var i = matchers.length;
			while ( i-- ) {
				if ( !matchers[ i ]( elem, context, xml ) ) {
					return false;
				}
			}
			return true;
		} :
		matchers[ 0 ];
}

function multipleContexts( selector, contexts, results ) {
	var i = 0,
		len = contexts.length;
	for ( ; i < len; i++ ) {
		find( selector, contexts[ i ], results );
	}
	return results;
}

function condense( unmatched, map, filter, context, xml ) {
	var elem,
		newUnmatched = [],
		i = 0,
		len = unmatched.length,
		mapped = map != null;

	for ( ; i < len; i++ ) {
		if ( ( elem = unmatched[ i ] ) ) {
			if ( !filter || filter( elem, context, xml ) ) {
				newUnmatched.push( elem );
				if ( mapped ) {
					map.push( i );
				}
			}
		}
	}

	return newUnmatched;
}

function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
	if ( postFilter && !postFilter[ expando ] ) {
		postFilter = setMatcher( postFilter );
	}
	if ( postFinder && !postFinder[ expando ] ) {
		postFinder = setMatcher( postFinder, postSelector );
	}
	return markFunction( function( seed, results, context, xml ) {
		var temp, i, elem, matcherOut,
			preMap = [],
			postMap = [],
			preexisting = results.length,

			// Get initial elements from seed or context
			elems = seed ||
				multipleContexts( selector || "*",
					context.nodeType ? [ context ] : context, [] ),

			// Prefilter to get matcher input, preserving a map for seed-results synchronization
			matcherIn = preFilter && ( seed || !selector ) ?
				condense( elems, preMap, preFilter, context, xml ) :
				elems;

		if ( matcher ) {

			// If we have a postFinder, or filtered seed, or non-seed postFilter
			// or preexisting results,
			matcherOut = postFinder || ( seed ? preFilter : preexisting || postFilter ) ?

				// ...intermediate processing is necessary
				[] :

				// ...otherwise use results directly
				results;

			// Find primary matches
			matcher( matcherIn, matcherOut, context, xml );
		} else {
			matcherOut = matcherIn;
		}

		// Apply postFilter
		if ( postFilter ) {
			temp = condense( matcherOut, postMap );
			postFilter( temp, [], context, xml );

			// Un-match failing elements by moving them back to matcherIn
			i = temp.length;
			while ( i-- ) {
				if ( ( elem = temp[ i ] ) ) {
					matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );
				}
			}
		}

		if ( seed ) {
			if ( postFinder || preFilter ) {
				if ( postFinder ) {

					// Get the final matcherOut by condensing this intermediate into postFinder contexts
					temp = [];
					i = matcherOut.length;
					while ( i-- ) {
						if ( ( elem = matcherOut[ i ] ) ) {

							// Restore matcherIn since elem is not yet a final match
							temp.push( ( matcherIn[ i ] = elem ) );
						}
					}
					postFinder( null, ( matcherOut = [] ), temp, xml );
				}

				// Move matched elements from seed to results to keep them synchronized
				i = matcherOut.length;
				while ( i-- ) {
					if ( ( elem = matcherOut[ i ] ) &&
						( temp = postFinder ? indexOf.call( seed, elem ) : preMap[ i ] ) > -1 ) {

						seed[ temp ] = !( results[ temp ] = elem );
					}
				}
			}

		// Add elements to results, through postFinder if defined
		} else {
			matcherOut = condense(
				matcherOut === results ?
					matcherOut.splice( preexisting, matcherOut.length ) :
					matcherOut
			);
			if ( postFinder ) {
				postFinder( null, results, matcherOut, xml );
			} else {
				push.apply( results, matcherOut );
			}
		}
	} );
}

function matcherFromTokens( tokens ) {
	var checkContext, matcher, j,
		len = tokens.length,
		leadingRelative = Expr.relative[ tokens[ 0 ].type ],
		implicitRelative = leadingRelative || Expr.relative[ " " ],
		i = leadingRelative ? 1 : 0,

		// The foundational matcher ensures that elements are reachable from top-level context(s)
		matchContext = addCombinator( function( elem ) {
			return elem === checkContext;
		}, implicitRelative, true ),
		matchAnyContext = addCombinator( function( elem ) {
			return indexOf.call( checkContext, elem ) > -1;
		}, implicitRelative, true ),
		matchers = [ function( elem, context, xml ) {

			// Support: IE 11+, Edge 17 - 18+
			// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
			// two documents; shallow comparisons work.
			// eslint-disable-next-line eqeqeq
			var ret = ( !leadingRelative && ( xml || context != outermostContext ) ) || (
				( checkContext = context ).nodeType ?
					matchContext( elem, context, xml ) :
					matchAnyContext( elem, context, xml ) );

			// Avoid hanging onto element
			// (see https://github.com/jquery/sizzle/issues/299)
			checkContext = null;
			return ret;
		} ];

	for ( ; i < len; i++ ) {
		if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {
			matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
		} else {
			matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );

			// Return special upon seeing a positional matcher
			if ( matcher[ expando ] ) {

				// Find the next relative operator (if any) for proper handling
				j = ++i;
				for ( ; j < len; j++ ) {
					if ( Expr.relative[ tokens[ j ].type ] ) {
						break;
					}
				}
				return setMatcher(
					i > 1 && elementMatcher( matchers ),
					i > 1 && toSelector(

						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
						tokens.slice( 0, i - 1 )
							.concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
					).replace( rtrimCSS, "$1" ),
					matcher,
					i < j && matcherFromTokens( tokens.slice( i, j ) ),
					j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
					j < len && toSelector( tokens )
				);
			}
			matchers.push( matcher );
		}
	}

	return elementMatcher( matchers );
}

function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
	var bySet = setMatchers.length > 0,
		byElement = elementMatchers.length > 0,
		superMatcher = function( seed, context, xml, results, outermost ) {
			var elem, j, matcher,
				matchedCount = 0,
				i = "0",
				unmatched = seed && [],
				setMatched = [],
				contextBackup = outermostContext,

				// We must always have either seed elements or outermost context
				elems = seed || byElement && Expr.find.TAG( "*", outermost ),

				// Use integer dirruns iff this is the outermost matcher
				dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),
				len = elems.length;

			if ( outermost ) {

				// Support: IE 11+, Edge 17 - 18+
				// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
				// two documents; shallow comparisons work.
				// eslint-disable-next-line eqeqeq
				outermostContext = context == document || context || outermost;
			}

			// Add elements passing elementMatchers directly to results
			// Support: iOS <=7 - 9 only
			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching
			// elements by id. (see trac-14142)
			for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {
				if ( byElement && elem ) {
					j = 0;

					// Support: IE 11+, Edge 17 - 18+
					// IE/Edge sometimes throw a "Permission denied" error when strict-comparing
					// two documents; shallow comparisons work.
					// eslint-disable-next-line eqeqeq
					if ( !context && elem.ownerDocument != document ) {
						setDocument( elem );
						xml = !documentIsHTML;
					}
					while ( ( matcher = elementMatchers[ j++ ] ) ) {
						if ( matcher( elem, context || document, xml ) ) {
							push.call( results, elem );
							break;
						}
					}
					if ( outermost ) {
						dirruns = dirrunsUnique;
					}
				}

				// Track unmatched elements for set filters
				if ( bySet ) {

					// They will have gone through all possible matchers
					if ( ( elem = !matcher && elem ) ) {
						matchedCount--;
					}

					// Lengthen the array for every element, matched or not
					if ( seed ) {
						unmatched.push( elem );
					}
				}
			}

			// `i` is now the count of elements visited above, and adding it to `matchedCount`
			// makes the latter nonnegative.
			matchedCount += i;

			// Apply set filters to unmatched elements
			// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
			// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
			// no element matchers and no seed.
			// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
			// case, which will result in a "00" `matchedCount` that differs from `i` but is also
			// numerically zero.
			if ( bySet && i !== matchedCount ) {
				j = 0;
				while ( ( matcher = setMatchers[ j++ ] ) ) {
					matcher( unmatched, setMatched, context, xml );
				}

				if ( seed ) {

					// Reintegrate element matches to eliminate the need for sorting
					if ( matchedCount > 0 ) {
						while ( i-- ) {
							if ( !( unmatched[ i ] || setMatched[ i ] ) ) {
								setMatched[ i ] = pop.call( results );
							}
						}
					}

					// Discard index placeholder values to get only actual matches
					setMatched = condense( setMatched );
				}

				// Add matches to results
				push.apply( results, setMatched );

				// Seedless set matches succeeding multiple successful matchers stipulate sorting
				if ( outermost && !seed && setMatched.length > 0 &&
					( matchedCount + setMatchers.length ) > 1 ) {

					jQuery.uniqueSort( results );
				}
			}

			// Override manipulation of globals by nested matchers
			if ( outermost ) {
				dirruns = dirrunsUnique;
				outermostContext = contextBackup;
			}

			return unmatched;
		};

	return bySet ?
		markFunction( superMatcher ) :
		superMatcher;
}

function compile( selector, match /* Internal Use Only */ ) {
	var i,
		setMatchers = [],
		elementMatchers = [],
		cached = compilerCache[ selector + " " ];

	if ( !cached ) {

		// Generate a function of recursive functions that can be used to check each element
		if ( !match ) {
			match = tokenize( selector );
		}
		i = match.length;
		while ( i-- ) {
			cached = matcherFromTokens( match[ i ] );
			if ( cached[ expando ] ) {
				setMatchers.push( cached );
			} else {
				elementMatchers.push( cached );
			}
		}

		// Cache the compiled function
		cached = compilerCache( selector,
			matcherFromGroupMatchers( elementMatchers, setMatchers ) );

		// Save selector and tokenization
		cached.selector = selector;
	}
	return cached;
}

/**
 * A low-level selection function that works with jQuery's compiled
 *  selector functions
 * @param {String|Function} selector A selector or a pre-compiled
 *  selector function built with jQuery selector compile
 * @param {Element} context
 * @param {Array} [results]
 * @param {Array} [seed] A set of elements to match against
 */
function select( selector, context, results, seed ) {
	var i, tokens, token, type, find,
		compiled = typeof selector === "function" && selector,
		match = !seed && tokenize( ( selector = compiled.selector || selector ) );

	results = results || [];

	// Try to minimize operations if there is only one selector in the list and no seed
	// (the latter of which guarantees us context)
	if ( match.length === 1 ) {

		// Reduce context if the leading compound selector is an ID
		tokens = match[ 0 ] = match[ 0 ].slice( 0 );
		if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
				context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {

			context = ( Expr.find.ID(
				token.matches[ 0 ].replace( runescape, funescape ),
				context
			) || [] )[ 0 ];
			if ( !context ) {
				return results;

			// Precompiled matchers will still verify ancestry, so step up a level
			} else if ( compiled ) {
				context = context.parentNode;
			}

			selector = selector.slice( tokens.shift().value.length );
		}

		// Fetch a seed set for right-to-left matching
		i = matchExpr.needsContext.test( selector ) ? 0 : tokens.length;
		while ( i-- ) {
			token = tokens[ i ];

			// Abort if we hit a combinator
			if ( Expr.relative[ ( type = token.type ) ] ) {
				break;
			}
			if ( ( find = Expr.find[ type ] ) ) {

				// Search, expanding context for leading sibling combinators
				if ( ( seed = find(
					token.matches[ 0 ].replace( runescape, funescape ),
					rsibling.test( tokens[ 0 ].type ) &&
						testContext( context.parentNode ) || context
				) ) ) {

					// If seed is empty or no tokens remain, we can return early
					tokens.splice( i, 1 );
					selector = seed.length && toSelector( tokens );
					if ( !selector ) {
						push.apply( results, seed );
						return results;
					}

					break;
				}
			}
		}
	}

	// Compile and execute a filtering function if one is not provided
	// Provide `match` to avoid retokenization if we modified the selector above
	( compiled || compile( selector, match ) )(
		seed,
		context,
		!documentIsHTML,
		results,
		!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
	);
	return results;
}

// One-time assignments

// Support: Android <=4.0 - 4.1+
// Sort stability
support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;

// Initialize against the default document
setDocument();

// Support: Android <=4.0 - 4.1+
// Detached nodes confoundingly follow *each other*
support.sortDetached = assert( function( el ) {

	// Should return 1, but returns 4 (following)
	return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1;
} );

jQuery.find = find;

// Deprecated
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
jQuery.unique = jQuery.uniqueSort;

// These have always been private, but they used to be documented as part of
// Sizzle so let's maintain them for now for backwards compatibility purposes.
find.compile = compile;
find.select = select;
find.setDocument = setDocument;
find.tokenize = tokenize;

find.escape = jQuery.escapeSelector;
find.getText = jQuery.text;
find.isXML = jQuery.isXMLDoc;
find.selectors = jQuery.expr;
find.support = jQuery.support;
find.uniqueSort = jQuery.uniqueSort;

	/* eslint-enable */

} )();


var dir = function( elem, dir, until ) {
	var matched = [],
		truncate = until !== undefined;

	while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
		if ( elem.nodeType === 1 ) {
			if ( truncate && jQuery( elem ).is( until ) ) {
				break;
			}
			matched.push( elem );
		}
	}
	return matched;
};


var siblings = function( n, elem ) {
	var matched = [];

	for ( ; n; n = n.nextSibling ) {
		if ( n.nodeType === 1 && n !== elem ) {
			matched.push( n );
		}
	}

	return matched;
};


var rneedsContext = jQuery.expr.match.needsContext;

var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );



// Implement the identical functionality for filter and not
function winnow( elements, qualifier, not ) {
	if ( isFunction( qualifier ) ) {
		return jQuery.grep( elements, function( elem, i ) {
			return !!qualifier.call( elem, i, elem ) !== not;
		} );
	}

	// Single element
	if ( qualifier.nodeType ) {
		return jQuery.grep( elements, function( elem ) {
			return ( elem === qualifier ) !== not;
		} );
	}

	// Arraylike of elements (jQuery, arguments, Array)
	if ( typeof qualifier !== "string" ) {
		return jQuery.grep( elements, function( elem ) {
			return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
		} );
	}

	// Filtered directly for both simple and complex selectors
	return jQuery.filter( qualifier, elements, not );
}

jQuery.filter = function( expr, elems, not ) {
	var elem = elems[ 0 ];

	if ( not ) {
		expr = ":not(" + expr + ")";
	}

	if ( elems.length === 1 && elem.nodeType === 1 ) {
		return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
	}

	return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
		return elem.nodeType === 1;
	} ) );
};

jQuery.fn.extend( {
	find: function( selector ) {
		var i, ret,
			len = this.length,
			self = this;

		if ( typeof selector !== "string" ) {
			return this.pushStack( jQuery( selector ).filter( function() {
				for ( i = 0; i < len; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) {
						return true;
					}
				}
			} ) );
		}

		ret = this.pushStack( [] );

		for ( i = 0; i < len; i++ ) {
			jQuery.find( selector, self[ i ], ret );
		}

		return len > 1 ? jQuery.uniqueSort( ret ) : ret;
	},
	filter: function( selector ) {
		return this.pushStack( winnow( this, selector || [], false ) );
	},
	not: function( selector ) {
		return this.pushStack( winnow( this, selector || [], true ) );
	},
	is: function( selector ) {
		return !!winnow(
			this,

			// If this is a positional/relative selector, check membership in the returned set
			// so $("p:first").is("p:last") won't return true for a doc with two "p".
			typeof selector === "string" && rneedsContext.test( selector ) ?
				jQuery( selector ) :
				selector || [],
			false
		).length;
	}
} );


// Initialize a jQuery object


// A central reference to the root jQuery(document)
var rootjQuery,

	// A simple way to check for HTML strings
	// Prioritize #id over <tag> to avoid XSS via location.hash (trac-9521)
	// Strict HTML recognition (trac-11290: must start with <)
	// Shortcut simple #id case for speed
	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,

	init = jQuery.fn.init = function( selector, context, root ) {
		var match, elem;

		// HANDLE: $(""), $(null), $(undefined), $(false)
		if ( !selector ) {
			return this;
		}

		// Method init() accepts an alternate rootjQuery
		// so migrate can support jQuery.sub (gh-2101)
		root = root || rootjQuery;

		// Handle HTML strings
		if ( typeof selector === "string" ) {
			if ( selector[ 0 ] === "<" &&
				selector[ selector.length - 1 ] === ">" &&
				selector.length >= 3 ) {

				// Assume that strings that start and end with <> are HTML and skip the regex check
				match = [ null, selector, null ];

			} else {
				match = rquickExpr.exec( selector );
			}

			// Match html or make sure no context is specified for #id
			if ( match && ( match[ 1 ] || !context ) ) {

				// HANDLE: $(html) -> $(array)
				if ( match[ 1 ] ) {
					context = context instanceof jQuery ? context[ 0 ] : context;

					// Option to run scripts is true for back-compat
					// Intentionally let the error be thrown if parseHTML is not present
					jQuery.merge( this, jQuery.parseHTML(
						match[ 1 ],
						context && context.nodeType ? context.ownerDocument || context : document,
						true
					) );

					// HANDLE: $(html, props)
					if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
						for ( match in context ) {

							// Properties of context are called as methods if possible
							if ( isFunction( this[ match ] ) ) {
								this[ match ]( context[ match ] );

							// ...and otherwise set as attributes
							} else {
								this.attr( match, context[ match ] );
							}
						}
					}

					return this;

				// HANDLE: $(#id)
				} else {
					elem = document.getElementById( match[ 2 ] );

					if ( elem ) {

						// Inject the element directly into the jQuery object
						this[ 0 ] = elem;
						this.length = 1;
					}
					return this;
				}

			// HANDLE: $(expr, $(...))
			} else if ( !context || context.jquery ) {
				return ( context || root ).find( selector );

			// HANDLE: $(expr, context)
			// (which is just equivalent to: $(context).find(expr)
			} else {
				return this.constructor( context ).find( selector );
			}

		// HANDLE: $(DOMElement)
		} else if ( selector.nodeType ) {
			this[ 0 ] = selector;
			this.length = 1;
			return this;

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( isFunction( selector ) ) {
			return root.ready !== undefined ?
				root.ready( selector ) :

				// Execute immediately if ready is not present
				selector( jQuery );
		}

		return jQuery.makeArray( selector, this );
	};

// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;

// Initialize central reference
rootjQuery = jQuery( document );


var rparentsprev = /^(?:parents|prev(?:Until|All))/,

	// Methods guaranteed to produce a unique set when starting from a unique set
	guaranteedUnique = {
		children: true,
		contents: true,
		next: true,
		prev: true
	};

jQuery.fn.extend( {
	has: function( target ) {
		var targets = jQuery( target, this ),
			l = targets.length;

		return this.filter( function() {
			var i = 0;
			for ( ; i < l; i++ ) {
				if ( jQuery.contains( this, targets[ i ] ) ) {
					return true;
				}
			}
		} );
	},

	closest: function( selectors, context ) {
		var cur,
			i = 0,
			l = this.length,
			matched = [],
			targets = typeof selectors !== "string" && jQuery( selectors );

		// Positional selectors never match, since there's no _selection_ context
		if ( !rneedsContext.test( selectors ) ) {
			for ( ; i < l; i++ ) {
				for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {

					// Always skip document fragments
					if ( cur.nodeType < 11 && ( targets ?
						targets.index( cur ) > -1 :

						// Don't pass non-elements to jQuery#find
						cur.nodeType === 1 &&
							jQuery.find.matchesSelector( cur, selectors ) ) ) {

						matched.push( cur );
						break;
					}
				}
			}
		}

		return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
	},

	// Determine the position of an element within the set
	index: function( elem ) {

		// No argument, return index in parent
		if ( !elem ) {
			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
		}

		// Index in selector
		if ( typeof elem === "string" ) {
			return indexOf.call( jQuery( elem ), this[ 0 ] );
		}

		// Locate the position of the desired element
		return indexOf.call( this,

			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[ 0 ] : elem
		);
	},

	add: function( selector, context ) {
		return this.pushStack(
			jQuery.uniqueSort(
				jQuery.merge( this.get(), jQuery( selector, context ) )
			)
		);
	},

	addBack: function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter( selector )
		);
	}
} );

function sibling( cur, dir ) {
	while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
	return cur;
}

jQuery.each( {
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, _i, until ) {
		return dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return sibling( elem, "nextSibling" );
	},
	prev: function( elem ) {
		return sibling( elem, "previousSibling" );
	},
	nextAll: function( elem ) {
		return dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, _i, until ) {
		return dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, _i, until ) {
		return dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return siblings( ( elem.parentNode || {} ).firstChild, elem );
	},
	children: function( elem ) {
		return siblings( elem.firstChild );
	},
	contents: function( elem ) {
		if ( elem.contentDocument != null &&

			// Support: IE 11+
			// <object> elements with no `data` attribute has an object
			// `contentDocument` with a `null` prototype.
			getProto( elem.contentDocument ) ) {

			return elem.contentDocument;
		}

		// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
		// Treat the template element as a regular one in browsers that
		// don't support it.
		if ( nodeName( elem, "template" ) ) {
			elem = elem.content || elem;
		}

		return jQuery.merge( [], elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var matched = jQuery.map( this, fn, until );

		if ( name.slice( -5 ) !== "Until" ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			matched = jQuery.filter( selector, matched );
		}

		if ( this.length > 1 ) {

			// Remove duplicates
			if ( !guaranteedUnique[ name ] ) {
				jQuery.uniqueSort( matched );
			}

			// Reverse order for parents* and prev-derivatives
			if ( rparentsprev.test( name ) ) {
				matched.reverse();
			}
		}

		return this.pushStack( matched );
	};
} );
var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );



// Convert String-formatted options into Object-formatted ones
function createOptions( options ) {
	var object = {};
	jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
		object[ flag ] = true;
	} );
	return object;
}

/*
 * Create a callback list using the following parameters:
 *
 *	options: an optional list of space-separated options that will change how
 *			the callback list behaves or a more traditional option object
 *
 * By default a callback list will act like an event callback list and can be
 * "fired" multiple times.
 *
 * Possible options:
 *
 *	once:			will ensure the callback list can only be fired once (like a Deferred)
 *
 *	memory:			will keep track of previous values and will call any callback added
 *					after the list has been fired right away with the latest "memorized"
 *					values (like a Deferred)
 *
 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
 *
 *	stopOnFalse:	interrupt callings when a callback returns false
 *
 */
jQuery.Callbacks = function( options ) {

	// Convert options from String-formatted to Object-formatted if needed
	// (we check in cache first)
	options = typeof options === "string" ?
		createOptions( options ) :
		jQuery.extend( {}, options );

	var // Flag to know if list is currently firing
		firing,

		// Last fire value for non-forgettable lists
		memory,

		// Flag to know if list was already fired
		fired,

		// Flag to prevent firing
		locked,

		// Actual callback list
		list = [],

		// Queue of execution data for repeatable lists
		queue = [],

		// Index of currently firing callback (modified by add/remove as needed)
		firingIndex = -1,

		// Fire callbacks
		fire = function() {

			// Enforce single-firing
			locked = locked || options.once;

			// Execute callbacks for all pending executions,
			// respecting firingIndex overrides and runtime changes
			fired = firing = true;
			for ( ; queue.length; firingIndex = -1 ) {
				memory = queue.shift();
				while ( ++firingIndex < list.length ) {

					// Run callback and check for early termination
					if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
						options.stopOnFalse ) {

						// Jump to end and forget the data so .add doesn't re-fire
						firingIndex = list.length;
						memory = false;
					}
				}
			}

			// Forget the data if we're done with it
			if ( !options.memory ) {
				memory = false;
			}

			firing = false;

			// Clean up if we're done firing for good
			if ( locked ) {

				// Keep an empty list if we have data for future add calls
				if ( memory ) {
					list = [];

				// Otherwise, this object is spent
				} else {
					list = "";
				}
			}
		},

		// Actual Callbacks object
		self = {

			// Add a callback or a collection of callbacks to the list
			add: function() {
				if ( list ) {

					// If we have memory from a past run, we should fire after adding
					if ( memory && !firing ) {
						firingIndex = list.length - 1;
						queue.push( memory );
					}

					( function add( args ) {
						jQuery.each( args, function( _, arg ) {
							if ( isFunction( arg ) ) {
								if ( !options.unique || !self.has( arg ) ) {
									list.push( arg );
								}
							} else if ( arg && arg.length && toType( arg ) !== "string" ) {

								// Inspect recursively
								add( arg );
							}
						} );
					} )( arguments );

					if ( memory && !firing ) {
						fire();
					}
				}
				return this;
			},

			// Remove a callback from the list
			remove: function() {
				jQuery.each( arguments, function( _, arg ) {
					var index;
					while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
						list.splice( index, 1 );

						// Handle firing indexes
						if ( index <= firingIndex ) {
							firingIndex--;
						}
					}
				} );
				return this;
			},

			// Check if a given callback is in the list.
			// If no argument is given, return whether or not list has callbacks attached.
			has: function( fn ) {
				return fn ?
					jQuery.inArray( fn, list ) > -1 :
					list.length > 0;
			},

			// Remove all callbacks from the list
			empty: function() {
				if ( list ) {
					list = [];
				}
				return this;
			},

			// Disable .fire and .add
			// Abort any current/pending executions
			// Clear all callbacks and values
			disable: function() {
				locked = queue = [];
				list = memory = "";
				return this;
			},
			disabled: function() {
				return !list;
			},

			// Disable .fire
			// Also disable .add unless we have memory (since it would have no effect)
			// Abort any pending executions
			lock: function() {
				locked = queue = [];
				if ( !memory && !firing ) {
					list = memory = "";
				}
				return this;
			},
			locked: function() {
				return !!locked;
			},

			// Call all callbacks with the given context and arguments
			fireWith: function( context, args ) {
				if ( !locked ) {
					args = args || [];
					args = [ context, args.slice ? args.slice() : args ];
					queue.push( args );
					if ( !firing ) {
						fire();
					}
				}
				return this;
			},

			// Call all the callbacks with the given arguments
			fire: function() {
				self.fireWith( this, arguments );
				return this;
			},

			// To know if the callbacks have already been called at least once
			fired: function() {
				return !!fired;
			}
		};

	return self;
};


function Identity( v ) {
	return v;
}
function Thrower( ex ) {
	throw ex;
}

function adoptValue( value, resolve, reject, noValue ) {
	var method;

	try {

		// Check for promise aspect first to privilege synchronous behavior
		if ( value && isFunction( ( method = value.promise ) ) ) {
			method.call( value ).done( resolve ).fail( reject );

		// Other thenables
		} else if ( value && isFunction( ( method = value.then ) ) ) {
			method.call( value, resolve, reject );

		// Other non-thenables
		} else {

			// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
			// * false: [ value ].slice( 0 ) => resolve( value )
			// * true: [ value ].slice( 1 ) => resolve()
			resolve.apply( undefined, [ value ].slice( noValue ) );
		}

	// For Promises/A+, convert exceptions into rejections
	// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
	// Deferred#then to conditionally suppress rejection.
	} catch ( value ) {

		// Support: Android 4.0 only
		// Strict mode functions invoked without .call/.apply get global-object context
		reject.apply( undefined, [ value ] );
	}
}

jQuery.extend( {

	Deferred: function( func ) {
		var tuples = [

				// action, add listener, callbacks,
				// ... .then handlers, argument index, [final state]
				[ "notify", "progress", jQuery.Callbacks( "memory" ),
					jQuery.Callbacks( "memory" ), 2 ],
				[ "resolve", "done", jQuery.Callbacks( "once memory" ),
					jQuery.Callbacks( "once memory" ), 0, "resolved" ],
				[ "reject", "fail", jQuery.Callbacks( "once memory" ),
					jQuery.Callbacks( "once memory" ), 1, "rejected" ]
			],
			state = "pending",
			promise = {
				state: function() {
					return state;
				},
				always: function() {
					deferred.done( arguments ).fail( arguments );
					return this;
				},
				"catch": function( fn ) {
					return promise.then( null, fn );
				},

				// Keep pipe for back-compat
				pipe: function( /* fnDone, fnFail, fnProgress */ ) {
					var fns = arguments;

					return jQuery.Deferred( function( newDefer ) {
						jQuery.each( tuples, function( _i, tuple ) {

							// Map tuples (progress, done, fail) to arguments (done, fail, progress)
							var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];

							// deferred.progress(function() { bind to newDefer or newDefer.notify })
							// deferred.done(function() { bind to newDefer or newDefer.resolve })
							// deferred.fail(function() { bind to newDefer or newDefer.reject })
							deferred[ tuple[ 1 ] ]( function() {
								var returned = fn && fn.apply( this, arguments );
								if ( returned && isFunction( returned.promise ) ) {
									returned.promise()
										.progress( newDefer.notify )
										.done( newDefer.resolve )
										.fail( newDefer.reject );
								} else {
									newDefer[ tuple[ 0 ] + "With" ](
										this,
										fn ? [ returned ] : arguments
									);
								}
							} );
						} );
						fns = null;
					} ).promise();
				},
				then: function( onFulfilled, onRejected, onProgress ) {
					var maxDepth = 0;
					function resolve( depth, deferred, handler, special ) {
						return function() {
							var that = this,
								args = arguments,
								mightThrow = function() {
									var returned, then;

									// Support: Promises/A+ section 2.3.3.3.3
									// https://promisesaplus.com/#point-59
									// Ignore double-resolution attempts
									if ( depth < maxDepth ) {
										return;
									}

									returned = handler.apply( that, args );

									// Support: Promises/A+ section 2.3.1
									// https://promisesaplus.com/#point-48
									if ( returned === deferred.promise() ) {
										throw new TypeError( "Thenable self-resolution" );
									}

									// Support: Promises/A+ sections 2.3.3.1, 3.5
									// https://promisesaplus.com/#point-54
									// https://promisesaplus.com/#point-75
									// Retrieve `then` only once
									then = returned &&

										// Support: Promises/A+ section 2.3.4
										// https://promisesaplus.com/#point-64
										// Only check objects and functions for thenability
										( typeof returned === "object" ||
											typeof returned === "function" ) &&
										returned.then;

									// Handle a returned thenable
									if ( isFunction( then ) ) {

										// Special processors (notify) just wait for resolution
										if ( special ) {
											then.call(
												returned,
												resolve( maxDepth, deferred, Identity, special ),
												resolve( maxDepth, deferred, Thrower, special )
											);

										// Normal processors (resolve) also hook into progress
										} else {

											// ...and disregard older resolution values
											maxDepth++;

											then.call(
												returned,
												resolve( maxDepth, deferred, Identity, special ),
												resolve( maxDepth, deferred, Thrower, special ),
												resolve( maxDepth, deferred, Identity,
													deferred.notifyWith )
											);
										}

									// Handle all other returned values
									} else {

										// Only substitute handlers pass on context
										// and multiple values (non-spec behavior)
										if ( handler !== Identity ) {
											that = undefined;
											args = [ returned ];
										}

										// Process the value(s)
										// Default process is resolve
										( special || deferred.resolveWith )( that, args );
									}
								},

								// Only normal processors (resolve) catch and reject exceptions
								process = special ?
									mightThrow :
									function() {
										try {
											mightThrow();
										} catch ( e ) {

											if ( jQuery.Deferred.exceptionHook ) {
												jQuery.Deferred.exceptionHook( e,
													process.error );
											}

											// Support: Promises/A+ section 2.3.3.3.4.1
											// https://promisesaplus.com/#point-61
											// Ignore post-resolution exceptions
											if ( depth + 1 >= maxDepth ) {

												// Only substitute handlers pass on context
												// and multiple values (non-spec behavior)
												if ( handler !== Thrower ) {
													that = undefined;
													args = [ e ];
												}

												deferred.rejectWith( that, args );
											}
										}
									};

							// Support: Promises/A+ section 2.3.3.3.1
							// https://promisesaplus.com/#point-57
							// Re-resolve promises immediately to dodge false rejection from
							// subsequent errors
							if ( depth ) {
								process();
							} else {

								// Call an optional hook to record the error, in case of exception
								// since it's otherwise lost when execution goes async
								if ( jQuery.Deferred.getErrorHook ) {
									process.error = jQuery.Deferred.getErrorHook();

								// The deprecated alias of the above. While the name suggests
								// returning the stack, not an error instance, jQuery just passes
								// it directly to `console.warn` so both will work; an instance
								// just better cooperates with source maps.
								} else if ( jQuery.Deferred.getStackHook ) {
									process.error = jQuery.Deferred.getStackHook();
								}
								window.setTimeout( process );
							}
						};
					}

					return jQuery.Deferred( function( newDefer ) {

						// progress_handlers.add( ... )
						tuples[ 0 ][ 3 ].add(
							resolve(
								0,
								newDefer,
								isFunction( onProgress ) ?
									onProgress :
									Identity,
								newDefer.notifyWith
							)
						);

						// fulfilled_handlers.add( ... )
						tuples[ 1 ][ 3 ].add(
							resolve(
								0,
								newDefer,
								isFunction( onFulfilled ) ?
									onFulfilled :
									Identity
							)
						);

						// rejected_handlers.add( ... )
						tuples[ 2 ][ 3 ].add(
							resolve(
								0,
								newDefer,
								isFunction( onRejected ) ?
									onRejected :
									Thrower
							)
						);
					} ).promise();
				},

				// Get a promise for this deferred
				// If obj is provided, the promise aspect is added to the object
				promise: function( obj ) {
					return obj != null ? jQuery.extend( obj, promise ) : promise;
				}
			},
			deferred = {};

		// Add list-specific methods
		jQuery.each( tuples, function( i, tuple ) {
			var list = tuple[ 2 ],
				stateString = tuple[ 5 ];

			// promise.progress = list.add
			// promise.done = list.add
			// promise.fail = list.add
			promise[ tuple[ 1 ] ] = list.add;

			// Handle state
			if ( stateString ) {
				list.add(
					function() {

						// state = "resolved" (i.e., fulfilled)
						// state = "rejected"
						state = stateString;
					},

					// rejected_callbacks.disable
					// fulfilled_callbacks.disable
					tuples[ 3 - i ][ 2 ].disable,

					// rejected_handlers.disable
					// fulfilled_handlers.disable
					tuples[ 3 - i ][ 3 ].disable,

					// progress_callbacks.lock
					tuples[ 0 ][ 2 ].lock,

					// progress_handlers.lock
					tuples[ 0 ][ 3 ].lock
				);
			}

			// progress_handlers.fire
			// fulfilled_handlers.fire
			// rejected_handlers.fire
			list.add( tuple[ 3 ].fire );

			// deferred.notify = function() { deferred.notifyWith(...) }
			// deferred.resolve = function() { deferred.resolveWith(...) }
			// deferred.reject = function() { deferred.rejectWith(...) }
			deferred[ tuple[ 0 ] ] = function() {
				deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
				return this;
			};

			// deferred.notifyWith = list.fireWith
			// deferred.resolveWith = list.fireWith
			// deferred.rejectWith = list.fireWith
			deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
		} );

		// Make the deferred a promise
		promise.promise( deferred );

		// Call given func if any
		if ( func ) {
			func.call( deferred, deferred );
		}

		// All done!
		return deferred;
	},

	// Deferred helper
	when: function( singleValue ) {
		var

			// count of uncompleted subordinates
			remaining = arguments.length,

			// count of unprocessed arguments
			i = remaining,

			// subordinate fulfillment data
			resolveContexts = Array( i ),
			resolveValues = slice.call( arguments ),

			// the primary Deferred
			primary = jQuery.Deferred(),

			// subordinate callback factory
			updateFunc = function( i ) {
				return function( value ) {
					resolveContexts[ i ] = this;
					resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
					if ( !( --remaining ) ) {
						primary.resolveWith( resolveContexts, resolveValues );
					}
				};
			};

		// Single- and empty arguments are adopted like Promise.resolve
		if ( remaining <= 1 ) {
			adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject,
				!remaining );

			// Use .then() to unwrap secondary thenables (cf. gh-3000)
			if ( primary.state() === "pending" ||
				isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {

				return primary.then();
			}
		}

		// Multiple arguments are aggregated like Promise.all array elements
		while ( i-- ) {
			adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject );
		}

		return primary.promise();
	}
} );


// These usually indicate a programmer mistake during development,
// warn about them ASAP rather than swallowing them by default.
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;

// If `jQuery.Deferred.getErrorHook` is defined, `asyncError` is an error
// captured before the async barrier to get the original error cause
// which may otherwise be hidden.
jQuery.Deferred.exceptionHook = function( error, asyncError ) {

	// Support: IE 8 - 9 only
	// Console exists when dev tools are open, which can happen at any time
	if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
		window.console.warn( "jQuery.Deferred exception: " + error.message,
			error.stack, asyncError );
	}
};




jQuery.readyException = function( error ) {
	window.setTimeout( function() {
		throw error;
	} );
};




// The deferred used on DOM ready
var readyList = jQuery.Deferred();

jQuery.fn.ready = function( fn ) {

	readyList
		.then( fn )

		// Wrap jQuery.readyException in a function so that the lookup
		// happens at the time of error handling instead of callback
		// registration.
		.catch( function( error ) {
			jQuery.readyException( error );
		} );

	return this;
};

jQuery.extend( {

	// Is the DOM ready to be used? Set to true once it occurs.
	isReady: false,

	// A counter to track how many items to wait for before
	// the ready event fires. See trac-6781
	readyWait: 1,

	// Handle when the DOM is ready
	ready: function( wait ) {

		// Abort if there are pending holds or we're already ready
		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
			return;
		}

		// Remember that the DOM is ready
		jQuery.isReady = true;

		// If a normal DOM Ready event fired, decrement, and wait if need be
		if ( wait !== true && --jQuery.readyWait > 0 ) {
			return;
		}

		// If there are functions bound, to execute
		readyList.resolveWith( document, [ jQuery ] );
	}
} );

jQuery.ready.then = readyList.then;

// The ready event handler and self cleanup method
function completed() {
	document.removeEventListener( "DOMContentLoaded", completed );
	window.removeEventListener( "load", completed );
	jQuery.ready();
}

// Catch cases where $(document).ready() is called
// after the browser event has already occurred.
// Support: IE <=9 - 10 only
// Older IE sometimes signals "interactive" too soon
if ( document.readyState === "complete" ||
	( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {

	// Handle it asynchronously to allow scripts the opportunity to delay ready
	window.setTimeout( jQuery.ready );

} else {

	// Use the handy event callback
	document.addEventListener( "DOMContentLoaded", completed );

	// A fallback to window.onload, that will always work
	window.addEventListener( "load", completed );
}




// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
	var i = 0,
		len = elems.length,
		bulk = key == null;

	// Sets many values
	if ( toType( key ) === "object" ) {
		chainable = true;
		for ( i in key ) {
			access( elems, fn, i, key[ i ], true, emptyGet, raw );
		}

	// Sets one value
	} else if ( value !== undefined ) {
		chainable = true;

		if ( !isFunction( value ) ) {
			raw = true;
		}

		if ( bulk ) {

			// Bulk operations run against the entire set
			if ( raw ) {
				fn.call( elems, value );
				fn = null;

			// ...except when executing function values
			} else {
				bulk = fn;
				fn = function( elem, _key, value ) {
					return bulk.call( jQuery( elem ), value );
				};
			}
		}

		if ( fn ) {
			for ( ; i < len; i++ ) {
				fn(
					elems[ i ], key, raw ?
						value :
						value.call( elems[ i ], i, fn( elems[ i ], key ) )
				);
			}
		}
	}

	if ( chainable ) {
		return elems;
	}

	// Gets
	if ( bulk ) {
		return fn.call( elems );
	}

	return len ? fn( elems[ 0 ], key ) : emptyGet;
};


// Matches dashed string for camelizing
var rmsPrefix = /^-ms-/,
	rdashAlpha = /-([a-z])/g;

// Used by camelCase as callback to replace()
function fcamelCase( _all, letter ) {
	return letter.toUpperCase();
}

// Convert dashed to camelCase; used by the css and data modules
// Support: IE <=9 - 11, Edge 12 - 15
// Microsoft forgot to hump their vendor prefix (trac-9572)
function camelCase( string ) {
	return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
}
var acceptData = function( owner ) {

	// Accepts only:
	//  - Node
	//    - Node.ELEMENT_NODE
	//    - Node.DOCUMENT_NODE
	//  - Object
	//    - Any
	return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
};




function Data() {
	this.expando = jQuery.expando + Data.uid++;
}

Data.uid = 1;

Data.prototype = {

	cache: function( owner ) {

		// Check if the owner object already has a cache
		var value = owner[ this.expando ];

		// If not, create one
		if ( !value ) {
			value = {};

			// We can accept data for non-element nodes in modern browsers,
			// but we should not, see trac-8335.
			// Always return an empty object.
			if ( acceptData( owner ) ) {

				// If it is a node unlikely to be stringify-ed or looped over
				// use plain assignment
				if ( owner.nodeType ) {
					owner[ this.expando ] = value;

				// Otherwise secure it in a non-enumerable property
				// configurable must be true to allow the property to be
				// deleted when data is removed
				} else {
					Object.defineProperty( owner, this.expando, {
						value: value,
						configurable: true
					} );
				}
			}
		}

		return value;
	},
	set: function( owner, data, value ) {
		var prop,
			cache = this.cache( owner );

		// Handle: [ owner, key, value ] args
		// Always use camelCase key (gh-2257)
		if ( typeof data === "string" ) {
			cache[ camelCase( data ) ] = value;

		// Handle: [ owner, { properties } ] args
		} else {

			// Copy the properties one-by-one to the cache object
			for ( prop in data ) {
				cache[ camelCase( prop ) ] = data[ prop ];
			}
		}
		return cache;
	},
	get: function( owner, key ) {
		return key === undefined ?
			this.cache( owner ) :

			// Always use camelCase key (gh-2257)
			owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
	},
	access: function( owner, key, value ) {

		// In cases where either:
		//
		//   1. No key was specified
		//   2. A string key was specified, but no value provided
		//
		// Take the "read" path and allow the get method to determine
		// which value to return, respectively either:
		//
		//   1. The entire cache object
		//   2. The data stored at the key
		//
		if ( key === undefined ||
				( ( key && typeof key === "string" ) && value === undefined ) ) {

			return this.get( owner, key );
		}

		// When the key is not a string, or both a key and value
		// are specified, set or extend (existing objects) with either:
		//
		//   1. An object of properties
		//   2. A key and value
		//
		this.set( owner, key, value );

		// Since the "set" path can have two possible entry points
		// return the expected data based on which path was taken[*]
		return value !== undefined ? value : key;
	},
	remove: function( owner, key ) {
		var i,
			cache = owner[ this.expando ];

		if ( cache === undefined ) {
			return;
		}

		if ( key !== undefined ) {

			// Support array or space separated string of keys
			if ( Array.isArray( key ) ) {

				// If key is an array of keys...
				// We always set camelCase keys, so remove that.
				key = key.map( camelCase );
			} else {
				key = camelCase( key );

				// If a key with the spaces exists, use it.
				// Otherwise, create an array by matching non-whitespace
				key = key in cache ?
					[ key ] :
					( key.match( rnothtmlwhite ) || [] );
			}

			i = key.length;

			while ( i-- ) {
				delete cache[ key[ i ] ];
			}
		}

		// Remove the expando if there's no more data
		if ( key === undefined || jQuery.isEmptyObject( cache ) ) {

			// Support: Chrome <=35 - 45
			// Webkit & Blink performance suffers when deleting properties
			// from DOM nodes, so set to undefined instead
			// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
			if ( owner.nodeType ) {
				owner[ this.expando ] = undefined;
			} else {
				delete owner[ this.expando ];
			}
		}
	},
	hasData: function( owner ) {
		var cache = owner[ this.expando ];
		return cache !== undefined && !jQuery.isEmptyObject( cache );
	}
};
var dataPriv = new Data();

var dataUser = new Data();



//	Implementation Summary
//
//	1. Enforce API surface and semantic compatibility with 1.9.x branch
//	2. Improve the module's maintainability by reducing the storage
//		paths to a single mechanism.
//	3. Use the same single mechanism to support "private" and "user" data.
//	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
//	5. Avoid exposing implementation details on user objects (eg. expando properties)
//	6. Provide a clear path for implementation upgrade to WeakMap in 2014

var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
	rmultiDash = /[A-Z]/g;

function getData( data ) {
	if ( data === "true" ) {
		return true;
	}

	if ( data === "false" ) {
		return false;
	}

	if ( data === "null" ) {
		return null;
	}

	// Only convert to a number if it doesn't change the string
	if ( data === +data + "" ) {
		return +data;
	}

	if ( rbrace.test( data ) ) {
		return JSON.parse( data );
	}

	return data;
}

function dataAttr( elem, key, data ) {
	var name;

	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
	if ( data === undefined && elem.nodeType === 1 ) {
		name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
		data = elem.getAttribute( name );

		if ( typeof data === "string" ) {
			try {
				data = getData( data );
			} catch ( e ) {}

			// Make sure we set the data so it isn't changed later
			dataUser.set( elem, key, data );
		} else {
			data = undefined;
		}
	}
	return data;
}

jQuery.extend( {
	hasData: function( elem ) {
		return dataUser.hasData( elem ) || dataPriv.hasData( elem );
	},

	data: function( elem, name, data ) {
		return dataUser.access( elem, name, data );
	},

	removeData: function( elem, name ) {
		dataUser.remove( elem, name );
	},

	// TODO: Now that all calls to _data and _removeData have been replaced
	// with direct calls to dataPriv methods, these can be deprecated.
	_data: function( elem, name, data ) {
		return dataPriv.access( elem, name, data );
	},

	_removeData: function( elem, name ) {
		dataPriv.remove( elem, name );
	}
} );

jQuery.fn.extend( {
	data: function( key, value ) {
		var i, name, data,
			elem = this[ 0 ],
			attrs = elem && elem.attributes;

		// Gets all values
		if ( key === undefined ) {
			if ( this.length ) {
				data = dataUser.get( elem );

				if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
					i = attrs.length;
					while ( i-- ) {

						// Support: IE 11 only
						// The attrs elements can be null (trac-14894)
						if ( attrs[ i ] ) {
							name = attrs[ i ].name;
							if ( name.indexOf( "data-" ) === 0 ) {
								name = camelCase( name.slice( 5 ) );
								dataAttr( elem, name, data[ name ] );
							}
						}
					}
					dataPriv.set( elem, "hasDataAttrs", true );
				}
			}

			return data;
		}

		// Sets multiple values
		if ( typeof key === "object" ) {
			return this.each( function() {
				dataUser.set( this, key );
			} );
		}

		return access( this, function( value ) {
			var data;

			// The calling jQuery object (element matches) is not empty
			// (and therefore has an element appears at this[ 0 ]) and the
			// `value` parameter was not undefined. An empty jQuery object
			// will result in `undefined` for elem = this[ 0 ] which will
			// throw an exception if an attempt to read a data cache is made.
			if ( elem && value === undefined ) {

				// Attempt to get data from the cache
				// The key will always be camelCased in Data
				data = dataUser.get( elem, key );
				if ( data !== undefined ) {
					return data;
				}

				// Attempt to "discover" the data in
				// HTML5 custom data-* attrs
				data = dataAttr( elem, key );
				if ( data !== undefined ) {
					return data;
				}

				// We tried really hard, but the data doesn't exist.
				return;
			}

			// Set the data...
			this.each( function() {

				// We always store the camelCased key
				dataUser.set( this, key, value );
			} );
		}, null, value, arguments.length > 1, null, true );
	},

	removeData: function( key ) {
		return this.each( function() {
			dataUser.remove( this, key );
		} );
	}
} );


jQuery.extend( {
	queue: function( elem, type, data ) {
		var queue;

		if ( elem ) {
			type = ( type || "fx" ) + "queue";
			queue = dataPriv.get( elem, type );

			// Speed up dequeue by getting out quickly if this is just a lookup
			if ( data ) {
				if ( !queue || Array.isArray( data ) ) {
					queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
				} else {
					queue.push( data );
				}
			}
			return queue || [];
		}
	},

	dequeue: function( elem, type ) {
		type = type || "fx";

		var queue = jQuery.queue( elem, type ),
			startLength = queue.length,
			fn = queue.shift(),
			hooks = jQuery._queueHooks( elem, type ),
			next = function() {
				jQuery.dequeue( elem, type );
			};

		// If the fx queue is dequeued, always remove the progress sentinel
		if ( fn === "inprogress" ) {
			fn = queue.shift();
			startLength--;
		}

		if ( fn ) {

			// Add a progress sentinel to prevent the fx queue from being
			// automatically dequeued
			if ( type === "fx" ) {
				queue.unshift( "inprogress" );
			}

			// Clear up the last queue stop function
			delete hooks.stop;
			fn.call( elem, next, hooks );
		}

		if ( !startLength && hooks ) {
			hooks.empty.fire();
		}
	},

	// Not public - generate a queueHooks object, or return the current one
	_queueHooks: function( elem, type ) {
		var key = type + "queueHooks";
		return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
			empty: jQuery.Callbacks( "once memory" ).add( function() {
				dataPriv.remove( elem, [ type + "queue", key ] );
			} )
		} );
	}
} );

jQuery.fn.extend( {
	queue: function( type, data ) {
		var setter = 2;

		if ( typeof type !== "string" ) {
			data = type;
			type = "fx";
			setter--;
		}

		if ( arguments.length < setter ) {
			return jQuery.queue( this[ 0 ], type );
		}

		return data === undefined ?
			this :
			this.each( function() {
				var queue = jQuery.queue( this, type, data );

				// Ensure a hooks for this queue
				jQuery._queueHooks( this, type );

				if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
					jQuery.dequeue( this, type );
				}
			} );
	},
	dequeue: function( type ) {
		return this.each( function() {
			jQuery.dequeue( this, type );
		} );
	},
	clearQueue: function( type ) {
		return this.queue( type || "fx", [] );
	},

	// Get a promise resolved when queues of a certain type
	// are emptied (fx is the type by default)
	promise: function( type, obj ) {
		var tmp,
			count = 1,
			defer = jQuery.Deferred(),
			elements = this,
			i = this.length,
			resolve = function() {
				if ( !( --count ) ) {
					defer.resolveWith( elements, [ elements ] );
				}
			};

		if ( typeof type !== "string" ) {
			obj = type;
			type = undefined;
		}
		type = type || "fx";

		while ( i-- ) {
			tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
			if ( tmp && tmp.empty ) {
				count++;
				tmp.empty.add( resolve );
			}
		}
		resolve();
		return defer.promise( obj );
	}
} );
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;

var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );


var cssExpand = [ "Top", "Right", "Bottom", "Left" ];

var documentElement = document.documentElement;



	var isAttached = function( elem ) {
			return jQuery.contains( elem.ownerDocument, elem );
		},
		composed = { composed: true };

	// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
	// Check attachment across shadow DOM boundaries when possible (gh-3504)
	// Support: iOS 10.0-10.2 only
	// Early iOS 10 versions support `attachShadow` but not `getRootNode`,
	// leading to errors. We need to check for `getRootNode`.
	if ( documentElement.getRootNode ) {
		isAttached = function( elem ) {
			return jQuery.contains( elem.ownerDocument, elem ) ||
				elem.getRootNode( composed ) === elem.ownerDocument;
		};
	}
var isHiddenWithinTree = function( elem, el ) {

		// isHiddenWithinTree might be called from jQuery#filter function;
		// in that case, element will be second argument
		elem = el || elem;

		// Inline style trumps all
		return elem.style.display === "none" ||
			elem.style.display === "" &&

			// Otherwise, check computed style
			// Support: Firefox <=43 - 45
			// Disconnected elements can have computed display: none, so first confirm that elem is
			// in the document.
			isAttached( elem ) &&

			jQuery.css( elem, "display" ) === "none";
	};



function adjustCSS( elem, prop, valueParts, tween ) {
	var adjusted, scale,
		maxIterations = 20,
		currentValue = tween ?
			function() {
				return tween.cur();
			} :
			function() {
				return jQuery.css( elem, prop, "" );
			},
		initial = currentValue(),
		unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),

		// Starting value computation is required for potential unit mismatches
		initialInUnit = elem.nodeType &&
			( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
			rcssNum.exec( jQuery.css( elem, prop ) );

	if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {

		// Support: Firefox <=54
		// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
		initial = initial / 2;

		// Trust units reported by jQuery.css
		unit = unit || initialInUnit[ 3 ];

		// Iteratively approximate from a nonzero starting point
		initialInUnit = +initial || 1;

		while ( maxIterations-- ) {

			// Evaluate and update our best guess (doubling guesses that zero out).
			// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
			jQuery.style( elem, prop, initialInUnit + unit );
			if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
				maxIterations = 0;
			}
			initialInUnit = initialInUnit / scale;

		}

		initialInUnit = initialInUnit * 2;
		jQuery.style( elem, prop, initialInUnit + unit );

		// Make sure we update the tween properties later on
		valueParts = valueParts || [];
	}

	if ( valueParts ) {
		initialInUnit = +initialInUnit || +initial || 0;

		// Apply relative offset (+=/-=) if specified
		adjusted = valueParts[ 1 ] ?
			initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
			+valueParts[ 2 ];
		if ( tween ) {
			tween.unit = unit;
			tween.start = initialInUnit;
			tween.end = adjusted;
		}
	}
	return adjusted;
}


var defaultDisplayMap = {};

function getDefaultDisplay( elem ) {
	var temp,
		doc = elem.ownerDocument,
		nodeName = elem.nodeName,
		display = defaultDisplayMap[ nodeName ];

	if ( display ) {
		return display;
	}

	temp = doc.body.appendChild( doc.createElement( nodeName ) );
	display = jQuery.css( temp, "display" );

	temp.parentNode.removeChild( temp );

	if ( display === "none" ) {
		display = "block";
	}
	defaultDisplayMap[ nodeName ] = display;

	return display;
}

function showHide( elements, show ) {
	var display, elem,
		values = [],
		index = 0,
		length = elements.length;

	// Determine new display value for elements that need to change
	for ( ; index < length; index++ ) {
		elem = elements[ index ];
		if ( !elem.style ) {
			continue;
		}

		display = elem.style.display;
		if ( show ) {

			// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
			// check is required in this first loop unless we have a nonempty display value (either
			// inline or about-to-be-restored)
			if ( display === "none" ) {
				values[ index ] = dataPriv.get( elem, "display" ) || null;
				if ( !values[ index ] ) {
					elem.style.display = "";
				}
			}
			if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
				values[ index ] = getDefaultDisplay( elem );
			}
		} else {
			if ( display !== "none" ) {
				values[ index ] = "none";

				// Remember what we're overwriting
				dataPriv.set( elem, "display", display );
			}
		}
	}

	// Set the display of the elements in a second loop to avoid constant reflow
	for ( index = 0; index < length; index++ ) {
		if ( values[ index ] != null ) {
			elements[ index ].style.display = values[ index ];
		}
	}

	return elements;
}

jQuery.fn.extend( {
	show: function() {
		return showHide( this, true );
	},
	hide: function() {
		return showHide( this );
	},
	toggle: function( state ) {
		if ( typeof state === "boolean" ) {
			return state ? this.show() : this.hide();
		}

		return this.each( function() {
			if ( isHiddenWithinTree( this ) ) {
				jQuery( this ).show();
			} else {
				jQuery( this ).hide();
			}
		} );
	}
} );
var rcheckableType = ( /^(?:checkbox|radio)$/i );

var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );

var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );



( function() {
	var fragment = document.createDocumentFragment(),
		div = fragment.appendChild( document.createElement( "div" ) ),
		input = document.createElement( "input" );

	// Support: Android 4.0 - 4.3 only
	// Check state lost if the name is set (trac-11217)
	// Support: Windows Web Apps (WWA)
	// `name` and `type` must use .setAttribute for WWA (trac-14901)
	input.setAttribute( "type", "radio" );
	input.setAttribute( "checked", "checked" );
	input.setAttribute( "name", "t" );

	div.appendChild( input );

	// Support: Android <=4.1 only
	// Older WebKit doesn't clone checked state correctly in fragments
	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;

	// Support: IE <=11 only
	// Make sure textarea (and checkbox) defaultValue is properly cloned
	div.innerHTML = "<textarea>x</textarea>";
	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;

	// Support: IE <=9 only
	// IE <=9 replaces <option> tags with their contents when inserted outside of
	// the select element.
	div.innerHTML = "<option></option>";
	support.option = !!div.lastChild;
} )();


// We have to close these tags to support XHTML (trac-13200)
var wrapMap = {

	// XHTML parsers do not magically insert elements in the
	// same way that tag soup parsers do. So we cannot shorten
	// this by omitting <tbody> or other required elements.
	thead: [ 1, "<table>", "</table>" ],
	col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
	tr: [ 2, "<table><tbody>", "</tbody></table>" ],
	td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],

	_default: [ 0, "", "" ]
};

wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;

// Support: IE <=9 only
if ( !support.option ) {
	wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ];
}


function getAll( context, tag ) {

	// Support: IE <=9 - 11 only
	// Use typeof to avoid zero-argument method invocation on host objects (trac-15151)
	var ret;

	if ( typeof context.getElementsByTagName !== "undefined" ) {
		ret = context.getElementsByTagName( tag || "*" );

	} else if ( typeof context.querySelectorAll !== "undefined" ) {
		ret = context.querySelectorAll( tag || "*" );

	} else {
		ret = [];
	}

	if ( tag === undefined || tag && nodeName( context, tag ) ) {
		return jQuery.merge( [ context ], ret );
	}

	return ret;
}


// Mark scripts as having already been evaluated
function setGlobalEval( elems, refElements ) {
	var i = 0,
		l = elems.length;

	for ( ; i < l; i++ ) {
		dataPriv.set(
			elems[ i ],
			"globalEval",
			!refElements || dataPriv.get( refElements[ i ], "globalEval" )
		);
	}
}


var rhtml = /<|&#?\w+;/;

function buildFragment( elems, context, scripts, selection, ignored ) {
	var elem, tmp, tag, wrap, attached, j,
		fragment = context.createDocumentFragment(),
		nodes = [],
		i = 0,
		l = elems.length;

	for ( ; i < l; i++ ) {
		elem = elems[ i ];

		if ( elem || elem === 0 ) {

			// Add nodes directly
			if ( toType( elem ) === "object" ) {

				// Support: Android <=4.0 only, PhantomJS 1 only
				// push.apply(_, arraylike) throws on ancient WebKit
				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );

			// Convert non-html into a text node
			} else if ( !rhtml.test( elem ) ) {
				nodes.push( context.createTextNode( elem ) );

			// Convert html into DOM nodes
			} else {
				tmp = tmp || fragment.appendChild( context.createElement( "div" ) );

				// Deserialize a standard representation
				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
				wrap = wrapMap[ tag ] || wrapMap._default;
				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

				// Descend through wrappers to the right content
				j = wrap[ 0 ];
				while ( j-- ) {
					tmp = tmp.lastChild;
				}

				// Support: Android <=4.0 only, PhantomJS 1 only
				// push.apply(_, arraylike) throws on ancient WebKit
				jQuery.merge( nodes, tmp.childNodes );

				// Remember the top-level container
				tmp = fragment.firstChild;

				// Ensure the created nodes are orphaned (trac-12392)
				tmp.textContent = "";
			}
		}
	}

	// Remove wrapper from fragment
	fragment.textContent = "";

	i = 0;
	while ( ( elem = nodes[ i++ ] ) ) {

		// Skip elements already in the context collection (trac-4087)
		if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
			if ( ignored ) {
				ignored.push( elem );
			}
			continue;
		}

		attached = isAttached( elem );

		// Append to fragment
		tmp = getAll( fragment.appendChild( elem ), "script" );

		// Preserve script evaluation history
		if ( attached ) {
			setGlobalEval( tmp );
		}

		// Capture executables
		if ( scripts ) {
			j = 0;
			while ( ( elem = tmp[ j++ ] ) ) {
				if ( rscriptType.test( elem.type || "" ) ) {
					scripts.push( elem );
				}
			}
		}
	}

	return fragment;
}


var rtypenamespace = /^([^.]*)(?:\.(.+)|)/;

function returnTrue() {
	return true;
}

function returnFalse() {
	return false;
}

function on( elem, types, selector, data, fn, one ) {
	var origFn, type;

	// Types can be a map of types/handlers
	if ( typeof types === "object" ) {

		// ( types-Object, selector, data )
		if ( typeof selector !== "string" ) {

			// ( types-Object, data )
			data = data || selector;
			selector = undefined;
		}
		for ( type in types ) {
			on( elem, type, selector, data, types[ type ], one );
		}
		return elem;
	}

	if ( data == null && fn == null ) {

		// ( types, fn )
		fn = selector;
		data = selector = undefined;
	} else if ( fn == null ) {
		if ( typeof selector === "string" ) {

			// ( types, selector, fn )
			fn = data;
			data = undefined;
		} else {

			// ( types, data, fn )
			fn = data;
			data = selector;
			selector = undefined;
		}
	}
	if ( fn === false ) {
		fn = returnFalse;
	} else if ( !fn ) {
		return elem;
	}

	if ( one === 1 ) {
		origFn = fn;
		fn = function( event ) {

			// Can use an empty set, since event contains the info
			jQuery().off( event );
			return origFn.apply( this, arguments );
		};

		// Use same guid so caller can remove using origFn
		fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
	}
	return elem.each( function() {
		jQuery.event.add( this, types, fn, data, selector );
	} );
}

/*
 * Helper functions for managing events -- not part of the public interface.
 * Props to Dean Edwards' addEvent library for many of the ideas.
 */
jQuery.event = {

	global: {},

	add: function( elem, types, handler, data, selector ) {

		var handleObjIn, eventHandle, tmp,
			events, t, handleObj,
			special, handlers, type, namespaces, origType,
			elemData = dataPriv.get( elem );

		// Only attach events to objects that accept data
		if ( !acceptData( elem ) ) {
			return;
		}

		// Caller can pass in an object of custom data in lieu of the handler
		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
			selector = handleObjIn.selector;
		}

		// Ensure that invalid selectors throw exceptions at attach time
		// Evaluate against documentElement in case elem is a non-element node (e.g., document)
		if ( selector ) {
			jQuery.find.matchesSelector( documentElement, selector );
		}

		// Make sure that the handler has a unique ID, used to find/remove it later
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// Init the element's event structure and main handler, if this is the first
		if ( !( events = elemData.events ) ) {
			events = elemData.events = Object.create( null );
		}
		if ( !( eventHandle = elemData.handle ) ) {
			eventHandle = elemData.handle = function( e ) {

				// Discard the second event of a jQuery.event.trigger() and
				// when an event is called after a page has unloaded
				return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
			};
		}

		// Handle multiple events separated by a space
		types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			tmp = rtypenamespace.exec( types[ t ] ) || [];
			type = origType = tmp[ 1 ];
			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();

			// There *must* be a type, no attaching namespace-only handlers
			if ( !type ) {
				continue;
			}

			// If event changes its type, use the special event handlers for the changed type
			special = jQuery.event.special[ type ] || {};

			// If selector defined, determine special event api type, otherwise given type
			type = ( selector ? special.delegateType : special.bindType ) || type;

			// Update special based on newly reset type
			special = jQuery.event.special[ type ] || {};

			// handleObj is passed to all event handlers
			handleObj = jQuery.extend( {
				type: type,
				origType: origType,
				data: data,
				handler: handler,
				guid: handler.guid,
				selector: selector,
				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
				namespace: namespaces.join( "." )
			}, handleObjIn );

			// Init the event handler queue if we're the first
			if ( !( handlers = events[ type ] ) ) {
				handlers = events[ type ] = [];
				handlers.delegateCount = 0;

				// Only use addEventListener if the special events handler returns false
				if ( !special.setup ||
					special.setup.call( elem, data, namespaces, eventHandle ) === false ) {

					if ( elem.addEventListener ) {
						elem.addEventListener( type, eventHandle );
					}
				}
			}

			if ( special.add ) {
				special.add.call( elem, handleObj );

				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// Add to the element's handler list, delegates in front
			if ( selector ) {
				handlers.splice( handlers.delegateCount++, 0, handleObj );
			} else {
				handlers.push( handleObj );
			}

			// Keep track of which events have ever been used, for event optimization
			jQuery.event.global[ type ] = true;
		}

	},

	// Detach an event or set of events from an element
	remove: function( elem, types, handler, selector, mappedTypes ) {

		var j, origCount, tmp,
			events, t, handleObj,
			special, handlers, type, namespaces, origType,
			elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );

		if ( !elemData || !( events = elemData.events ) ) {
			return;
		}

		// Once for each type.namespace in types; type may be omitted
		types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			tmp = rtypenamespace.exec( types[ t ] ) || [];
			type = origType = tmp[ 1 ];
			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();

			// Unbind all events (on this namespace, if provided) for the element
			if ( !type ) {
				for ( type in events ) {
					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
				}
				continue;
			}

			special = jQuery.event.special[ type ] || {};
			type = ( selector ? special.delegateType : special.bindType ) || type;
			handlers = events[ type ] || [];
			tmp = tmp[ 2 ] &&
				new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );

			// Remove matching events
			origCount = j = handlers.length;
			while ( j-- ) {
				handleObj = handlers[ j ];

				if ( ( mappedTypes || origType === handleObj.origType ) &&
					( !handler || handler.guid === handleObj.guid ) &&
					( !tmp || tmp.test( handleObj.namespace ) ) &&
					( !selector || selector === handleObj.selector ||
						selector === "**" && handleObj.selector ) ) {
					handlers.splice( j, 1 );

					if ( handleObj.selector ) {
						handlers.delegateCount--;
					}
					if ( special.remove ) {
						special.remove.call( elem, handleObj );
					}
				}
			}

			// Remove generic event handler if we removed something and no more handlers exist
			// (avoids potential for endless recursion during removal of special event handlers)
			if ( origCount && !handlers.length ) {
				if ( !special.teardown ||
					special.teardown.call( elem, namespaces, elemData.handle ) === false ) {

					jQuery.removeEvent( elem, type, elemData.handle );
				}

				delete events[ type ];
			}
		}

		// Remove data and the expando if it's no longer used
		if ( jQuery.isEmptyObject( events ) ) {
			dataPriv.remove( elem, "handle events" );
		}
	},

	dispatch: function( nativeEvent ) {

		var i, j, ret, matched, handleObj, handlerQueue,
			args = new Array( arguments.length ),

			// Make a writable jQuery.Event from the native event object
			event = jQuery.event.fix( nativeEvent ),

			handlers = (
				dataPriv.get( this, "events" ) || Object.create( null )
			)[ event.type ] || [],
			special = jQuery.event.special[ event.type ] || {};

		// Use the fix-ed jQuery.Event rather than the (read-only) native event
		args[ 0 ] = event;

		for ( i = 1; i < arguments.length; i++ ) {
			args[ i ] = arguments[ i ];
		}

		event.delegateTarget = this;

		// Call the preDispatch hook for the mapped type, and let it bail if desired
		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
			return;
		}

		// Determine handlers
		handlerQueue = jQuery.event.handlers.call( this, event, handlers );

		// Run delegates first; they may want to stop propagation beneath us
		i = 0;
		while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
			event.currentTarget = matched.elem;

			j = 0;
			while ( ( handleObj = matched.handlers[ j++ ] ) &&
				!event.isImmediatePropagationStopped() ) {

				// If the event is namespaced, then each handler is only invoked if it is
				// specially universal or its namespaces are a superset of the event's.
				if ( !event.rnamespace || handleObj.namespace === false ||
					event.rnamespace.test( handleObj.namespace ) ) {

					event.handleObj = handleObj;
					event.data = handleObj.data;

					ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
						handleObj.handler ).apply( matched.elem, args );

					if ( ret !== undefined ) {
						if ( ( event.result = ret ) === false ) {
							event.preventDefault();
							event.stopPropagation();
						}
					}
				}
			}
		}

		// Call the postDispatch hook for the mapped type
		if ( special.postDispatch ) {
			special.postDispatch.call( this, event );
		}

		return event.result;
	},

	handlers: function( event, handlers ) {
		var i, handleObj, sel, matchedHandlers, matchedSelectors,
			handlerQueue = [],
			delegateCount = handlers.delegateCount,
			cur = event.target;

		// Find delegate handlers
		if ( delegateCount &&

			// Support: IE <=9
			// Black-hole SVG <use> instance trees (trac-13180)
			cur.nodeType &&

			// Support: Firefox <=42
			// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
			// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
			// Support: IE 11 only
			// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
			!( event.type === "click" && event.button >= 1 ) ) {

			for ( ; cur !== this; cur = cur.parentNode || this ) {

				// Don't check non-elements (trac-13208)
				// Don't process clicks on disabled elements (trac-6911, trac-8165, trac-11382, trac-11764)
				if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
					matchedHandlers = [];
					matchedSelectors = {};
					for ( i = 0; i < delegateCount; i++ ) {
						handleObj = handlers[ i ];

						// Don't conflict with Object.prototype properties (trac-13203)
						sel = handleObj.selector + " ";

						if ( matchedSelectors[ sel ] === undefined ) {
							matchedSelectors[ sel ] = handleObj.needsContext ?
								jQuery( sel, this ).index( cur ) > -1 :
								jQuery.find( sel, this, null, [ cur ] ).length;
						}
						if ( matchedSelectors[ sel ] ) {
							matchedHandlers.push( handleObj );
						}
					}
					if ( matchedHandlers.length ) {
						handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
					}
				}
			}
		}

		// Add the remaining (directly-bound) handlers
		cur = this;
		if ( delegateCount < handlers.length ) {
			handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
		}

		return handlerQueue;
	},

	addProp: function( name, hook ) {
		Object.defineProperty( jQuery.Event.prototype, name, {
			enumerable: true,
			configurable: true,

			get: isFunction( hook ) ?
				function() {
					if ( this.originalEvent ) {
						return hook( this.originalEvent );
					}
				} :
				function() {
					if ( this.originalEvent ) {
						return this.originalEvent[ name ];
					}
				},

			set: function( value ) {
				Object.defineProperty( this, name, {
					enumerable: true,
					configurable: true,
					writable: true,
					value: value
				} );
			}
		} );
	},

	fix: function( originalEvent ) {
		return originalEvent[ jQuery.expando ] ?
			originalEvent :
			new jQuery.Event( originalEvent );
	},

	special: {
		load: {

			// Prevent triggered image.load events from bubbling to window.load
			noBubble: true
		},
		click: {

			// Utilize native event to ensure correct state for checkable inputs
			setup: function( data ) {

				// For mutual compressibility with _default, replace `this` access with a local var.
				// `|| data` is dead code meant only to preserve the variable through minification.
				var el = this || data;

				// Claim the first handler
				if ( rcheckableType.test( el.type ) &&
					el.click && nodeName( el, "input" ) ) {

					// dataPriv.set( el, "click", ... )
					leverageNative( el, "click", true );
				}

				// Return false to allow normal processing in the caller
				return false;
			},
			trigger: function( data ) {

				// For mutual compressibility with _default, replace `this` access with a local var.
				// `|| data` is dead code meant only to preserve the variable through minification.
				var el = this || data;

				// Force setup before triggering a click
				if ( rcheckableType.test( el.type ) &&
					el.click && nodeName( el, "input" ) ) {

					leverageNative( el, "click" );
				}

				// Return non-false to allow normal event-path propagation
				return true;
			},

			// For cross-browser consistency, suppress native .click() on links
			// Also prevent it if we're currently inside a leveraged native-event stack
			_default: function( event ) {
				var target = event.target;
				return rcheckableType.test( target.type ) &&
					target.click && nodeName( target, "input" ) &&
					dataPriv.get( target, "click" ) ||
					nodeName( target, "a" );
			}
		},

		beforeunload: {
			postDispatch: function( event ) {

				// Support: Firefox 20+
				// Firefox doesn't alert if the returnValue field is not set.
				if ( event.result !== undefined && event.originalEvent ) {
					event.originalEvent.returnValue = event.result;
				}
			}
		}
	}
};

// Ensure the presence of an event listener that handles manually-triggered
// synthetic events by interrupting progress until reinvoked in response to
// *native* events that it fires directly, ensuring that state changes have
// already occurred before other listeners are invoked.
function leverageNative( el, type, isSetup ) {

	// Missing `isSetup` indicates a trigger call, which must force setup through jQuery.event.add
	if ( !isSetup ) {
		if ( dataPriv.get( el, type ) === undefined ) {
			jQuery.event.add( el, type, returnTrue );
		}
		return;
	}

	// Register the controller as a special universal handler for all event namespaces
	dataPriv.set( el, type, false );
	jQuery.event.add( el, type, {
		namespace: false,
		handler: function( event ) {
			var result,
				saved = dataPriv.get( this, type );

			if ( ( event.isTrigger & 1 ) && this[ type ] ) {

				// Interrupt processing of the outer synthetic .trigger()ed event
				if ( !saved ) {

					// Store arguments for use when handling the inner native event
					// There will always be at least one argument (an event object), so this array
					// will not be confused with a leftover capture object.
					saved = slice.call( arguments );
					dataPriv.set( this, type, saved );

					// Trigger the native event and capture its result
					this[ type ]();
					result = dataPriv.get( this, type );
					dataPriv.set( this, type, false );

					if ( saved !== result ) {

						// Cancel the outer synthetic event
						event.stopImmediatePropagation();
						event.preventDefault();

						return result;
					}

				// If this is an inner synthetic event for an event with a bubbling surrogate
				// (focus or blur), assume that the surrogate already propagated from triggering
				// the native event and prevent that from happening again here.
				// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
				// bubbling surrogate propagates *after* the non-bubbling base), but that seems
				// less bad than duplication.
				} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
					event.stopPropagation();
				}

			// If this is a native event triggered above, everything is now in order
			// Fire an inner synthetic event with the original arguments
			} else if ( saved ) {

				// ...and capture the result
				dataPriv.set( this, type, jQuery.event.trigger(
					saved[ 0 ],
					saved.slice( 1 ),
					this
				) );

				// Abort handling of the native event by all jQuery handlers while allowing
				// native handlers on the same element to run. On target, this is achieved
				// by stopping immediate propagation just on the jQuery event. However,
				// the native event is re-wrapped by a jQuery one on each level of the
				// propagation so the only way to stop it for jQuery is to stop it for
				// everyone via native `stopPropagation()`. This is not a problem for
				// focus/blur which don't bubble, but it does also stop click on checkboxes
				// and radios. We accept this limitation.
				event.stopPropagation();
				event.isImmediatePropagationStopped = returnTrue;
			}
		}
	} );
}

jQuery.removeEvent = function( elem, type, handle ) {

	// This "if" is needed for plain objects
	if ( elem.removeEventListener ) {
		elem.removeEventListener( type, handle );
	}
};

jQuery.Event = function( src, props ) {

	// Allow instantiation without the 'new' keyword
	if ( !( this instanceof jQuery.Event ) ) {
		return new jQuery.Event( src, props );
	}

	// Event object
	if ( src && src.type ) {
		this.originalEvent = src;
		this.type = src.type;

		// Events bubbling up the document may have been marked as prevented
		// by a handler lower down the tree; reflect the correct value.
		this.isDefaultPrevented = src.defaultPrevented ||
				src.defaultPrevented === undefined &&

				// Support: Android <=2.3 only
				src.returnValue === false ?
			returnTrue :
			returnFalse;

		// Create target properties
		// Support: Safari <=6 - 7 only
		// Target should not be a text node (trac-504, trac-13143)
		this.target = ( src.target && src.target.nodeType === 3 ) ?
			src.target.parentNode :
			src.target;

		this.currentTarget = src.currentTarget;
		this.relatedTarget = src.relatedTarget;

	// Event type
	} else {
		this.type = src;
	}

	// Put explicitly provided properties onto the event object
	if ( props ) {
		jQuery.extend( this, props );
	}

	// Create a timestamp if incoming event doesn't have one
	this.timeStamp = src && src.timeStamp || Date.now();

	// Mark it as fixed
	this[ jQuery.expando ] = true;
};

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
	constructor: jQuery.Event,
	isDefaultPrevented: returnFalse,
	isPropagationStopped: returnFalse,
	isImmediatePropagationStopped: returnFalse,
	isSimulated: false,

	preventDefault: function() {
		var e = this.originalEvent;

		this.isDefaultPrevented = returnTrue;

		if ( e && !this.isSimulated ) {
			e.preventDefault();
		}
	},
	stopPropagation: function() {
		var e = this.originalEvent;

		this.isPropagationStopped = returnTrue;

		if ( e && !this.isSimulated ) {
			e.stopPropagation();
		}
	},
	stopImmediatePropagation: function() {
		var e = this.originalEvent;

		this.isImmediatePropagationStopped = returnTrue;

		if ( e && !this.isSimulated ) {
			e.stopImmediatePropagation();
		}

		this.stopPropagation();
	}
};

// Includes all common event props including KeyEvent and MouseEvent specific props
jQuery.each( {
	altKey: true,
	bubbles: true,
	cancelable: true,
	changedTouches: true,
	ctrlKey: true,
	detail: true,
	eventPhase: true,
	metaKey: true,
	pageX: true,
	pageY: true,
	shiftKey: true,
	view: true,
	"char": true,
	code: true,
	charCode: true,
	key: true,
	keyCode: true,
	button: true,
	buttons: true,
	clientX: true,
	clientY: true,
	offsetX: true,
	offsetY: true,
	pointerId: true,
	pointerType: true,
	screenX: true,
	screenY: true,
	targetTouches: true,
	toElement: true,
	touches: true,
	which: true
}, jQuery.event.addProp );

jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {

	function focusMappedHandler( nativeEvent ) {
		if ( document.documentMode ) {

			// Support: IE 11+
			// Attach a single focusin/focusout handler on the document while someone wants
			// focus/blur. This is because the former are synchronous in IE while the latter
			// are async. In other browsers, all those handlers are invoked synchronously.

			// `handle` from private data would already wrap the event, but we need
			// to change the `type` here.
			var handle = dataPriv.get( this, "handle" ),
				event = jQuery.event.fix( nativeEvent );
			event.type = nativeEvent.type === "focusin" ? "focus" : "blur";
			event.isSimulated = true;

			// First, handle focusin/focusout
			handle( nativeEvent );

			// ...then, handle focus/blur
			//
			// focus/blur don't bubble while focusin/focusout do; simulate the former by only
			// invoking the handler at the lower level.
			if ( event.target === event.currentTarget ) {

				// The setup part calls `leverageNative`, which, in turn, calls
				// `jQuery.event.add`, so event handle will already have been set
				// by this point.
				handle( event );
			}
		} else {

			// For non-IE browsers, attach a single capturing handler on the document
			// while someone wants focusin/focusout.
			jQuery.event.simulate( delegateType, nativeEvent.target,
				jQuery.event.fix( nativeEvent ) );
		}
	}

	jQuery.event.special[ type ] = {

		// Utilize native event if possible so blur/focus sequence is correct
		setup: function() {

			var attaches;

			// Claim the first handler
			// dataPriv.set( this, "focus", ... )
			// dataPriv.set( this, "blur", ... )
			leverageNative( this, type, true );

			if ( document.documentMode ) {

				// Support: IE 9 - 11+
				// We use the same native handler for focusin & focus (and focusout & blur)
				// so we need to coordinate setup & teardown parts between those events.
				// Use `delegateType` as the key as `type` is already used by `leverageNative`.
				attaches = dataPriv.get( this, delegateType );
				if ( !attaches ) {
					this.addEventListener( delegateType, focusMappedHandler );
				}
				dataPriv.set( this, delegateType, ( attaches || 0 ) + 1 );
			} else {

				// Return false to allow normal processing in the caller
				return false;
			}
		},
		trigger: function() {

			// Force setup before trigger
			leverageNative( this, type );

			// Return non-false to allow normal event-path propagation
			return true;
		},

		teardown: function() {
			var attaches;

			if ( document.documentMode ) {
				attaches = dataPriv.get( this, delegateType ) - 1;
				if ( !attaches ) {
					this.removeEventListener( delegateType, focusMappedHandler );
					dataPriv.remove( this, delegateType );
				} else {
					dataPriv.set( this, delegateType, attaches );
				}
			} else {

				// Return false to indicate standard teardown should be applied
				return false;
			}
		},

		// Suppress native focus or blur if we're currently inside
		// a leveraged native-event stack
		_default: function( event ) {
			return dataPriv.get( event.target, type );
		},

		delegateType: delegateType
	};

	// Support: Firefox <=44
	// Firefox doesn't have focus(in | out) events
	// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
	//
	// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
	// focus(in | out) events fire after focus & blur events,
	// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
	// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
	//
	// Support: IE 9 - 11+
	// To preserve relative focusin/focus & focusout/blur event order guaranteed on the 3.x branch,
	// attach a single handler for both events in IE.
	jQuery.event.special[ delegateType ] = {
		setup: function() {

			// Handle: regular nodes (via `this.ownerDocument`), window
			// (via `this.document`) & document (via `this`).
			var doc = this.ownerDocument || this.document || this,
				dataHolder = document.documentMode ? this : doc,
				attaches = dataPriv.get( dataHolder, delegateType );

			// Support: IE 9 - 11+
			// We use the same native handler for focusin & focus (and focusout & blur)
			// so we need to coordinate setup & teardown parts between those events.
			// Use `delegateType` as the key as `type` is already used by `leverageNative`.
			if ( !attaches ) {
				if ( document.documentMode ) {
					this.addEventListener( delegateType, focusMappedHandler );
				} else {
					doc.addEventListener( type, focusMappedHandler, true );
				}
			}
			dataPriv.set( dataHolder, delegateType, ( attaches || 0 ) + 1 );
		},
		teardown: function() {
			var doc = this.ownerDocument || this.document || this,
				dataHolder = document.documentMode ? this : doc,
				attaches = dataPriv.get( dataHolder, delegateType ) - 1;

			if ( !attaches ) {
				if ( document.documentMode ) {
					this.removeEventListener( delegateType, focusMappedHandler );
				} else {
					doc.removeEventListener( type, focusMappedHandler, true );
				}
				dataPriv.remove( dataHolder, delegateType );
			} else {
				dataPriv.set( dataHolder, delegateType, attaches );
			}
		}
	};
} );

// Create mouseenter/leave events using mouseover/out and event-time checks
// so that event delegation works in jQuery.
// Do the same for pointerenter/pointerleave and pointerover/pointerout
//
// Support: Safari 7 only
// Safari sends mouseenter too often; see:
// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
// for the description of the bug (it existed in older Chrome versions as well).
jQuery.each( {
	mouseenter: "mouseover",
	mouseleave: "mouseout",
	pointerenter: "pointerover",
	pointerleave: "pointerout"
}, function( orig, fix ) {
	jQuery.event.special[ orig ] = {
		delegateType: fix,
		bindType: fix,

		handle: function( event ) {
			var ret,
				target = this,
				related = event.relatedTarget,
				handleObj = event.handleObj;

			// For mouseenter/leave call the handler if related is outside the target.
			// NB: No relatedTarget if the mouse left/entered the browser window
			if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
				event.type = handleObj.origType;
				ret = handleObj.handler.apply( this, arguments );
				event.type = fix;
			}
			return ret;
		}
	};
} );

jQuery.fn.extend( {

	on: function( types, selector, data, fn ) {
		return on( this, types, selector, data, fn );
	},
	one: function( types, selector, data, fn ) {
		return on( this, types, selector, data, fn, 1 );
	},
	off: function( types, selector, fn ) {
		var handleObj, type;
		if ( types && types.preventDefault && types.handleObj ) {

			// ( event )  dispatched jQuery.Event
			handleObj = types.handleObj;
			jQuery( types.delegateTarget ).off(
				handleObj.namespace ?
					handleObj.origType + "." + handleObj.namespace :
					handleObj.origType,
				handleObj.selector,
				handleObj.handler
			);
			return this;
		}
		if ( typeof types === "object" ) {

			// ( types-object [, selector] )
			for ( type in types ) {
				this.off( type, selector, types[ type ] );
			}
			return this;
		}
		if ( selector === false || typeof selector === "function" ) {

			// ( types [, fn] )
			fn = selector;
			selector = undefined;
		}
		if ( fn === false ) {
			fn = returnFalse;
		}
		return this.each( function() {
			jQuery.event.remove( this, types, fn, selector );
		} );
	}
} );


var

	// Support: IE <=10 - 11, Edge 12 - 13 only
	// In IE/Edge using regex groups here causes severe slowdowns.
	// See https://connect.microsoft.com/IE/feedback/details/1736512/
	rnoInnerhtml = /<script|<style|<link/i,

	// checked="checked" or checked
	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,

	rcleanScript = /^\s*<!\[CDATA\[|\]\]>\s*$/g;

// Prefer a tbody over its parent table for containing new rows
function manipulationTarget( elem, content ) {
	if ( nodeName( elem, "table" ) &&
		nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {

		return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
	}

	return elem;
}

// Replace/restore the type attribute of script elements for safe DOM manipulation
function disableScript( elem ) {
	elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
	return elem;
}
function restoreScript( elem ) {
	if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
		elem.type = elem.type.slice( 5 );
	} else {
		elem.removeAttribute( "type" );
	}

	return elem;
}

function cloneCopyEvent( src, dest ) {
	var i, l, type, pdataOld, udataOld, udataCur, events;

	if ( dest.nodeType !== 1 ) {
		return;
	}

	// 1. Copy private data: events, handlers, etc.
	if ( dataPriv.hasData( src ) ) {
		pdataOld = dataPriv.get( src );
		events = pdataOld.events;

		if ( events ) {
			dataPriv.remove( dest, "handle events" );

			for ( type in events ) {
				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
					jQuery.event.add( dest, type, events[ type ][ i ] );
				}
			}
		}
	}

	// 2. Copy user data
	if ( dataUser.hasData( src ) ) {
		udataOld = dataUser.access( src );
		udataCur = jQuery.extend( {}, udataOld );

		dataUser.set( dest, udataCur );
	}
}

// Fix IE bugs, see support tests
function fixInput( src, dest ) {
	var nodeName = dest.nodeName.toLowerCase();

	// Fails to persist the checked state of a cloned checkbox or radio button.
	if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
		dest.checked = src.checked;

	// Fails to return the selected option to the default selected state when cloning options
	} else if ( nodeName === "input" || nodeName === "textarea" ) {
		dest.defaultValue = src.defaultValue;
	}
}

function domManip( collection, args, callback, ignored ) {

	// Flatten any nested arrays
	args = flat( args );

	var fragment, first, scripts, hasScripts, node, doc,
		i = 0,
		l = collection.length,
		iNoClone = l - 1,
		value = args[ 0 ],
		valueIsFunction = isFunction( value );

	// We can't cloneNode fragments that contain checked, in WebKit
	if ( valueIsFunction ||
			( l > 1 && typeof value === "string" &&
				!support.checkClone && rchecked.test( value ) ) ) {
		return collection.each( function( index ) {
			var self = collection.eq( index );
			if ( valueIsFunction ) {
				args[ 0 ] = value.call( this, index, self.html() );
			}
			domManip( self, args, callback, ignored );
		} );
	}

	if ( l ) {
		fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
		first = fragment.firstChild;

		if ( fragment.childNodes.length === 1 ) {
			fragment = first;
		}

		// Require either new content or an interest in ignored elements to invoke the callback
		if ( first || ignored ) {
			scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
			hasScripts = scripts.length;

			// Use the original fragment for the last item
			// instead of the first because it can end up
			// being emptied incorrectly in certain situations (trac-8070).
			for ( ; i < l; i++ ) {
				node = fragment;

				if ( i !== iNoClone ) {
					node = jQuery.clone( node, true, true );

					// Keep references to cloned scripts for later restoration
					if ( hasScripts ) {

						// Support: Android <=4.0 only, PhantomJS 1 only
						// push.apply(_, arraylike) throws on ancient WebKit
						jQuery.merge( scripts, getAll( node, "script" ) );
					}
				}

				callback.call( collection[ i ], node, i );
			}

			if ( hasScripts ) {
				doc = scripts[ scripts.length - 1 ].ownerDocument;

				// Re-enable scripts
				jQuery.map( scripts, restoreScript );

				// Evaluate executable scripts on first document insertion
				for ( i = 0; i < hasScripts; i++ ) {
					node = scripts[ i ];
					if ( rscriptType.test( node.type || "" ) &&
						!dataPriv.access( node, "globalEval" ) &&
						jQuery.contains( doc, node ) ) {

						if ( node.src && ( node.type || "" ).toLowerCase()  !== "module" ) {

							// Optional AJAX dependency, but won't run scripts if not present
							if ( jQuery._evalUrl && !node.noModule ) {
								jQuery._evalUrl( node.src, {
									nonce: node.nonce || node.getAttribute( "nonce" )
								}, doc );
							}
						} else {

							// Unwrap a CDATA section containing script contents. This shouldn't be
							// needed as in XML documents they're already not visible when
							// inspecting element contents and in HTML documents they have no
							// meaning but we're preserving that logic for backwards compatibility.
							// This will be removed completely in 4.0. See gh-4904.
							DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
						}
					}
				}
			}
		}
	}

	return collection;
}

function remove( elem, selector, keepData ) {
	var node,
		nodes = selector ? jQuery.filter( selector, elem ) : elem,
		i = 0;

	for ( ; ( node = nodes[ i ] ) != null; i++ ) {
		if ( !keepData && node.nodeType === 1 ) {
			jQuery.cleanData( getAll( node ) );
		}

		if ( node.parentNode ) {
			if ( keepData && isAttached( node ) ) {
				setGlobalEval( getAll( node, "script" ) );
			}
			node.parentNode.removeChild( node );
		}
	}

	return elem;
}

jQuery.extend( {
	htmlPrefilter: function( html ) {
		return html;
	},

	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
		var i, l, srcElements, destElements,
			clone = elem.cloneNode( true ),
			inPage = isAttached( elem );

		// Fix IE cloning issues
		if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
				!jQuery.isXMLDoc( elem ) ) {

			// We eschew jQuery#find here for performance reasons:
			// https://jsperf.com/getall-vs-sizzle/2
			destElements = getAll( clone );
			srcElements = getAll( elem );

			for ( i = 0, l = srcElements.length; i < l; i++ ) {
				fixInput( srcElements[ i ], destElements[ i ] );
			}
		}

		// Copy the events from the original to the clone
		if ( dataAndEvents ) {
			if ( deepDataAndEvents ) {
				srcElements = srcElements || getAll( elem );
				destElements = destElements || getAll( clone );

				for ( i = 0, l = srcElements.length; i < l; i++ ) {
					cloneCopyEvent( srcElements[ i ], destElements[ i ] );
				}
			} else {
				cloneCopyEvent( elem, clone );
			}
		}

		// Preserve script evaluation history
		destElements = getAll( clone, "script" );
		if ( destElements.length > 0 ) {
			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
		}

		// Return the cloned set
		return clone;
	},

	cleanData: function( elems ) {
		var data, elem, type,
			special = jQuery.event.special,
			i = 0;

		for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
			if ( acceptData( elem ) ) {
				if ( ( data = elem[ dataPriv.expando ] ) ) {
					if ( data.events ) {
						for ( type in data.events ) {
							if ( special[ type ] ) {
								jQuery.event.remove( elem, type );

							// This is a shortcut to avoid jQuery.event.remove's overhead
							} else {
								jQuery.removeEvent( elem, type, data.handle );
							}
						}
					}

					// Support: Chrome <=35 - 45+
					// Assign undefined instead of using delete, see Data#remove
					elem[ dataPriv.expando ] = undefined;
				}
				if ( elem[ dataUser.expando ] ) {

					// Support: Chrome <=35 - 45+
					// Assign undefined instead of using delete, see Data#remove
					elem[ dataUser.expando ] = undefined;
				}
			}
		}
	}
} );

jQuery.fn.extend( {
	detach: function( selector ) {
		return remove( this, selector, true );
	},

	remove: function( selector ) {
		return remove( this, selector );
	},

	text: function( value ) {
		return access( this, function( value ) {
			return value === undefined ?
				jQuery.text( this ) :
				this.empty().each( function() {
					if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
						this.textContent = value;
					}
				} );
		}, null, value, arguments.length );
	},

	append: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
				var target = manipulationTarget( this, elem );
				target.appendChild( elem );
			}
		} );
	},

	prepend: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
				var target = manipulationTarget( this, elem );
				target.insertBefore( elem, target.firstChild );
			}
		} );
	},

	before: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.parentNode ) {
				this.parentNode.insertBefore( elem, this );
			}
		} );
	},

	after: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.parentNode ) {
				this.parentNode.insertBefore( elem, this.nextSibling );
			}
		} );
	},

	empty: function() {
		var elem,
			i = 0;

		for ( ; ( elem = this[ i ] ) != null; i++ ) {
			if ( elem.nodeType === 1 ) {

				// Prevent memory leaks
				jQuery.cleanData( getAll( elem, false ) );

				// Remove any remaining nodes
				elem.textContent = "";
			}
		}

		return this;
	},

	clone: function( dataAndEvents, deepDataAndEvents ) {
		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

		return this.map( function() {
			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
		} );
	},

	html: function( value ) {
		return access( this, function( value ) {
			var elem = this[ 0 ] || {},
				i = 0,
				l = this.length;

			if ( value === undefined && elem.nodeType === 1 ) {
				return elem.innerHTML;
			}

			// See if we can take a shortcut and just use innerHTML
			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {

				value = jQuery.htmlPrefilter( value );

				try {
					for ( ; i < l; i++ ) {
						elem = this[ i ] || {};

						// Remove element nodes and prevent memory leaks
						if ( elem.nodeType === 1 ) {
							jQuery.cleanData( getAll( elem, false ) );
							elem.innerHTML = value;
						}
					}

					elem = 0;

				// If using innerHTML throws an exception, use the fallback method
				} catch ( e ) {}
			}

			if ( elem ) {
				this.empty().append( value );
			}
		}, null, value, arguments.length );
	},

	replaceWith: function() {
		var ignored = [];

		// Make the changes, replacing each non-ignored context element with the new content
		return domManip( this, arguments, function( elem ) {
			var parent = this.parentNode;

			if ( jQuery.inArray( this, ignored ) < 0 ) {
				jQuery.cleanData( getAll( this ) );
				if ( parent ) {
					parent.replaceChild( elem, this );
				}
			}

		// Force callback invocation
		}, ignored );
	}
} );

jQuery.each( {
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function( name, original ) {
	jQuery.fn[ name ] = function( selector ) {
		var elems,
			ret = [],
			insert = jQuery( selector ),
			last = insert.length - 1,
			i = 0;

		for ( ; i <= last; i++ ) {
			elems = i === last ? this : this.clone( true );
			jQuery( insert[ i ] )[ original ]( elems );

			// Support: Android <=4.0 only, PhantomJS 1 only
			// .get() because push.apply(_, arraylike) throws on ancient WebKit
			push.apply( ret, elems.get() );
		}

		return this.pushStack( ret );
	};
} );
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );

var rcustomProp = /^--/;


var getStyles = function( elem ) {

		// Support: IE <=11 only, Firefox <=30 (trac-15098, trac-14150)
		// IE throws on elements created in popups
		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
		var view = elem.ownerDocument.defaultView;

		if ( !view || !view.opener ) {
			view = window;
		}

		return view.getComputedStyle( elem );
	};

var swap = function( elem, options, callback ) {
	var ret, name,
		old = {};

	// Remember the old values, and insert the new ones
	for ( name in options ) {
		old[ name ] = elem.style[ name ];
		elem.style[ name ] = options[ name ];
	}

	ret = callback.call( elem );

	// Revert the old values
	for ( name in options ) {
		elem.style[ name ] = old[ name ];
	}

	return ret;
};


var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );



( function() {

	// Executing both pixelPosition & boxSizingReliable tests require only one layout
	// so they're executed at the same time to save the second computation.
	function computeStyleTests() {

		// This is a singleton, we need to execute it only once
		if ( !div ) {
			return;
		}

		container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
			"margin-top:1px;padding:0;border:0";
		div.style.cssText =
			"position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
			"margin:auto;border:1px;padding:1px;" +
			"width:60%;top:1%";
		documentElement.appendChild( container ).appendChild( div );

		var divStyle = window.getComputedStyle( div );
		pixelPositionVal = divStyle.top !== "1%";

		// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
		reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;

		// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
		// Some styles come back with percentage values, even though they shouldn't
		div.style.right = "60%";
		pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;

		// Support: IE 9 - 11 only
		// Detect misreporting of content dimensions for box-sizing:border-box elements
		boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;

		// Support: IE 9 only
		// Detect overflow:scroll screwiness (gh-3699)
		// Support: Chrome <=64
		// Don't get tricked when zoom affects offsetWidth (gh-4029)
		div.style.position = "absolute";
		scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;

		documentElement.removeChild( container );

		// Nullify the div so it wouldn't be stored in the memory and
		// it will also be a sign that checks already performed
		div = null;
	}

	function roundPixelMeasures( measure ) {
		return Math.round( parseFloat( measure ) );
	}

	var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
		reliableTrDimensionsVal, reliableMarginLeftVal,
		container = document.createElement( "div" ),
		div = document.createElement( "div" );

	// Finish early in limited (non-browser) environments
	if ( !div.style ) {
		return;
	}

	// Support: IE <=9 - 11 only
	// Style of cloned element affects source element cloned (trac-8908)
	div.style.backgroundClip = "content-box";
	div.cloneNode( true ).style.backgroundClip = "";
	support.clearCloneStyle = div.style.backgroundClip === "content-box";

	jQuery.extend( support, {
		boxSizingReliable: function() {
			computeStyleTests();
			return boxSizingReliableVal;
		},
		pixelBoxStyles: function() {
			computeStyleTests();
			return pixelBoxStylesVal;
		},
		pixelPosition: function() {
			computeStyleTests();
			return pixelPositionVal;
		},
		reliableMarginLeft: function() {
			computeStyleTests();
			return reliableMarginLeftVal;
		},
		scrollboxSize: function() {
			computeStyleTests();
			return scrollboxSizeVal;
		},

		// Support: IE 9 - 11+, Edge 15 - 18+
		// IE/Edge misreport `getComputedStyle` of table rows with width/height
		// set in CSS while `offset*` properties report correct values.
		// Behavior in IE 9 is more subtle than in newer versions & it passes
		// some versions of this test; make sure not to make it pass there!
		//
		// Support: Firefox 70+
		// Only Firefox includes border widths
		// in computed dimensions. (gh-4529)
		reliableTrDimensions: function() {
			var table, tr, trChild, trStyle;
			if ( reliableTrDimensionsVal == null ) {
				table = document.createElement( "table" );
				tr = document.createElement( "tr" );
				trChild = document.createElement( "div" );

				table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate";
				tr.style.cssText = "box-sizing:content-box;border:1px solid";

				// Support: Chrome 86+
				// Height set through cssText does not get applied.
				// Computed height then comes back as 0.
				tr.style.height = "1px";
				trChild.style.height = "9px";

				// Support: Android 8 Chrome 86+
				// In our bodyBackground.html iframe,
				// display for all div elements is set to "inline",
				// which causes a problem only in Android 8 Chrome 86.
				// Ensuring the div is `display: block`
				// gets around this issue.
				trChild.style.display = "block";

				documentElement
					.appendChild( table )
					.appendChild( tr )
					.appendChild( trChild );

				trStyle = window.getComputedStyle( tr );
				reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) +
					parseInt( trStyle.borderTopWidth, 10 ) +
					parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight;

				documentElement.removeChild( table );
			}
			return reliableTrDimensionsVal;
		}
	} );
} )();


function curCSS( elem, name, computed ) {
	var width, minWidth, maxWidth, ret,
		isCustomProp = rcustomProp.test( name ),

		// Support: Firefox 51+
		// Retrieving style before computed somehow
		// fixes an issue with getting wrong values
		// on detached elements
		style = elem.style;

	computed = computed || getStyles( elem );

	// getPropertyValue is needed for:
	//   .css('filter') (IE 9 only, trac-12537)
	//   .css('--customProperty) (gh-3144)
	if ( computed ) {

		// Support: IE <=9 - 11+
		// IE only supports `"float"` in `getPropertyValue`; in computed styles
		// it's only available as `"cssFloat"`. We no longer modify properties
		// sent to `.css()` apart from camelCasing, so we need to check both.
		// Normally, this would create difference in behavior: if
		// `getPropertyValue` returns an empty string, the value returned
		// by `.css()` would be `undefined`. This is usually the case for
		// disconnected elements. However, in IE even disconnected elements
		// with no styles return `"none"` for `getPropertyValue( "float" )`
		ret = computed.getPropertyValue( name ) || computed[ name ];

		if ( isCustomProp && ret ) {

			// Support: Firefox 105+, Chrome <=105+
			// Spec requires trimming whitespace for custom properties (gh-4926).
			// Firefox only trims leading whitespace. Chrome just collapses
			// both leading & trailing whitespace to a single space.
			//
			// Fall back to `undefined` if empty string returned.
			// This collapses a missing definition with property defined
			// and set to an empty string but there's no standard API
			// allowing us to differentiate them without a performance penalty
			// and returning `undefined` aligns with older jQuery.
			//
			// rtrimCSS treats U+000D CARRIAGE RETURN and U+000C FORM FEED
			// as whitespace while CSS does not, but this is not a problem
			// because CSS preprocessing replaces them with U+000A LINE FEED
			// (which *is* CSS whitespace)
			// https://www.w3.org/TR/css-syntax-3/#input-preprocessing
			ret = ret.replace( rtrimCSS, "$1" ) || undefined;
		}

		if ( ret === "" && !isAttached( elem ) ) {
			ret = jQuery.style( elem, name );
		}

		// A tribute to the "awesome hack by Dean Edwards"
		// Android Browser returns percentage for some values,
		// but width seems to be reliably pixels.
		// This is against the CSSOM draft spec:
		// https://drafts.csswg.org/cssom/#resolved-values
		if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {

			// Remember the original values
			width = style.width;
			minWidth = style.minWidth;
			maxWidth = style.maxWidth;

			// Put in the new values to get a computed value out
			style.minWidth = style.maxWidth = style.width = ret;
			ret = computed.width;

			// Revert the changed values
			style.width = width;
			style.minWidth = minWidth;
			style.maxWidth = maxWidth;
		}
	}

	return ret !== undefined ?

		// Support: IE <=9 - 11 only
		// IE returns zIndex value as an integer.
		ret + "" :
		ret;
}


function addGetHookIf( conditionFn, hookFn ) {

	// Define the hook, we'll check on the first run if it's really needed.
	return {
		get: function() {
			if ( conditionFn() ) {

				// Hook not needed (or it's not possible to use it due
				// to missing dependency), remove it.
				delete this.get;
				return;
			}

			// Hook needed; redefine it so that the support test is not executed again.
			return ( this.get = hookFn ).apply( this, arguments );
		}
	};
}


var cssPrefixes = [ "Webkit", "Moz", "ms" ],
	emptyStyle = document.createElement( "div" ).style,
	vendorProps = {};

// Return a vendor-prefixed property or undefined
function vendorPropName( name ) {

	// Check for vendor prefixed names
	var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
		i = cssPrefixes.length;

	while ( i-- ) {
		name = cssPrefixes[ i ] + capName;
		if ( name in emptyStyle ) {
			return name;
		}
	}
}

// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
function finalPropName( name ) {
	var final = jQuery.cssProps[ name ] || vendorProps[ name ];

	if ( final ) {
		return final;
	}
	if ( name in emptyStyle ) {
		return name;
	}
	return vendorProps[ name ] = vendorPropName( name ) || name;
}


var

	// Swappable if display is none or starts with table
	// except "table", "table-cell", or "table-caption"
	// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
	cssNormalTransform = {
		letterSpacing: "0",
		fontWeight: "400"
	};

function setPositiveNumber( _elem, value, subtract ) {

	// Any relative (+/-) values have already been
	// normalized at this point
	var matches = rcssNum.exec( value );
	return matches ?

		// Guard against undefined "subtract", e.g., when used as in cssHooks
		Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
		value;
}

function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
	var i = dimension === "width" ? 1 : 0,
		extra = 0,
		delta = 0,
		marginDelta = 0;

	// Adjustment may not be necessary
	if ( box === ( isBorderBox ? "border" : "content" ) ) {
		return 0;
	}

	for ( ; i < 4; i += 2 ) {

		// Both box models exclude margin
		// Count margin delta separately to only add it after scroll gutter adjustment.
		// This is needed to make negative margins work with `outerHeight( true )` (gh-3982).
		if ( box === "margin" ) {
			marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
		}

		// If we get here with a content-box, we're seeking "padding" or "border" or "margin"
		if ( !isBorderBox ) {

			// Add padding
			delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );

			// For "border" or "margin", add border
			if ( box !== "padding" ) {
				delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );

			// But still keep track of it otherwise
			} else {
				extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
			}

		// If we get here with a border-box (content + padding + border), we're seeking "content" or
		// "padding" or "margin"
		} else {

			// For "content", subtract padding
			if ( box === "content" ) {
				delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
			}

			// For "content" or "padding", subtract border
			if ( box !== "margin" ) {
				delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
			}
		}
	}

	// Account for positive content-box scroll gutter when requested by providing computedVal
	if ( !isBorderBox && computedVal >= 0 ) {

		// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
		// Assuming integer scroll gutter, subtract the rest and round down
		delta += Math.max( 0, Math.ceil(
			elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
			computedVal -
			delta -
			extra -
			0.5

		// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
		// Use an explicit zero to avoid NaN (gh-3964)
		) ) || 0;
	}

	return delta + marginDelta;
}

function getWidthOrHeight( elem, dimension, extra ) {

	// Start with computed style
	var styles = getStyles( elem ),

		// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
		// Fake content-box until we know it's needed to know the true value.
		boxSizingNeeded = !support.boxSizingReliable() || extra,
		isBorderBox = boxSizingNeeded &&
			jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
		valueIsBorderBox = isBorderBox,

		val = curCSS( elem, dimension, styles ),
		offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );

	// Support: Firefox <=54
	// Return a confounding non-pixel value or feign ignorance, as appropriate.
	if ( rnumnonpx.test( val ) ) {
		if ( !extra ) {
			return val;
		}
		val = "auto";
	}


	// Support: IE 9 - 11 only
	// Use offsetWidth/offsetHeight for when box sizing is unreliable.
	// In those cases, the computed value can be trusted to be border-box.
	if ( ( !support.boxSizingReliable() && isBorderBox ||

		// Support: IE 10 - 11+, Edge 15 - 18+
		// IE/Edge misreport `getComputedStyle` of table rows with width/height
		// set in CSS while `offset*` properties report correct values.
		// Interestingly, in some cases IE 9 doesn't suffer from this issue.
		!support.reliableTrDimensions() && nodeName( elem, "tr" ) ||

		// Fall back to offsetWidth/offsetHeight when value is "auto"
		// This happens for inline elements with no explicit setting (gh-3571)
		val === "auto" ||

		// Support: Android <=4.1 - 4.3 only
		// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
		!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&

		// Make sure the element is visible & connected
		elem.getClientRects().length ) {

		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";

		// Where available, offsetWidth/offsetHeight approximate border box dimensions.
		// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
		// retrieved value as a content box dimension.
		valueIsBorderBox = offsetProp in elem;
		if ( valueIsBorderBox ) {
			val = elem[ offsetProp ];
		}
	}

	// Normalize "" and auto
	val = parseFloat( val ) || 0;

	// Adjust for the element's box model
	return ( val +
		boxModelAdjustment(
			elem,
			dimension,
			extra || ( isBorderBox ? "border" : "content" ),
			valueIsBorderBox,
			styles,

			// Provide the current computed size to request scroll gutter calculation (gh-3589)
			val
		)
	) + "px";
}

jQuery.extend( {

	// Add in style property hooks for overriding the default
	// behavior of getting and setting a style property
	cssHooks: {
		opacity: {
			get: function( elem, computed ) {
				if ( computed ) {

					// We should always get a number back from opacity
					var ret = curCSS( elem, "opacity" );
					return ret === "" ? "1" : ret;
				}
			}
		}
	},

	// Don't automatically add "px" to these possibly-unitless properties
	cssNumber: {
		animationIterationCount: true,
		aspectRatio: true,
		borderImageSlice: true,
		columnCount: true,
		flexGrow: true,
		flexShrink: true,
		fontWeight: true,
		gridArea: true,
		gridColumn: true,
		gridColumnEnd: true,
		gridColumnStart: true,
		gridRow: true,
		gridRowEnd: true,
		gridRowStart: true,
		lineHeight: true,
		opacity: true,
		order: true,
		orphans: true,
		scale: true,
		widows: true,
		zIndex: true,
		zoom: true,

		// SVG-related
		fillOpacity: true,
		floodOpacity: true,
		stopOpacity: true,
		strokeMiterlimit: true,
		strokeOpacity: true
	},

	// Add in properties whose names you wish to fix before
	// setting or getting the value
	cssProps: {},

	// Get and set the style property on a DOM Node
	style: function( elem, name, value, extra ) {

		// Don't set styles on text and comment nodes
		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
			return;
		}

		// Make sure that we're working with the right name
		var ret, type, hooks,
			origName = camelCase( name ),
			isCustomProp = rcustomProp.test( name ),
			style = elem.style;

		// Make sure that we're working with the right name. We don't
		// want to query the value if it is a CSS custom property
		// since they are user-defined.
		if ( !isCustomProp ) {
			name = finalPropName( origName );
		}

		// Gets hook for the prefixed version, then unprefixed version
		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

		// Check if we're setting a value
		if ( value !== undefined ) {
			type = typeof value;

			// Convert "+=" or "-=" to relative numbers (trac-7345)
			if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
				value = adjustCSS( elem, name, ret );

				// Fixes bug trac-9237
				type = "number";
			}

			// Make sure that null and NaN values aren't set (trac-7116)
			if ( value == null || value !== value ) {
				return;
			}

			// If a number was passed in, add the unit (except for certain CSS properties)
			// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
			// "px" to a few hardcoded values.
			if ( type === "number" && !isCustomProp ) {
				value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
			}

			// background-* props affect original clone's values
			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
				style[ name ] = "inherit";
			}

			// If a hook was provided, use that value, otherwise just set the specified value
			if ( !hooks || !( "set" in hooks ) ||
				( value = hooks.set( elem, value, extra ) ) !== undefined ) {

				if ( isCustomProp ) {
					style.setProperty( name, value );
				} else {
					style[ name ] = value;
				}
			}

		} else {

			// If a hook was provided get the non-computed value from there
			if ( hooks && "get" in hooks &&
				( ret = hooks.get( elem, false, extra ) ) !== undefined ) {

				return ret;
			}

			// Otherwise just get the value from the style object
			return style[ name ];
		}
	},

	css: function( elem, name, extra, styles ) {
		var val, num, hooks,
			origName = camelCase( name ),
			isCustomProp = rcustomProp.test( name );

		// Make sure that we're working with the right name. We don't
		// want to modify the value if it is a CSS custom property
		// since they are user-defined.
		if ( !isCustomProp ) {
			name = finalPropName( origName );
		}

		// Try prefixed name followed by the unprefixed name
		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

		// If a hook was provided get the computed value from there
		if ( hooks && "get" in hooks ) {
			val = hooks.get( elem, true, extra );
		}

		// Otherwise, if a way to get the computed value exists, use that
		if ( val === undefined ) {
			val = curCSS( elem, name, styles );
		}

		// Convert "normal" to computed value
		if ( val === "normal" && name in cssNormalTransform ) {
			val = cssNormalTransform[ name ];
		}

		// Make numeric if forced or a qualifier was provided and val looks numeric
		if ( extra === "" || extra ) {
			num = parseFloat( val );
			return extra === true || isFinite( num ) ? num || 0 : val;
		}

		return val;
	}
} );

jQuery.each( [ "height", "width" ], function( _i, dimension ) {
	jQuery.cssHooks[ dimension ] = {
		get: function( elem, computed, extra ) {
			if ( computed ) {

				// Certain elements can have dimension info if we invisibly show them
				// but it must have a current display style that would benefit
				return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&

					// Support: Safari 8+
					// Table columns in Safari have non-zero offsetWidth & zero
					// getBoundingClientRect().width unless display is changed.
					// Support: IE <=11 only
					// Running getBoundingClientRect on a disconnected node
					// in IE throws an error.
					( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
					swap( elem, cssShow, function() {
						return getWidthOrHeight( elem, dimension, extra );
					} ) :
					getWidthOrHeight( elem, dimension, extra );
			}
		},

		set: function( elem, value, extra ) {
			var matches,
				styles = getStyles( elem ),

				// Only read styles.position if the test has a chance to fail
				// to avoid forcing a reflow.
				scrollboxSizeBuggy = !support.scrollboxSize() &&
					styles.position === "absolute",

				// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
				boxSizingNeeded = scrollboxSizeBuggy || extra,
				isBorderBox = boxSizingNeeded &&
					jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
				subtract = extra ?
					boxModelAdjustment(
						elem,
						dimension,
						extra,
						isBorderBox,
						styles
					) :
					0;

			// Account for unreliable border-box dimensions by comparing offset* to computed and
			// faking a content-box to get border and padding (gh-3699)
			if ( isBorderBox && scrollboxSizeBuggy ) {
				subtract -= Math.ceil(
					elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
					parseFloat( styles[ dimension ] ) -
					boxModelAdjustment( elem, dimension, "border", false, styles ) -
					0.5
				);
			}

			// Convert to pixels if value adjustment is needed
			if ( subtract && ( matches = rcssNum.exec( value ) ) &&
				( matches[ 3 ] || "px" ) !== "px" ) {

				elem.style[ dimension ] = value;
				value = jQuery.css( elem, dimension );
			}

			return setPositiveNumber( elem, value, subtract );
		}
	};
} );

jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
	function( elem, computed ) {
		if ( computed ) {
			return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
				elem.getBoundingClientRect().left -
					swap( elem, { marginLeft: 0 }, function() {
						return elem.getBoundingClientRect().left;
					} )
			) + "px";
		}
	}
);

// These hooks are used by animate to expand properties
jQuery.each( {
	margin: "",
	padding: "",
	border: "Width"
}, function( prefix, suffix ) {
	jQuery.cssHooks[ prefix + suffix ] = {
		expand: function( value ) {
			var i = 0,
				expanded = {},

				// Assumes a single number if not a string
				parts = typeof value === "string" ? value.split( " " ) : [ value ];

			for ( ; i < 4; i++ ) {
				expanded[ prefix + cssExpand[ i ] + suffix ] =
					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
			}

			return expanded;
		}
	};

	if ( prefix !== "margin" ) {
		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
	}
} );

jQuery.fn.extend( {
	css: function( name, value ) {
		return access( this, function( elem, name, value ) {
			var styles, len,
				map = {},
				i = 0;

			if ( Array.isArray( name ) ) {
				styles = getStyles( elem );
				len = name.length;

				for ( ; i < len; i++ ) {
					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
				}

				return map;
			}

			return value !== undefined ?
				jQuery.style( elem, name, value ) :
				jQuery.css( elem, name );
		}, name, value, arguments.length > 1 );
	}
} );


function Tween( elem, options, prop, end, easing ) {
	return new Tween.prototype.init( elem, options, prop, end, easing );
}
jQuery.Tween = Tween;

Tween.prototype = {
	constructor: Tween,
	init: function( elem, options, prop, end, easing, unit ) {
		this.elem = elem;
		this.prop = prop;
		this.easing = easing || jQuery.easing._default;
		this.options = options;
		this.start = this.now = this.cur();
		this.end = end;
		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
	},
	cur: function() {
		var hooks = Tween.propHooks[ this.prop ];

		return hooks && hooks.get ?
			hooks.get( this ) :
			Tween.propHooks._default.get( this );
	},
	run: function( percent ) {
		var eased,
			hooks = Tween.propHooks[ this.prop ];

		if ( this.options.duration ) {
			this.pos = eased = jQuery.easing[ this.easing ](
				percent, this.options.duration * percent, 0, 1, this.options.duration
			);
		} else {
			this.pos = eased = percent;
		}
		this.now = ( this.end - this.start ) * eased + this.start;

		if ( this.options.step ) {
			this.options.step.call( this.elem, this.now, this );
		}

		if ( hooks && hooks.set ) {
			hooks.set( this );
		} else {
			Tween.propHooks._default.set( this );
		}
		return this;
	}
};

Tween.prototype.init.prototype = Tween.prototype;

Tween.propHooks = {
	_default: {
		get: function( tween ) {
			var result;

			// Use a property on the element directly when it is not a DOM element,
			// or when there is no matching style property that exists.
			if ( tween.elem.nodeType !== 1 ||
				tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
				return tween.elem[ tween.prop ];
			}

			// Passing an empty string as a 3rd parameter to .css will automatically
			// attempt a parseFloat and fallback to a string if the parse fails.
			// Simple values such as "10px" are parsed to Float;
			// complex values such as "rotate(1rad)" are returned as-is.
			result = jQuery.css( tween.elem, tween.prop, "" );

			// Empty strings, null, undefined and "auto" are converted to 0.
			return !result || result === "auto" ? 0 : result;
		},
		set: function( tween ) {

			// Use step hook for back compat.
			// Use cssHook if its there.
			// Use .style if available and use plain properties where available.
			if ( jQuery.fx.step[ tween.prop ] ) {
				jQuery.fx.step[ tween.prop ]( tween );
			} else if ( tween.elem.nodeType === 1 && (
				jQuery.cssHooks[ tween.prop ] ||
					tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
			} else {
				tween.elem[ tween.prop ] = tween.now;
			}
		}
	}
};

// Support: IE <=9 only
// Panic based approach to setting things on disconnected nodes
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
	set: function( tween ) {
		if ( tween.elem.nodeType && tween.elem.parentNode ) {
			tween.elem[ tween.prop ] = tween.now;
		}
	}
};

jQuery.easing = {
	linear: function( p ) {
		return p;
	},
	swing: function( p ) {
		return 0.5 - Math.cos( p * Math.PI ) / 2;
	},
	_default: "swing"
};

jQuery.fx = Tween.prototype.init;

// Back compat <1.8 extension point
jQuery.fx.step = {};




var
	fxNow, inProgress,
	rfxtypes = /^(?:toggle|show|hide)$/,
	rrun = /queueHooks$/;

function schedule() {
	if ( inProgress ) {
		if ( document.hidden === false && window.requestAnimationFrame ) {
			window.requestAnimationFrame( schedule );
		} else {
			window.setTimeout( schedule, jQuery.fx.interval );
		}

		jQuery.fx.tick();
	}
}

// Animations created synchronously will run synchronously
function createFxNow() {
	window.setTimeout( function() {
		fxNow = undefined;
	} );
	return ( fxNow = Date.now() );
}

// Generate parameters to create a standard animation
function genFx( type, includeWidth ) {
	var which,
		i = 0,
		attrs = { height: type };

	// If we include width, step value is 1 to do all cssExpand values,
	// otherwise step value is 2 to skip over Left and Right
	includeWidth = includeWidth ? 1 : 0;
	for ( ; i < 4; i += 2 - includeWidth ) {
		which = cssExpand[ i ];
		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
	}

	if ( includeWidth ) {
		attrs.opacity = attrs.width = type;
	}

	return attrs;
}

function createTween( value, prop, animation ) {
	var tween,
		collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
		index = 0,
		length = collection.length;
	for ( ; index < length; index++ ) {
		if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {

			// We're done with this property
			return tween;
		}
	}
}

function defaultPrefilter( elem, props, opts ) {
	var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
		isBox = "width" in props || "height" in props,
		anim = this,
		orig = {},
		style = elem.style,
		hidden = elem.nodeType && isHiddenWithinTree( elem ),
		dataShow = dataPriv.get( elem, "fxshow" );

	// Queue-skipping animations hijack the fx hooks
	if ( !opts.queue ) {
		hooks = jQuery._queueHooks( elem, "fx" );
		if ( hooks.unqueued == null ) {
			hooks.unqueued = 0;
			oldfire = hooks.empty.fire;
			hooks.empty.fire = function() {
				if ( !hooks.unqueued ) {
					oldfire();
				}
			};
		}
		hooks.unqueued++;

		anim.always( function() {

			// Ensure the complete handler is called before this completes
			anim.always( function() {
				hooks.unqueued--;
				if ( !jQuery.queue( elem, "fx" ).length ) {
					hooks.empty.fire();
				}
			} );
		} );
	}

	// Detect show/hide animations
	for ( prop in props ) {
		value = props[ prop ];
		if ( rfxtypes.test( value ) ) {
			delete props[ prop ];
			toggle = toggle || value === "toggle";
			if ( value === ( hidden ? "hide" : "show" ) ) {

				// Pretend to be hidden if this is a "show" and
				// there is still data from a stopped show/hide
				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
					hidden = true;

				// Ignore all other no-op show/hide data
				} else {
					continue;
				}
			}
			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
		}
	}

	// Bail out if this is a no-op like .hide().hide()
	propTween = !jQuery.isEmptyObject( props );
	if ( !propTween && jQuery.isEmptyObject( orig ) ) {
		return;
	}

	// Restrict "overflow" and "display" styles during box animations
	if ( isBox && elem.nodeType === 1 ) {

		// Support: IE <=9 - 11, Edge 12 - 15
		// Record all 3 overflow attributes because IE does not infer the shorthand
		// from identically-valued overflowX and overflowY and Edge just mirrors
		// the overflowX value there.
		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];

		// Identify a display type, preferring old show/hide data over the CSS cascade
		restoreDisplay = dataShow && dataShow.display;
		if ( restoreDisplay == null ) {
			restoreDisplay = dataPriv.get( elem, "display" );
		}
		display = jQuery.css( elem, "display" );
		if ( display === "none" ) {
			if ( restoreDisplay ) {
				display = restoreDisplay;
			} else {

				// Get nonempty value(s) by temporarily forcing visibility
				showHide( [ elem ], true );
				restoreDisplay = elem.style.display || restoreDisplay;
				display = jQuery.css( elem, "display" );
				showHide( [ elem ] );
			}
		}

		// Animate inline elements as inline-block
		if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
			if ( jQuery.css( elem, "float" ) === "none" ) {

				// Restore the original display value at the end of pure show/hide animations
				if ( !propTween ) {
					anim.done( function() {
						style.display = restoreDisplay;
					} );
					if ( restoreDisplay == null ) {
						display = style.display;
						restoreDisplay = display === "none" ? "" : display;
					}
				}
				style.display = "inline-block";
			}
		}
	}

	if ( opts.overflow ) {
		style.overflow = "hidden";
		anim.always( function() {
			style.overflow = opts.overflow[ 0 ];
			style.overflowX = opts.overflow[ 1 ];
			style.overflowY = opts.overflow[ 2 ];
		} );
	}

	// Implement show/hide animations
	propTween = false;
	for ( prop in orig ) {

		// General show/hide setup for this element animation
		if ( !propTween ) {
			if ( dataShow ) {
				if ( "hidden" in dataShow ) {
					hidden = dataShow.hidden;
				}
			} else {
				dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
			}

			// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
			if ( toggle ) {
				dataShow.hidden = !hidden;
			}

			// Show elements before animating them
			if ( hidden ) {
				showHide( [ elem ], true );
			}

			/* eslint-disable no-loop-func */

			anim.done( function() {

				/* eslint-enable no-loop-func */

				// The final step of a "hide" animation is actually hiding the element
				if ( !hidden ) {
					showHide( [ elem ] );
				}
				dataPriv.remove( elem, "fxshow" );
				for ( prop in orig ) {
					jQuery.style( elem, prop, orig[ prop ] );
				}
			} );
		}

		// Per-property setup
		propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
		if ( !( prop in dataShow ) ) {
			dataShow[ prop ] = propTween.start;
			if ( hidden ) {
				propTween.end = propTween.start;
				propTween.start = 0;
			}
		}
	}
}

function propFilter( props, specialEasing ) {
	var index, name, easing, value, hooks;

	// camelCase, specialEasing and expand cssHook pass
	for ( index in props ) {
		name = camelCase( index );
		easing = specialEasing[ name ];
		value = props[ index ];
		if ( Array.isArray( value ) ) {
			easing = value[ 1 ];
			value = props[ index ] = value[ 0 ];
		}

		if ( index !== name ) {
			props[ name ] = value;
			delete props[ index ];
		}

		hooks = jQuery.cssHooks[ name ];
		if ( hooks && "expand" in hooks ) {
			value = hooks.expand( value );
			delete props[ name ];

			// Not quite $.extend, this won't overwrite existing keys.
			// Reusing 'index' because we have the correct "name"
			for ( index in value ) {
				if ( !( index in props ) ) {
					props[ index ] = value[ index ];
					specialEasing[ index ] = easing;
				}
			}
		} else {
			specialEasing[ name ] = easing;
		}
	}
}

function Animation( elem, properties, options ) {
	var result,
		stopped,
		index = 0,
		length = Animation.prefilters.length,
		deferred = jQuery.Deferred().always( function() {

			// Don't match elem in the :animated selector
			delete tick.elem;
		} ),
		tick = function() {
			if ( stopped ) {
				return false;
			}
			var currentTime = fxNow || createFxNow(),
				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),

				// Support: Android 2.3 only
				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (trac-12497)
				temp = remaining / animation.duration || 0,
				percent = 1 - temp,
				index = 0,
				length = animation.tweens.length;

			for ( ; index < length; index++ ) {
				animation.tweens[ index ].run( percent );
			}

			deferred.notifyWith( elem, [ animation, percent, remaining ] );

			// If there's more to do, yield
			if ( percent < 1 && length ) {
				return remaining;
			}

			// If this was an empty animation, synthesize a final progress notification
			if ( !length ) {
				deferred.notifyWith( elem, [ animation, 1, 0 ] );
			}

			// Resolve the animation and report its conclusion
			deferred.resolveWith( elem, [ animation ] );
			return false;
		},
		animation = deferred.promise( {
			elem: elem,
			props: jQuery.extend( {}, properties ),
			opts: jQuery.extend( true, {
				specialEasing: {},
				easing: jQuery.easing._default
			}, options ),
			originalProperties: properties,
			originalOptions: options,
			startTime: fxNow || createFxNow(),
			duration: options.duration,
			tweens: [],
			createTween: function( prop, end ) {
				var tween = jQuery.Tween( elem, animation.opts, prop, end,
					animation.opts.specialEasing[ prop ] || animation.opts.easing );
				animation.tweens.push( tween );
				return tween;
			},
			stop: function( gotoEnd ) {
				var index = 0,

					// If we are going to the end, we want to run all the tweens
					// otherwise we skip this part
					length = gotoEnd ? animation.tweens.length : 0;
				if ( stopped ) {
					return this;
				}
				stopped = true;
				for ( ; index < length; index++ ) {
					animation.tweens[ index ].run( 1 );
				}

				// Resolve when we played the last frame; otherwise, reject
				if ( gotoEnd ) {
					deferred.notifyWith( elem, [ animation, 1, 0 ] );
					deferred.resolveWith( elem, [ animation, gotoEnd ] );
				} else {
					deferred.rejectWith( elem, [ animation, gotoEnd ] );
				}
				return this;
			}
		} ),
		props = animation.props;

	propFilter( props, animation.opts.specialEasing );

	for ( ; index < length; index++ ) {
		result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
		if ( result ) {
			if ( isFunction( result.stop ) ) {
				jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
					result.stop.bind( result );
			}
			return result;
		}
	}

	jQuery.map( props, createTween, animation );

	if ( isFunction( animation.opts.start ) ) {
		animation.opts.start.call( elem, animation );
	}

	// Attach callbacks from options
	animation
		.progress( animation.opts.progress )
		.done( animation.opts.done, animation.opts.complete )
		.fail( animation.opts.fail )
		.always( animation.opts.always );

	jQuery.fx.timer(
		jQuery.extend( tick, {
			elem: elem,
			anim: animation,
			queue: animation.opts.queue
		} )
	);

	return animation;
}

jQuery.Animation = jQuery.extend( Animation, {

	tweeners: {
		"*": [ function( prop, value ) {
			var tween = this.createTween( prop, value );
			adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
			return tween;
		} ]
	},

	tweener: function( props, callback ) {
		if ( isFunction( props ) ) {
			callback = props;
			props = [ "*" ];
		} else {
			props = props.match( rnothtmlwhite );
		}

		var prop,
			index = 0,
			length = props.length;

		for ( ; index < length; index++ ) {
			prop = props[ index ];
			Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
			Animation.tweeners[ prop ].unshift( callback );
		}
	},

	prefilters: [ defaultPrefilter ],

	prefilter: function( callback, prepend ) {
		if ( prepend ) {
			Animation.prefilters.unshift( callback );
		} else {
			Animation.prefilters.push( callback );
		}
	}
} );

jQuery.speed = function( speed, easing, fn ) {
	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
		complete: fn || !fn && easing ||
			isFunction( speed ) && speed,
		duration: speed,
		easing: fn && easing || easing && !isFunction( easing ) && easing
	};

	// Go to the end state if fx are off
	if ( jQuery.fx.off ) {
		opt.duration = 0;

	} else {
		if ( typeof opt.duration !== "number" ) {
			if ( opt.duration in jQuery.fx.speeds ) {
				opt.duration = jQuery.fx.speeds[ opt.duration ];

			} else {
				opt.duration = jQuery.fx.speeds._default;
			}
		}
	}

	// Normalize opt.queue - true/undefined/null -> "fx"
	if ( opt.queue == null || opt.queue === true ) {
		opt.queue = "fx";
	}

	// Queueing
	opt.old = opt.complete;

	opt.complete = function() {
		if ( isFunction( opt.old ) ) {
			opt.old.call( this );
		}

		if ( opt.queue ) {
			jQuery.dequeue( this, opt.queue );
		}
	};

	return opt;
};

jQuery.fn.extend( {
	fadeTo: function( speed, to, easing, callback ) {

		// Show any hidden elements after setting opacity to 0
		return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()

			// Animate to the value specified
			.end().animate( { opacity: to }, speed, easing, callback );
	},
	animate: function( prop, speed, easing, callback ) {
		var empty = jQuery.isEmptyObject( prop ),
			optall = jQuery.speed( speed, easing, callback ),
			doAnimation = function() {

				// Operate on a copy of prop so per-property easing won't be lost
				var anim = Animation( this, jQuery.extend( {}, prop ), optall );

				// Empty animations, or finishing resolves immediately
				if ( empty || dataPriv.get( this, "finish" ) ) {
					anim.stop( true );
				}
			};

		doAnimation.finish = doAnimation;

		return empty || optall.queue === false ?
			this.each( doAnimation ) :
			this.queue( optall.queue, doAnimation );
	},
	stop: function( type, clearQueue, gotoEnd ) {
		var stopQueue = function( hooks ) {
			var stop = hooks.stop;
			delete hooks.stop;
			stop( gotoEnd );
		};

		if ( typeof type !== "string" ) {
			gotoEnd = clearQueue;
			clearQueue = type;
			type = undefined;
		}
		if ( clearQueue ) {
			this.queue( type || "fx", [] );
		}

		return this.each( function() {
			var dequeue = true,
				index = type != null && type + "queueHooks",
				timers = jQuery.timers,
				data = dataPriv.get( this );

			if ( index ) {
				if ( data[ index ] && data[ index ].stop ) {
					stopQueue( data[ index ] );
				}
			} else {
				for ( index in data ) {
					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
						stopQueue( data[ index ] );
					}
				}
			}

			for ( index = timers.length; index--; ) {
				if ( timers[ index ].elem === this &&
					( type == null || timers[ index ].queue === type ) ) {

					timers[ index ].anim.stop( gotoEnd );
					dequeue = false;
					timers.splice( index, 1 );
				}
			}

			// Start the next in the queue if the last step wasn't forced.
			// Timers currently will call their complete callbacks, which
			// will dequeue but only if they were gotoEnd.
			if ( dequeue || !gotoEnd ) {
				jQuery.dequeue( this, type );
			}
		} );
	},
	finish: function( type ) {
		if ( type !== false ) {
			type = type || "fx";
		}
		return this.each( function() {
			var index,
				data = dataPriv.get( this ),
				queue = data[ type + "queue" ],
				hooks = data[ type + "queueHooks" ],
				timers = jQuery.timers,
				length = queue ? queue.length : 0;

			// Enable finishing flag on private data
			data.finish = true;

			// Empty the queue first
			jQuery.queue( this, type, [] );

			if ( hooks && hooks.stop ) {
				hooks.stop.call( this, true );
			}

			// Look for any active animations, and finish them
			for ( index = timers.length; index--; ) {
				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
					timers[ index ].anim.stop( true );
					timers.splice( index, 1 );
				}
			}

			// Look for any animations in the old queue and finish them
			for ( index = 0; index < length; index++ ) {
				if ( queue[ index ] && queue[ index ].finish ) {
					queue[ index ].finish.call( this );
				}
			}

			// Turn off finishing flag
			delete data.finish;
		} );
	}
} );

jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) {
	var cssFn = jQuery.fn[ name ];
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return speed == null || typeof speed === "boolean" ?
			cssFn.apply( this, arguments ) :
			this.animate( genFx( name, true ), speed, easing, callback );
	};
} );

// Generate shortcuts for custom animations
jQuery.each( {
	slideDown: genFx( "show" ),
	slideUp: genFx( "hide" ),
	slideToggle: genFx( "toggle" ),
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" },
	fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return this.animate( props, speed, easing, callback );
	};
} );

jQuery.timers = [];
jQuery.fx.tick = function() {
	var timer,
		i = 0,
		timers = jQuery.timers;

	fxNow = Date.now();

	for ( ; i < timers.length; i++ ) {
		timer = timers[ i ];

		// Run the timer and safely remove it when done (allowing for external removal)
		if ( !timer() && timers[ i ] === timer ) {
			timers.splice( i--, 1 );
		}
	}

	if ( !timers.length ) {
		jQuery.fx.stop();
	}
	fxNow = undefined;
};

jQuery.fx.timer = function( timer ) {
	jQuery.timers.push( timer );
	jQuery.fx.start();
};

jQuery.fx.interval = 13;
jQuery.fx.start = function() {
	if ( inProgress ) {
		return;
	}

	inProgress = true;
	schedule();
};

jQuery.fx.stop = function() {
	inProgress = null;
};

jQuery.fx.speeds = {
	slow: 600,
	fast: 200,

	// Default speed
	_default: 400
};


// Based off of the plugin by Clint Helfers, with permission.
jQuery.fn.delay = function( time, type ) {
	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
	type = type || "fx";

	return this.queue( type, function( next, hooks ) {
		var timeout = window.setTimeout( next, time );
		hooks.stop = function() {
			window.clearTimeout( timeout );
		};
	} );
};


( function() {
	var input = document.createElement( "input" ),
		select = document.createElement( "select" ),
		opt = select.appendChild( document.createElement( "option" ) );

	input.type = "checkbox";

	// Support: Android <=4.3 only
	// Default value for a checkbox should be "on"
	support.checkOn = input.value !== "";

	// Support: IE <=11 only
	// Must access selectedIndex to make default options select
	support.optSelected = opt.selected;

	// Support: IE <=11 only
	// An input loses its value after becoming a radio
	input = document.createElement( "input" );
	input.value = "t";
	input.type = "radio";
	support.radioValue = input.value === "t";
} )();


var boolHook,
	attrHandle = jQuery.expr.attrHandle;

jQuery.fn.extend( {
	attr: function( name, value ) {
		return access( this, jQuery.attr, name, value, arguments.length > 1 );
	},

	removeAttr: function( name ) {
		return this.each( function() {
			jQuery.removeAttr( this, name );
		} );
	}
} );

jQuery.extend( {
	attr: function( elem, name, value ) {
		var ret, hooks,
			nType = elem.nodeType;

		// Don't get/set attributes on text, comment and attribute nodes
		if ( nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}

		// Fallback to prop when attributes are not supported
		if ( typeof elem.getAttribute === "undefined" ) {
			return jQuery.prop( elem, name, value );
		}

		// Attribute hooks are determined by the lowercase version
		// Grab necessary hook if one is defined
		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
			hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
				( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
		}

		if ( value !== undefined ) {
			if ( value === null ) {
				jQuery.removeAttr( elem, name );
				return;
			}

			if ( hooks && "set" in hooks &&
				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
				return ret;
			}

			elem.setAttribute( name, value + "" );
			return value;
		}

		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
			return ret;
		}

		ret = jQuery.find.attr( elem, name );

		// Non-existent attributes return null, we normalize to undefined
		return ret == null ? undefined : ret;
	},

	attrHooks: {
		type: {
			set: function( elem, value ) {
				if ( !support.radioValue && value === "radio" &&
					nodeName( elem, "input" ) ) {
					var val = elem.value;
					elem.setAttribute( "type", value );
					if ( val ) {
						elem.value = val;
					}
					return value;
				}
			}
		}
	},

	removeAttr: function( elem, value ) {
		var name,
			i = 0,

			// Attribute names can contain non-HTML whitespace characters
			// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
			attrNames = value && value.match( rnothtmlwhite );

		if ( attrNames && elem.nodeType === 1 ) {
			while ( ( name = attrNames[ i++ ] ) ) {
				elem.removeAttribute( name );
			}
		}
	}
} );

// Hooks for boolean attributes
boolHook = {
	set: function( elem, value, name ) {
		if ( value === false ) {

			// Remove boolean attributes when set to false
			jQuery.removeAttr( elem, name );
		} else {
			elem.setAttribute( name, name );
		}
		return name;
	}
};

jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) {
	var getter = attrHandle[ name ] || jQuery.find.attr;

	attrHandle[ name ] = function( elem, name, isXML ) {
		var ret, handle,
			lowercaseName = name.toLowerCase();

		if ( !isXML ) {

			// Avoid an infinite loop by temporarily removing this function from the getter
			handle = attrHandle[ lowercaseName ];
			attrHandle[ lowercaseName ] = ret;
			ret = getter( elem, name, isXML ) != null ?
				lowercaseName :
				null;
			attrHandle[ lowercaseName ] = handle;
		}
		return ret;
	};
} );




var rfocusable = /^(?:input|select|textarea|button)$/i,
	rclickable = /^(?:a|area)$/i;

jQuery.fn.extend( {
	prop: function( name, value ) {
		return access( this, jQuery.prop, name, value, arguments.length > 1 );
	},

	removeProp: function( name ) {
		return this.each( function() {
			delete this[ jQuery.propFix[ name ] || name ];
		} );
	}
} );

jQuery.extend( {
	prop: function( elem, name, value ) {
		var ret, hooks,
			nType = elem.nodeType;

		// Don't get/set properties on text, comment and attribute nodes
		if ( nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}

		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {

			// Fix name and attach hooks
			name = jQuery.propFix[ name ] || name;
			hooks = jQuery.propHooks[ name ];
		}

		if ( value !== undefined ) {
			if ( hooks && "set" in hooks &&
				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
				return ret;
			}

			return ( elem[ name ] = value );
		}

		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
			return ret;
		}

		return elem[ name ];
	},

	propHooks: {
		tabIndex: {
			get: function( elem ) {

				// Support: IE <=9 - 11 only
				// elem.tabIndex doesn't always return the
				// correct value when it hasn't been explicitly set
				// Use proper attribute retrieval (trac-12072)
				var tabindex = jQuery.find.attr( elem, "tabindex" );

				if ( tabindex ) {
					return parseInt( tabindex, 10 );
				}

				if (
					rfocusable.test( elem.nodeName ) ||
					rclickable.test( elem.nodeName ) &&
					elem.href
				) {
					return 0;
				}

				return -1;
			}
		}
	},

	propFix: {
		"for": "htmlFor",
		"class": "className"
	}
} );

// Support: IE <=11 only
// Accessing the selectedIndex property
// forces the browser to respect setting selected
// on the option
// The getter ensures a default option is selected
// when in an optgroup
// eslint rule "no-unused-expressions" is disabled for this code
// since it considers such accessions noop
if ( !support.optSelected ) {
	jQuery.propHooks.selected = {
		get: function( elem ) {

			/* eslint no-unused-expressions: "off" */

			var parent = elem.parentNode;
			if ( parent && parent.parentNode ) {
				parent.parentNode.selectedIndex;
			}
			return null;
		},
		set: function( elem ) {

			/* eslint no-unused-expressions: "off" */

			var parent = elem.parentNode;
			if ( parent ) {
				parent.selectedIndex;

				if ( parent.parentNode ) {
					parent.parentNode.selectedIndex;
				}
			}
		}
	};
}

jQuery.each( [
	"tabIndex",
	"readOnly",
	"maxLength",
	"cellSpacing",
	"cellPadding",
	"rowSpan",
	"colSpan",
	"useMap",
	"frameBorder",
	"contentEditable"
], function() {
	jQuery.propFix[ this.toLowerCase() ] = this;
} );




	// Strip and collapse whitespace according to HTML spec
	// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
	function stripAndCollapse( value ) {
		var tokens = value.match( rnothtmlwhite ) || [];
		return tokens.join( " " );
	}


function getClass( elem ) {
	return elem.getAttribute && elem.getAttribute( "class" ) || "";
}

function classesToArray( value ) {
	if ( Array.isArray( value ) ) {
		return value;
	}
	if ( typeof value === "string" ) {
		return value.match( rnothtmlwhite ) || [];
	}
	return [];
}

jQuery.fn.extend( {
	addClass: function( value ) {
		var classNames, cur, curValue, className, i, finalValue;

		if ( isFunction( value ) ) {
			return this.each( function( j ) {
				jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
			} );
		}

		classNames = classesToArray( value );

		if ( classNames.length ) {
			return this.each( function() {
				curValue = getClass( this );
				cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );

				if ( cur ) {
					for ( i = 0; i < classNames.length; i++ ) {
						className = classNames[ i ];
						if ( cur.indexOf( " " + className + " " ) < 0 ) {
							cur += className + " ";
						}
					}

					// Only assign if different to avoid unneeded rendering.
					finalValue = stripAndCollapse( cur );
					if ( curValue !== finalValue ) {
						this.setAttribute( "class", finalValue );
					}
				}
			} );
		}

		return this;
	},

	removeClass: function( value ) {
		var classNames, cur, curValue, className, i, finalValue;

		if ( isFunction( value ) ) {
			return this.each( function( j ) {
				jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
			} );
		}

		if ( !arguments.length ) {
			return this.attr( "class", "" );
		}

		classNames = classesToArray( value );

		if ( classNames.length ) {
			return this.each( function() {
				curValue = getClass( this );

				// This expression is here for better compressibility (see addClass)
				cur = this.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );

				if ( cur ) {
					for ( i = 0; i < classNames.length; i++ ) {
						className = classNames[ i ];

						// Remove *all* instances
						while ( cur.indexOf( " " + className + " " ) > -1 ) {
							cur = cur.replace( " " + className + " ", " " );
						}
					}

					// Only assign if different to avoid unneeded rendering.
					finalValue = stripAndCollapse( cur );
					if ( curValue !== finalValue ) {
						this.setAttribute( "class", finalValue );
					}
				}
			} );
		}

		return this;
	},

	toggleClass: function( value, stateVal ) {
		var classNames, className, i, self,
			type = typeof value,
			isValidValue = type === "string" || Array.isArray( value );

		if ( isFunction( value ) ) {
			return this.each( function( i ) {
				jQuery( this ).toggleClass(
					value.call( this, i, getClass( this ), stateVal ),
					stateVal
				);
			} );
		}

		if ( typeof stateVal === "boolean" && isValidValue ) {
			return stateVal ? this.addClass( value ) : this.removeClass( value );
		}

		classNames = classesToArray( value );

		return this.each( function() {
			if ( isValidValue ) {

				// Toggle individual class names
				self = jQuery( this );

				for ( i = 0; i < classNames.length; i++ ) {
					className = classNames[ i ];

					// Check each className given, space separated list
					if ( self.hasClass( className ) ) {
						self.removeClass( className );
					} else {
						self.addClass( className );
					}
				}

			// Toggle whole class name
			} else if ( value === undefined || type === "boolean" ) {
				className = getClass( this );
				if ( className ) {

					// Store className if set
					dataPriv.set( this, "__className__", className );
				}

				// If the element has a class name or if we're passed `false`,
				// then remove the whole classname (if there was one, the above saved it).
				// Otherwise bring back whatever was previously saved (if anything),
				// falling back to the empty string if nothing was stored.
				if ( this.setAttribute ) {
					this.setAttribute( "class",
						className || value === false ?
							"" :
							dataPriv.get( this, "__className__" ) || ""
					);
				}
			}
		} );
	},

	hasClass: function( selector ) {
		var className, elem,
			i = 0;

		className = " " + selector + " ";
		while ( ( elem = this[ i++ ] ) ) {
			if ( elem.nodeType === 1 &&
				( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
				return true;
			}
		}

		return false;
	}
} );




var rreturn = /\r/g;

jQuery.fn.extend( {
	val: function( value ) {
		var hooks, ret, valueIsFunction,
			elem = this[ 0 ];

		if ( !arguments.length ) {
			if ( elem ) {
				hooks = jQuery.valHooks[ elem.type ] ||
					jQuery.valHooks[ elem.nodeName.toLowerCase() ];

				if ( hooks &&
					"get" in hooks &&
					( ret = hooks.get( elem, "value" ) ) !== undefined
				) {
					return ret;
				}

				ret = elem.value;

				// Handle most common string cases
				if ( typeof ret === "string" ) {
					return ret.replace( rreturn, "" );
				}

				// Handle cases where value is null/undef or number
				return ret == null ? "" : ret;
			}

			return;
		}

		valueIsFunction = isFunction( value );

		return this.each( function( i ) {
			var val;

			if ( this.nodeType !== 1 ) {
				return;
			}

			if ( valueIsFunction ) {
				val = value.call( this, i, jQuery( this ).val() );
			} else {
				val = value;
			}

			// Treat null/undefined as ""; convert numbers to string
			if ( val == null ) {
				val = "";

			} else if ( typeof val === "number" ) {
				val += "";

			} else if ( Array.isArray( val ) ) {
				val = jQuery.map( val, function( value ) {
					return value == null ? "" : value + "";
				} );
			}

			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];

			// If set returns undefined, fall back to normal setting
			if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
				this.value = val;
			}
		} );
	}
} );

jQuery.extend( {
	valHooks: {
		option: {
			get: function( elem ) {

				var val = jQuery.find.attr( elem, "value" );
				return val != null ?
					val :

					// Support: IE <=10 - 11 only
					// option.text throws exceptions (trac-14686, trac-14858)
					// Strip and collapse whitespace
					// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
					stripAndCollapse( jQuery.text( elem ) );
			}
		},
		select: {
			get: function( elem ) {
				var value, option, i,
					options = elem.options,
					index = elem.selectedIndex,
					one = elem.type === "select-one",
					values = one ? null : [],
					max = one ? index + 1 : options.length;

				if ( index < 0 ) {
					i = max;

				} else {
					i = one ? index : 0;
				}

				// Loop through all the selected options
				for ( ; i < max; i++ ) {
					option = options[ i ];

					// Support: IE <=9 only
					// IE8-9 doesn't update selected after form reset (trac-2551)
					if ( ( option.selected || i === index ) &&

							// Don't return options that are disabled or in a disabled optgroup
							!option.disabled &&
							( !option.parentNode.disabled ||
								!nodeName( option.parentNode, "optgroup" ) ) ) {

						// Get the specific value for the option
						value = jQuery( option ).val();

						// We don't need an array for one selects
						if ( one ) {
							return value;
						}

						// Multi-Selects return an array
						values.push( value );
					}
				}

				return values;
			},

			set: function( elem, value ) {
				var optionSet, option,
					options = elem.options,
					values = jQuery.makeArray( value ),
					i = options.length;

				while ( i-- ) {
					option = options[ i ];

					/* eslint-disable no-cond-assign */

					if ( option.selected =
						jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
					) {
						optionSet = true;
					}

					/* eslint-enable no-cond-assign */
				}

				// Force browsers to behave consistently when non-matching value is set
				if ( !optionSet ) {
					elem.selectedIndex = -1;
				}
				return values;
			}
		}
	}
} );

// Radios and checkboxes getter/setter
jQuery.each( [ "radio", "checkbox" ], function() {
	jQuery.valHooks[ this ] = {
		set: function( elem, value ) {
			if ( Array.isArray( value ) ) {
				return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
			}
		}
	};
	if ( !support.checkOn ) {
		jQuery.valHooks[ this ].get = function( elem ) {
			return elem.getAttribute( "value" ) === null ? "on" : elem.value;
		};
	}
} );




// Return jQuery for attributes-only inclusion
var location = window.location;

var nonce = { guid: Date.now() };

var rquery = ( /\?/ );



// Cross-browser xml parsing
jQuery.parseXML = function( data ) {
	var xml, parserErrorElem;
	if ( !data || typeof data !== "string" ) {
		return null;
	}

	// Support: IE 9 - 11 only
	// IE throws on parseFromString with invalid input.
	try {
		xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
	} catch ( e ) {}

	parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ];
	if ( !xml || parserErrorElem ) {
		jQuery.error( "Invalid XML: " + (
			parserErrorElem ?
				jQuery.map( parserErrorElem.childNodes, function( el ) {
					return el.textContent;
				} ).join( "\n" ) :
				data
		) );
	}
	return xml;
};


var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
	stopPropagationCallback = function( e ) {
		e.stopPropagation();
	};

jQuery.extend( jQuery.event, {

	trigger: function( event, data, elem, onlyHandlers ) {

		var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
			eventPath = [ elem || document ],
			type = hasOwn.call( event, "type" ) ? event.type : event,
			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];

		cur = lastElement = tmp = elem = elem || document;

		// Don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		// focus/blur morphs to focusin/out; ensure we're not firing them right now
		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
			return;
		}

		if ( type.indexOf( "." ) > -1 ) {

			// Namespaced trigger; create a regexp to match event type in handle()
			namespaces = type.split( "." );
			type = namespaces.shift();
			namespaces.sort();
		}
		ontype = type.indexOf( ":" ) < 0 && "on" + type;

		// Caller can pass in a jQuery.Event object, Object, or just an event type string
		event = event[ jQuery.expando ] ?
			event :
			new jQuery.Event( type, typeof event === "object" && event );

		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
		event.isTrigger = onlyHandlers ? 2 : 3;
		event.namespace = namespaces.join( "." );
		event.rnamespace = event.namespace ?
			new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
			null;

		// Clean up the event in case it is being reused
		event.result = undefined;
		if ( !event.target ) {
			event.target = elem;
		}

		// Clone any incoming data and prepend the event, creating the handler arg list
		data = data == null ?
			[ event ] :
			jQuery.makeArray( data, [ event ] );

		// Allow special events to draw outside the lines
		special = jQuery.event.special[ type ] || {};
		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
			return;
		}

		// Determine event propagation path in advance, per W3C events spec (trac-9951)
		// Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724)
		if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {

			bubbleType = special.delegateType || type;
			if ( !rfocusMorph.test( bubbleType + type ) ) {
				cur = cur.parentNode;
			}
			for ( ; cur; cur = cur.parentNode ) {
				eventPath.push( cur );
				tmp = cur;
			}

			// Only add window if we got to document (e.g., not plain obj or detached DOM)
			if ( tmp === ( elem.ownerDocument || document ) ) {
				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
			}
		}

		// Fire handlers on the event path
		i = 0;
		while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
			lastElement = cur;
			event.type = i > 1 ?
				bubbleType :
				special.bindType || type;

			// jQuery handler
			handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] &&
				dataPriv.get( cur, "handle" );
			if ( handle ) {
				handle.apply( cur, data );
			}

			// Native handler
			handle = ontype && cur[ ontype ];
			if ( handle && handle.apply && acceptData( cur ) ) {
				event.result = handle.apply( cur, data );
				if ( event.result === false ) {
					event.preventDefault();
				}
			}
		}
		event.type = type;

		// If nobody prevented the default action, do it now
		if ( !onlyHandlers && !event.isDefaultPrevented() ) {

			if ( ( !special._default ||
				special._default.apply( eventPath.pop(), data ) === false ) &&
				acceptData( elem ) ) {

				// Call a native DOM method on the target with the same name as the event.
				// Don't do default actions on window, that's where global variables be (trac-6170)
				if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {

					// Don't re-trigger an onFOO event when we call its FOO() method
					tmp = elem[ ontype ];

					if ( tmp ) {
						elem[ ontype ] = null;
					}

					// Prevent re-triggering of the same event, since we already bubbled it above
					jQuery.event.triggered = type;

					if ( event.isPropagationStopped() ) {
						lastElement.addEventListener( type, stopPropagationCallback );
					}

					elem[ type ]();

					if ( event.isPropagationStopped() ) {
						lastElement.removeEventListener( type, stopPropagationCallback );
					}

					jQuery.event.triggered = undefined;

					if ( tmp ) {
						elem[ ontype ] = tmp;
					}
				}
			}
		}

		return event.result;
	},

	// Piggyback on a donor event to simulate a different one
	// Used only for `focus(in | out)` events
	simulate: function( type, elem, event ) {
		var e = jQuery.extend(
			new jQuery.Event(),
			event,
			{
				type: type,
				isSimulated: true
			}
		);

		jQuery.event.trigger( e, null, elem );
	}

} );

jQuery.fn.extend( {

	trigger: function( type, data ) {
		return this.each( function() {
			jQuery.event.trigger( type, data, this );
		} );
	},
	triggerHandler: function( type, data ) {
		var elem = this[ 0 ];
		if ( elem ) {
			return jQuery.event.trigger( type, data, elem, true );
		}
	}
} );


var
	rbracket = /\[\]$/,
	rCRLF = /\r?\n/g,
	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
	rsubmittable = /^(?:input|select|textarea|keygen)/i;

function buildParams( prefix, obj, traditional, add ) {
	var name;

	if ( Array.isArray( obj ) ) {

		// Serialize array item.
		jQuery.each( obj, function( i, v ) {
			if ( traditional || rbracket.test( prefix ) ) {

				// Treat each array item as a scalar.
				add( prefix, v );

			} else {

				// Item is non-scalar (array or object), encode its numeric index.
				buildParams(
					prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
					v,
					traditional,
					add
				);
			}
		} );

	} else if ( !traditional && toType( obj ) === "object" ) {

		// Serialize object item.
		for ( name in obj ) {
			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
		}

	} else {

		// Serialize scalar item.
		add( prefix, obj );
	}
}

// Serialize an array of form elements or a set of
// key/values into a query string
jQuery.param = function( a, traditional ) {
	var prefix,
		s = [],
		add = function( key, valueOrFunction ) {

			// If value is a function, invoke it and use its return value
			var value = isFunction( valueOrFunction ) ?
				valueOrFunction() :
				valueOrFunction;

			s[ s.length ] = encodeURIComponent( key ) + "=" +
				encodeURIComponent( value == null ? "" : value );
		};

	if ( a == null ) {
		return "";
	}

	// If an array was passed in, assume that it is an array of form elements.
	if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {

		// Serialize the form elements
		jQuery.each( a, function() {
			add( this.name, this.value );
		} );

	} else {

		// If traditional, encode the "old" way (the way 1.3.2 or older
		// did it), otherwise encode params recursively.
		for ( prefix in a ) {
			buildParams( prefix, a[ prefix ], traditional, add );
		}
	}

	// Return the resulting serialization
	return s.join( "&" );
};

jQuery.fn.extend( {
	serialize: function() {
		return jQuery.param( this.serializeArray() );
	},
	serializeArray: function() {
		return this.map( function() {

			// Can add propHook for "elements" to filter or add form elements
			var elements = jQuery.prop( this, "elements" );
			return elements ? jQuery.makeArray( elements ) : this;
		} ).filter( function() {
			var type = this.type;

			// Use .is( ":disabled" ) so that fieldset[disabled] works
			return this.name && !jQuery( this ).is( ":disabled" ) &&
				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
				( this.checked || !rcheckableType.test( type ) );
		} ).map( function( _i, elem ) {
			var val = jQuery( this ).val();

			if ( val == null ) {
				return null;
			}

			if ( Array.isArray( val ) ) {
				return jQuery.map( val, function( val ) {
					return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
				} );
			}

			return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
		} ).get();
	}
} );


var
	r20 = /%20/g,
	rhash = /#.*$/,
	rantiCache = /([?&])_=[^&]*/,
	rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,

	// trac-7653, trac-8125, trac-8152: local protocol detection
	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
	rnoContent = /^(?:GET|HEAD)$/,
	rprotocol = /^\/\//,

	/* Prefilters
	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
	 * 2) These are called:
	 *    - BEFORE asking for a transport
	 *    - AFTER param serialization (s.data is a string if s.processData is true)
	 * 3) key is the dataType
	 * 4) the catchall symbol "*" can be used
	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
	 */
	prefilters = {},

	/* Transports bindings
	 * 1) key is the dataType
	 * 2) the catchall symbol "*" can be used
	 * 3) selection will start with transport dataType and THEN go to "*" if needed
	 */
	transports = {},

	// Avoid comment-prolog char sequence (trac-10098); must appease lint and evade compression
	allTypes = "*/".concat( "*" ),

	// Anchor tag for parsing the document origin
	originAnchor = document.createElement( "a" );

originAnchor.href = location.href;

// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {

	// dataTypeExpression is optional and defaults to "*"
	return function( dataTypeExpression, func ) {

		if ( typeof dataTypeExpression !== "string" ) {
			func = dataTypeExpression;
			dataTypeExpression = "*";
		}

		var dataType,
			i = 0,
			dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];

		if ( isFunction( func ) ) {

			// For each dataType in the dataTypeExpression
			while ( ( dataType = dataTypes[ i++ ] ) ) {

				// Prepend if requested
				if ( dataType[ 0 ] === "+" ) {
					dataType = dataType.slice( 1 ) || "*";
					( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );

				// Otherwise append
				} else {
					( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
				}
			}
		}
	};
}

// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {

	var inspected = {},
		seekingTransport = ( structure === transports );

	function inspect( dataType ) {
		var selected;
		inspected[ dataType ] = true;
		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
			if ( typeof dataTypeOrTransport === "string" &&
				!seekingTransport && !inspected[ dataTypeOrTransport ] ) {

				options.dataTypes.unshift( dataTypeOrTransport );
				inspect( dataTypeOrTransport );
				return false;
			} else if ( seekingTransport ) {
				return !( selected = dataTypeOrTransport );
			}
		} );
		return selected;
	}

	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}

// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes trac-9887
function ajaxExtend( target, src ) {
	var key, deep,
		flatOptions = jQuery.ajaxSettings.flatOptions || {};

	for ( key in src ) {
		if ( src[ key ] !== undefined ) {
			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
		}
	}
	if ( deep ) {
		jQuery.extend( true, target, deep );
	}

	return target;
}

/* Handles responses to an ajax request:
 * - finds the right dataType (mediates between content-type and expected dataType)
 * - returns the corresponding response
 */
function ajaxHandleResponses( s, jqXHR, responses ) {

	var ct, type, finalDataType, firstDataType,
		contents = s.contents,
		dataTypes = s.dataTypes;

	// Remove auto dataType and get content-type in the process
	while ( dataTypes[ 0 ] === "*" ) {
		dataTypes.shift();
		if ( ct === undefined ) {
			ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
		}
	}

	// Check if we're dealing with a known content-type
	if ( ct ) {
		for ( type in contents ) {
			if ( contents[ type ] && contents[ type ].test( ct ) ) {
				dataTypes.unshift( type );
				break;
			}
		}
	}

	// Check to see if we have a response for the expected dataType
	if ( dataTypes[ 0 ] in responses ) {
		finalDataType = dataTypes[ 0 ];
	} else {

		// Try convertible dataTypes
		for ( type in responses ) {
			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
				finalDataType = type;
				break;
			}
			if ( !firstDataType ) {
				firstDataType = type;
			}
		}

		// Or just use first one
		finalDataType = finalDataType || firstDataType;
	}

	// If we found a dataType
	// We add the dataType to the list if needed
	// and return the corresponding response
	if ( finalDataType ) {
		if ( finalDataType !== dataTypes[ 0 ] ) {
			dataTypes.unshift( finalDataType );
		}
		return responses[ finalDataType ];
	}
}

/* Chain conversions given the request and the original response
 * Also sets the responseXXX fields on the jqXHR instance
 */
function ajaxConvert( s, response, jqXHR, isSuccess ) {
	var conv2, current, conv, tmp, prev,
		converters = {},

		// Work with a copy of dataTypes in case we need to modify it for conversion
		dataTypes = s.dataTypes.slice();

	// Create converters map with lowercased keys
	if ( dataTypes[ 1 ] ) {
		for ( conv in s.converters ) {
			converters[ conv.toLowerCase() ] = s.converters[ conv ];
		}
	}

	current = dataTypes.shift();

	// Convert to each sequential dataType
	while ( current ) {

		if ( s.responseFields[ current ] ) {
			jqXHR[ s.responseFields[ current ] ] = response;
		}

		// Apply the dataFilter if provided
		if ( !prev && isSuccess && s.dataFilter ) {
			response = s.dataFilter( response, s.dataType );
		}

		prev = current;
		current = dataTypes.shift();

		if ( current ) {

			// There's only work to do if current dataType is non-auto
			if ( current === "*" ) {

				current = prev;

			// Convert response if prev dataType is non-auto and differs from current
			} else if ( prev !== "*" && prev !== current ) {

				// Seek a direct converter
				conv = converters[ prev + " " + current ] || converters[ "* " + current ];

				// If none found, seek a pair
				if ( !conv ) {
					for ( conv2 in converters ) {

						// If conv2 outputs current
						tmp = conv2.split( " " );
						if ( tmp[ 1 ] === current ) {

							// If prev can be converted to accepted input
							conv = converters[ prev + " " + tmp[ 0 ] ] ||
								converters[ "* " + tmp[ 0 ] ];
							if ( conv ) {

								// Condense equivalence converters
								if ( conv === true ) {
									conv = converters[ conv2 ];

								// Otherwise, insert the intermediate dataType
								} else if ( converters[ conv2 ] !== true ) {
									current = tmp[ 0 ];
									dataTypes.unshift( tmp[ 1 ] );
								}
								break;
							}
						}
					}
				}

				// Apply converter (if not an equivalence)
				if ( conv !== true ) {

					// Unless errors are allowed to bubble, catch and return them
					if ( conv && s.throws ) {
						response = conv( response );
					} else {
						try {
							response = conv( response );
						} catch ( e ) {
							return {
								state: "parsererror",
								error: conv ? e : "No conversion from " + prev + " to " + current
							};
						}
					}
				}
			}
		}
	}

	return { state: "success", data: response };
}

jQuery.extend( {

	// Counter for holding the number of active queries
	active: 0,

	// Last-Modified header cache for next request
	lastModified: {},
	etag: {},

	ajaxSettings: {
		url: location.href,
		type: "GET",
		isLocal: rlocalProtocol.test( location.protocol ),
		global: true,
		processData: true,
		async: true,
		contentType: "application/x-www-form-urlencoded; charset=UTF-8",

		/*
		timeout: 0,
		data: null,
		dataType: null,
		username: null,
		password: null,
		cache: null,
		throws: false,
		traditional: false,
		headers: {},
		*/

		accepts: {
			"*": allTypes,
			text: "text/plain",
			html: "text/html",
			xml: "application/xml, text/xml",
			json: "application/json, text/javascript"
		},

		contents: {
			xml: /\bxml\b/,
			html: /\bhtml/,
			json: /\bjson\b/
		},

		responseFields: {
			xml: "responseXML",
			text: "responseText",
			json: "responseJSON"
		},

		// Data converters
		// Keys separate source (or catchall "*") and destination types with a single space
		converters: {

			// Convert anything to text
			"* text": String,

			// Text to html (true = no transformation)
			"text html": true,

			// Evaluate text as a json expression
			"text json": JSON.parse,

			// Parse text as xml
			"text xml": jQuery.parseXML
		},

		// For options that shouldn't be deep extended:
		// you can add your own custom options here if
		// and when you create one that shouldn't be
		// deep extended (see ajaxExtend)
		flatOptions: {
			url: true,
			context: true
		}
	},

	// Creates a full fledged settings object into target
	// with both ajaxSettings and settings fields.
	// If target is omitted, writes into ajaxSettings.
	ajaxSetup: function( target, settings ) {
		return settings ?

			// Building a settings object
			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :

			// Extending ajaxSettings
			ajaxExtend( jQuery.ajaxSettings, target );
	},

	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
	ajaxTransport: addToPrefiltersOrTransports( transports ),

	// Main method
	ajax: function( url, options ) {

		// If url is an object, simulate pre-1.5 signature
		if ( typeof url === "object" ) {
			options = url;
			url = undefined;
		}

		// Force options to be an object
		options = options || {};

		var transport,

			// URL without anti-cache param
			cacheURL,

			// Response headers
			responseHeadersString,
			responseHeaders,

			// timeout handle
			timeoutTimer,

			// Url cleanup var
			urlAnchor,

			// Request state (becomes false upon send and true upon completion)
			completed,

			// To know if global events are to be dispatched
			fireGlobals,

			// Loop variable
			i,

			// uncached part of the url
			uncached,

			// Create the final options object
			s = jQuery.ajaxSetup( {}, options ),

			// Callbacks context
			callbackContext = s.context || s,

			// Context for global events is callbackContext if it is a DOM node or jQuery collection
			globalEventContext = s.context &&
				( callbackContext.nodeType || callbackContext.jquery ) ?
				jQuery( callbackContext ) :
				jQuery.event,

			// Deferreds
			deferred = jQuery.Deferred(),
			completeDeferred = jQuery.Callbacks( "once memory" ),

			// Status-dependent callbacks
			statusCode = s.statusCode || {},

			// Headers (they are sent all at once)
			requestHeaders = {},
			requestHeadersNames = {},

			// Default abort message
			strAbort = "canceled",

			// Fake xhr
			jqXHR = {
				readyState: 0,

				// Builds headers hashtable if needed
				getResponseHeader: function( key ) {
					var match;
					if ( completed ) {
						if ( !responseHeaders ) {
							responseHeaders = {};
							while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
								responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
									( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
										.concat( match[ 2 ] );
							}
						}
						match = responseHeaders[ key.toLowerCase() + " " ];
					}
					return match == null ? null : match.join( ", " );
				},

				// Raw string
				getAllResponseHeaders: function() {
					return completed ? responseHeadersString : null;
				},

				// Caches the header
				setRequestHeader: function( name, value ) {
					if ( completed == null ) {
						name = requestHeadersNames[ name.toLowerCase() ] =
							requestHeadersNames[ name.toLowerCase() ] || name;
						requestHeaders[ name ] = value;
					}
					return this;
				},

				// Overrides response content-type header
				overrideMimeType: function( type ) {
					if ( completed == null ) {
						s.mimeType = type;
					}
					return this;
				},

				// Status-dependent callbacks
				statusCode: function( map ) {
					var code;
					if ( map ) {
						if ( completed ) {

							// Execute the appropriate callbacks
							jqXHR.always( map[ jqXHR.status ] );
						} else {

							// Lazy-add the new callbacks in a way that preserves old ones
							for ( code in map ) {
								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
							}
						}
					}
					return this;
				},

				// Cancel the request
				abort: function( statusText ) {
					var finalText = statusText || strAbort;
					if ( transport ) {
						transport.abort( finalText );
					}
					done( 0, finalText );
					return this;
				}
			};

		// Attach deferreds
		deferred.promise( jqXHR );

		// Add protocol if not provided (prefilters might expect it)
		// Handle falsy url in the settings object (trac-10093: consistency with old signature)
		// We also use the url parameter if available
		s.url = ( ( url || s.url || location.href ) + "" )
			.replace( rprotocol, location.protocol + "//" );

		// Alias method option to type as per ticket trac-12004
		s.type = options.method || options.type || s.method || s.type;

		// Extract dataTypes list
		s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];

		// A cross-domain request is in order when the origin doesn't match the current origin.
		if ( s.crossDomain == null ) {
			urlAnchor = document.createElement( "a" );

			// Support: IE <=8 - 11, Edge 12 - 15
			// IE throws exception on accessing the href property if url is malformed,
			// e.g. http://example.com:80x/
			try {
				urlAnchor.href = s.url;

				// Support: IE <=8 - 11 only
				// Anchor's host property isn't correctly set when s.url is relative
				urlAnchor.href = urlAnchor.href;
				s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
					urlAnchor.protocol + "//" + urlAnchor.host;
			} catch ( e ) {

				// If there is an error parsing the URL, assume it is crossDomain,
				// it can be rejected by the transport if it is invalid
				s.crossDomain = true;
			}
		}

		// Convert data if not already a string
		if ( s.data && s.processData && typeof s.data !== "string" ) {
			s.data = jQuery.param( s.data, s.traditional );
		}

		// Apply prefilters
		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

		// If request was aborted inside a prefilter, stop there
		if ( completed ) {
			return jqXHR;
		}

		// We can fire global events as of now if asked to
		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (trac-15118)
		fireGlobals = jQuery.event && s.global;

		// Watch for a new set of requests
		if ( fireGlobals && jQuery.active++ === 0 ) {
			jQuery.event.trigger( "ajaxStart" );
		}

		// Uppercase the type
		s.type = s.type.toUpperCase();

		// Determine if request has content
		s.hasContent = !rnoContent.test( s.type );

		// Save the URL in case we're toying with the If-Modified-Since
		// and/or If-None-Match header later on
		// Remove hash to simplify url manipulation
		cacheURL = s.url.replace( rhash, "" );

		// More options handling for requests with no content
		if ( !s.hasContent ) {

			// Remember the hash so we can put it back
			uncached = s.url.slice( cacheURL.length );

			// If data is available and should be processed, append data to url
			if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
				cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;

				// trac-9682: remove data so that it's not used in an eventual retry
				delete s.data;
			}

			// Add or update anti-cache param if needed
			if ( s.cache === false ) {
				cacheURL = cacheURL.replace( rantiCache, "$1" );
				uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) +
					uncached;
			}

			// Put hash and anti-cache on the URL that will be requested (gh-1732)
			s.url = cacheURL + uncached;

		// Change '%20' to '+' if this is encoded form body content (gh-2658)
		} else if ( s.data && s.processData &&
			( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
			s.data = s.data.replace( r20, "+" );
		}

		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
		if ( s.ifModified ) {
			if ( jQuery.lastModified[ cacheURL ] ) {
				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
			}
			if ( jQuery.etag[ cacheURL ] ) {
				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
			}
		}

		// Set the correct header, if data is being sent
		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
			jqXHR.setRequestHeader( "Content-Type", s.contentType );
		}

		// Set the Accepts header for the server, depending on the dataType
		jqXHR.setRequestHeader(
			"Accept",
			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
				s.accepts[ s.dataTypes[ 0 ] ] +
					( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
				s.accepts[ "*" ]
		);

		// Check for headers option
		for ( i in s.headers ) {
			jqXHR.setRequestHeader( i, s.headers[ i ] );
		}

		// Allow custom headers/mimetypes and early abort
		if ( s.beforeSend &&
			( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {

			// Abort if not done already and return
			return jqXHR.abort();
		}

		// Aborting is no longer a cancellation
		strAbort = "abort";

		// Install callbacks on deferreds
		completeDeferred.add( s.complete );
		jqXHR.done( s.success );
		jqXHR.fail( s.error );

		// Get transport
		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );

		// If no transport, we auto-abort
		if ( !transport ) {
			done( -1, "No Transport" );
		} else {
			jqXHR.readyState = 1;

			// Send global event
			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
			}

			// If request was aborted inside ajaxSend, stop there
			if ( completed ) {
				return jqXHR;
			}

			// Timeout
			if ( s.async && s.timeout > 0 ) {
				timeoutTimer = window.setTimeout( function() {
					jqXHR.abort( "timeout" );
				}, s.timeout );
			}

			try {
				completed = false;
				transport.send( requestHeaders, done );
			} catch ( e ) {

				// Rethrow post-completion exceptions
				if ( completed ) {
					throw e;
				}

				// Propagate others as results
				done( -1, e );
			}
		}

		// Callback for when everything is done
		function done( status, nativeStatusText, responses, headers ) {
			var isSuccess, success, error, response, modified,
				statusText = nativeStatusText;

			// Ignore repeat invocations
			if ( completed ) {
				return;
			}

			completed = true;

			// Clear timeout if it exists
			if ( timeoutTimer ) {
				window.clearTimeout( timeoutTimer );
			}

			// Dereference transport for early garbage collection
			// (no matter how long the jqXHR object will be used)
			transport = undefined;

			// Cache response headers
			responseHeadersString = headers || "";

			// Set readyState
			jqXHR.readyState = status > 0 ? 4 : 0;

			// Determine if successful
			isSuccess = status >= 200 && status < 300 || status === 304;

			// Get response data
			if ( responses ) {
				response = ajaxHandleResponses( s, jqXHR, responses );
			}

			// Use a noop converter for missing script but not if jsonp
			if ( !isSuccess &&
				jQuery.inArray( "script", s.dataTypes ) > -1 &&
				jQuery.inArray( "json", s.dataTypes ) < 0 ) {
				s.converters[ "text script" ] = function() {};
			}

			// Convert no matter what (that way responseXXX fields are always set)
			response = ajaxConvert( s, response, jqXHR, isSuccess );

			// If successful, handle type chaining
			if ( isSuccess ) {

				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
				if ( s.ifModified ) {
					modified = jqXHR.getResponseHeader( "Last-Modified" );
					if ( modified ) {
						jQuery.lastModified[ cacheURL ] = modified;
					}
					modified = jqXHR.getResponseHeader( "etag" );
					if ( modified ) {
						jQuery.etag[ cacheURL ] = modified;
					}
				}

				// if no content
				if ( status === 204 || s.type === "HEAD" ) {
					statusText = "nocontent";

				// if not modified
				} else if ( status === 304 ) {
					statusText = "notmodified";

				// If we have data, let's convert it
				} else {
					statusText = response.state;
					success = response.data;
					error = response.error;
					isSuccess = !error;
				}
			} else {

				// Extract error from statusText and normalize for non-aborts
				error = statusText;
				if ( status || !statusText ) {
					statusText = "error";
					if ( status < 0 ) {
						status = 0;
					}
				}
			}

			// Set data for the fake xhr object
			jqXHR.status = status;
			jqXHR.statusText = ( nativeStatusText || statusText ) + "";

			// Success/Error
			if ( isSuccess ) {
				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
			} else {
				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
			}

			// Status-dependent callbacks
			jqXHR.statusCode( statusCode );
			statusCode = undefined;

			if ( fireGlobals ) {
				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
					[ jqXHR, s, isSuccess ? success : error ] );
			}

			// Complete
			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );

				// Handle the global AJAX counter
				if ( !( --jQuery.active ) ) {
					jQuery.event.trigger( "ajaxStop" );
				}
			}
		}

		return jqXHR;
	},

	getJSON: function( url, data, callback ) {
		return jQuery.get( url, data, callback, "json" );
	},

	getScript: function( url, callback ) {
		return jQuery.get( url, undefined, callback, "script" );
	}
} );

jQuery.each( [ "get", "post" ], function( _i, method ) {
	jQuery[ method ] = function( url, data, callback, type ) {

		// Shift arguments if data argument was omitted
		if ( isFunction( data ) ) {
			type = type || callback;
			callback = data;
			data = undefined;
		}

		// The url can be an options object (which then must have .url)
		return jQuery.ajax( jQuery.extend( {
			url: url,
			type: method,
			dataType: type,
			data: data,
			success: callback
		}, jQuery.isPlainObject( url ) && url ) );
	};
} );

jQuery.ajaxPrefilter( function( s ) {
	var i;
	for ( i in s.headers ) {
		if ( i.toLowerCase() === "content-type" ) {
			s.contentType = s.headers[ i ] || "";
		}
	}
} );


jQuery._evalUrl = function( url, options, doc ) {
	return jQuery.ajax( {
		url: url,

		// Make this explicit, since user can override this through ajaxSetup (trac-11264)
		type: "GET",
		dataType: "script",
		cache: true,
		async: false,
		global: false,

		// Only evaluate the response if it is successful (gh-4126)
		// dataFilter is not invoked for failure responses, so using it instead
		// of the default converter is kludgy but it works.
		converters: {
			"text script": function() {}
		},
		dataFilter: function( response ) {
			jQuery.globalEval( response, options, doc );
		}
	} );
};


jQuery.fn.extend( {
	wrapAll: function( html ) {
		var wrap;

		if ( this[ 0 ] ) {
			if ( isFunction( html ) ) {
				html = html.call( this[ 0 ] );
			}

			// The elements to wrap the target around
			wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );

			if ( this[ 0 ].parentNode ) {
				wrap.insertBefore( this[ 0 ] );
			}

			wrap.map( function() {
				var elem = this;

				while ( elem.firstElementChild ) {
					elem = elem.firstElementChild;
				}

				return elem;
			} ).append( this );
		}

		return this;
	},

	wrapInner: function( html ) {
		if ( isFunction( html ) ) {
			return this.each( function( i ) {
				jQuery( this ).wrapInner( html.call( this, i ) );
			} );
		}

		return this.each( function() {
			var self = jQuery( this ),
				contents = self.contents();

			if ( contents.length ) {
				contents.wrapAll( html );

			} else {
				self.append( html );
			}
		} );
	},

	wrap: function( html ) {
		var htmlIsFunction = isFunction( html );

		return this.each( function( i ) {
			jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
		} );
	},

	unwrap: function( selector ) {
		this.parent( selector ).not( "body" ).each( function() {
			jQuery( this ).replaceWith( this.childNodes );
		} );
		return this;
	}
} );


jQuery.expr.pseudos.hidden = function( elem ) {
	return !jQuery.expr.pseudos.visible( elem );
};
jQuery.expr.pseudos.visible = function( elem ) {
	return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};




jQuery.ajaxSettings.xhr = function() {
	try {
		return new window.XMLHttpRequest();
	} catch ( e ) {}
};

var xhrSuccessStatus = {

		// File protocol always yields status code 0, assume 200
		0: 200,

		// Support: IE <=9 only
		// trac-1450: sometimes IE returns 1223 when it should be 204
		1223: 204
	},
	xhrSupported = jQuery.ajaxSettings.xhr();

support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
support.ajax = xhrSupported = !!xhrSupported;

jQuery.ajaxTransport( function( options ) {
	var callback, errorCallback;

	// Cross domain only allowed if supported through XMLHttpRequest
	if ( support.cors || xhrSupported && !options.crossDomain ) {
		return {
			send: function( headers, complete ) {
				var i,
					xhr = options.xhr();

				xhr.open(
					options.type,
					options.url,
					options.async,
					options.username,
					options.password
				);

				// Apply custom fields if provided
				if ( options.xhrFields ) {
					for ( i in options.xhrFields ) {
						xhr[ i ] = options.xhrFields[ i ];
					}
				}

				// Override mime type if needed
				if ( options.mimeType && xhr.overrideMimeType ) {
					xhr.overrideMimeType( options.mimeType );
				}

				// X-Requested-With header
				// For cross-domain requests, seeing as conditions for a preflight are
				// akin to a jigsaw puzzle, we simply never set it to be sure.
				// (it can always be set on a per-request basis or even using ajaxSetup)
				// For same-domain requests, won't change header if already provided.
				if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
					headers[ "X-Requested-With" ] = "XMLHttpRequest";
				}

				// Set headers
				for ( i in headers ) {
					xhr.setRequestHeader( i, headers[ i ] );
				}

				// Callback
				callback = function( type ) {
					return function() {
						if ( callback ) {
							callback = errorCallback = xhr.onload =
								xhr.onerror = xhr.onabort = xhr.ontimeout =
									xhr.onreadystatechange = null;

							if ( type === "abort" ) {
								xhr.abort();
							} else if ( type === "error" ) {

								// Support: IE <=9 only
								// On a manual native abort, IE9 throws
								// errors on any property access that is not readyState
								if ( typeof xhr.status !== "number" ) {
									complete( 0, "error" );
								} else {
									complete(

										// File: protocol always yields status 0; see trac-8605, trac-14207
										xhr.status,
										xhr.statusText
									);
								}
							} else {
								complete(
									xhrSuccessStatus[ xhr.status ] || xhr.status,
									xhr.statusText,

									// Support: IE <=9 only
									// IE9 has no XHR2 but throws on binary (trac-11426)
									// For XHR2 non-text, let the caller handle it (gh-2498)
									( xhr.responseType || "text" ) !== "text"  ||
									typeof xhr.responseText !== "string" ?
										{ binary: xhr.response } :
										{ text: xhr.responseText },
									xhr.getAllResponseHeaders()
								);
							}
						}
					};
				};

				// Listen to events
				xhr.onload = callback();
				errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );

				// Support: IE 9 only
				// Use onreadystatechange to replace onabort
				// to handle uncaught aborts
				if ( xhr.onabort !== undefined ) {
					xhr.onabort = errorCallback;
				} else {
					xhr.onreadystatechange = function() {

						// Check readyState before timeout as it changes
						if ( xhr.readyState === 4 ) {

							// Allow onerror to be called first,
							// but that will not handle a native abort
							// Also, save errorCallback to a variable
							// as xhr.onerror cannot be accessed
							window.setTimeout( function() {
								if ( callback ) {
									errorCallback();
								}
							} );
						}
					};
				}

				// Create the abort callback
				callback = callback( "abort" );

				try {

					// Do send the request (this may raise an exception)
					xhr.send( options.hasContent && options.data || null );
				} catch ( e ) {

					// trac-14683: Only rethrow if this hasn't been notified as an error yet
					if ( callback ) {
						throw e;
					}
				}
			},

			abort: function() {
				if ( callback ) {
					callback();
				}
			}
		};
	}
} );




// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
jQuery.ajaxPrefilter( function( s ) {
	if ( s.crossDomain ) {
		s.contents.script = false;
	}
} );

// Install script dataType
jQuery.ajaxSetup( {
	accepts: {
		script: "text/javascript, application/javascript, " +
			"application/ecmascript, application/x-ecmascript"
	},
	contents: {
		script: /\b(?:java|ecma)script\b/
	},
	converters: {
		"text script": function( text ) {
			jQuery.globalEval( text );
			return text;
		}
	}
} );

// Handle cache's special case and crossDomain
jQuery.ajaxPrefilter( "script", function( s ) {
	if ( s.cache === undefined ) {
		s.cache = false;
	}
	if ( s.crossDomain ) {
		s.type = "GET";
	}
} );

// Bind script tag hack transport
jQuery.ajaxTransport( "script", function( s ) {

	// This transport only deals with cross domain or forced-by-attrs requests
	if ( s.crossDomain || s.scriptAttrs ) {
		var script, callback;
		return {
			send: function( _, complete ) {
				script = jQuery( "<script>" )
					.attr( s.scriptAttrs || {} )
					.prop( { charset: s.scriptCharset, src: s.url } )
					.on( "load error", callback = function( evt ) {
						script.remove();
						callback = null;
						if ( evt ) {
							complete( evt.type === "error" ? 404 : 200, evt.type );
						}
					} );

				// Use native DOM manipulation to avoid our domManip AJAX trickery
				document.head.appendChild( script[ 0 ] );
			},
			abort: function() {
				if ( callback ) {
					callback();
				}
			}
		};
	}
} );




var oldCallbacks = [],
	rjsonp = /(=)\?(?=&|$)|\?\?/;

// Default jsonp settings
jQuery.ajaxSetup( {
	jsonp: "callback",
	jsonpCallback: function() {
		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) );
		this[ callback ] = true;
		return callback;
	}
} );

// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {

	var callbackName, overwritten, responseContainer,
		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
			"url" :
			typeof s.data === "string" &&
				( s.contentType || "" )
					.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
				rjsonp.test( s.data ) && "data"
		);

	// Handle iff the expected data type is "jsonp" or we have a parameter to set
	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {

		// Get callback name, remembering preexisting value associated with it
		callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
			s.jsonpCallback() :
			s.jsonpCallback;

		// Insert callback into url or form data
		if ( jsonProp ) {
			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
		} else if ( s.jsonp !== false ) {
			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
		}

		// Use data converter to retrieve json after script execution
		s.converters[ "script json" ] = function() {
			if ( !responseContainer ) {
				jQuery.error( callbackName + " was not called" );
			}
			return responseContainer[ 0 ];
		};

		// Force json dataType
		s.dataTypes[ 0 ] = "json";

		// Install callback
		overwritten = window[ callbackName ];
		window[ callbackName ] = function() {
			responseContainer = arguments;
		};

		// Clean-up function (fires after converters)
		jqXHR.always( function() {

			// If previous value didn't exist - remove it
			if ( overwritten === undefined ) {
				jQuery( window ).removeProp( callbackName );

			// Otherwise restore preexisting value
			} else {
				window[ callbackName ] = overwritten;
			}

			// Save back as free
			if ( s[ callbackName ] ) {

				// Make sure that re-using the options doesn't screw things around
				s.jsonpCallback = originalSettings.jsonpCallback;

				// Save the callback name for future use
				oldCallbacks.push( callbackName );
			}

			// Call if it was a function and we have a response
			if ( responseContainer && isFunction( overwritten ) ) {
				overwritten( responseContainer[ 0 ] );
			}

			responseContainer = overwritten = undefined;
		} );

		// Delegate to script
		return "script";
	}
} );




// Support: Safari 8 only
// In Safari 8 documents created via document.implementation.createHTMLDocument
// collapse sibling forms: the second one becomes a child of the first one.
// Because of that, this security measure has to be disabled in Safari 8.
// https://bugs.webkit.org/show_bug.cgi?id=137337
support.createHTMLDocument = ( function() {
	var body = document.implementation.createHTMLDocument( "" ).body;
	body.innerHTML = "<form></form><form></form>";
	return body.childNodes.length === 2;
} )();


// Argument "data" should be string of html
// context (optional): If specified, the fragment will be created in this context,
// defaults to document
// keepScripts (optional): If true, will include scripts passed in the html string
jQuery.parseHTML = function( data, context, keepScripts ) {
	if ( typeof data !== "string" ) {
		return [];
	}
	if ( typeof context === "boolean" ) {
		keepScripts = context;
		context = false;
	}

	var base, parsed, scripts;

	if ( !context ) {

		// Stop scripts or inline event handlers from being executed immediately
		// by using document.implementation
		if ( support.createHTMLDocument ) {
			context = document.implementation.createHTMLDocument( "" );

			// Set the base href for the created document
			// so any parsed elements with URLs
			// are based on the document's URL (gh-2965)
			base = context.createElement( "base" );
			base.href = document.location.href;
			context.head.appendChild( base );
		} else {
			context = document;
		}
	}

	parsed = rsingleTag.exec( data );
	scripts = !keepScripts && [];

	// Single tag
	if ( parsed ) {
		return [ context.createElement( parsed[ 1 ] ) ];
	}

	parsed = buildFragment( [ data ], context, scripts );

	if ( scripts && scripts.length ) {
		jQuery( scripts ).remove();
	}

	return jQuery.merge( [], parsed.childNodes );
};


/**
 * Load a url into a page
 */
jQuery.fn.load = function( url, params, callback ) {
	var selector, type, response,
		self = this,
		off = url.indexOf( " " );

	if ( off > -1 ) {
		selector = stripAndCollapse( url.slice( off ) );
		url = url.slice( 0, off );
	}

	// If it's a function
	if ( isFunction( params ) ) {

		// We assume that it's the callback
		callback = params;
		params = undefined;

	// Otherwise, build a param string
	} else if ( params && typeof params === "object" ) {
		type = "POST";
	}

	// If we have elements to modify, make the request
	if ( self.length > 0 ) {
		jQuery.ajax( {
			url: url,

			// If "type" variable is undefined, then "GET" method will be used.
			// Make value of this field explicit since
			// user can override it through ajaxSetup method
			type: type || "GET",
			dataType: "html",
			data: params
		} ).done( function( responseText ) {

			// Save response for use in complete callback
			response = arguments;

			self.html( selector ?

				// If a selector was specified, locate the right elements in a dummy div
				// Exclude scripts to avoid IE 'Permission Denied' errors
				jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :

				// Otherwise use the full result
				responseText );

		// If the request succeeds, this function gets "data", "status", "jqXHR"
		// but they are ignored because response was set above.
		// If it fails, this function gets "jqXHR", "status", "error"
		} ).always( callback && function( jqXHR, status ) {
			self.each( function() {
				callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
			} );
		} );
	}

	return this;
};




jQuery.expr.pseudos.animated = function( elem ) {
	return jQuery.grep( jQuery.timers, function( fn ) {
		return elem === fn.elem;
	} ).length;
};




jQuery.offset = {
	setOffset: function( elem, options, i ) {
		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
			position = jQuery.css( elem, "position" ),
			curElem = jQuery( elem ),
			props = {};

		// Set position first, in-case top/left are set even on static elem
		if ( position === "static" ) {
			elem.style.position = "relative";
		}

		curOffset = curElem.offset();
		curCSSTop = jQuery.css( elem, "top" );
		curCSSLeft = jQuery.css( elem, "left" );
		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
			( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;

		// Need to be able to calculate position if either
		// top or left is auto and position is either absolute or fixed
		if ( calculatePosition ) {
			curPosition = curElem.position();
			curTop = curPosition.top;
			curLeft = curPosition.left;

		} else {
			curTop = parseFloat( curCSSTop ) || 0;
			curLeft = parseFloat( curCSSLeft ) || 0;
		}

		if ( isFunction( options ) ) {

			// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
			options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
		}

		if ( options.top != null ) {
			props.top = ( options.top - curOffset.top ) + curTop;
		}
		if ( options.left != null ) {
			props.left = ( options.left - curOffset.left ) + curLeft;
		}

		if ( "using" in options ) {
			options.using.call( elem, props );

		} else {
			curElem.css( props );
		}
	}
};

jQuery.fn.extend( {

	// offset() relates an element's border box to the document origin
	offset: function( options ) {

		// Preserve chaining for setter
		if ( arguments.length ) {
			return options === undefined ?
				this :
				this.each( function( i ) {
					jQuery.offset.setOffset( this, options, i );
				} );
		}

		var rect, win,
			elem = this[ 0 ];

		if ( !elem ) {
			return;
		}

		// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
		// Support: IE <=11 only
		// Running getBoundingClientRect on a
		// disconnected node in IE throws an error
		if ( !elem.getClientRects().length ) {
			return { top: 0, left: 0 };
		}

		// Get document-relative position by adding viewport scroll to viewport-relative gBCR
		rect = elem.getBoundingClientRect();
		win = elem.ownerDocument.defaultView;
		return {
			top: rect.top + win.pageYOffset,
			left: rect.left + win.pageXOffset
		};
	},

	// position() relates an element's margin box to its offset parent's padding box
	// This corresponds to the behavior of CSS absolute positioning
	position: function() {
		if ( !this[ 0 ] ) {
			return;
		}

		var offsetParent, offset, doc,
			elem = this[ 0 ],
			parentOffset = { top: 0, left: 0 };

		// position:fixed elements are offset from the viewport, which itself always has zero offset
		if ( jQuery.css( elem, "position" ) === "fixed" ) {

			// Assume position:fixed implies availability of getBoundingClientRect
			offset = elem.getBoundingClientRect();

		} else {
			offset = this.offset();

			// Account for the *real* offset parent, which can be the document or its root element
			// when a statically positioned element is identified
			doc = elem.ownerDocument;
			offsetParent = elem.offsetParent || doc.documentElement;
			while ( offsetParent &&
				( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
				jQuery.css( offsetParent, "position" ) === "static" ) {

				offsetParent = offsetParent.parentNode;
			}
			if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {

				// Incorporate borders into its offset, since they are outside its content origin
				parentOffset = jQuery( offsetParent ).offset();
				parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
				parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
			}
		}

		// Subtract parent offsets and element margins
		return {
			top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
		};
	},

	// This method will return documentElement in the following cases:
	// 1) For the element inside the iframe without offsetParent, this method will return
	//    documentElement of the parent window
	// 2) For the hidden or detached element
	// 3) For body or html element, i.e. in case of the html node - it will return itself
	//
	// but those exceptions were never presented as a real life use-cases
	// and might be considered as more preferable results.
	//
	// This logic, however, is not guaranteed and can change at any point in the future
	offsetParent: function() {
		return this.map( function() {
			var offsetParent = this.offsetParent;

			while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
				offsetParent = offsetParent.offsetParent;
			}

			return offsetParent || documentElement;
		} );
	}
} );

// Create scrollLeft and scrollTop methods
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
	var top = "pageYOffset" === prop;

	jQuery.fn[ method ] = function( val ) {
		return access( this, function( elem, method, val ) {

			// Coalesce documents and windows
			var win;
			if ( isWindow( elem ) ) {
				win = elem;
			} else if ( elem.nodeType === 9 ) {
				win = elem.defaultView;
			}

			if ( val === undefined ) {
				return win ? win[ prop ] : elem[ method ];
			}

			if ( win ) {
				win.scrollTo(
					!top ? val : win.pageXOffset,
					top ? val : win.pageYOffset
				);

			} else {
				elem[ method ] = val;
			}
		}, method, val, arguments.length );
	};
} );

// Support: Safari <=7 - 9.1, Chrome <=37 - 49
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
// getComputedStyle returns percent when specified for top/left/bottom/right;
// rather than make the css module depend on the offset module, just check for it here
jQuery.each( [ "top", "left" ], function( _i, prop ) {
	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
		function( elem, computed ) {
			if ( computed ) {
				computed = curCSS( elem, prop );

				// If curCSS returns percentage, fallback to offset
				return rnumnonpx.test( computed ) ?
					jQuery( elem ).position()[ prop ] + "px" :
					computed;
			}
		}
	);
} );


// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
	jQuery.each( {
		padding: "inner" + name,
		content: type,
		"": "outer" + name
	}, function( defaultExtra, funcName ) {

		// Margin is only for outerHeight, outerWidth
		jQuery.fn[ funcName ] = function( margin, value ) {
			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );

			return access( this, function( elem, type, value ) {
				var doc;

				if ( isWindow( elem ) ) {

					// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
					return funcName.indexOf( "outer" ) === 0 ?
						elem[ "inner" + name ] :
						elem.document.documentElement[ "client" + name ];
				}

				// Get document width or height
				if ( elem.nodeType === 9 ) {
					doc = elem.documentElement;

					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
					// whichever is greatest
					return Math.max(
						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
						elem.body[ "offset" + name ], doc[ "offset" + name ],
						doc[ "client" + name ]
					);
				}

				return value === undefined ?

					// Get width or height on the element, requesting but not forcing parseFloat
					jQuery.css( elem, type, extra ) :

					// Set width or height on the element
					jQuery.style( elem, type, value, extra );
			}, type, chainable ? margin : undefined, chainable );
		};
	} );
} );


jQuery.each( [
	"ajaxStart",
	"ajaxStop",
	"ajaxComplete",
	"ajaxError",
	"ajaxSuccess",
	"ajaxSend"
], function( _i, type ) {
	jQuery.fn[ type ] = function( fn ) {
		return this.on( type, fn );
	};
} );




jQuery.fn.extend( {

	bind: function( types, data, fn ) {
		return this.on( types, null, data, fn );
	},
	unbind: function( types, fn ) {
		return this.off( types, null, fn );
	},

	delegate: function( selector, types, data, fn ) {
		return this.on( types, selector, data, fn );
	},
	undelegate: function( selector, types, fn ) {

		// ( namespace ) or ( selector, types [, fn] )
		return arguments.length === 1 ?
			this.off( selector, "**" ) :
			this.off( types, selector || "**", fn );
	},

	hover: function( fnOver, fnOut ) {
		return this
			.on( "mouseenter", fnOver )
			.on( "mouseleave", fnOut || fnOver );
	}
} );

jQuery.each(
	( "blur focus focusin focusout resize scroll click dblclick " +
	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
	"change select submit keydown keypress keyup contextmenu" ).split( " " ),
	function( _i, name ) {

		// Handle event binding
		jQuery.fn[ name ] = function( data, fn ) {
			return arguments.length > 0 ?
				this.on( name, null, data, fn ) :
				this.trigger( name );
		};
	}
);




// Support: Android <=4.0 only
// Make sure we trim BOM and NBSP
// Require that the "whitespace run" starts from a non-whitespace
// to avoid O(N^2) behavior when the engine would try matching "\s+$" at each space position.
var rtrim = /^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;

// Bind a function to a context, optionally partially applying any
// arguments.
// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
// However, it is not slated for removal any time soon
jQuery.proxy = function( fn, context ) {
	var tmp, args, proxy;

	if ( typeof context === "string" ) {
		tmp = fn[ context ];
		context = fn;
		fn = tmp;
	}

	// Quick check to determine if target is callable, in the spec
	// this throws a TypeError, but we will just return undefined.
	if ( !isFunction( fn ) ) {
		return undefined;
	}

	// Simulated bind
	args = slice.call( arguments, 2 );
	proxy = function() {
		return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
	};

	// Set the guid of unique handler to the same of original handler, so it can be removed
	proxy.guid = fn.guid = fn.guid || jQuery.guid++;

	return proxy;
};

jQuery.holdReady = function( hold ) {
	if ( hold ) {
		jQuery.readyWait++;
	} else {
		jQuery.ready( true );
	}
};
jQuery.isArray = Array.isArray;
jQuery.parseJSON = JSON.parse;
jQuery.nodeName = nodeName;
jQuery.isFunction = isFunction;
jQuery.isWindow = isWindow;
jQuery.camelCase = camelCase;
jQuery.type = toType;

jQuery.now = Date.now;

jQuery.isNumeric = function( obj ) {

	// As of jQuery 3.0, isNumeric is limited to
	// strings and numbers (primitives or objects)
	// that can be coerced to finite numbers (gh-2662)
	var type = jQuery.type( obj );
	return ( type === "number" || type === "string" ) &&

		// parseFloat NaNs numeric-cast false positives ("")
		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
		// subtraction forces infinities to NaN
		!isNaN( obj - parseFloat( obj ) );
};

jQuery.trim = function( text ) {
	return text == null ?
		"" :
		( text + "" ).replace( rtrim, "$1" );
};



// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.

// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon

if ( typeof define === "function" && define.amd ) {
	define( "jquery", [], function() {
		return jQuery;
	} );
}




var

	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,

	// Map over the $ in case of overwrite
	_$ = window.$;

jQuery.noConflict = function( deep ) {
	if ( window.$ === jQuery ) {
		window.$ = _$;
	}

	if ( deep && window.jQuery === jQuery ) {
		window.jQuery = _jQuery;
	}

	return jQuery;
};

// Expose jQuery and $ identifiers, even in AMD
// (trac-7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (trac-13566)
if ( typeof noGlobal === "undefined" ) {
	window.jQuery = window.$ = jQuery;
}




return jQuery;
} );

/*!
 * Select2 4.0.5
 * https://select2.github.io
 *
 * Released under the MIT license
 * https://github.com/select2/select2/blob/master/LICENSE.md
 */
(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // Node/CommonJS
    module.exports = function (root, jQuery) {
      if (jQuery === undefined) {
        // require('jQuery') returns a factory that requires window to
        // build a jQuery instance, we normalize how we use modules
        // that require this pattern but the window provided is a noop
        // if it's defined (how jquery works)
        if (typeof window !== 'undefined') {
          jQuery = require('jquery');
        }
        else {
          jQuery = require('jquery')(root);
        }
      }
      factory(jQuery);
      return jQuery;
    };
  } else {
    // Browser globals
    factory(jQuery);
  }
} (function (jQuery) {
  // This is needed so we can catch the AMD loader configuration and use it
  // The inner file should be wrapped (by `banner.start.js`) in a function that
  // returns the AMD loader references.
  var S2 =(function () {
  // Restore the Select2 AMD loader so it can be used
  // Needed mostly in the language files, where the loader is not inserted
  if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
    var S2 = jQuery.fn.select2.amd;
  }
var S2;(function () { if (!S2 || !S2.requirejs) {
if (!S2) { S2 = {}; } else { require = S2; }
/**
 * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
 * Released under MIT license, http://github.com/requirejs/almond/LICENSE
 */
//Going sloppy to avoid 'use strict' string cost, but strict practices should
//be followed.
/*global setTimeout: false */

var requirejs, require, define;
(function (undef) {
    var main, req, makeMap, handlers,
        defined = {},
        waiting = {},
        config = {},
        defining = {},
        hasOwn = Object.prototype.hasOwnProperty,
        aps = [].slice,
        jsSuffixRegExp = /\.js$/;

    function hasProp(obj, prop) {
        return hasOwn.call(obj, prop);
    }

    /**
     * Given a relative module name, like ./something, normalize it to
     * a real name that can be mapped to a path.
     * @param {String} name the relative name
     * @param {String} baseName a real name that the name arg is relative
     * to.
     * @returns {String} normalized name
     */
    function normalize(name, baseName) {
        var nameParts, nameSegment, mapValue, foundMap, lastIndex,
            foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
            baseParts = baseName && baseName.split("/"),
            map = config.map,
            starMap = (map && map['*']) || {};

        //Adjust any relative paths.
        if (name) {
            name = name.split('/');
            lastIndex = name.length - 1;

            // If wanting node ID compatibility, strip .js from end
            // of IDs. Have to do this here, and not in nameToUrl
            // because node allows either .js or non .js to map
            // to same file.
            if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
                name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
            }

            // Starts with a '.' so need the baseName
            if (name[0].charAt(0) === '.' && baseParts) {
                //Convert baseName to array, and lop off the last part,
                //so that . matches that 'directory' and not name of the baseName's
                //module. For instance, baseName of 'one/two/three', maps to
                //'one/two/three.js', but we want the directory, 'one/two' for
                //this normalization.
                normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
                name = normalizedBaseParts.concat(name);
            }

            //start trimDots
            for (i = 0; i < name.length; i++) {
                part = name[i];
                if (part === '.') {
                    name.splice(i, 1);
                    i -= 1;
                } else if (part === '..') {
                    // If at the start, or previous value is still ..,
                    // keep them so that when converted to a path it may
                    // still work when converted to a path, even though
                    // as an ID it is less than ideal. In larger point
                    // releases, may be better to just kick out an error.
                    if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
                        continue;
                    } else if (i > 0) {
                        name.splice(i - 1, 2);
                        i -= 2;
                    }
                }
            }
            //end trimDots

            name = name.join('/');
        }

        //Apply map config if available.
        if ((baseParts || starMap) && map) {
            nameParts = name.split('/');

            for (i = nameParts.length; i > 0; i -= 1) {
                nameSegment = nameParts.slice(0, i).join("/");

                if (baseParts) {
                    //Find the longest baseName segment match in the config.
                    //So, do joins on the biggest to smallest lengths of baseParts.
                    for (j = baseParts.length; j > 0; j -= 1) {
                        mapValue = map[baseParts.slice(0, j).join('/')];

                        //baseName segment has  config, find if it has one for
                        //this name.
                        if (mapValue) {
                            mapValue = mapValue[nameSegment];
                            if (mapValue) {
                                //Match, update name to the new value.
                                foundMap = mapValue;
                                foundI = i;
                                break;
                            }
                        }
                    }
                }

                if (foundMap) {
                    break;
                }

                //Check for a star map match, but just hold on to it,
                //if there is a shorter segment match later in a matching
                //config, then favor over this star map.
                if (!foundStarMap && starMap && starMap[nameSegment]) {
                    foundStarMap = starMap[nameSegment];
                    starI = i;
                }
            }

            if (!foundMap && foundStarMap) {
                foundMap = foundStarMap;
                foundI = starI;
            }

            if (foundMap) {
                nameParts.splice(0, foundI, foundMap);
                name = nameParts.join('/');
            }
        }

        return name;
    }

    function makeRequire(relName, forceSync) {
        return function () {
            //A version of a require function that passes a moduleName
            //value for items that may need to
            //look up paths relative to the moduleName
            var args = aps.call(arguments, 0);

            //If first arg is not require('string'), and there is only
            //one arg, it is the array form without a callback. Insert
            //a null so that the following concat is correct.
            if (typeof args[0] !== 'string' && args.length === 1) {
                args.push(null);
            }
            return req.apply(undef, args.concat([relName, forceSync]));
        };
    }

    function makeNormalize(relName) {
        return function (name) {
            return normalize(name, relName);
        };
    }

    function makeLoad(depName) {
        return function (value) {
            defined[depName] = value;
        };
    }

    function callDep(name) {
        if (hasProp(waiting, name)) {
            var args = waiting[name];
            delete waiting[name];
            defining[name] = true;
            main.apply(undef, args);
        }

        if (!hasProp(defined, name) && !hasProp(defining, name)) {
            throw new Error('No ' + name);
        }
        return defined[name];
    }

    //Turns a plugin!resource to [plugin, resource]
    //with the plugin being undefined if the name
    //did not have a plugin prefix.
    function splitPrefix(name) {
        var prefix,
            index = name ? name.indexOf('!') : -1;
        if (index > -1) {
            prefix = name.substring(0, index);
            name = name.substring(index + 1, name.length);
        }
        return [prefix, name];
    }

    //Creates a parts array for a relName where first part is plugin ID,
    //second part is resource ID. Assumes relName has already been normalized.
    function makeRelParts(relName) {
        return relName ? splitPrefix(relName) : [];
    }

    /**
     * Makes a name map, normalizing the name, and using a plugin
     * for normalization if necessary. Grabs a ref to plugin
     * too, as an optimization.
     */
    makeMap = function (name, relParts) {
        var plugin,
            parts = splitPrefix(name),
            prefix = parts[0],
            relResourceName = relParts[1];

        name = parts[1];

        if (prefix) {
            prefix = normalize(prefix, relResourceName);
            plugin = callDep(prefix);
        }

        //Normalize according
        if (prefix) {
            if (plugin && plugin.normalize) {
                name = plugin.normalize(name, makeNormalize(relResourceName));
            } else {
                name = normalize(name, relResourceName);
            }
        } else {
            name = normalize(name, relResourceName);
            parts = splitPrefix(name);
            prefix = parts[0];
            name = parts[1];
            if (prefix) {
                plugin = callDep(prefix);
            }
        }

        //Using ridiculous property names for space reasons
        return {
            f: prefix ? prefix + '!' + name : name, //fullName
            n: name,
            pr: prefix,
            p: plugin
        };
    };

    function makeConfig(name) {
        return function () {
            return (config && config.config && config.config[name]) || {};
        };
    }

    handlers = {
        require: function (name) {
            return makeRequire(name);
        },
        exports: function (name) {
            var e = defined[name];
            if (typeof e !== 'undefined') {
                return e;
            } else {
                return (defined[name] = {});
            }
        },
        module: function (name) {
            return {
                id: name,
                uri: '',
                exports: defined[name],
                config: makeConfig(name)
            };
        }
    };

    main = function (name, deps, callback, relName) {
        var cjsModule, depName, ret, map, i, relParts,
            args = [],
            callbackType = typeof callback,
            usingExports;

        //Use name if no relName
        relName = relName || name;
        relParts = makeRelParts(relName);

        //Call the callback to define the module, if necessary.
        if (callbackType === 'undefined' || callbackType === 'function') {
            //Pull out the defined dependencies and pass the ordered
            //values to the callback.
            //Default to [require, exports, module] if no deps
            deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
            for (i = 0; i < deps.length; i += 1) {
                map = makeMap(deps[i], relParts);
                depName = map.f;

                //Fast path CommonJS standard dependencies.
                if (depName === "require") {
                    args[i] = handlers.require(name);
                } else if (depName === "exports") {
                    //CommonJS module spec 1.1
                    args[i] = handlers.exports(name);
                    usingExports = true;
                } else if (depName === "module") {
                    //CommonJS module spec 1.1
                    cjsModule = args[i] = handlers.module(name);
                } else if (hasProp(defined, depName) ||
                           hasProp(waiting, depName) ||
                           hasProp(defining, depName)) {
                    args[i] = callDep(depName);
                } else if (map.p) {
                    map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
                    args[i] = defined[depName];
                } else {
                    throw new Error(name + ' missing ' + depName);
                }
            }

            ret = callback ? callback.apply(defined[name], args) : undefined;

            if (name) {
                //If setting exports via "module" is in play,
                //favor that over return value and exports. After that,
                //favor a non-undefined return value over exports use.
                if (cjsModule && cjsModule.exports !== undef &&
                        cjsModule.exports !== defined[name]) {
                    defined[name] = cjsModule.exports;
                } else if (ret !== undef || !usingExports) {
                    //Use the return value from the function.
                    defined[name] = ret;
                }
            }
        } else if (name) {
            //May just be an object definition for the module. Only
            //worry about defining if have a module name.
            defined[name] = callback;
        }
    };

    requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
        if (typeof deps === "string") {
            if (handlers[deps]) {
                //callback in this case is really relName
                return handlers[deps](callback);
            }
            //Just return the module wanted. In this scenario, the
            //deps arg is the module name, and second arg (if passed)
            //is just the relName.
            //Normalize module name, if it contains . or ..
            return callDep(makeMap(deps, makeRelParts(callback)).f);
        } else if (!deps.splice) {
            //deps is a config object, not an array.
            config = deps;
            if (config.deps) {
                req(config.deps, config.callback);
            }
            if (!callback) {
                return;
            }

            if (callback.splice) {
                //callback is an array, which means it is a dependency list.
                //Adjust args if there are dependencies
                deps = callback;
                callback = relName;
                relName = null;
            } else {
                deps = undef;
            }
        }

        //Support require(['a'])
        callback = callback || function () {};

        //If relName is a function, it is an errback handler,
        //so remove it.
        if (typeof relName === 'function') {
            relName = forceSync;
            forceSync = alt;
        }

        //Simulate async callback;
        if (forceSync) {
            main(undef, deps, callback, relName);
        } else {
            //Using a non-zero value because of concern for what old browsers
            //do, and latest browsers "upgrade" to 4 if lower value is used:
            //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
            //If want a value immediately, use require('id') instead -- something
            //that works in almond on the global level, but not guaranteed and
            //unlikely to work in other AMD implementations.
            setTimeout(function () {
                main(undef, deps, callback, relName);
            }, 4);
        }

        return req;
    };

    /**
     * Just drops the config on the floor, but returns req in case
     * the config return value is used.
     */
    req.config = function (cfg) {
        return req(cfg);
    };

    /**
     * Expose module registry for debugging and tooling
     */
    requirejs._defined = defined;

    define = function (name, deps, callback) {
        if (typeof name !== 'string') {
            throw new Error('See almond README: incorrect module build, no module name');
        }

        //This module may not have dependencies
        if (!deps.splice) {
            //deps is not an array, so probably means
            //an object literal or factory function for
            //the value. Adjust args.
            callback = deps;
            deps = [];
        }

        if (!hasProp(defined, name) && !hasProp(waiting, name)) {
            waiting[name] = [name, deps, callback];
        }
    };

    define.amd = {
        jQuery: true
    };
}());

S2.requirejs = requirejs;S2.require = require;S2.define = define;
}
}());
S2.define("almond", function(){});

/* global jQuery:false, $:false */
S2.define('jquery',[],function () {
  var _$ = jQuery || $;

  if (_$ == null && console && console.error) {
    console.error(
      'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
      'found. Make sure that you are including jQuery before Select2 on your ' +
      'web page.'
    );
  }

  return _$;
});

S2.define('select2/utils',[
  'jquery'
], function ($) {
  var Utils = {};

  Utils.Extend = function (ChildClass, SuperClass) {
    var __hasProp = {}.hasOwnProperty;

    function BaseConstructor () {
      this.constructor = ChildClass;
    }

    for (var key in SuperClass) {
      if (__hasProp.call(SuperClass, key)) {
        ChildClass[key] = SuperClass[key];
      }
    }

    BaseConstructor.prototype = SuperClass.prototype;
    ChildClass.prototype = new BaseConstructor();
    ChildClass.__super__ = SuperClass.prototype;

    return ChildClass;
  };

  function getMethods (theClass) {
    var proto = theClass.prototype;

    var methods = [];

    for (var methodName in proto) {
      var m = proto[methodName];

      if (typeof m !== 'function') {
        continue;
      }

      if (methodName === 'constructor') {
        continue;
      }

      methods.push(methodName);
    }

    return methods;
  }

  Utils.Decorate = function (SuperClass, DecoratorClass) {
    var decoratedMethods = getMethods(DecoratorClass);
    var superMethods = getMethods(SuperClass);

    function DecoratedClass () {
      var unshift = Array.prototype.unshift;

      var argCount = DecoratorClass.prototype.constructor.length;

      var calledConstructor = SuperClass.prototype.constructor;

      if (argCount > 0) {
        unshift.call(arguments, SuperClass.prototype.constructor);

        calledConstructor = DecoratorClass.prototype.constructor;
      }

      calledConstructor.apply(this, arguments);
    }

    DecoratorClass.displayName = SuperClass.displayName;

    function ctr () {
      this.constructor = DecoratedClass;
    }

    DecoratedClass.prototype = new ctr();

    for (var m = 0; m < superMethods.length; m++) {
        var superMethod = superMethods[m];

        DecoratedClass.prototype[superMethod] =
          SuperClass.prototype[superMethod];
    }

    var calledMethod = function (methodName) {
      // Stub out the original method if it's not decorating an actual method
      var originalMethod = function () {};

      if (methodName in DecoratedClass.prototype) {
        originalMethod = DecoratedClass.prototype[methodName];
      }

      var decoratedMethod = DecoratorClass.prototype[methodName];

      return function () {
        var unshift = Array.prototype.unshift;

        unshift.call(arguments, originalMethod);

        return decoratedMethod.apply(this, arguments);
      };
    };

    for (var d = 0; d < decoratedMethods.length; d++) {
      var decoratedMethod = decoratedMethods[d];

      DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
    }

    return DecoratedClass;
  };

  var Observable = function () {
    this.listeners = {};
  };

  Observable.prototype.on = function (event, callback) {
    this.listeners = this.listeners || {};

    if (event in this.listeners) {
      this.listeners[event].push(callback);
    } else {
      this.listeners[event] = [callback];
    }
  };

  Observable.prototype.trigger = function (event) {
    var slice = Array.prototype.slice;
    var params = slice.call(arguments, 1);

    this.listeners = this.listeners || {};

    // Params should always come in as an array
    if (params == null) {
      params = [];
    }

    // If there are no arguments to the event, use a temporary object
    if (params.length === 0) {
      params.push({});
    }

    // Set the `_type` of the first object to the event
    params[0]._type = event;

    if (event in this.listeners) {
      this.invoke(this.listeners[event], slice.call(arguments, 1));
    }

    if ('*' in this.listeners) {
      this.invoke(this.listeners['*'], arguments);
    }
  };

  Observable.prototype.invoke = function (listeners, params) {
    for (var i = 0, len = listeners.length; i < len; i++) {
      listeners[i].apply(this, params);
    }
  };

  Utils.Observable = Observable;

  Utils.generateChars = function (length) {
    var chars = '';

    for (var i = 0; i < length; i++) {
      var randomChar = Math.floor(Math.random() * 36);
      chars += randomChar.toString(36);
    }

    return chars;
  };

  Utils.bind = function (func, context) {
    return function () {
      func.apply(context, arguments);
    };
  };

  Utils._convertData = function (data) {
    for (var originalKey in data) {
      var keys = originalKey.split('-');

      var dataLevel = data;

      if (keys.length === 1) {
        continue;
      }

      for (var k = 0; k < keys.length; k++) {
        var key = keys[k];

        // Lowercase the first letter
        // By default, dash-separated becomes camelCase
        key = key.substring(0, 1).toLowerCase() + key.substring(1);

        if (!(key in dataLevel)) {
          dataLevel[key] = {};
        }

        if (k == keys.length - 1) {
          dataLevel[key] = data[originalKey];
        }

        dataLevel = dataLevel[key];
      }

      delete data[originalKey];
    }

    return data;
  };

  Utils.hasScroll = function (index, el) {
    // Adapted from the function created by @ShadowScripter
    // and adapted by @BillBarry on the Stack Exchange Code Review website.
    // The original code can be found at
    // http://codereview.stackexchange.com/q/13338
    // and was designed to be used with the Sizzle selector engine.

    var $el = $(el);
    var overflowX = el.style.overflowX;
    var overflowY = el.style.overflowY;

    //Check both x and y declarations
    if (overflowX === overflowY &&
        (overflowY === 'hidden' || overflowY === 'visible')) {
      return false;
    }

    if (overflowX === 'scroll' || overflowY === 'scroll') {
      return true;
    }

    return ($el.innerHeight() < el.scrollHeight ||
      $el.innerWidth() < el.scrollWidth);
  };

  Utils.escapeMarkup = function (markup) {
    var replaceMap = {
      '\\': '&#92;',
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      '\'': '&#39;',
      '/': '&#47;'
    };

    // Do not try to escape the markup if it's not a string
    if (typeof markup !== 'string') {
      return markup;
    }

    return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
      return replaceMap[match];
    });
  };

  // Append an array of jQuery nodes to a given element.
  Utils.appendMany = function ($element, $nodes) {
    // jQuery 1.7.x does not support $.fn.append() with an array
    // Fall back to a jQuery object collection using $.fn.add()
    if ($.fn.jquery.substr(0, 3) === '1.7') {
      var $jqNodes = $();

      $.map($nodes, function (node) {
        $jqNodes = $jqNodes.add(node);
      });

      $nodes = $jqNodes;
    }

    $element.append($nodes);
  };

  return Utils;
});

S2.define('select2/results',[
  'jquery',
  './utils'
], function ($, Utils) {
  function Results ($element, options, dataAdapter) {
    this.$element = $element;
    this.data = dataAdapter;
    this.options = options;

    Results.__super__.constructor.call(this);
  }

  Utils.Extend(Results, Utils.Observable);

  Results.prototype.render = function () {
    var $results = $(
      '<ul class="select2-results__options" role="tree"></ul>'
    );

    if (this.options.get('multiple')) {
      $results.attr('aria-multiselectable', 'true');
    }

    this.$results = $results;

    return $results;
  };

  Results.prototype.clear = function () {
    this.$results.empty();
  };

  Results.prototype.displayMessage = function (params) {
    var escapeMarkup = this.options.get('escapeMarkup');

    this.clear();
    this.hideLoading();

    var $message = $(
      '<li role="treeitem" aria-live="assertive"' +
      ' class="select2-results__option"></li>'
    );

    var message = this.options.get('translations').get(params.message);

    $message.append(
      escapeMarkup(
        message(params.args)
      )
    );

    $message[0].className += ' select2-results__message';

    this.$results.append($message);
  };

  Results.prototype.hideMessages = function () {
    this.$results.find('.select2-results__message').remove();
  };

  Results.prototype.append = function (data) {
    this.hideLoading();

    var $options = [];

    if (data.results == null || data.results.length === 0) {
      if (this.$results.children().length === 0) {
        this.trigger('results:message', {
          message: 'noResults'
        });
      }

      return;
    }

    data.results = this.sort(data.results);

    for (var d = 0; d < data.results.length; d++) {
      var item = data.results[d];

      var $option = this.option(item);

      $options.push($option);
    }

    this.$results.append($options);
  };

  Results.prototype.position = function ($results, $dropdown) {
    var $resultsContainer = $dropdown.find('.select2-results');
    $resultsContainer.append($results);
  };

  Results.prototype.sort = function (data) {
    var sorter = this.options.get('sorter');

    return sorter(data);
  };

  Results.prototype.highlightFirstItem = function () {
    var $options = this.$results
      .find('.select2-results__option[aria-selected]');

    var $selected = $options.filter('[aria-selected=true]');

    // Check if there are any selected options
    if ($selected.length > 0) {
      // If there are selected options, highlight the first
      $selected.first().trigger('mouseenter');
    } else {
      // If there are no selected options, highlight the first option
      // in the dropdown
      $options.first().trigger('mouseenter');
    }

    this.ensureHighlightVisible();
  };

  Results.prototype.setClasses = function () {
    var self = this;

    this.data.current(function (selected) {
      var selectedIds = $.map(selected, function (s) {
        return s.id.toString();
      });

      var $options = self.$results
        .find('.select2-results__option[aria-selected]');

      $options.each(function () {
        var $option = $(this);

        var item = $.data(this, 'data');

        // id needs to be converted to a string when comparing
        var id = '' + item.id;

        if ((item.element != null && item.element.selected) ||
            (item.element == null && $.inArray(id, selectedIds) > -1)) {
          $option.attr('aria-selected', 'true');
        } else {
          $option.attr('aria-selected', 'false');
        }
      });

    });
  };

  Results.prototype.showLoading = function (params) {
    this.hideLoading();

    var loadingMore = this.options.get('translations').get('searching');

    var loading = {
      disabled: true,
      loading: true,
      text: loadingMore(params)
    };
    var $loading = this.option(loading);
    $loading.className += ' loading-results';

    this.$results.prepend($loading);
  };

  Results.prototype.hideLoading = function () {
    this.$results.find('.loading-results').remove();
  };

  Results.prototype.option = function (data) {
    var option = document.createElement('li');
    option.className = 'select2-results__option';

    var attrs = {
      'role': 'treeitem',
      'aria-selected': 'false'
    };

    if (data.disabled) {
      delete attrs['aria-selected'];
      attrs['aria-disabled'] = 'true';
    }

    if (data.id == null) {
      delete attrs['aria-selected'];
    }

    if (data._resultId != null) {
      option.id = data._resultId;
    }

    if (data.title) {
      option.title = data.title;
    }

    if (data.children) {
      attrs.role = 'group';
      attrs['aria-label'] = data.text;
      delete attrs['aria-selected'];
    }

    for (var attr in attrs) {
      var val = attrs[attr];

      option.setAttribute(attr, val);
    }

    if (data.children) {
      var $option = $(option);

      var label = document.createElement('strong');
      label.className = 'select2-results__group';

      var $label = $(label);
      this.template(data, label);

      var $children = [];

      for (var c = 0; c < data.children.length; c++) {
        var child = data.children[c];

        var $child = this.option(child);

        $children.push($child);
      }

      var $childrenContainer = $('<ul></ul>', {
        'class': 'select2-results__options select2-results__options--nested'
      });

      $childrenContainer.append($children);

      $option.append(label);
      $option.append($childrenContainer);
    } else {
      this.template(data, option);
    }

    $.data(option, 'data', data);

    return option;
  };

  Results.prototype.bind = function (container, $container) {
    var self = this;

    var id = container.id + '-results';

    this.$results.attr('id', id);

    container.on('results:all', function (params) {
      self.clear();
      self.append(params.data);

      if (container.isOpen()) {
        self.setClasses();
        self.highlightFirstItem();
      }
    });

    container.on('results:append', function (params) {
      self.append(params.data);

      if (container.isOpen()) {
        self.setClasses();
      }
    });

    container.on('query', function (params) {
      self.hideMessages();
      self.showLoading(params);
    });

    container.on('select', function () {
      if (!container.isOpen()) {
        return;
      }

      self.setClasses();
      self.highlightFirstItem();
    });

    container.on('unselect', function () {
      if (!container.isOpen()) {
        return;
      }

      self.setClasses();
      self.highlightFirstItem();
    });

    container.on('open', function () {
      // When the dropdown is open, aria-expended="true"
      self.$results.attr('aria-expanded', 'true');
      self.$results.attr('aria-hidden', 'false');

      self.setClasses();
      self.ensureHighlightVisible();
    });

    container.on('close', function () {
      // When the dropdown is closed, aria-expended="false"
      self.$results.attr('aria-expanded', 'false');
      self.$results.attr('aria-hidden', 'true');
      self.$results.removeAttr('aria-activedescendant');
    });

    container.on('results:toggle', function () {
      var $highlighted = self.getHighlightedResults();

      if ($highlighted.length === 0) {
        return;
      }

      $highlighted.trigger('mouseup');
    });

    container.on('results:select', function () {
      var $highlighted = self.getHighlightedResults();

      if ($highlighted.length === 0) {
        return;
      }

      var data = $highlighted.data('data');

      if ($highlighted.attr('aria-selected') == 'true') {
        self.trigger('close', {});
      } else {
        self.trigger('select', {
          data: data
        });
      }
    });

    container.on('results:previous', function () {
      var $highlighted = self.getHighlightedResults();

      var $options = self.$results.find('[aria-selected]');

      var currentIndex = $options.index($highlighted);

      // If we are already at te top, don't move further
      if (currentIndex === 0) {
        return;
      }

      var nextIndex = currentIndex - 1;

      // If none are highlighted, highlight the first
      if ($highlighted.length === 0) {
        nextIndex = 0;
      }

      var $next = $options.eq(nextIndex);

      $next.trigger('mouseenter');

      var currentOffset = self.$results.offset().top;
      var nextTop = $next.offset().top;
      var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);

      if (nextIndex === 0) {
        self.$results.scrollTop(0);
      } else if (nextTop - currentOffset < 0) {
        self.$results.scrollTop(nextOffset);
      }
    });

    container.on('results:next', function () {
      var $highlighted = self.getHighlightedResults();

      var $options = self.$results.find('[aria-selected]');

      var currentIndex = $options.index($highlighted);

      var nextIndex = currentIndex + 1;

      // If we are at the last option, stay there
      if (nextIndex >= $options.length) {
        return;
      }

      var $next = $options.eq(nextIndex);

      $next.trigger('mouseenter');

      var currentOffset = self.$results.offset().top +
        self.$results.outerHeight(false);
      var nextBottom = $next.offset().top + $next.outerHeight(false);
      var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;

      if (nextIndex === 0) {
        self.$results.scrollTop(0);
      } else if (nextBottom > currentOffset) {
        self.$results.scrollTop(nextOffset);
      }
    });

    container.on('results:focus', function (params) {
      params.element.addClass('select2-results__option--highlighted');
    });

    container.on('results:message', function (params) {
      self.displayMessage(params);
    });

    if ($.fn.mousewheel) {
      this.$results.on('mousewheel', function (e) {
        var top = self.$results.scrollTop();

        var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;

        var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
        var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();

        if (isAtTop) {
          self.$results.scrollTop(0);

          e.preventDefault();
          e.stopPropagation();
        } else if (isAtBottom) {
          self.$results.scrollTop(
            self.$results.get(0).scrollHeight - self.$results.height()
          );

          e.preventDefault();
          e.stopPropagation();
        }
      });
    }

    this.$results.on('mouseup', '.select2-results__option[aria-selected]',
      function (evt) {
      var $this = $(this);

      var data = $this.data('data');

      if ($this.attr('aria-selected') === 'true') {
        if (self.options.get('multiple')) {
          self.trigger('unselect', {
            originalEvent: evt,
            data: data
          });
        } else {
          self.trigger('close', {});
        }

        return;
      }

      self.trigger('select', {
        originalEvent: evt,
        data: data
      });
    });

    this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
      function (evt) {
      var data = $(this).data('data');

      self.getHighlightedResults()
          .removeClass('select2-results__option--highlighted');

      self.trigger('results:focus', {
        data: data,
        element: $(this)
      });
    });
  };

  Results.prototype.getHighlightedResults = function () {
    var $highlighted = this.$results
    .find('.select2-results__option--highlighted');

    return $highlighted;
  };

  Results.prototype.destroy = function () {
    this.$results.remove();
  };

  Results.prototype.ensureHighlightVisible = function () {
    var $highlighted = this.getHighlightedResults();

    if ($highlighted.length === 0) {
      return;
    }

    var $options = this.$results.find('[aria-selected]');

    var currentIndex = $options.index($highlighted);

    var currentOffset = this.$results.offset().top;
    var nextTop = $highlighted.offset().top;
    var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);

    var offsetDelta = nextTop - currentOffset;
    nextOffset -= $highlighted.outerHeight(false) * 2;

    if (currentIndex <= 2) {
      this.$results.scrollTop(0);
    } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
      this.$results.scrollTop(nextOffset);
    }
  };

  Results.prototype.template = function (result, container) {
    var template = this.options.get('templateResult');
    var escapeMarkup = this.options.get('escapeMarkup');

    var content = template(result, container);

    if (content == null) {
      container.style.display = 'none';
    } else if (typeof content === 'string') {
      container.innerHTML = escapeMarkup(content);
    } else {
      $(container).append(content);
    }
  };

  return Results;
});

S2.define('select2/keys',[

], function () {
  var KEYS = {
    BACKSPACE: 8,
    TAB: 9,
    ENTER: 13,
    SHIFT: 16,
    CTRL: 17,
    ALT: 18,
    ESC: 27,
    SPACE: 32,
    PAGE_UP: 33,
    PAGE_DOWN: 34,
    END: 35,
    HOME: 36,
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,
    DELETE: 46
  };

  return KEYS;
});

S2.define('select2/selection/base',[
  'jquery',
  '../utils',
  '../keys'
], function ($, Utils, KEYS) {
  function BaseSelection ($element, options) {
    this.$element = $element;
    this.options = options;

    BaseSelection.__super__.constructor.call(this);
  }

  Utils.Extend(BaseSelection, Utils.Observable);

  BaseSelection.prototype.render = function () {
    var $selection = $(
      '<span class="select2-selection" role="combobox" ' +
      ' aria-haspopup="true" aria-expanded="false">' +
      '</span>'
    );

    this._tabindex = 0;

    if (this.$element.data('old-tabindex') != null) {
      this._tabindex = this.$element.data('old-tabindex');
    } else if (this.$element.attr('tabindex') != null) {
      this._tabindex = this.$element.attr('tabindex');
    }

    $selection.attr('title', this.$element.attr('title'));
    $selection.attr('tabindex', this._tabindex);

    this.$selection = $selection;

    return $selection;
  };

  BaseSelection.prototype.bind = function (container, $container) {
    var self = this;

    var id = container.id + '-container';
    var resultsId = container.id + '-results';

    this.container = container;

    this.$selection.on('focus', function (evt) {
      self.trigger('focus', evt);
    });

    this.$selection.on('blur', function (evt) {
      self._handleBlur(evt);
    });

    this.$selection.on('keydown', function (evt) {
      self.trigger('keypress', evt);

      if (evt.which === KEYS.SPACE) {
        evt.preventDefault();
      }
    });

    container.on('results:focus', function (params) {
      self.$selection.attr('aria-activedescendant', params.data._resultId);
    });

    container.on('selection:update', function (params) {
      self.update(params.data);
    });

    container.on('open', function () {
      // When the dropdown is open, aria-expanded="true"
      self.$selection.attr('aria-expanded', 'true');
      self.$selection.attr('aria-owns', resultsId);

      self._attachCloseHandler(container);
    });

    container.on('close', function () {
      // When the dropdown is closed, aria-expanded="false"
      self.$selection.attr('aria-expanded', 'false');
      self.$selection.removeAttr('aria-activedescendant');
      self.$selection.removeAttr('aria-owns');

      self.$selection.focus();

      self._detachCloseHandler(container);
    });

    container.on('enable', function () {
      self.$selection.attr('tabindex', self._tabindex);
    });

    container.on('disable', function () {
      self.$selection.attr('tabindex', '-1');
    });
  };

  BaseSelection.prototype._handleBlur = function (evt) {
    var self = this;

    // This needs to be delayed as the active element is the body when the tab
    // key is pressed, possibly along with others.
    window.setTimeout(function () {
      // Don't trigger `blur` if the focus is still in the selection
      if (
        (document.activeElement == self.$selection[0]) ||
        ($.contains(self.$selection[0], document.activeElement))
      ) {
        return;
      }

      self.trigger('blur', evt);
    }, 1);
  };

  BaseSelection.prototype._attachCloseHandler = function (container) {
    var self = this;

    $(document.body).on('mousedown.select2.' + container.id, function (e) {
      var $target = $(e.target);

      var $select = $target.closest('.select2');

      var $all = $('.select2.select2-container--open');

      $all.each(function () {
        var $this = $(this);

        if (this == $select[0]) {
          return;
        }

        var $element = $this.data('element');

        $element.select2('close');
      });
    });
  };

  BaseSelection.prototype._detachCloseHandler = function (container) {
    $(document.body).off('mousedown.select2.' + container.id);
  };

  BaseSelection.prototype.position = function ($selection, $container) {
    var $selectionContainer = $container.find('.selection');
    $selectionContainer.append($selection);
  };

  BaseSelection.prototype.destroy = function () {
    this._detachCloseHandler(this.container);
  };

  BaseSelection.prototype.update = function (data) {
    throw new Error('The `update` method must be defined in child classes.');
  };

  return BaseSelection;
});

S2.define('select2/selection/single',[
  'jquery',
  './base',
  '../utils',
  '../keys'
], function ($, BaseSelection, Utils, KEYS) {
  function SingleSelection () {
    SingleSelection.__super__.constructor.apply(this, arguments);
  }

  Utils.Extend(SingleSelection, BaseSelection);

  SingleSelection.prototype.render = function () {
    var $selection = SingleSelection.__super__.render.call(this);

    $selection.addClass('select2-selection--single');

    $selection.html(
      '<span class="select2-selection__rendered"></span>' +
      '<span class="select2-selection__arrow" role="presentation">' +
        '<b role="presentation"></b>' +
      '</span>'
    );

    return $selection;
  };

  SingleSelection.prototype.bind = function (container, $container) {
    var self = this;

    SingleSelection.__super__.bind.apply(this, arguments);

    var id = container.id + '-container';

    this.$selection.find('.select2-selection__rendered').attr('id', id);
    this.$selection.attr('aria-labelledby', id);

    this.$selection.on('mousedown', function (evt) {
      // Only respond to left clicks
      if (evt.which !== 1) {
        return;
      }

      self.trigger('toggle', {
        originalEvent: evt
      });
    });

    this.$selection.on('focus', function (evt) {
      // User focuses on the container
    });

    this.$selection.on('blur', function (evt) {
      // User exits the container
    });

    container.on('focus', function (evt) {
      if (!container.isOpen()) {
        self.$selection.focus();
      }
    });

    container.on('selection:update', function (params) {
      self.update(params.data);
    });
  };

  SingleSelection.prototype.clear = function () {
    this.$selection.find('.select2-selection__rendered').empty();
  };

  SingleSelection.prototype.display = function (data, container) {
    var template = this.options.get('templateSelection');
    var escapeMarkup = this.options.get('escapeMarkup');

    return escapeMarkup(template(data, container));
  };

  SingleSelection.prototype.selectionContainer = function () {
    return $('<span></span>');
  };

  SingleSelection.prototype.update = function (data) {
    if (data.length === 0) {
      this.clear();
      return;
    }

    var selection = data[0];

    var $rendered = this.$selection.find('.select2-selection__rendered');
    var formatted = this.display(selection, $rendered);

    $rendered.empty().append(formatted);
    $rendered.prop('title', selection.title || selection.text);
  };

  return SingleSelection;
});

S2.define('select2/selection/multiple',[
  'jquery',
  './base',
  '../utils'
], function ($, BaseSelection, Utils) {
  function MultipleSelection ($element, options) {
    MultipleSelection.__super__.constructor.apply(this, arguments);
  }

  Utils.Extend(MultipleSelection, BaseSelection);

  MultipleSelection.prototype.render = function () {
    var $selection = MultipleSelection.__super__.render.call(this);

    $selection.addClass('select2-selection--multiple');

    $selection.html(
      '<ul class="select2-selection__rendered"></ul>'
    );

    return $selection;
  };

  MultipleSelection.prototype.bind = function (container, $container) {
    var self = this;

    MultipleSelection.__super__.bind.apply(this, arguments);

    this.$selection.on('click', function (evt) {
      self.trigger('toggle', {
        originalEvent: evt
      });
    });

    this.$selection.on(
      'click',
      '.select2-selection__choice__remove',
      function (evt) {
        // Ignore the event if it is disabled
        if (self.options.get('disabled')) {
          return;
        }

        var $remove = $(this);
        var $selection = $remove.parent();

        var data = $selection.data('data');

        self.trigger('unselect', {
          originalEvent: evt,
          data: data
        });
      }
    );
  };

  MultipleSelection.prototype.clear = function () {
    this.$selection.find('.select2-selection__rendered').empty();
  };

  MultipleSelection.prototype.display = function (data, container) {
    var template = this.options.get('templateSelection');
    var escapeMarkup = this.options.get('escapeMarkup');

    return escapeMarkup(template(data, container));
  };

  MultipleSelection.prototype.selectionContainer = function () {
    var $container = $(
      '<li class="select2-selection__choice">' +
        '<span class="select2-selection__choice__remove" role="presentation">' +
          '&times;' +
        '</span>' +
      '</li>'
    );

    return $container;
  };

  MultipleSelection.prototype.update = function (data) {
    this.clear();

    if (data.length === 0) {
      return;
    }

    var $selections = [];

    for (var d = 0; d < data.length; d++) {
      var selection = data[d];

      var $selection = this.selectionContainer();
      var formatted = this.display(selection, $selection);

      $selection.append(formatted);
      $selection.prop('title', selection.title || selection.text);

      $selection.data('data', selection);

      $selections.push($selection);
    }

    var $rendered = this.$selection.find('.select2-selection__rendered');

    Utils.appendMany($rendered, $selections);
  };

  return MultipleSelection;
});

S2.define('select2/selection/placeholder',[
  '../utils'
], function (Utils) {
  function Placeholder (decorated, $element, options) {
    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));

    decorated.call(this, $element, options);
  }

  Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
    if (typeof placeholder === 'string') {
      placeholder = {
        id: '',
        text: placeholder
      };
    }

    return placeholder;
  };

  Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
    var $placeholder = this.selectionContainer();

    $placeholder.html(this.display(placeholder));
    $placeholder.addClass('select2-selection__placeholder')
                .removeClass('select2-selection__choice');

    return $placeholder;
  };

  Placeholder.prototype.update = function (decorated, data) {
    var singlePlaceholder = (
      data.length == 1 && data[0].id != this.placeholder.id
    );
    var multipleSelections = data.length > 1;

    if (multipleSelections || singlePlaceholder) {
      return decorated.call(this, data);
    }

    this.clear();

    var $placeholder = this.createPlaceholder(this.placeholder);

    this.$selection.find('.select2-selection__rendered').append($placeholder);
  };

  return Placeholder;
});

S2.define('select2/selection/allowClear',[
  'jquery',
  '../keys'
], function ($, KEYS) {
  function AllowClear () { }

  AllowClear.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    if (this.placeholder == null) {
      if (this.options.get('debug') && window.console && console.error) {
        console.error(
          'Select2: The `allowClear` option should be used in combination ' +
          'with the `placeholder` option.'
        );
      }
    }

    this.$selection.on('mousedown', '.select2-selection__clear',
      function (evt) {
        self._handleClear(evt);
    });

    container.on('keypress', function (evt) {
      self._handleKeyboardClear(evt, container);
    });
  };

  AllowClear.prototype._handleClear = function (_, evt) {
    // Ignore the event if it is disabled
    if (this.options.get('disabled')) {
      return;
    }

    var $clear = this.$selection.find('.select2-selection__clear');

    // Ignore the event if nothing has been selected
    if ($clear.length === 0) {
      return;
    }

    evt.stopPropagation();

    var data = $clear.data('data');

    for (var d = 0; d < data.length; d++) {
      var unselectData = {
        data: data[d]
      };

      // Trigger the `unselect` event, so people can prevent it from being
      // cleared.
      this.trigger('unselect', unselectData);

      // If the event was prevented, don't clear it out.
      if (unselectData.prevented) {
        return;
      }
    }

    this.$element.val(this.placeholder.id).trigger('change');

    this.trigger('toggle', {});
  };

  AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
    if (container.isOpen()) {
      return;
    }

    if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
      this._handleClear(evt);
    }
  };

  AllowClear.prototype.update = function (decorated, data) {
    decorated.call(this, data);

    if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
        data.length === 0) {
      return;
    }

    var $remove = $(
      '<span class="select2-selection__clear">' +
        '&times;' +
      '</span>'
    );
    $remove.data('data', data);

    this.$selection.find('.select2-selection__rendered').prepend($remove);
  };

  return AllowClear;
});

S2.define('select2/selection/search',[
  'jquery',
  '../utils',
  '../keys'
], function ($, Utils, KEYS) {
  function Search (decorated, $element, options) {
    decorated.call(this, $element, options);
  }

  Search.prototype.render = function (decorated) {
    var $search = $(
      '<li class="select2-search select2-search--inline">' +
        '<input class="select2-search__field" type="search" tabindex="-1"' +
        ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
        ' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
      '</li>'
    );

    this.$searchContainer = $search;
    this.$search = $search.find('input');

    var $rendered = decorated.call(this);

    this._transferTabIndex();

    return $rendered;
  };

  Search.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('open', function () {
      self.$search.trigger('focus');
    });

    container.on('close', function () {
      self.$search.val('');
      self.$search.removeAttr('aria-activedescendant');
      self.$search.trigger('focus');
    });

    container.on('enable', function () {
      self.$search.prop('disabled', false);

      self._transferTabIndex();
    });

    container.on('disable', function () {
      self.$search.prop('disabled', true);
    });

    container.on('focus', function (evt) {
      self.$search.trigger('focus');
    });

    container.on('results:focus', function (params) {
      self.$search.attr('aria-activedescendant', params.id);
    });

    this.$selection.on('focusin', '.select2-search--inline', function (evt) {
      self.trigger('focus', evt);
    });

    this.$selection.on('focusout', '.select2-search--inline', function (evt) {
      self._handleBlur(evt);
    });

    this.$selection.on('keydown', '.select2-search--inline', function (evt) {
      evt.stopPropagation();

      self.trigger('keypress', evt);

      self._keyUpPrevented = evt.isDefaultPrevented();

      var key = evt.which;

      if (key === KEYS.BACKSPACE && self.$search.val() === '') {
        var $previousChoice = self.$searchContainer
          .prev('.select2-selection__choice');

        if ($previousChoice.length > 0) {
          var item = $previousChoice.data('data');

          self.searchRemoveChoice(item);

          evt.preventDefault();
        }
      }
    });

    // Try to detect the IE version should the `documentMode` property that
    // is stored on the document. This is only implemented in IE and is
    // slightly cleaner than doing a user agent check.
    // This property is not available in Edge, but Edge also doesn't have
    // this bug.
    var msie = document.documentMode;
    var disableInputEvents = msie && msie <= 11;

    // Workaround for browsers which do not support the `input` event
    // This will prevent double-triggering of events for browsers which support
    // both the `keyup` and `input` events.
    this.$selection.on(
      'input.searchcheck',
      '.select2-search--inline',
      function (evt) {
        // IE will trigger the `input` event when a placeholder is used on a
        // search box. To get around this issue, we are forced to ignore all
        // `input` events in IE and keep using `keyup`.
        if (disableInputEvents) {
          self.$selection.off('input.search input.searchcheck');
          return;
        }

        // Unbind the duplicated `keyup` event
        self.$selection.off('keyup.search');
      }
    );

    this.$selection.on(
      'keyup.search input.search',
      '.select2-search--inline',
      function (evt) {
        // IE will trigger the `input` event when a placeholder is used on a
        // search box. To get around this issue, we are forced to ignore all
        // `input` events in IE and keep using `keyup`.
        if (disableInputEvents && evt.type === 'input') {
          self.$selection.off('input.search input.searchcheck');
          return;
        }

        var key = evt.which;

        // We can freely ignore events from modifier keys
        if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
          return;
        }

        // Tabbing will be handled during the `keydown` phase
        if (key == KEYS.TAB) {
          return;
        }

        self.handleSearch(evt);
      }
    );
  };

  /**
   * This method will transfer the tabindex attribute from the rendered
   * selection to the search box. This allows for the search box to be used as
   * the primary focus instead of the selection container.
   *
   * @private
   */
  Search.prototype._transferTabIndex = function (decorated) {
    this.$search.attr('tabindex', this.$selection.attr('tabindex'));
    this.$selection.attr('tabindex', '-1');
  };

  Search.prototype.createPlaceholder = function (decorated, placeholder) {
    this.$search.attr('placeholder', placeholder.text);
  };

  Search.prototype.update = function (decorated, data) {
    var searchHadFocus = this.$search[0] == document.activeElement;

    this.$search.attr('placeholder', '');

    decorated.call(this, data);

    this.$selection.find('.select2-selection__rendered')
                   .append(this.$searchContainer);

    this.resizeSearch();
    if (searchHadFocus) {
      this.$search.focus();
    }
  };

  Search.prototype.handleSearch = function () {
    this.resizeSearch();

    if (!this._keyUpPrevented) {
      var input = this.$search.val();

      this.trigger('query', {
        term: input
      });
    }

    this._keyUpPrevented = false;
  };

  Search.prototype.searchRemoveChoice = function (decorated, item) {
    this.trigger('unselect', {
      data: item
    });

    this.$search.val(item.text);
    this.handleSearch();
  };

  Search.prototype.resizeSearch = function () {
    this.$search.css('width', '25px');

    var width = '';

    if (this.$search.attr('placeholder') !== '') {
      width = this.$selection.find('.select2-selection__rendered').innerWidth();
    } else {
      var minimumWidth = this.$search.val().length + 1;

      width = (minimumWidth * 0.75) + 'em';
    }

    this.$search.css('width', width);
  };

  return Search;
});

S2.define('select2/selection/eventRelay',[
  'jquery'
], function ($) {
  function EventRelay () { }

  EventRelay.prototype.bind = function (decorated, container, $container) {
    var self = this;
    var relayEvents = [
      'open', 'opening',
      'close', 'closing',
      'select', 'selecting',
      'unselect', 'unselecting'
    ];

    var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];

    decorated.call(this, container, $container);

    container.on('*', function (name, params) {
      // Ignore events that should not be relayed
      if ($.inArray(name, relayEvents) === -1) {
        return;
      }

      // The parameters should always be an object
      params = params || {};

      // Generate the jQuery event for the Select2 event
      var evt = $.Event('select2:' + name, {
        params: params
      });

      self.$element.trigger(evt);

      // Only handle preventable events if it was one
      if ($.inArray(name, preventableEvents) === -1) {
        return;
      }

      params.prevented = evt.isDefaultPrevented();
    });
  };

  return EventRelay;
});

S2.define('select2/translation',[
  'jquery',
  'require'
], function ($, require) {
  function Translation (dict) {
    this.dict = dict || {};
  }

  Translation.prototype.all = function () {
    return this.dict;
  };

  Translation.prototype.get = function (key) {
    return this.dict[key];
  };

  Translation.prototype.extend = function (translation) {
    this.dict = $.extend({}, translation.all(), this.dict);
  };

  // Static functions

  Translation._cache = {};

  Translation.loadPath = function (path) {
    if (!(path in Translation._cache)) {
      var translations = require(path);

      Translation._cache[path] = translations;
    }

    return new Translation(Translation._cache[path]);
  };

  return Translation;
});

S2.define('select2/diacritics',[

], function () {
  var diacritics = {
    '\u24B6': 'A',
    '\uFF21': 'A',
    '\u00C0': 'A',
    '\u00C1': 'A',
    '\u00C2': 'A',
    '\u1EA6': 'A',
    '\u1EA4': 'A',
    '\u1EAA': 'A',
    '\u1EA8': 'A',
    '\u00C3': 'A',
    '\u0100': 'A',
    '\u0102': 'A',
    '\u1EB0': 'A',
    '\u1EAE': 'A',
    '\u1EB4': 'A',
    '\u1EB2': 'A',
    '\u0226': 'A',
    '\u01E0': 'A',
    '\u00C4': 'A',
    '\u01DE': 'A',
    '\u1EA2': 'A',
    '\u00C5': 'A',
    '\u01FA': 'A',
    '\u01CD': 'A',
    '\u0200': 'A',
    '\u0202': 'A',
    '\u1EA0': 'A',
    '\u1EAC': 'A',
    '\u1EB6': 'A',
    '\u1E00': 'A',
    '\u0104': 'A',
    '\u023A': 'A',
    '\u2C6F': 'A',
    '\uA732': 'AA',
    '\u00C6': 'AE',
    '\u01FC': 'AE',
    '\u01E2': 'AE',
    '\uA734': 'AO',
    '\uA736': 'AU',
    '\uA738': 'AV',
    '\uA73A': 'AV',
    '\uA73C': 'AY',
    '\u24B7': 'B',
    '\uFF22': 'B',
    '\u1E02': 'B',
    '\u1E04': 'B',
    '\u1E06': 'B',
    '\u0243': 'B',
    '\u0182': 'B',
    '\u0181': 'B',
    '\u24B8': 'C',
    '\uFF23': 'C',
    '\u0106': 'C',
    '\u0108': 'C',
    '\u010A': 'C',
    '\u010C': 'C',
    '\u00C7': 'C',
    '\u1E08': 'C',
    '\u0187': 'C',
    '\u023B': 'C',
    '\uA73E': 'C',
    '\u24B9': 'D',
    '\uFF24': 'D',
    '\u1E0A': 'D',
    '\u010E': 'D',
    '\u1E0C': 'D',
    '\u1E10': 'D',
    '\u1E12': 'D',
    '\u1E0E': 'D',
    '\u0110': 'D',
    '\u018B': 'D',
    '\u018A': 'D',
    '\u0189': 'D',
    '\uA779': 'D',
    '\u01F1': 'DZ',
    '\u01C4': 'DZ',
    '\u01F2': 'Dz',
    '\u01C5': 'Dz',
    '\u24BA': 'E',
    '\uFF25': 'E',
    '\u00C8': 'E',
    '\u00C9': 'E',
    '\u00CA': 'E',
    '\u1EC0': 'E',
    '\u1EBE': 'E',
    '\u1EC4': 'E',
    '\u1EC2': 'E',
    '\u1EBC': 'E',
    '\u0112': 'E',
    '\u1E14': 'E',
    '\u1E16': 'E',
    '\u0114': 'E',
    '\u0116': 'E',
    '\u00CB': 'E',
    '\u1EBA': 'E',
    '\u011A': 'E',
    '\u0204': 'E',
    '\u0206': 'E',
    '\u1EB8': 'E',
    '\u1EC6': 'E',
    '\u0228': 'E',
    '\u1E1C': 'E',
    '\u0118': 'E',
    '\u1E18': 'E',
    '\u1E1A': 'E',
    '\u0190': 'E',
    '\u018E': 'E',
    '\u24BB': 'F',
    '\uFF26': 'F',
    '\u1E1E': 'F',
    '\u0191': 'F',
    '\uA77B': 'F',
    '\u24BC': 'G',
    '\uFF27': 'G',
    '\u01F4': 'G',
    '\u011C': 'G',
    '\u1E20': 'G',
    '\u011E': 'G',
    '\u0120': 'G',
    '\u01E6': 'G',
    '\u0122': 'G',
    '\u01E4': 'G',
    '\u0193': 'G',
    '\uA7A0': 'G',
    '\uA77D': 'G',
    '\uA77E': 'G',
    '\u24BD': 'H',
    '\uFF28': 'H',
    '\u0124': 'H',
    '\u1E22': 'H',
    '\u1E26': 'H',
    '\u021E': 'H',
    '\u1E24': 'H',
    '\u1E28': 'H',
    '\u1E2A': 'H',
    '\u0126': 'H',
    '\u2C67': 'H',
    '\u2C75': 'H',
    '\uA78D': 'H',
    '\u24BE': 'I',
    '\uFF29': 'I',
    '\u00CC': 'I',
    '\u00CD': 'I',
    '\u00CE': 'I',
    '\u0128': 'I',
    '\u012A': 'I',
    '\u012C': 'I',
    '\u0130': 'I',
    '\u00CF': 'I',
    '\u1E2E': 'I',
    '\u1EC8': 'I',
    '\u01CF': 'I',
    '\u0208': 'I',
    '\u020A': 'I',
    '\u1ECA': 'I',
    '\u012E': 'I',
    '\u1E2C': 'I',
    '\u0197': 'I',
    '\u24BF': 'J',
    '\uFF2A': 'J',
    '\u0134': 'J',
    '\u0248': 'J',
    '\u24C0': 'K',
    '\uFF2B': 'K',
    '\u1E30': 'K',
    '\u01E8': 'K',
    '\u1E32': 'K',
    '\u0136': 'K',
    '\u1E34': 'K',
    '\u0198': 'K',
    '\u2C69': 'K',
    '\uA740': 'K',
    '\uA742': 'K',
    '\uA744': 'K',
    '\uA7A2': 'K',
    '\u24C1': 'L',
    '\uFF2C': 'L',
    '\u013F': 'L',
    '\u0139': 'L',
    '\u013D': 'L',
    '\u1E36': 'L',
    '\u1E38': 'L',
    '\u013B': 'L',
    '\u1E3C': 'L',
    '\u1E3A': 'L',
    '\u0141': 'L',
    '\u023D': 'L',
    '\u2C62': 'L',
    '\u2C60': 'L',
    '\uA748': 'L',
    '\uA746': 'L',
    '\uA780': 'L',
    '\u01C7': 'LJ',
    '\u01C8': 'Lj',
    '\u24C2': 'M',
    '\uFF2D': 'M',
    '\u1E3E': 'M',
    '\u1E40': 'M',
    '\u1E42': 'M',
    '\u2C6E': 'M',
    '\u019C': 'M',
    '\u24C3': 'N',
    '\uFF2E': 'N',
    '\u01F8': 'N',
    '\u0143': 'N',
    '\u00D1': 'N',
    '\u1E44': 'N',
    '\u0147': 'N',
    '\u1E46': 'N',
    '\u0145': 'N',
    '\u1E4A': 'N',
    '\u1E48': 'N',
    '\u0220': 'N',
    '\u019D': 'N',
    '\uA790': 'N',
    '\uA7A4': 'N',
    '\u01CA': 'NJ',
    '\u01CB': 'Nj',
    '\u24C4': 'O',
    '\uFF2F': 'O',
    '\u00D2': 'O',
    '\u00D3': 'O',
    '\u00D4': 'O',
    '\u1ED2': 'O',
    '\u1ED0': 'O',
    '\u1ED6': 'O',
    '\u1ED4': 'O',
    '\u00D5': 'O',
    '\u1E4C': 'O',
    '\u022C': 'O',
    '\u1E4E': 'O',
    '\u014C': 'O',
    '\u1E50': 'O',
    '\u1E52': 'O',
    '\u014E': 'O',
    '\u022E': 'O',
    '\u0230': 'O',
    '\u00D6': 'O',
    '\u022A': 'O',
    '\u1ECE': 'O',
    '\u0150': 'O',
    '\u01D1': 'O',
    '\u020C': 'O',
    '\u020E': 'O',
    '\u01A0': 'O',
    '\u1EDC': 'O',
    '\u1EDA': 'O',
    '\u1EE0': 'O',
    '\u1EDE': 'O',
    '\u1EE2': 'O',
    '\u1ECC': 'O',
    '\u1ED8': 'O',
    '\u01EA': 'O',
    '\u01EC': 'O',
    '\u00D8': 'O',
    '\u01FE': 'O',
    '\u0186': 'O',
    '\u019F': 'O',
    '\uA74A': 'O',
    '\uA74C': 'O',
    '\u01A2': 'OI',
    '\uA74E': 'OO',
    '\u0222': 'OU',
    '\u24C5': 'P',
    '\uFF30': 'P',
    '\u1E54': 'P',
    '\u1E56': 'P',
    '\u01A4': 'P',
    '\u2C63': 'P',
    '\uA750': 'P',
    '\uA752': 'P',
    '\uA754': 'P',
    '\u24C6': 'Q',
    '\uFF31': 'Q',
    '\uA756': 'Q',
    '\uA758': 'Q',
    '\u024A': 'Q',
    '\u24C7': 'R',
    '\uFF32': 'R',
    '\u0154': 'R',
    '\u1E58': 'R',
    '\u0158': 'R',
    '\u0210': 'R',
    '\u0212': 'R',
    '\u1E5A': 'R',
    '\u1E5C': 'R',
    '\u0156': 'R',
    '\u1E5E': 'R',
    '\u024C': 'R',
    '\u2C64': 'R',
    '\uA75A': 'R',
    '\uA7A6': 'R',
    '\uA782': 'R',
    '\u24C8': 'S',
    '\uFF33': 'S',
    '\u1E9E': 'S',
    '\u015A': 'S',
    '\u1E64': 'S',
    '\u015C': 'S',
    '\u1E60': 'S',
    '\u0160': 'S',
    '\u1E66': 'S',
    '\u1E62': 'S',
    '\u1E68': 'S',
    '\u0218': 'S',
    '\u015E': 'S',
    '\u2C7E': 'S',
    '\uA7A8': 'S',
    '\uA784': 'S',
    '\u24C9': 'T',
    '\uFF34': 'T',
    '\u1E6A': 'T',
    '\u0164': 'T',
    '\u1E6C': 'T',
    '\u021A': 'T',
    '\u0162': 'T',
    '\u1E70': 'T',
    '\u1E6E': 'T',
    '\u0166': 'T',
    '\u01AC': 'T',
    '\u01AE': 'T',
    '\u023E': 'T',
    '\uA786': 'T',
    '\uA728': 'TZ',
    '\u24CA': 'U',
    '\uFF35': 'U',
    '\u00D9': 'U',
    '\u00DA': 'U',
    '\u00DB': 'U',
    '\u0168': 'U',
    '\u1E78': 'U',
    '\u016A': 'U',
    '\u1E7A': 'U',
    '\u016C': 'U',
    '\u00DC': 'U',
    '\u01DB': 'U',
    '\u01D7': 'U',
    '\u01D5': 'U',
    '\u01D9': 'U',
    '\u1EE6': 'U',
    '\u016E': 'U',
    '\u0170': 'U',
    '\u01D3': 'U',
    '\u0214': 'U',
    '\u0216': 'U',
    '\u01AF': 'U',
    '\u1EEA': 'U',
    '\u1EE8': 'U',
    '\u1EEE': 'U',
    '\u1EEC': 'U',
    '\u1EF0': 'U',
    '\u1EE4': 'U',
    '\u1E72': 'U',
    '\u0172': 'U',
    '\u1E76': 'U',
    '\u1E74': 'U',
    '\u0244': 'U',
    '\u24CB': 'V',
    '\uFF36': 'V',
    '\u1E7C': 'V',
    '\u1E7E': 'V',
    '\u01B2': 'V',
    '\uA75E': 'V',
    '\u0245': 'V',
    '\uA760': 'VY',
    '\u24CC': 'W',
    '\uFF37': 'W',
    '\u1E80': 'W',
    '\u1E82': 'W',
    '\u0174': 'W',
    '\u1E86': 'W',
    '\u1E84': 'W',
    '\u1E88': 'W',
    '\u2C72': 'W',
    '\u24CD': 'X',
    '\uFF38': 'X',
    '\u1E8A': 'X',
    '\u1E8C': 'X',
    '\u24CE': 'Y',
    '\uFF39': 'Y',
    '\u1EF2': 'Y',
    '\u00DD': 'Y',
    '\u0176': 'Y',
    '\u1EF8': 'Y',
    '\u0232': 'Y',
    '\u1E8E': 'Y',
    '\u0178': 'Y',
    '\u1EF6': 'Y',
    '\u1EF4': 'Y',
    '\u01B3': 'Y',
    '\u024E': 'Y',
    '\u1EFE': 'Y',
    '\u24CF': 'Z',
    '\uFF3A': 'Z',
    '\u0179': 'Z',
    '\u1E90': 'Z',
    '\u017B': 'Z',
    '\u017D': 'Z',
    '\u1E92': 'Z',
    '\u1E94': 'Z',
    '\u01B5': 'Z',
    '\u0224': 'Z',
    '\u2C7F': 'Z',
    '\u2C6B': 'Z',
    '\uA762': 'Z',
    '\u24D0': 'a',
    '\uFF41': 'a',
    '\u1E9A': 'a',
    '\u00E0': 'a',
    '\u00E1': 'a',
    '\u00E2': 'a',
    '\u1EA7': 'a',
    '\u1EA5': 'a',
    '\u1EAB': 'a',
    '\u1EA9': 'a',
    '\u00E3': 'a',
    '\u0101': 'a',
    '\u0103': 'a',
    '\u1EB1': 'a',
    '\u1EAF': 'a',
    '\u1EB5': 'a',
    '\u1EB3': 'a',
    '\u0227': 'a',
    '\u01E1': 'a',
    '\u00E4': 'a',
    '\u01DF': 'a',
    '\u1EA3': 'a',
    '\u00E5': 'a',
    '\u01FB': 'a',
    '\u01CE': 'a',
    '\u0201': 'a',
    '\u0203': 'a',
    '\u1EA1': 'a',
    '\u1EAD': 'a',
    '\u1EB7': 'a',
    '\u1E01': 'a',
    '\u0105': 'a',
    '\u2C65': 'a',
    '\u0250': 'a',
    '\uA733': 'aa',
    '\u00E6': 'ae',
    '\u01FD': 'ae',
    '\u01E3': 'ae',
    '\uA735': 'ao',
    '\uA737': 'au',
    '\uA739': 'av',
    '\uA73B': 'av',
    '\uA73D': 'ay',
    '\u24D1': 'b',
    '\uFF42': 'b',
    '\u1E03': 'b',
    '\u1E05': 'b',
    '\u1E07': 'b',
    '\u0180': 'b',
    '\u0183': 'b',
    '\u0253': 'b',
    '\u24D2': 'c',
    '\uFF43': 'c',
    '\u0107': 'c',
    '\u0109': 'c',
    '\u010B': 'c',
    '\u010D': 'c',
    '\u00E7': 'c',
    '\u1E09': 'c',
    '\u0188': 'c',
    '\u023C': 'c',
    '\uA73F': 'c',
    '\u2184': 'c',
    '\u24D3': 'd',
    '\uFF44': 'd',
    '\u1E0B': 'd',
    '\u010F': 'd',
    '\u1E0D': 'd',
    '\u1E11': 'd',
    '\u1E13': 'd',
    '\u1E0F': 'd',
    '\u0111': 'd',
    '\u018C': 'd',
    '\u0256': 'd',
    '\u0257': 'd',
    '\uA77A': 'd',
    '\u01F3': 'dz',
    '\u01C6': 'dz',
    '\u24D4': 'e',
    '\uFF45': 'e',
    '\u00E8': 'e',
    '\u00E9': 'e',
    '\u00EA': 'e',
    '\u1EC1': 'e',
    '\u1EBF': 'e',
    '\u1EC5': 'e',
    '\u1EC3': 'e',
    '\u1EBD': 'e',
    '\u0113': 'e',
    '\u1E15': 'e',
    '\u1E17': 'e',
    '\u0115': 'e',
    '\u0117': 'e',
    '\u00EB': 'e',
    '\u1EBB': 'e',
    '\u011B': 'e',
    '\u0205': 'e',
    '\u0207': 'e',
    '\u1EB9': 'e',
    '\u1EC7': 'e',
    '\u0229': 'e',
    '\u1E1D': 'e',
    '\u0119': 'e',
    '\u1E19': 'e',
    '\u1E1B': 'e',
    '\u0247': 'e',
    '\u025B': 'e',
    '\u01DD': 'e',
    '\u24D5': 'f',
    '\uFF46': 'f',
    '\u1E1F': 'f',
    '\u0192': 'f',
    '\uA77C': 'f',
    '\u24D6': 'g',
    '\uFF47': 'g',
    '\u01F5': 'g',
    '\u011D': 'g',
    '\u1E21': 'g',
    '\u011F': 'g',
    '\u0121': 'g',
    '\u01E7': 'g',
    '\u0123': 'g',
    '\u01E5': 'g',
    '\u0260': 'g',
    '\uA7A1': 'g',
    '\u1D79': 'g',
    '\uA77F': 'g',
    '\u24D7': 'h',
    '\uFF48': 'h',
    '\u0125': 'h',
    '\u1E23': 'h',
    '\u1E27': 'h',
    '\u021F': 'h',
    '\u1E25': 'h',
    '\u1E29': 'h',
    '\u1E2B': 'h',
    '\u1E96': 'h',
    '\u0127': 'h',
    '\u2C68': 'h',
    '\u2C76': 'h',
    '\u0265': 'h',
    '\u0195': 'hv',
    '\u24D8': 'i',
    '\uFF49': 'i',
    '\u00EC': 'i',
    '\u00ED': 'i',
    '\u00EE': 'i',
    '\u0129': 'i',
    '\u012B': 'i',
    '\u012D': 'i',
    '\u00EF': 'i',
    '\u1E2F': 'i',
    '\u1EC9': 'i',
    '\u01D0': 'i',
    '\u0209': 'i',
    '\u020B': 'i',
    '\u1ECB': 'i',
    '\u012F': 'i',
    '\u1E2D': 'i',
    '\u0268': 'i',
    '\u0131': 'i',
    '\u24D9': 'j',
    '\uFF4A': 'j',
    '\u0135': 'j',
    '\u01F0': 'j',
    '\u0249': 'j',
    '\u24DA': 'k',
    '\uFF4B': 'k',
    '\u1E31': 'k',
    '\u01E9': 'k',
    '\u1E33': 'k',
    '\u0137': 'k',
    '\u1E35': 'k',
    '\u0199': 'k',
    '\u2C6A': 'k',
    '\uA741': 'k',
    '\uA743': 'k',
    '\uA745': 'k',
    '\uA7A3': 'k',
    '\u24DB': 'l',
    '\uFF4C': 'l',
    '\u0140': 'l',
    '\u013A': 'l',
    '\u013E': 'l',
    '\u1E37': 'l',
    '\u1E39': 'l',
    '\u013C': 'l',
    '\u1E3D': 'l',
    '\u1E3B': 'l',
    '\u017F': 'l',
    '\u0142': 'l',
    '\u019A': 'l',
    '\u026B': 'l',
    '\u2C61': 'l',
    '\uA749': 'l',
    '\uA781': 'l',
    '\uA747': 'l',
    '\u01C9': 'lj',
    '\u24DC': 'm',
    '\uFF4D': 'm',
    '\u1E3F': 'm',
    '\u1E41': 'm',
    '\u1E43': 'm',
    '\u0271': 'm',
    '\u026F': 'm',
    '\u24DD': 'n',
    '\uFF4E': 'n',
    '\u01F9': 'n',
    '\u0144': 'n',
    '\u00F1': 'n',
    '\u1E45': 'n',
    '\u0148': 'n',
    '\u1E47': 'n',
    '\u0146': 'n',
    '\u1E4B': 'n',
    '\u1E49': 'n',
    '\u019E': 'n',
    '\u0272': 'n',
    '\u0149': 'n',
    '\uA791': 'n',
    '\uA7A5': 'n',
    '\u01CC': 'nj',
    '\u24DE': 'o',
    '\uFF4F': 'o',
    '\u00F2': 'o',
    '\u00F3': 'o',
    '\u00F4': 'o',
    '\u1ED3': 'o',
    '\u1ED1': 'o',
    '\u1ED7': 'o',
    '\u1ED5': 'o',
    '\u00F5': 'o',
    '\u1E4D': 'o',
    '\u022D': 'o',
    '\u1E4F': 'o',
    '\u014D': 'o',
    '\u1E51': 'o',
    '\u1E53': 'o',
    '\u014F': 'o',
    '\u022F': 'o',
    '\u0231': 'o',
    '\u00F6': 'o',
    '\u022B': 'o',
    '\u1ECF': 'o',
    '\u0151': 'o',
    '\u01D2': 'o',
    '\u020D': 'o',
    '\u020F': 'o',
    '\u01A1': 'o',
    '\u1EDD': 'o',
    '\u1EDB': 'o',
    '\u1EE1': 'o',
    '\u1EDF': 'o',
    '\u1EE3': 'o',
    '\u1ECD': 'o',
    '\u1ED9': 'o',
    '\u01EB': 'o',
    '\u01ED': 'o',
    '\u00F8': 'o',
    '\u01FF': 'o',
    '\u0254': 'o',
    '\uA74B': 'o',
    '\uA74D': 'o',
    '\u0275': 'o',
    '\u01A3': 'oi',
    '\u0223': 'ou',
    '\uA74F': 'oo',
    '\u24DF': 'p',
    '\uFF50': 'p',
    '\u1E55': 'p',
    '\u1E57': 'p',
    '\u01A5': 'p',
    '\u1D7D': 'p',
    '\uA751': 'p',
    '\uA753': 'p',
    '\uA755': 'p',
    '\u24E0': 'q',
    '\uFF51': 'q',
    '\u024B': 'q',
    '\uA757': 'q',
    '\uA759': 'q',
    '\u24E1': 'r',
    '\uFF52': 'r',
    '\u0155': 'r',
    '\u1E59': 'r',
    '\u0159': 'r',
    '\u0211': 'r',
    '\u0213': 'r',
    '\u1E5B': 'r',
    '\u1E5D': 'r',
    '\u0157': 'r',
    '\u1E5F': 'r',
    '\u024D': 'r',
    '\u027D': 'r',
    '\uA75B': 'r',
    '\uA7A7': 'r',
    '\uA783': 'r',
    '\u24E2': 's',
    '\uFF53': 's',
    '\u00DF': 's',
    '\u015B': 's',
    '\u1E65': 's',
    '\u015D': 's',
    '\u1E61': 's',
    '\u0161': 's',
    '\u1E67': 's',
    '\u1E63': 's',
    '\u1E69': 's',
    '\u0219': 's',
    '\u015F': 's',
    '\u023F': 's',
    '\uA7A9': 's',
    '\uA785': 's',
    '\u1E9B': 's',
    '\u24E3': 't',
    '\uFF54': 't',
    '\u1E6B': 't',
    '\u1E97': 't',
    '\u0165': 't',
    '\u1E6D': 't',
    '\u021B': 't',
    '\u0163': 't',
    '\u1E71': 't',
    '\u1E6F': 't',
    '\u0167': 't',
    '\u01AD': 't',
    '\u0288': 't',
    '\u2C66': 't',
    '\uA787': 't',
    '\uA729': 'tz',
    '\u24E4': 'u',
    '\uFF55': 'u',
    '\u00F9': 'u',
    '\u00FA': 'u',
    '\u00FB': 'u',
    '\u0169': 'u',
    '\u1E79': 'u',
    '\u016B': 'u',
    '\u1E7B': 'u',
    '\u016D': 'u',
    '\u00FC': 'u',
    '\u01DC': 'u',
    '\u01D8': 'u',
    '\u01D6': 'u',
    '\u01DA': 'u',
    '\u1EE7': 'u',
    '\u016F': 'u',
    '\u0171': 'u',
    '\u01D4': 'u',
    '\u0215': 'u',
    '\u0217': 'u',
    '\u01B0': 'u',
    '\u1EEB': 'u',
    '\u1EE9': 'u',
    '\u1EEF': 'u',
    '\u1EED': 'u',
    '\u1EF1': 'u',
    '\u1EE5': 'u',
    '\u1E73': 'u',
    '\u0173': 'u',
    '\u1E77': 'u',
    '\u1E75': 'u',
    '\u0289': 'u',
    '\u24E5': 'v',
    '\uFF56': 'v',
    '\u1E7D': 'v',
    '\u1E7F': 'v',
    '\u028B': 'v',
    '\uA75F': 'v',
    '\u028C': 'v',
    '\uA761': 'vy',
    '\u24E6': 'w',
    '\uFF57': 'w',
    '\u1E81': 'w',
    '\u1E83': 'w',
    '\u0175': 'w',
    '\u1E87': 'w',
    '\u1E85': 'w',
    '\u1E98': 'w',
    '\u1E89': 'w',
    '\u2C73': 'w',
    '\u24E7': 'x',
    '\uFF58': 'x',
    '\u1E8B': 'x',
    '\u1E8D': 'x',
    '\u24E8': 'y',
    '\uFF59': 'y',
    '\u1EF3': 'y',
    '\u00FD': 'y',
    '\u0177': 'y',
    '\u1EF9': 'y',
    '\u0233': 'y',
    '\u1E8F': 'y',
    '\u00FF': 'y',
    '\u1EF7': 'y',
    '\u1E99': 'y',
    '\u1EF5': 'y',
    '\u01B4': 'y',
    '\u024F': 'y',
    '\u1EFF': 'y',
    '\u24E9': 'z',
    '\uFF5A': 'z',
    '\u017A': 'z',
    '\u1E91': 'z',
    '\u017C': 'z',
    '\u017E': 'z',
    '\u1E93': 'z',
    '\u1E95': 'z',
    '\u01B6': 'z',
    '\u0225': 'z',
    '\u0240': 'z',
    '\u2C6C': 'z',
    '\uA763': 'z',
    '\u0386': '\u0391',
    '\u0388': '\u0395',
    '\u0389': '\u0397',
    '\u038A': '\u0399',
    '\u03AA': '\u0399',
    '\u038C': '\u039F',
    '\u038E': '\u03A5',
    '\u03AB': '\u03A5',
    '\u038F': '\u03A9',
    '\u03AC': '\u03B1',
    '\u03AD': '\u03B5',
    '\u03AE': '\u03B7',
    '\u03AF': '\u03B9',
    '\u03CA': '\u03B9',
    '\u0390': '\u03B9',
    '\u03CC': '\u03BF',
    '\u03CD': '\u03C5',
    '\u03CB': '\u03C5',
    '\u03B0': '\u03C5',
    '\u03C9': '\u03C9',
    '\u03C2': '\u03C3'
  };

  return diacritics;
});

S2.define('select2/data/base',[
  '../utils'
], function (Utils) {
  function BaseAdapter ($element, options) {
    BaseAdapter.__super__.constructor.call(this);
  }

  Utils.Extend(BaseAdapter, Utils.Observable);

  BaseAdapter.prototype.current = function (callback) {
    throw new Error('The `current` method must be defined in child classes.');
  };

  BaseAdapter.prototype.query = function (params, callback) {
    throw new Error('The `query` method must be defined in child classes.');
  };

  BaseAdapter.prototype.bind = function (container, $container) {
    // Can be implemented in subclasses
  };

  BaseAdapter.prototype.destroy = function () {
    // Can be implemented in subclasses
  };

  BaseAdapter.prototype.generateResultId = function (container, data) {
    var id = container.id + '-result-';

    id += Utils.generateChars(4);

    if (data.id != null) {
      id += '-' + data.id.toString();
    } else {
      id += '-' + Utils.generateChars(4);
    }
    return id;
  };

  return BaseAdapter;
});

S2.define('select2/data/select',[
  './base',
  '../utils',
  'jquery'
], function (BaseAdapter, Utils, $) {
  function SelectAdapter ($element, options) {
    this.$element = $element;
    this.options = options;

    SelectAdapter.__super__.constructor.call(this);
  }

  Utils.Extend(SelectAdapter, BaseAdapter);

  SelectAdapter.prototype.current = function (callback) {
    var data = [];
    var self = this;

    this.$element.find(':selected').each(function () {
      var $option = $(this);

      var option = self.item($option);

      data.push(option);
    });

    callback(data);
  };

  SelectAdapter.prototype.select = function (data) {
    var self = this;

    data.selected = true;

    // If data.element is a DOM node, use it instead
    if ($(data.element).is('option')) {
      data.element.selected = true;

      this.$element.trigger('change');

      return;
    }

    if (this.$element.prop('multiple')) {
      this.current(function (currentData) {
        var val = [];

        data = [data];
        data.push.apply(data, currentData);

        for (var d = 0; d < data.length; d++) {
          var id = data[d].id;

          if ($.inArray(id, val) === -1) {
            val.push(id);
          }
        }

        self.$element.val(val);
        self.$element.trigger('change');
      });
    } else {
      var val = data.id;

      this.$element.val(val);
      this.$element.trigger('change');
    }
  };

  SelectAdapter.prototype.unselect = function (data) {
    var self = this;

    if (!this.$element.prop('multiple')) {
      return;
    }

    data.selected = false;

    if ($(data.element).is('option')) {
      data.element.selected = false;

      this.$element.trigger('change');

      return;
    }

    this.current(function (currentData) {
      var val = [];

      for (var d = 0; d < currentData.length; d++) {
        var id = currentData[d].id;

        if (id !== data.id && $.inArray(id, val) === -1) {
          val.push(id);
        }
      }

      self.$element.val(val);

      self.$element.trigger('change');
    });
  };

  SelectAdapter.prototype.bind = function (container, $container) {
    var self = this;

    this.container = container;

    container.on('select', function (params) {
      self.select(params.data);
    });

    container.on('unselect', function (params) {
      self.unselect(params.data);
    });
  };

  SelectAdapter.prototype.destroy = function () {
    // Remove anything added to child elements
    this.$element.find('*').each(function () {
      // Remove any custom data set by Select2
      $.removeData(this, 'data');
    });
  };

  SelectAdapter.prototype.query = function (params, callback) {
    var data = [];
    var self = this;

    var $options = this.$element.children();

    $options.each(function () {
      var $option = $(this);

      if (!$option.is('option') && !$option.is('optgroup')) {
        return;
      }

      var option = self.item($option);

      var matches = self.matches(params, option);

      if (matches !== null) {
        data.push(matches);
      }
    });

    callback({
      results: data
    });
  };

  SelectAdapter.prototype.addOptions = function ($options) {
    Utils.appendMany(this.$element, $options);
  };

  SelectAdapter.prototype.option = function (data) {
    var option;

    if (data.children) {
      option = document.createElement('optgroup');
      option.label = data.text;
    } else {
      option = document.createElement('option');

      if (option.textContent !== undefined) {
        option.textContent = data.text;
      } else {
        option.innerText = data.text;
      }
    }

    if (data.id !== undefined) {
      option.value = data.id;
    }

    if (data.disabled) {
      option.disabled = true;
    }

    if (data.selected) {
      option.selected = true;
    }

    if (data.title) {
      option.title = data.title;
    }

    var $option = $(option);

    var normalizedData = this._normalizeItem(data);
    normalizedData.element = option;

    // Override the option's data with the combined data
    $.data(option, 'data', normalizedData);

    return $option;
  };

  SelectAdapter.prototype.item = function ($option) {
    var data = {};

    data = $.data($option[0], 'data');

    if (data != null) {
      return data;
    }

    if ($option.is('option')) {
      data = {
        id: $option.val(),
        text: $option.text(),
        disabled: $option.prop('disabled'),
        selected: $option.prop('selected'),
        title: $option.prop('title')
      };
    } else if ($option.is('optgroup')) {
      data = {
        text: $option.prop('label'),
        children: [],
        title: $option.prop('title')
      };

      var $children = $option.children('option');
      var children = [];

      for (var c = 0; c < $children.length; c++) {
        var $child = $($children[c]);

        var child = this.item($child);

        children.push(child);
      }

      data.children = children;
    }

    data = this._normalizeItem(data);
    data.element = $option[0];

    $.data($option[0], 'data', data);

    return data;
  };

  SelectAdapter.prototype._normalizeItem = function (item) {
    if (!$.isPlainObject(item)) {
      item = {
        id: item,
        text: item
      };
    }

    item = $.extend({}, {
      text: ''
    }, item);

    var defaults = {
      selected: false,
      disabled: false
    };

    if (item.id != null) {
      item.id = item.id.toString();
    }

    if (item.text != null) {
      item.text = item.text.toString();
    }

    if (item._resultId == null && item.id && this.container != null) {
      item._resultId = this.generateResultId(this.container, item);
    }

    return $.extend({}, defaults, item);
  };

  SelectAdapter.prototype.matches = function (params, data) {
    var matcher = this.options.get('matcher');

    return matcher(params, data);
  };

  return SelectAdapter;
});

S2.define('select2/data/array',[
  './select',
  '../utils',
  'jquery'
], function (SelectAdapter, Utils, $) {
  function ArrayAdapter ($element, options) {
    var data = options.get('data') || [];

    ArrayAdapter.__super__.constructor.call(this, $element, options);

    this.addOptions(this.convertToOptions(data));
  }

  Utils.Extend(ArrayAdapter, SelectAdapter);

  ArrayAdapter.prototype.select = function (data) {
    var $option = this.$element.find('option').filter(function (i, elm) {
      return elm.value == data.id.toString();
    });

    if ($option.length === 0) {
      $option = this.option(data);

      this.addOptions($option);
    }

    ArrayAdapter.__super__.select.call(this, data);
  };

  ArrayAdapter.prototype.convertToOptions = function (data) {
    var self = this;

    var $existing = this.$element.find('option');
    var existingIds = $existing.map(function () {
      return self.item($(this)).id;
    }).get();

    var $options = [];

    // Filter out all items except for the one passed in the argument
    function onlyItem (item) {
      return function () {
        return $(this).val() == item.id;
      };
    }

    for (var d = 0; d < data.length; d++) {
      var item = this._normalizeItem(data[d]);

      // Skip items which were pre-loaded, only merge the data
      if ($.inArray(item.id, existingIds) >= 0) {
        var $existingOption = $existing.filter(onlyItem(item));

        var existingData = this.item($existingOption);
        var newData = $.extend(true, {}, item, existingData);

        var $newOption = this.option(newData);

        $existingOption.replaceWith($newOption);

        continue;
      }

      var $option = this.option(item);

      if (item.children) {
        var $children = this.convertToOptions(item.children);

        Utils.appendMany($option, $children);
      }

      $options.push($option);
    }

    return $options;
  };

  return ArrayAdapter;
});

S2.define('select2/data/ajax',[
  './array',
  '../utils',
  'jquery'
], function (ArrayAdapter, Utils, $) {
  function AjaxAdapter ($element, options) {
    this.ajaxOptions = this._applyDefaults(options.get('ajax'));

    if (this.ajaxOptions.processResults != null) {
      this.processResults = this.ajaxOptions.processResults;
    }

    AjaxAdapter.__super__.constructor.call(this, $element, options);
  }

  Utils.Extend(AjaxAdapter, ArrayAdapter);

  AjaxAdapter.prototype._applyDefaults = function (options) {
    var defaults = {
      data: function (params) {
        return $.extend({}, params, {
          q: params.term
        });
      },
      transport: function (params, success, failure) {
        var $request = $.ajax(params);

        $request.then(success);
        $request.fail(failure);

        return $request;
      }
    };

    return $.extend({}, defaults, options, true);
  };

  AjaxAdapter.prototype.processResults = function (results) {
    return results;
  };

  AjaxAdapter.prototype.query = function (params, callback) {
    var matches = [];
    var self = this;

    if (this._request != null) {
      // JSONP requests cannot always be aborted
      if ($.isFunction(this._request.abort)) {
        this._request.abort();
      }

      this._request = null;
    }

    var options = $.extend({
      type: 'GET'
    }, this.ajaxOptions);

    if (typeof options.url === 'function') {
      options.url = options.url.call(this.$element, params);
    }

    if (typeof options.data === 'function') {
      options.data = options.data.call(this.$element, params);
    }

    function request () {
      var $request = options.transport(options, function (data) {
        var results = self.processResults(data, params);

        if (self.options.get('debug') && window.console && console.error) {
          // Check to make sure that the response included a `results` key.
          if (!results || !results.results || !$.isArray(results.results)) {
            console.error(
              'Select2: The AJAX results did not return an array in the ' +
              '`results` key of the response.'
            );
          }
        }

        callback(results);
      }, function () {
        // Attempt to detect if a request was aborted
        // Only works if the transport exposes a status property
        if ($request.status && $request.status === '0') {
          return;
        }

        self.trigger('results:message', {
          message: 'errorLoading'
        });
      });

      self._request = $request;
    }

    if (this.ajaxOptions.delay && params.term != null) {
      if (this._queryTimeout) {
        window.clearTimeout(this._queryTimeout);
      }

      this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
    } else {
      request();
    }
  };

  return AjaxAdapter;
});

S2.define('select2/data/tags',[
  'jquery'
], function ($) {
  function Tags (decorated, $element, options) {
    var tags = options.get('tags');

    var createTag = options.get('createTag');

    if (createTag !== undefined) {
      this.createTag = createTag;
    }

    var insertTag = options.get('insertTag');

    if (insertTag !== undefined) {
        this.insertTag = insertTag;
    }

    decorated.call(this, $element, options);

    if ($.isArray(tags)) {
      for (var t = 0; t < tags.length; t++) {
        var tag = tags[t];
        var item = this._normalizeItem(tag);

        var $option = this.option(item);

        this.$element.append($option);
      }
    }
  }

  Tags.prototype.query = function (decorated, params, callback) {
    var self = this;

    this._removeOldTags();

    if (params.term == null || params.page != null) {
      decorated.call(this, params, callback);
      return;
    }

    function wrapper (obj, child) {
      var data = obj.results;

      for (var i = 0; i < data.length; i++) {
        var option = data[i];

        var checkChildren = (
          option.children != null &&
          !wrapper({
            results: option.children
          }, true)
        );

        var optionText = (option.text || '').toUpperCase();
        var paramsTerm = (params.term || '').toUpperCase();

        var checkText = optionText === paramsTerm;

        if (checkText || checkChildren) {
          if (child) {
            return false;
          }

          obj.data = data;
          callback(obj);

          return;
        }
      }

      if (child) {
        return true;
      }

      var tag = self.createTag(params);

      if (tag != null) {
        var $option = self.option(tag);
        $option.attr('data-select2-tag', true);

        self.addOptions([$option]);

        self.insertTag(data, tag);
      }

      obj.results = data;

      callback(obj);
    }

    decorated.call(this, params, wrapper);
  };

  Tags.prototype.createTag = function (decorated, params) {
    var term = $.trim(params.term);

    if (term === '') {
      return null;
    }

    return {
      id: term,
      text: term
    };
  };

  Tags.prototype.insertTag = function (_, data, tag) {
    data.unshift(tag);
  };

  Tags.prototype._removeOldTags = function (_) {
    var tag = this._lastTag;

    var $options = this.$element.find('option[data-select2-tag]');

    $options.each(function () {
      if (this.selected) {
        return;
      }

      $(this).remove();
    });
  };

  return Tags;
});

S2.define('select2/data/tokenizer',[
  'jquery'
], function ($) {
  function Tokenizer (decorated, $element, options) {
    var tokenizer = options.get('tokenizer');

    if (tokenizer !== undefined) {
      this.tokenizer = tokenizer;
    }

    decorated.call(this, $element, options);
  }

  Tokenizer.prototype.bind = function (decorated, container, $container) {
    decorated.call(this, container, $container);

    this.$search =  container.dropdown.$search || container.selection.$search ||
      $container.find('.select2-search__field');
  };

  Tokenizer.prototype.query = function (decorated, params, callback) {
    var self = this;

    function createAndSelect (data) {
      // Normalize the data object so we can use it for checks
      var item = self._normalizeItem(data);

      // Check if the data object already exists as a tag
      // Select it if it doesn't
      var $existingOptions = self.$element.find('option').filter(function () {
        return $(this).val() === item.id;
      });

      // If an existing option wasn't found for it, create the option
      if (!$existingOptions.length) {
        var $option = self.option(item);
        $option.attr('data-select2-tag', true);

        self._removeOldTags();
        self.addOptions([$option]);
      }

      // Select the item, now that we know there is an option for it
      select(item);
    }

    function select (data) {
      self.trigger('select', {
        data: data
      });
    }

    params.term = params.term || '';

    var tokenData = this.tokenizer(params, this.options, createAndSelect);

    if (tokenData.term !== params.term) {
      // Replace the search term if we have the search box
      if (this.$search.length) {
        this.$search.val(tokenData.term);
        this.$search.focus();
      }

      params.term = tokenData.term;
    }

    decorated.call(this, params, callback);
  };

  Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
    var separators = options.get('tokenSeparators') || [];
    var term = params.term;
    var i = 0;

    var createTag = this.createTag || function (params) {
      return {
        id: params.term,
        text: params.term
      };
    };

    while (i < term.length) {
      var termChar = term[i];

      if ($.inArray(termChar, separators) === -1) {
        i++;

        continue;
      }

      var part = term.substr(0, i);
      var partParams = $.extend({}, params, {
        term: part
      });

      var data = createTag(partParams);

      if (data == null) {
        i++;
        continue;
      }

      callback(data);

      // Reset the term to not include the tokenized portion
      term = term.substr(i + 1) || '';
      i = 0;
    }

    return {
      term: term
    };
  };

  return Tokenizer;
});

S2.define('select2/data/minimumInputLength',[

], function () {
  function MinimumInputLength (decorated, $e, options) {
    this.minimumInputLength = options.get('minimumInputLength');

    decorated.call(this, $e, options);
  }

  MinimumInputLength.prototype.query = function (decorated, params, callback) {
    params.term = params.term || '';

    if (params.term.length < this.minimumInputLength) {
      this.trigger('results:message', {
        message: 'inputTooShort',
        args: {
          minimum: this.minimumInputLength,
          input: params.term,
          params: params
        }
      });

      return;
    }

    decorated.call(this, params, callback);
  };

  return MinimumInputLength;
});

S2.define('select2/data/maximumInputLength',[

], function () {
  function MaximumInputLength (decorated, $e, options) {
    this.maximumInputLength = options.get('maximumInputLength');

    decorated.call(this, $e, options);
  }

  MaximumInputLength.prototype.query = function (decorated, params, callback) {
    params.term = params.term || '';

    if (this.maximumInputLength > 0 &&
        params.term.length > this.maximumInputLength) {
      this.trigger('results:message', {
        message: 'inputTooLong',
        args: {
          maximum: this.maximumInputLength,
          input: params.term,
          params: params
        }
      });

      return;
    }

    decorated.call(this, params, callback);
  };

  return MaximumInputLength;
});

S2.define('select2/data/maximumSelectionLength',[

], function (){
  function MaximumSelectionLength (decorated, $e, options) {
    this.maximumSelectionLength = options.get('maximumSelectionLength');

    decorated.call(this, $e, options);
  }

  MaximumSelectionLength.prototype.query =
    function (decorated, params, callback) {
      var self = this;

      this.current(function (currentData) {
        var count = currentData != null ? currentData.length : 0;
        if (self.maximumSelectionLength > 0 &&
          count >= self.maximumSelectionLength) {
          self.trigger('results:message', {
            message: 'maximumSelected',
            args: {
              maximum: self.maximumSelectionLength
            }
          });
          return;
        }
        decorated.call(self, params, callback);
      });
  };

  return MaximumSelectionLength;
});

S2.define('select2/dropdown',[
  'jquery',
  './utils'
], function ($, Utils) {
  function Dropdown ($element, options) {
    this.$element = $element;
    this.options = options;

    Dropdown.__super__.constructor.call(this);
  }

  Utils.Extend(Dropdown, Utils.Observable);

  Dropdown.prototype.render = function () {
    var $dropdown = $(
      '<span class="select2-dropdown">' +
        '<span class="select2-results"></span>' +
      '</span>'
    );

    $dropdown.attr('dir', this.options.get('dir'));

    this.$dropdown = $dropdown;

    return $dropdown;
  };

  Dropdown.prototype.bind = function () {
    // Should be implemented in subclasses
  };

  Dropdown.prototype.position = function ($dropdown, $container) {
    // Should be implmented in subclasses
  };

  Dropdown.prototype.destroy = function () {
    // Remove the dropdown from the DOM
    this.$dropdown.remove();
  };

  return Dropdown;
});

S2.define('select2/dropdown/search',[
  'jquery',
  '../utils'
], function ($, Utils) {
  function Search () { }

  Search.prototype.render = function (decorated) {
    var $rendered = decorated.call(this);

    var $search = $(
      '<span class="select2-search select2-search--dropdown">' +
        '<input class="select2-search__field" type="search" tabindex="-1"' +
        ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
        ' spellcheck="false" role="textbox" />' +
      '</span>'
    );

    this.$searchContainer = $search;
    this.$search = $search.find('input');

    $rendered.prepend($search);

    return $rendered;
  };

  Search.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    this.$search.on('keydown', function (evt) {
      self.trigger('keypress', evt);

      self._keyUpPrevented = evt.isDefaultPrevented();
    });

    // Workaround for browsers which do not support the `input` event
    // This will prevent double-triggering of events for browsers which support
    // both the `keyup` and `input` events.
    this.$search.on('input', function (evt) {
      // Unbind the duplicated `keyup` event
      $(this).off('keyup');
    });

    this.$search.on('keyup input', function (evt) {
      self.handleSearch(evt);
    });

    container.on('open', function () {
      self.$search.attr('tabindex', 0);

      self.$search.focus();

      window.setTimeout(function () {
        self.$search.focus();
      }, 0);
    });

    container.on('close', function () {
      self.$search.attr('tabindex', -1);

      self.$search.val('');
    });

    container.on('focus', function () {
      if (!container.isOpen()) {
        self.$search.focus();
      }
    });

    container.on('results:all', function (params) {
      if (params.query.term == null || params.query.term === '') {
        var showSearch = self.showSearch(params);

        if (showSearch) {
          self.$searchContainer.removeClass('select2-search--hide');
        } else {
          self.$searchContainer.addClass('select2-search--hide');
        }
      }
    });
  };

  Search.prototype.handleSearch = function (evt) {
    if (!this._keyUpPrevented) {
      var input = this.$search.val();

      this.trigger('query', {
        term: input
      });
    }

    this._keyUpPrevented = false;
  };

  Search.prototype.showSearch = function (_, params) {
    return true;
  };

  return Search;
});

S2.define('select2/dropdown/hidePlaceholder',[

], function () {
  function HidePlaceholder (decorated, $element, options, dataAdapter) {
    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));

    decorated.call(this, $element, options, dataAdapter);
  }

  HidePlaceholder.prototype.append = function (decorated, data) {
    data.results = this.removePlaceholder(data.results);

    decorated.call(this, data);
  };

  HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
    if (typeof placeholder === 'string') {
      placeholder = {
        id: '',
        text: placeholder
      };
    }

    return placeholder;
  };

  HidePlaceholder.prototype.removePlaceholder = function (_, data) {
    var modifiedData = data.slice(0);

    for (var d = data.length - 1; d >= 0; d--) {
      var item = data[d];

      if (this.placeholder.id === item.id) {
        modifiedData.splice(d, 1);
      }
    }

    return modifiedData;
  };

  return HidePlaceholder;
});

S2.define('select2/dropdown/infiniteScroll',[
  'jquery'
], function ($) {
  function InfiniteScroll (decorated, $element, options, dataAdapter) {
    this.lastParams = {};

    decorated.call(this, $element, options, dataAdapter);

    this.$loadingMore = this.createLoadingMore();
    this.loading = false;
  }

  InfiniteScroll.prototype.append = function (decorated, data) {
    this.$loadingMore.remove();
    this.loading = false;

    decorated.call(this, data);

    if (this.showLoadingMore(data)) {
      this.$results.append(this.$loadingMore);
    }
  };

  InfiniteScroll.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('query', function (params) {
      self.lastParams = params;
      self.loading = true;
    });

    container.on('query:append', function (params) {
      self.lastParams = params;
      self.loading = true;
    });

    this.$results.on('scroll', function () {
      var isLoadMoreVisible = $.contains(
        document.documentElement,
        self.$loadingMore[0]
      );

      if (self.loading || !isLoadMoreVisible) {
        return;
      }

      var currentOffset = self.$results.offset().top +
        self.$results.outerHeight(false);
      var loadingMoreOffset = self.$loadingMore.offset().top +
        self.$loadingMore.outerHeight(false);

      if (currentOffset + 50 >= loadingMoreOffset) {
        self.loadMore();
      }
    });
  };

  InfiniteScroll.prototype.loadMore = function () {
    this.loading = true;

    var params = $.extend({}, {page: 1}, this.lastParams);

    params.page++;

    this.trigger('query:append', params);
  };

  InfiniteScroll.prototype.showLoadingMore = function (_, data) {
    return data.pagination && data.pagination.more;
  };

  InfiniteScroll.prototype.createLoadingMore = function () {
    var $option = $(
      '<li ' +
      'class="select2-results__option select2-results__option--load-more"' +
      'role="treeitem" aria-disabled="true"></li>'
    );

    var message = this.options.get('translations').get('loadingMore');

    $option.html(message(this.lastParams));

    return $option;
  };

  return InfiniteScroll;
});

S2.define('select2/dropdown/attachBody',[
  'jquery',
  '../utils'
], function ($, Utils) {
  function AttachBody (decorated, $element, options) {
    this.$dropdownParent = options.get('dropdownParent') || $(document.body);

    decorated.call(this, $element, options);
  }

  AttachBody.prototype.bind = function (decorated, container, $container) {
    var self = this;

    var setupResultsEvents = false;

    decorated.call(this, container, $container);

    container.on('open', function () {
      self._showDropdown();
      self._attachPositioningHandler(container);

      if (!setupResultsEvents) {
        setupResultsEvents = true;

        container.on('results:all', function () {
          self._positionDropdown();
          self._resizeDropdown();
        });

        container.on('results:append', function () {
          self._positionDropdown();
          self._resizeDropdown();
        });
      }
    });

    container.on('close', function () {
      self._hideDropdown();
      self._detachPositioningHandler(container);
    });

    this.$dropdownContainer.on('mousedown', function (evt) {
      evt.stopPropagation();
    });
  };

  AttachBody.prototype.destroy = function (decorated) {
    decorated.call(this);

    this.$dropdownContainer.remove();
  };

  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
    // Clone all of the container classes
    $dropdown.attr('class', $container.attr('class'));

    $dropdown.removeClass('select2');
    $dropdown.addClass('select2-container--open');

    $dropdown.css({
      position: 'absolute',
      top: -999999
    });

    this.$container = $container;
  };

  AttachBody.prototype.render = function (decorated) {
    var $container = $('<span></span>');

    var $dropdown = decorated.call(this);
    $container.append($dropdown);

    this.$dropdownContainer = $container;

    return $container;
  };

  AttachBody.prototype._hideDropdown = function (decorated) {
    this.$dropdownContainer.detach();
  };

  AttachBody.prototype._attachPositioningHandler =
      function (decorated, container) {
    var self = this;

    var scrollEvent = 'scroll.select2.' + container.id;
    var resizeEvent = 'resize.select2.' + container.id;
    var orientationEvent = 'orientationchange.select2.' + container.id;

    var $watchers = this.$container.parents().filter(Utils.hasScroll);
    $watchers.each(function () {
      $(this).data('select2-scroll-position', {
        x: $(this).scrollLeft(),
        y: $(this).scrollTop()
      });
    });

    $watchers.on(scrollEvent, function (ev) {
      var position = $(this).data('select2-scroll-position');
      $(this).scrollTop(position.y);
    });

    $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
      function (e) {
      self._positionDropdown();
      self._resizeDropdown();
    });
  };

  AttachBody.prototype._detachPositioningHandler =
      function (decorated, container) {
    var scrollEvent = 'scroll.select2.' + container.id;
    var resizeEvent = 'resize.select2.' + container.id;
    var orientationEvent = 'orientationchange.select2.' + container.id;

    var $watchers = this.$container.parents().filter(Utils.hasScroll);
    $watchers.off(scrollEvent);

    $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
  };

  AttachBody.prototype._positionDropdown = function () {
    var $window = $(window);

    var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
    var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');

    var newDirection = null;

    var offset = this.$container.offset();

    offset.bottom = offset.top + this.$container.outerHeight(false);

    var container = {
      height: this.$container.outerHeight(false)
    };

    container.top = offset.top;
    container.bottom = offset.top + container.height;

    var dropdown = {
      height: this.$dropdown.outerHeight(false)
    };

    var viewport = {
      top: $window.scrollTop(),
      bottom: $window.scrollTop() + $window.height()
    };

    var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
    var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);

    var css = {
      left: offset.left,
      top: container.bottom
    };

    // Determine what the parent element is to use for calciulating the offset
    var $offsetParent = this.$dropdownParent;

    // For statically positoned elements, we need to get the element
    // that is determining the offset
    if ($offsetParent.css('position') === 'static') {
      $offsetParent = $offsetParent.offsetParent();
    }

    var parentOffset = $offsetParent.offset();

    css.top -= parentOffset.top;
    css.left -= parentOffset.left;

    if (!isCurrentlyAbove && !isCurrentlyBelow) {
      newDirection = 'below';
    }

    if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
      newDirection = 'above';
    } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
      newDirection = 'below';
    }

    if (newDirection == 'above' ||
      (isCurrentlyAbove && newDirection !== 'below')) {
      css.top = container.top - parentOffset.top - dropdown.height;
    }

    if (newDirection != null) {
      this.$dropdown
        .removeClass('select2-dropdown--below select2-dropdown--above')
        .addClass('select2-dropdown--' + newDirection);
      this.$container
        .removeClass('select2-container--below select2-container--above')
        .addClass('select2-container--' + newDirection);
    }

    this.$dropdownContainer.css(css);
  };

  AttachBody.prototype._resizeDropdown = function () {
    var css = {
      width: this.$container.outerWidth(false) + 'px'
    };

    if (this.options.get('dropdownAutoWidth')) {
      css.minWidth = css.width;
      css.position = 'relative';
      css.width = 'auto';
    }

    this.$dropdown.css(css);
  };

  AttachBody.prototype._showDropdown = function (decorated) {
    this.$dropdownContainer.appendTo(this.$dropdownParent);

    this._positionDropdown();
    this._resizeDropdown();
  };

  return AttachBody;
});

S2.define('select2/dropdown/minimumResultsForSearch',[

], function () {
  function countResults (data) {
    var count = 0;

    for (var d = 0; d < data.length; d++) {
      var item = data[d];

      if (item.children) {
        count += countResults(item.children);
      } else {
        count++;
      }
    }

    return count;
  }

  function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
    this.minimumResultsForSearch = options.get('minimumResultsForSearch');

    if (this.minimumResultsForSearch < 0) {
      this.minimumResultsForSearch = Infinity;
    }

    decorated.call(this, $element, options, dataAdapter);
  }

  MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
    if (countResults(params.data.results) < this.minimumResultsForSearch) {
      return false;
    }

    return decorated.call(this, params);
  };

  return MinimumResultsForSearch;
});

S2.define('select2/dropdown/selectOnClose',[

], function () {
  function SelectOnClose () { }

  SelectOnClose.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('close', function (params) {
      self._handleSelectOnClose(params);
    });
  };

  SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
    if (params && params.originalSelect2Event != null) {
      var event = params.originalSelect2Event;

      // Don't select an item if the close event was triggered from a select or
      // unselect event
      if (event._type === 'select' || event._type === 'unselect') {
        return;
      }
    }

    var $highlightedResults = this.getHighlightedResults();

    // Only select highlighted results
    if ($highlightedResults.length < 1) {
      return;
    }

    var data = $highlightedResults.data('data');

    // Don't re-select already selected resulte
    if (
      (data.element != null && data.element.selected) ||
      (data.element == null && data.selected)
    ) {
      return;
    }

    this.trigger('select', {
        data: data
    });
  };

  return SelectOnClose;
});

S2.define('select2/dropdown/closeOnSelect',[

], function () {
  function CloseOnSelect () { }

  CloseOnSelect.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('select', function (evt) {
      self._selectTriggered(evt);
    });

    container.on('unselect', function (evt) {
      self._selectTriggered(evt);
    });
  };

  CloseOnSelect.prototype._selectTriggered = function (_, evt) {
    var originalEvent = evt.originalEvent;

    // Don't close if the control key is being held
    if (originalEvent && originalEvent.ctrlKey) {
      return;
    }

    this.trigger('close', {
      originalEvent: originalEvent,
      originalSelect2Event: evt
    });
  };

  return CloseOnSelect;
});

S2.define('select2/i18n/en',[],function () {
  // English
  return {
    errorLoading: function () {
      return 'The results could not be loaded.';
    },
    inputTooLong: function (args) {
      var overChars = args.input.length - args.maximum;

      var message = 'Please delete ' + overChars + ' character';

      if (overChars != 1) {
        message += 's';
      }

      return message;
    },
    inputTooShort: function (args) {
      var remainingChars = args.minimum - args.input.length;

      var message = 'Please enter ' + remainingChars + ' or more characters';

      return message;
    },
    loadingMore: function () {
      return 'Loading more results…';
    },
    maximumSelected: function (args) {
      var message = 'You can only select ' + args.maximum + ' item';

      if (args.maximum != 1) {
        message += 's';
      }

      return message;
    },
    noResults: function () {
      return 'No results found';
    },
    searching: function () {
      return 'Searching…';
    }
  };
});

S2.define('select2/defaults',[
  'jquery',
  'require',

  './results',

  './selection/single',
  './selection/multiple',
  './selection/placeholder',
  './selection/allowClear',
  './selection/search',
  './selection/eventRelay',

  './utils',
  './translation',
  './diacritics',

  './data/select',
  './data/array',
  './data/ajax',
  './data/tags',
  './data/tokenizer',
  './data/minimumInputLength',
  './data/maximumInputLength',
  './data/maximumSelectionLength',

  './dropdown',
  './dropdown/search',
  './dropdown/hidePlaceholder',
  './dropdown/infiniteScroll',
  './dropdown/attachBody',
  './dropdown/minimumResultsForSearch',
  './dropdown/selectOnClose',
  './dropdown/closeOnSelect',

  './i18n/en'
], function ($, require,

             ResultsList,

             SingleSelection, MultipleSelection, Placeholder, AllowClear,
             SelectionSearch, EventRelay,

             Utils, Translation, DIACRITICS,

             SelectData, ArrayData, AjaxData, Tags, Tokenizer,
             MinimumInputLength, MaximumInputLength, MaximumSelectionLength,

             Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
             AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,

             EnglishTranslation) {
  function Defaults () {
    this.reset();
  }

  Defaults.prototype.apply = function (options) {
    options = $.extend(true, {}, this.defaults, options);

    if (options.dataAdapter == null) {
      if (options.ajax != null) {
        options.dataAdapter = AjaxData;
      } else if (options.data != null) {
        options.dataAdapter = ArrayData;
      } else {
        options.dataAdapter = SelectData;
      }

      if (options.minimumInputLength > 0) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          MinimumInputLength
        );
      }

      if (options.maximumInputLength > 0) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          MaximumInputLength
        );
      }

      if (options.maximumSelectionLength > 0) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          MaximumSelectionLength
        );
      }

      if (options.tags) {
        options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
      }

      if (options.tokenSeparators != null || options.tokenizer != null) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          Tokenizer
        );
      }

      if (options.query != null) {
        var Query = require(options.amdBase + 'compat/query');

        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          Query
        );
      }

      if (options.initSelection != null) {
        var InitSelection = require(options.amdBase + 'compat/initSelection');

        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          InitSelection
        );
      }
    }

    if (options.resultsAdapter == null) {
      options.resultsAdapter = ResultsList;

      if (options.ajax != null) {
        options.resultsAdapter = Utils.Decorate(
          options.resultsAdapter,
          InfiniteScroll
        );
      }

      if (options.placeholder != null) {
        options.resultsAdapter = Utils.Decorate(
          options.resultsAdapter,
          HidePlaceholder
        );
      }

      if (options.selectOnClose) {
        options.resultsAdapter = Utils.Decorate(
          options.resultsAdapter,
          SelectOnClose
        );
      }
    }

    if (options.dropdownAdapter == null) {
      if (options.multiple) {
        options.dropdownAdapter = Dropdown;
      } else {
        var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);

        options.dropdownAdapter = SearchableDropdown;
      }

      if (options.minimumResultsForSearch !== 0) {
        options.dropdownAdapter = Utils.Decorate(
          options.dropdownAdapter,
          MinimumResultsForSearch
        );
      }

      if (options.closeOnSelect) {
        options.dropdownAdapter = Utils.Decorate(
          options.dropdownAdapter,
          CloseOnSelect
        );
      }

      if (
        options.dropdownCssClass != null ||
        options.dropdownCss != null ||
        options.adaptDropdownCssClass != null
      ) {
        var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');

        options.dropdownAdapter = Utils.Decorate(
          options.dropdownAdapter,
          DropdownCSS
        );
      }

      options.dropdownAdapter = Utils.Decorate(
        options.dropdownAdapter,
        AttachBody
      );
    }

    if (options.selectionAdapter == null) {
      if (options.multiple) {
        options.selectionAdapter = MultipleSelection;
      } else {
        options.selectionAdapter = SingleSelection;
      }

      // Add the placeholder mixin if a placeholder was specified
      if (options.placeholder != null) {
        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          Placeholder
        );
      }

      if (options.allowClear) {
        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          AllowClear
        );
      }

      if (options.multiple) {
        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          SelectionSearch
        );
      }

      if (
        options.containerCssClass != null ||
        options.containerCss != null ||
        options.adaptContainerCssClass != null
      ) {
        var ContainerCSS = require(options.amdBase + 'compat/containerCss');

        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          ContainerCSS
        );
      }

      options.selectionAdapter = Utils.Decorate(
        options.selectionAdapter,
        EventRelay
      );
    }

    if (typeof options.language === 'string') {
      // Check if the language is specified with a region
      if (options.language.indexOf('-') > 0) {
        // Extract the region information if it is included
        var languageParts = options.language.split('-');
        var baseLanguage = languageParts[0];

        options.language = [options.language, baseLanguage];
      } else {
        options.language = [options.language];
      }
    }

    if ($.isArray(options.language)) {
      var languages = new Translation();
      options.language.push('en');

      var languageNames = options.language;

      for (var l = 0; l < languageNames.length; l++) {
        var name = languageNames[l];
        var language = {};

        try {
          // Try to load it with the original name
          language = Translation.loadPath(name);
        } catch (e) {
          try {
            // If we couldn't load it, check if it wasn't the full path
            name = this.defaults.amdLanguageBase + name;
            language = Translation.loadPath(name);
          } catch (ex) {
            // The translation could not be loaded at all. Sometimes this is
            // because of a configuration problem, other times this can be
            // because of how Select2 helps load all possible translation files.
            if (options.debug && window.console && console.warn) {
              console.warn(
                'Select2: The language file for "' + name + '" could not be ' +
                'automatically loaded. A fallback will be used instead.'
              );
            }

            continue;
          }
        }

        languages.extend(language);
      }

      options.translations = languages;
    } else {
      var baseTranslation = Translation.loadPath(
        this.defaults.amdLanguageBase + 'en'
      );
      var customTranslation = new Translation(options.language);

      customTranslation.extend(baseTranslation);

      options.translations = customTranslation;
    }

    return options;
  };

  Defaults.prototype.reset = function () {
    function stripDiacritics (text) {
      // Used 'uni range + named function' from http://jsperf.com/diacritics/18
      function match(a) {
        return DIACRITICS[a] || a;
      }

      return text.replace(/[^\u0000-\u007E]/g, match);
    }

    function matcher (params, data) {
      // Always return the object if there is nothing to compare
      if ($.trim(params.term) === '') {
        return data;
      }

      // Do a recursive check for options with children
      if (data.children && data.children.length > 0) {
        // Clone the data object if there are children
        // This is required as we modify the object to remove any non-matches
        var match = $.extend(true, {}, data);

        // Check each child of the option
        for (var c = data.children.length - 1; c >= 0; c--) {
          var child = data.children[c];

          var matches = matcher(params, child);

          // If there wasn't a match, remove the object in the array
          if (matches == null) {
            match.children.splice(c, 1);
          }
        }

        // If any children matched, return the new object
        if (match.children.length > 0) {
          return match;
        }

        // If there were no matching children, check just the plain object
        return matcher(params, match);
      }

      var original = stripDiacritics(data.text).toUpperCase();
      var term = stripDiacritics(params.term).toUpperCase();

      // Check if the text contains the term
      if (original.indexOf(term) > -1) {
        return data;
      }

      // If it doesn't contain the term, don't return anything
      return null;
    }

    this.defaults = {
      amdBase: './',
      amdLanguageBase: './i18n/',
      closeOnSelect: true,
      debug: false,
      dropdownAutoWidth: false,
      escapeMarkup: Utils.escapeMarkup,
      language: EnglishTranslation,
      matcher: matcher,
      minimumInputLength: 0,
      maximumInputLength: 0,
      maximumSelectionLength: 0,
      minimumResultsForSearch: 0,
      selectOnClose: false,
      sorter: function (data) {
        return data;
      },
      templateResult: function (result) {
        return result.text;
      },
      templateSelection: function (selection) {
        return selection.text;
      },
      theme: 'default',
      width: 'resolve'
    };
  };

  Defaults.prototype.set = function (key, value) {
    var camelKey = $.camelCase(key);

    var data = {};
    data[camelKey] = value;

    var convertedData = Utils._convertData(data);

    $.extend(this.defaults, convertedData);
  };

  var defaults = new Defaults();

  return defaults;
});

S2.define('select2/options',[
  'require',
  'jquery',
  './defaults',
  './utils'
], function (require, $, Defaults, Utils) {
  function Options (options, $element) {
    this.options = options;

    if ($element != null) {
      this.fromElement($element);
    }

    this.options = Defaults.apply(this.options);

    if ($element && $element.is('input')) {
      var InputCompat = require(this.get('amdBase') + 'compat/inputData');

      this.options.dataAdapter = Utils.Decorate(
        this.options.dataAdapter,
        InputCompat
      );
    }
  }

  Options.prototype.fromElement = function ($e) {
    var excludedData = ['select2'];

    if (this.options.multiple == null) {
      this.options.multiple = $e.prop('multiple');
    }

    if (this.options.disabled == null) {
      this.options.disabled = $e.prop('disabled');
    }

    if (this.options.language == null) {
      if ($e.prop('lang')) {
        this.options.language = $e.prop('lang').toLowerCase();
      } else if ($e.closest('[lang]').prop('lang')) {
        this.options.language = $e.closest('[lang]').prop('lang');
      }
    }

    if (this.options.dir == null) {
      if ($e.prop('dir')) {
        this.options.dir = $e.prop('dir');
      } else if ($e.closest('[dir]').prop('dir')) {
        this.options.dir = $e.closest('[dir]').prop('dir');
      } else {
        this.options.dir = 'ltr';
      }
    }

    $e.prop('disabled', this.options.disabled);
    $e.prop('multiple', this.options.multiple);

    if ($e.data('select2Tags')) {
      if (this.options.debug && window.console && console.warn) {
        console.warn(
          'Select2: The `data-select2-tags` attribute has been changed to ' +
          'use the `data-data` and `data-tags="true"` attributes and will be ' +
          'removed in future versions of Select2.'
        );
      }

      $e.data('data', $e.data('select2Tags'));
      $e.data('tags', true);
    }

    if ($e.data('ajaxUrl')) {
      if (this.options.debug && window.console && console.warn) {
        console.warn(
          'Select2: The `data-ajax-url` attribute has been changed to ' +
          '`data-ajax--url` and support for the old attribute will be removed' +
          ' in future versions of Select2.'
        );
      }

      $e.attr('ajax--url', $e.data('ajaxUrl'));
      $e.data('ajax--url', $e.data('ajaxUrl'));
    }

    var dataset = {};

    // Prefer the element's `dataset` attribute if it exists
    // jQuery 1.x does not correctly handle data attributes with multiple dashes
    if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
      dataset = $.extend(true, {}, $e[0].dataset, $e.data());
    } else {
      dataset = $e.data();
    }

    var data = $.extend(true, {}, dataset);

    data = Utils._convertData(data);

    for (var key in data) {
      if ($.inArray(key, excludedData) > -1) {
        continue;
      }

      if ($.isPlainObject(this.options[key])) {
        $.extend(this.options[key], data[key]);
      } else {
        this.options[key] = data[key];
      }
    }

    return this;
  };

  Options.prototype.get = function (key) {
    return this.options[key];
  };

  Options.prototype.set = function (key, val) {
    this.options[key] = val;
  };

  return Options;
});

S2.define('select2/core',[
  'jquery',
  './options',
  './utils',
  './keys'
], function ($, Options, Utils, KEYS) {
  var Select2 = function ($element, options) {
    if ($element.data('select2') != null) {
      $element.data('select2').destroy();
    }

    this.$element = $element;

    this.id = this._generateId($element);

    options = options || {};

    this.options = new Options(options, $element);

    Select2.__super__.constructor.call(this);

    // Set up the tabindex

    var tabindex = $element.attr('tabindex') || 0;
    $element.data('old-tabindex', tabindex);
    $element.attr('tabindex', '-1');

    // Set up containers and adapters

    var DataAdapter = this.options.get('dataAdapter');
    this.dataAdapter = new DataAdapter($element, this.options);

    var $container = this.render();

    this._placeContainer($container);

    var SelectionAdapter = this.options.get('selectionAdapter');
    this.selection = new SelectionAdapter($element, this.options);
    this.$selection = this.selection.render();

    this.selection.position(this.$selection, $container);

    var DropdownAdapter = this.options.get('dropdownAdapter');
    this.dropdown = new DropdownAdapter($element, this.options);
    this.$dropdown = this.dropdown.render();

    this.dropdown.position(this.$dropdown, $container);

    var ResultsAdapter = this.options.get('resultsAdapter');
    this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
    this.$results = this.results.render();

    this.results.position(this.$results, this.$dropdown);

    // Bind events

    var self = this;

    // Bind the container to all of the adapters
    this._bindAdapters();

    // Register any DOM event handlers
    this._registerDomEvents();

    // Register any internal event handlers
    this._registerDataEvents();
    this._registerSelectionEvents();
    this._registerDropdownEvents();
    this._registerResultsEvents();
    this._registerEvents();

    // Set the initial state
    this.dataAdapter.current(function (initialData) {
      self.trigger('selection:update', {
        data: initialData
      });
    });

    // Hide the original select
    $element.addClass('select2-hidden-accessible');
    $element.attr('aria-hidden', 'true');

    // Synchronize any monitored attributes
    this._syncAttributes();

    $element.data('select2', this);
  };

  Utils.Extend(Select2, Utils.Observable);

  Select2.prototype._generateId = function ($element) {
    var id = '';

    if ($element.attr('id') != null) {
      id = $element.attr('id');
    } else if ($element.attr('name') != null) {
      id = $element.attr('name') + '-' + Utils.generateChars(2);
    } else {
      id = Utils.generateChars(4);
    }

    id = id.replace(/(:|\.|\[|\]|,)/g, '');
    id = 'select2-' + id;

    return id;
  };

  Select2.prototype._placeContainer = function ($container) {
    $container.insertAfter(this.$element);

    var width = this._resolveWidth(this.$element, this.options.get('width'));

    if (width != null) {
      $container.css('width', width);
    }
  };

  Select2.prototype._resolveWidth = function ($element, method) {
    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;

    if (method == 'resolve') {
      var styleWidth = this._resolveWidth($element, 'style');

      if (styleWidth != null) {
        return styleWidth;
      }

      return this._resolveWidth($element, 'element');
    }

    if (method == 'element') {
      var elementWidth = $element.outerWidth(false);

      if (elementWidth <= 0) {
        return 'auto';
      }

      return elementWidth + 'px';
    }

    if (method == 'style') {
      var style = $element.attr('style');

      if (typeof(style) !== 'string') {
        return null;
      }

      var attrs = style.split(';');

      for (var i = 0, l = attrs.length; i < l; i = i + 1) {
        var attr = attrs[i].replace(/\s/g, '');
        var matches = attr.match(WIDTH);

        if (matches !== null && matches.length >= 1) {
          return matches[1];
        }
      }

      return null;
    }

    return method;
  };

  Select2.prototype._bindAdapters = function () {
    this.dataAdapter.bind(this, this.$container);
    this.selection.bind(this, this.$container);

    this.dropdown.bind(this, this.$container);
    this.results.bind(this, this.$container);
  };

  Select2.prototype._registerDomEvents = function () {
    var self = this;

    this.$element.on('change.select2', function () {
      self.dataAdapter.current(function (data) {
        self.trigger('selection:update', {
          data: data
        });
      });
    });

    this.$element.on('focus.select2', function (evt) {
      self.trigger('focus', evt);
    });

    this._syncA = Utils.bind(this._syncAttributes, this);
    this._syncS = Utils.bind(this._syncSubtree, this);

    if (this.$element[0].attachEvent) {
      this.$element[0].attachEvent('onpropertychange', this._syncA);
    }

    var observer = window.MutationObserver ||
      window.WebKitMutationObserver ||
      window.MozMutationObserver
    ;

    if (observer != null) {
      this._observer = new observer(function (mutations) {
        $.each(mutations, self._syncA);
        $.each(mutations, self._syncS);
      });
      this._observer.observe(this.$element[0], {
        attributes: true,
        childList: true,
        subtree: false
      });
    } else if (this.$element[0].addEventListener) {
      this.$element[0].addEventListener(
        'DOMAttrModified',
        self._syncA,
        false
      );
      this.$element[0].addEventListener(
        'DOMNodeInserted',
        self._syncS,
        false
      );
      this.$element[0].addEventListener(
        'DOMNodeRemoved',
        self._syncS,
        false
      );
    }
  };

  Select2.prototype._registerDataEvents = function () {
    var self = this;

    this.dataAdapter.on('*', function (name, params) {
      self.trigger(name, params);
    });
  };

  Select2.prototype._registerSelectionEvents = function () {
    var self = this;
    var nonRelayEvents = ['toggle', 'focus'];

    this.selection.on('toggle', function () {
      self.toggleDropdown();
    });

    this.selection.on('focus', function (params) {
      self.focus(params);
    });

    this.selection.on('*', function (name, params) {
      if ($.inArray(name, nonRelayEvents) !== -1) {
        return;
      }

      self.trigger(name, params);
    });
  };

  Select2.prototype._registerDropdownEvents = function () {
    var self = this;

    this.dropdown.on('*', function (name, params) {
      self.trigger(name, params);
    });
  };

  Select2.prototype._registerResultsEvents = function () {
    var self = this;

    this.results.on('*', function (name, params) {
      self.trigger(name, params);
    });
  };

  Select2.prototype._registerEvents = function () {
    var self = this;

    this.on('open', function () {
      self.$container.addClass('select2-container--open');
    });

    this.on('close', function () {
      self.$container.removeClass('select2-container--open');
    });

    this.on('enable', function () {
      self.$container.removeClass('select2-container--disabled');
    });

    this.on('disable', function () {
      self.$container.addClass('select2-container--disabled');
    });

    this.on('blur', function () {
      self.$container.removeClass('select2-container--focus');
    });

    this.on('query', function (params) {
      if (!self.isOpen()) {
        self.trigger('open', {});
      }

      this.dataAdapter.query(params, function (data) {
        self.trigger('results:all', {
          data: data,
          query: params
        });
      });
    });

    this.on('query:append', function (params) {
      this.dataAdapter.query(params, function (data) {
        self.trigger('results:append', {
          data: data,
          query: params
        });
      });
    });

    this.on('keypress', function (evt) {
      var key = evt.which;

      if (self.isOpen()) {
        if (key === KEYS.ESC || key === KEYS.TAB ||
            (key === KEYS.UP && evt.altKey)) {
          self.close();

          evt.preventDefault();
        } else if (key === KEYS.ENTER) {
          self.trigger('results:select', {});

          evt.preventDefault();
        } else if ((key === KEYS.SPACE && evt.ctrlKey)) {
          self.trigger('results:toggle', {});

          evt.preventDefault();
        } else if (key === KEYS.UP) {
          self.trigger('results:previous', {});

          evt.preventDefault();
        } else if (key === KEYS.DOWN) {
          self.trigger('results:next', {});

          evt.preventDefault();
        }
      } else {
        if (key === KEYS.ENTER || key === KEYS.SPACE ||
            (key === KEYS.DOWN && evt.altKey)) {
          self.open();

          evt.preventDefault();
        }
      }
    });
  };

  Select2.prototype._syncAttributes = function () {
    this.options.set('disabled', this.$element.prop('disabled'));

    if (this.options.get('disabled')) {
      if (this.isOpen()) {
        this.close();
      }

      this.trigger('disable', {});
    } else {
      this.trigger('enable', {});
    }
  };

  Select2.prototype._syncSubtree = function (evt, mutations) {
    var changed = false;
    var self = this;

    // Ignore any mutation events raised for elements that aren't options or
    // optgroups. This handles the case when the select element is destroyed
    if (
      evt && evt.target && (
        evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
      )
    ) {
      return;
    }

    if (!mutations) {
      // If mutation events aren't supported, then we can only assume that the
      // change affected the selections
      changed = true;
    } else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
      for (var n = 0; n < mutations.addedNodes.length; n++) {
        var node = mutations.addedNodes[n];

        if (node.selected) {
          changed = true;
        }
      }
    } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
      changed = true;
    }

    // Only re-pull the data if we think there is a change
    if (changed) {
      this.dataAdapter.current(function (currentData) {
        self.trigger('selection:update', {
          data: currentData
        });
      });
    }
  };

  /**
   * Override the trigger method to automatically trigger pre-events when
   * there are events that can be prevented.
   */
  Select2.prototype.trigger = function (name, args) {
    var actualTrigger = Select2.__super__.trigger;
    var preTriggerMap = {
      'open': 'opening',
      'close': 'closing',
      'select': 'selecting',
      'unselect': 'unselecting'
    };

    if (args === undefined) {
      args = {};
    }

    if (name in preTriggerMap) {
      var preTriggerName = preTriggerMap[name];
      var preTriggerArgs = {
        prevented: false,
        name: name,
        args: args
      };

      actualTrigger.call(this, preTriggerName, preTriggerArgs);

      if (preTriggerArgs.prevented) {
        args.prevented = true;

        return;
      }
    }

    actualTrigger.call(this, name, args);
  };

  Select2.prototype.toggleDropdown = function () {
    if (this.options.get('disabled')) {
      return;
    }

    if (this.isOpen()) {
      this.close();
    } else {
      this.open();
    }
  };

  Select2.prototype.open = function () {
    if (this.isOpen()) {
      return;
    }

    this.trigger('query', {});
  };

  Select2.prototype.close = function () {
    if (!this.isOpen()) {
      return;
    }

    this.trigger('close', {});
  };

  Select2.prototype.isOpen = function () {
    return this.$container.hasClass('select2-container--open');
  };

  Select2.prototype.hasFocus = function () {
    return this.$container.hasClass('select2-container--focus');
  };

  Select2.prototype.focus = function (data) {
    // No need to re-trigger focus events if we are already focused
    if (this.hasFocus()) {
      return;
    }

    this.$container.addClass('select2-container--focus');
    this.trigger('focus', {});
  };

  Select2.prototype.enable = function (args) {
    if (this.options.get('debug') && window.console && console.warn) {
      console.warn(
        'Select2: The `select2("enable")` method has been deprecated and will' +
        ' be removed in later Select2 versions. Use $element.prop("disabled")' +
        ' instead.'
      );
    }

    if (args == null || args.length === 0) {
      args = [true];
    }

    var disabled = !args[0];

    this.$element.prop('disabled', disabled);
  };

  Select2.prototype.data = function () {
    if (this.options.get('debug') &&
        arguments.length > 0 && window.console && console.warn) {
      console.warn(
        'Select2: Data can no longer be set using `select2("data")`. You ' +
        'should consider setting the value instead using `$element.val()`.'
      );
    }

    var data = [];

    this.dataAdapter.current(function (currentData) {
      data = currentData;
    });

    return data;
  };

  Select2.prototype.val = function (args) {
    if (this.options.get('debug') && window.console && console.warn) {
      console.warn(
        'Select2: The `select2("val")` method has been deprecated and will be' +
        ' removed in later Select2 versions. Use $element.val() instead.'
      );
    }

    if (args == null || args.length === 0) {
      return this.$element.val();
    }

    var newVal = args[0];

    if ($.isArray(newVal)) {
      newVal = $.map(newVal, function (obj) {
        return obj.toString();
      });
    }

    this.$element.val(newVal).trigger('change');
  };

  Select2.prototype.destroy = function () {
    this.$container.remove();

    if (this.$element[0].detachEvent) {
      this.$element[0].detachEvent('onpropertychange', this._syncA);
    }

    if (this._observer != null) {
      this._observer.disconnect();
      this._observer = null;
    } else if (this.$element[0].removeEventListener) {
      this.$element[0]
        .removeEventListener('DOMAttrModified', this._syncA, false);
      this.$element[0]
        .removeEventListener('DOMNodeInserted', this._syncS, false);
      this.$element[0]
        .removeEventListener('DOMNodeRemoved', this._syncS, false);
    }

    this._syncA = null;
    this._syncS = null;

    this.$element.off('.select2');
    this.$element.attr('tabindex', this.$element.data('old-tabindex'));

    this.$element.removeClass('select2-hidden-accessible');
    this.$element.attr('aria-hidden', 'false');
    this.$element.removeData('select2');

    this.dataAdapter.destroy();
    this.selection.destroy();
    this.dropdown.destroy();
    this.results.destroy();

    this.dataAdapter = null;
    this.selection = null;
    this.dropdown = null;
    this.results = null;
  };

  Select2.prototype.render = function () {
    var $container = $(
      '<span class="select2 select2-container">' +
        '<span class="selection"></span>' +
        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
      '</span>'
    );

    $container.attr('dir', this.options.get('dir'));

    this.$container = $container;

    this.$container.addClass('select2-container--' + this.options.get('theme'));

    $container.data('element', this.$element);

    return $container;
  };

  return Select2;
});

S2.define('jquery-mousewheel',[
  'jquery'
], function ($) {
  // Used to shim jQuery.mousewheel for non-full builds.
  return $;
});

S2.define('jquery.select2',[
  'jquery',
  'jquery-mousewheel',

  './select2/core',
  './select2/defaults'
], function ($, _, Select2, Defaults) {
  if ($.fn.select2 == null) {
    // All methods that should return the element
    var thisMethods = ['open', 'close', 'destroy'];

    $.fn.select2 = function (options) {
      options = options || {};

      if (typeof options === 'object') {
        this.each(function () {
          var instanceOptions = $.extend(true, {}, options);

          var instance = new Select2($(this), instanceOptions);
        });

        return this;
      } else if (typeof options === 'string') {
        var ret;
        var args = Array.prototype.slice.call(arguments, 1);

        this.each(function () {
          var instance = $(this).data('select2');

          if (instance == null && window.console && console.error) {
            console.error(
              'The select2(\'' + options + '\') method was called on an ' +
              'element that is not using Select2.'
            );
          }

          ret = instance[options].apply(instance, args);
        });

        // Check if we should be returning `this`
        if ($.inArray(options, thisMethods) > -1) {
          return this;
        }

        return ret;
      } else {
        throw new Error('Invalid arguments for Select2: ' + options);
      }
    };
  }

  if ($.fn.select2.defaults == null) {
    $.fn.select2.defaults = Defaults;
  }

  return Select2;
});

  // Return the AMD loader configuration so it can be used outside of this file
  return {
    define: S2.define,
    require: S2.require
  };
}());

  // Autoload the jQuery bindings
  // We know that all of the modules exist above this, so we're safe
  var select2 = S2.require('jquery.select2');

  // Hold the AMD module references on the jQuery function that was just loaded
  // This allows Select2 to use the internal loader outside of this file, such
  // as in the language files.
  jQuery.fn.select2.amd = S2;

  // Return the Select2 instance for anyone who is importing it.
  return select2;
}));

/*!
 * Bootstrap v3.4.1 (https://getbootstrap.com/)
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under the MIT license
 */

if (typeof jQuery === 'undefined') {
  throw new Error('Bootstrap\'s JavaScript requires jQuery')
}

+function ($) {
  'use strict';
  var version = $.fn.jquery.split(' ')[0].split('.')
  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
  }
}(jQuery);

/* ========================================================================
 * Bootstrap: transition.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#transitions
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
  // ============================================================

  function transitionEnd() {
    var el = document.createElement('bootstrap')

    var transEndEventNames = {
      WebkitTransition : 'webkitTransitionEnd',
      MozTransition    : 'transitionend',
      OTransition      : 'oTransitionEnd otransitionend',
      transition       : 'transitionend'
    }

    for (var name in transEndEventNames) {
      if (el.style[name] !== undefined) {
        return { end: transEndEventNames[name] }
      }
    }

    return false // explicit for ie8 (  ._.)
  }

  // https://blog.alexmaccaw.com/css-transitions
  $.fn.emulateTransitionEnd = function (duration) {
    var called = false
    var $el = this
    $(this).one('bsTransitionEnd', function () { called = true })
    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
    setTimeout(callback, duration)
    return this
  }

  $(function () {
    $.support.transition = transitionEnd()

    if (!$.support.transition) return

    $.event.special.bsTransitionEnd = {
      bindType: $.support.transition.end,
      delegateType: $.support.transition.end,
      handle: function (e) {
        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
      }
    }
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: alert.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#alerts
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // ALERT CLASS DEFINITION
  // ======================

  var dismiss = '[data-dismiss="alert"]'
  var Alert   = function (el) {
    $(el).on('click', dismiss, this.close)
  }

  Alert.VERSION = '3.4.1'

  Alert.TRANSITION_DURATION = 150

  Alert.prototype.close = function (e) {
    var $this    = $(this)
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    selector    = selector === '#' ? [] : selector
    var $parent = $(document).find(selector)

    if (e) e.preventDefault()

    if (!$parent.length) {
      $parent = $this.closest('.alert')
    }

    $parent.trigger(e = $.Event('close.bs.alert'))

    if (e.isDefaultPrevented()) return

    $parent.removeClass('in')

    function removeElement() {
      // detach from parent, fire event then clean up data
      $parent.detach().trigger('closed.bs.alert').remove()
    }

    $.support.transition && $parent.hasClass('fade') ?
      $parent
        .one('bsTransitionEnd', removeElement)
        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
      removeElement()
  }


  // ALERT PLUGIN DEFINITION
  // =======================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.alert')

      if (!data) $this.data('bs.alert', (data = new Alert(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  var old = $.fn.alert

  $.fn.alert             = Plugin
  $.fn.alert.Constructor = Alert


  // ALERT NO CONFLICT
  // =================

  $.fn.alert.noConflict = function () {
    $.fn.alert = old
    return this
  }


  // ALERT DATA-API
  // ==============

  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)

}(jQuery);

/* ========================================================================
 * Bootstrap: button.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#buttons
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // BUTTON PUBLIC CLASS DEFINITION
  // ==============================

  var Button = function (element, options) {
    this.$element  = $(element)
    this.options   = $.extend({}, Button.DEFAULTS, options)
    this.isLoading = false
  }

  Button.VERSION  = '3.4.1'

  Button.DEFAULTS = {
    loadingText: 'loading...'
  }

  Button.prototype.setState = function (state) {
    var d    = 'disabled'
    var $el  = this.$element
    var val  = $el.is('input') ? 'val' : 'html'
    var data = $el.data()

    state += 'Text'

    if (data.resetText == null) $el.data('resetText', $el[val]())

    // push to event loop to allow forms to submit
    setTimeout($.proxy(function () {
      $el[val](data[state] == null ? this.options[state] : data[state])

      if (state == 'loadingText') {
        this.isLoading = true
        $el.addClass(d).attr(d, d).prop(d, true)
      } else if (this.isLoading) {
        this.isLoading = false
        $el.removeClass(d).removeAttr(d).prop(d, false)
      }
    }, this), 0)
  }

  Button.prototype.toggle = function () {
    var changed = true
    var $parent = this.$element.closest('[data-toggle="buttons"]')

    if ($parent.length) {
      var $input = this.$element.find('input')
      if ($input.prop('type') == 'radio') {
        if ($input.prop('checked')) changed = false
        $parent.find('.active').removeClass('active')
        this.$element.addClass('active')
      } else if ($input.prop('type') == 'checkbox') {
        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
        this.$element.toggleClass('active')
      }
      $input.prop('checked', this.$element.hasClass('active'))
      if (changed) $input.trigger('change')
    } else {
      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
      this.$element.toggleClass('active')
    }
  }


  // BUTTON PLUGIN DEFINITION
  // ========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.button')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.button', (data = new Button(this, options)))

      if (option == 'toggle') data.toggle()
      else if (option) data.setState(option)
    })
  }

  var old = $.fn.button

  $.fn.button             = Plugin
  $.fn.button.Constructor = Button


  // BUTTON NO CONFLICT
  // ==================

  $.fn.button.noConflict = function () {
    $.fn.button = old
    return this
  }


  // BUTTON DATA-API
  // ===============

  $(document)
    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
      var $btn = $(e.target).closest('.btn')
      Plugin.call($btn, 'toggle')
      if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
        // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
        e.preventDefault()
        // The target component still receive the focus
        if ($btn.is('input,button')) $btn.trigger('focus')
        else $btn.find('input:visible,button:visible').first().trigger('focus')
      }
    })
    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
    })

}(jQuery);

/* ========================================================================
 * Bootstrap: carousel.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#carousel
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // CAROUSEL CLASS DEFINITION
  // =========================

  var Carousel = function (element, options) {
    this.$element    = $(element)
    this.$indicators = this.$element.find('.carousel-indicators')
    this.options     = options
    this.paused      = null
    this.sliding     = null
    this.interval    = null
    this.$active     = null
    this.$items      = null

    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))

    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
  }

  Carousel.VERSION  = '3.4.1'

  Carousel.TRANSITION_DURATION = 600

  Carousel.DEFAULTS = {
    interval: 5000,
    pause: 'hover',
    wrap: true,
    keyboard: true
  }

  Carousel.prototype.keydown = function (e) {
    if (/input|textarea/i.test(e.target.tagName)) return
    switch (e.which) {
      case 37: this.prev(); break
      case 39: this.next(); break
      default: return
    }

    e.preventDefault()
  }

  Carousel.prototype.cycle = function (e) {
    e || (this.paused = false)

    this.interval && clearInterval(this.interval)

    this.options.interval
      && !this.paused
      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))

    return this
  }

  Carousel.prototype.getItemIndex = function (item) {
    this.$items = item.parent().children('.item')
    return this.$items.index(item || this.$active)
  }

  Carousel.prototype.getItemForDirection = function (direction, active) {
    var activeIndex = this.getItemIndex(active)
    var willWrap = (direction == 'prev' && activeIndex === 0)
                || (direction == 'next' && activeIndex == (this.$items.length - 1))
    if (willWrap && !this.options.wrap) return active
    var delta = direction == 'prev' ? -1 : 1
    var itemIndex = (activeIndex + delta) % this.$items.length
    return this.$items.eq(itemIndex)
  }

  Carousel.prototype.to = function (pos) {
    var that        = this
    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))

    if (pos > (this.$items.length - 1) || pos < 0) return

    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
    if (activeIndex == pos) return this.pause().cycle()

    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
  }

  Carousel.prototype.pause = function (e) {
    e || (this.paused = true)

    if (this.$element.find('.next, .prev').length && $.support.transition) {
      this.$element.trigger($.support.transition.end)
      this.cycle(true)
    }

    this.interval = clearInterval(this.interval)

    return this
  }

  Carousel.prototype.next = function () {
    if (this.sliding) return
    return this.slide('next')
  }

  Carousel.prototype.prev = function () {
    if (this.sliding) return
    return this.slide('prev')
  }

  Carousel.prototype.slide = function (type, next) {
    var $active   = this.$element.find('.item.active')
    var $next     = next || this.getItemForDirection(type, $active)
    var isCycling = this.interval
    var direction = type == 'next' ? 'left' : 'right'
    var that      = this

    if ($next.hasClass('active')) return (this.sliding = false)

    var relatedTarget = $next[0]
    var slideEvent = $.Event('slide.bs.carousel', {
      relatedTarget: relatedTarget,
      direction: direction
    })
    this.$element.trigger(slideEvent)
    if (slideEvent.isDefaultPrevented()) return

    this.sliding = true

    isCycling && this.pause()

    if (this.$indicators.length) {
      this.$indicators.find('.active').removeClass('active')
      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
      $nextIndicator && $nextIndicator.addClass('active')
    }

    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
    if ($.support.transition && this.$element.hasClass('slide')) {
      $next.addClass(type)
      if (typeof $next === 'object' && $next.length) {
        $next[0].offsetWidth // force reflow
      }
      $active.addClass(direction)
      $next.addClass(direction)
      $active
        .one('bsTransitionEnd', function () {
          $next.removeClass([type, direction].join(' ')).addClass('active')
          $active.removeClass(['active', direction].join(' '))
          that.sliding = false
          setTimeout(function () {
            that.$element.trigger(slidEvent)
          }, 0)
        })
        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
    } else {
      $active.removeClass('active')
      $next.addClass('active')
      this.sliding = false
      this.$element.trigger(slidEvent)
    }

    isCycling && this.cycle()

    return this
  }


  // CAROUSEL PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.carousel')
      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
      var action  = typeof option == 'string' ? option : options.slide

      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
      if (typeof option == 'number') data.to(option)
      else if (action) data[action]()
      else if (options.interval) data.pause().cycle()
    })
  }

  var old = $.fn.carousel

  $.fn.carousel             = Plugin
  $.fn.carousel.Constructor = Carousel


  // CAROUSEL NO CONFLICT
  // ====================

  $.fn.carousel.noConflict = function () {
    $.fn.carousel = old
    return this
  }


  // CAROUSEL DATA-API
  // =================

  var clickHandler = function (e) {
    var $this   = $(this)
    var href    = $this.attr('href')
    if (href) {
      href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
    }

    var target  = $this.attr('data-target') || href
    var $target = $(document).find(target)

    if (!$target.hasClass('carousel')) return

    var options = $.extend({}, $target.data(), $this.data())
    var slideIndex = $this.attr('data-slide-to')
    if (slideIndex) options.interval = false

    Plugin.call($target, options)

    if (slideIndex) {
      $target.data('bs.carousel').to(slideIndex)
    }

    e.preventDefault()
  }

  $(document)
    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)

  $(window).on('load', function () {
    $('[data-ride="carousel"]').each(function () {
      var $carousel = $(this)
      Plugin.call($carousel, $carousel.data())
    })
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: collapse.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#collapse
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */

/* jshint latedef: false */

+function ($) {
  'use strict';

  // COLLAPSE PUBLIC CLASS DEFINITION
  // ================================

  var Collapse = function (element, options) {
    this.$element      = $(element)
    this.options       = $.extend({}, Collapse.DEFAULTS, options)
    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
    this.transitioning = null

    if (this.options.parent) {
      this.$parent = this.getParent()
    } else {
      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
    }

    if (this.options.toggle) this.toggle()
  }

  Collapse.VERSION  = '3.4.1'

  Collapse.TRANSITION_DURATION = 350

  Collapse.DEFAULTS = {
    toggle: true
  }

  Collapse.prototype.dimension = function () {
    var hasWidth = this.$element.hasClass('width')
    return hasWidth ? 'width' : 'height'
  }

  Collapse.prototype.show = function () {
    if (this.transitioning || this.$element.hasClass('in')) return

    var activesData
    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')

    if (actives && actives.length) {
      activesData = actives.data('bs.collapse')
      if (activesData && activesData.transitioning) return
    }

    var startEvent = $.Event('show.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    if (actives && actives.length) {
      Plugin.call(actives, 'hide')
      activesData || actives.data('bs.collapse', null)
    }

    var dimension = this.dimension()

    this.$element
      .removeClass('collapse')
      .addClass('collapsing')[dimension](0)
      .attr('aria-expanded', true)

    this.$trigger
      .removeClass('collapsed')
      .attr('aria-expanded', true)

    this.transitioning = 1

    var complete = function () {
      this.$element
        .removeClass('collapsing')
        .addClass('collapse in')[dimension]('')
      this.transitioning = 0
      this.$element
        .trigger('shown.bs.collapse')
    }

    if (!$.support.transition) return complete.call(this)

    var scrollSize = $.camelCase(['scroll', dimension].join('-'))

    this.$element
      .one('bsTransitionEnd', $.proxy(complete, this))
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
  }

  Collapse.prototype.hide = function () {
    if (this.transitioning || !this.$element.hasClass('in')) return

    var startEvent = $.Event('hide.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    var dimension = this.dimension()

    this.$element[dimension](this.$element[dimension]())[0].offsetHeight

    this.$element
      .addClass('collapsing')
      .removeClass('collapse in')
      .attr('aria-expanded', false)

    this.$trigger
      .addClass('collapsed')
      .attr('aria-expanded', false)

    this.transitioning = 1

    var complete = function () {
      this.transitioning = 0
      this.$element
        .removeClass('collapsing')
        .addClass('collapse')
        .trigger('hidden.bs.collapse')
    }

    if (!$.support.transition) return complete.call(this)

    this.$element
      [dimension](0)
      .one('bsTransitionEnd', $.proxy(complete, this))
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
  }

  Collapse.prototype.toggle = function () {
    this[this.$element.hasClass('in') ? 'hide' : 'show']()
  }

  Collapse.prototype.getParent = function () {
    return $(document).find(this.options.parent)
      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
      .each($.proxy(function (i, element) {
        var $element = $(element)
        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
      }, this))
      .end()
  }

  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
    var isOpen = $element.hasClass('in')

    $element.attr('aria-expanded', isOpen)
    $trigger
      .toggleClass('collapsed', !isOpen)
      .attr('aria-expanded', isOpen)
  }

  function getTargetFromTrigger($trigger) {
    var href
    var target = $trigger.attr('data-target')
      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7

    return $(document).find(target)
  }


  // COLLAPSE PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.collapse')
      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)

      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.collapse

  $.fn.collapse             = Plugin
  $.fn.collapse.Constructor = Collapse


  // COLLAPSE NO CONFLICT
  // ====================

  $.fn.collapse.noConflict = function () {
    $.fn.collapse = old
    return this
  }


  // COLLAPSE DATA-API
  // =================

  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
    var $this   = $(this)

    if (!$this.attr('data-target')) e.preventDefault()

    var $target = getTargetFromTrigger($this)
    var data    = $target.data('bs.collapse')
    var option  = data ? 'toggle' : $this.data()

    Plugin.call($target, option)
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: dropdown.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#dropdowns
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // DROPDOWN CLASS DEFINITION
  // =========================

  var backdrop = '.dropdown-backdrop'
  var toggle   = '[data-toggle="dropdown"]'
  var Dropdown = function (element) {
    $(element).on('click.bs.dropdown', this.toggle)
  }

  Dropdown.VERSION = '3.4.1'

  function getParent($this) {
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    var $parent = selector !== '#' ? $(document).find(selector) : null

    return $parent && $parent.length ? $parent : $this.parent()
  }

  function clearMenus(e) {
    if (e && e.which === 3) return
    $(backdrop).remove()
    $(toggle).each(function () {
      var $this         = $(this)
      var $parent       = getParent($this)
      var relatedTarget = { relatedTarget: this }

      if (!$parent.hasClass('open')) return

      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return

      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))

      if (e.isDefaultPrevented()) return

      $this.attr('aria-expanded', 'false')
      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
    })
  }

  Dropdown.prototype.toggle = function (e) {
    var $this = $(this)

    if ($this.is('.disabled, :disabled')) return

    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')

    clearMenus()

    if (!isActive) {
      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
        // if mobile we use a backdrop because click events don't delegate
        $(document.createElement('div'))
          .addClass('dropdown-backdrop')
          .insertAfter($(this))
          .on('click', clearMenus)
      }

      var relatedTarget = { relatedTarget: this }
      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))

      if (e.isDefaultPrevented()) return

      $this
        .trigger('focus')
        .attr('aria-expanded', 'true')

      $parent
        .toggleClass('open')
        .trigger($.Event('shown.bs.dropdown', relatedTarget))
    }

    return false
  }

  Dropdown.prototype.keydown = function (e) {
    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return

    var $this = $(this)

    e.preventDefault()
    e.stopPropagation()

    if ($this.is('.disabled, :disabled')) return

    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')

    if (!isActive && e.which != 27 || isActive && e.which == 27) {
      if (e.which == 27) $parent.find(toggle).trigger('focus')
      return $this.trigger('click')
    }

    var desc = ' li:not(.disabled):visible a'
    var $items = $parent.find('.dropdown-menu' + desc)

    if (!$items.length) return

    var index = $items.index(e.target)

    if (e.which == 38 && index > 0)                 index--         // up
    if (e.which == 40 && index < $items.length - 1) index++         // down
    if (!~index)                                    index = 0

    $items.eq(index).trigger('focus')
  }


  // DROPDOWN PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.dropdown')

      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  var old = $.fn.dropdown

  $.fn.dropdown             = Plugin
  $.fn.dropdown.Constructor = Dropdown


  // DROPDOWN NO CONFLICT
  // ====================

  $.fn.dropdown.noConflict = function () {
    $.fn.dropdown = old
    return this
  }


  // APPLY TO STANDARD DROPDOWN ELEMENTS
  // ===================================

  $(document)
    .on('click.bs.dropdown.data-api', clearMenus)
    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)

}(jQuery);

/* ========================================================================
 * Bootstrap: modal.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#modals
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // MODAL CLASS DEFINITION
  // ======================

  var Modal = function (element, options) {
    this.options = options
    this.$body = $(document.body)
    this.$element = $(element)
    this.$dialog = this.$element.find('.modal-dialog')
    this.$backdrop = null
    this.isShown = null
    this.originalBodyPad = null
    this.scrollbarWidth = 0
    this.ignoreBackdropClick = false
    this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'

    if (this.options.remote) {
      this.$element
        .find('.modal-content')
        .load(this.options.remote, $.proxy(function () {
          this.$element.trigger('loaded.bs.modal')
        }, this))
    }
  }

  Modal.VERSION = '3.4.1'

  Modal.TRANSITION_DURATION = 300
  Modal.BACKDROP_TRANSITION_DURATION = 150

  Modal.DEFAULTS = {
    backdrop: true,
    keyboard: true,
    show: true
  }

  Modal.prototype.toggle = function (_relatedTarget) {
    return this.isShown ? this.hide() : this.show(_relatedTarget)
  }

  Modal.prototype.show = function (_relatedTarget) {
    var that = this
    var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })

    this.$element.trigger(e)

    if (this.isShown || e.isDefaultPrevented()) return

    this.isShown = true

    this.checkScrollbar()
    this.setScrollbar()
    this.$body.addClass('modal-open')

    this.escape()
    this.resize()

    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))

    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
      })
    })

    this.backdrop(function () {
      var transition = $.support.transition && that.$element.hasClass('fade')

      if (!that.$element.parent().length) {
        that.$element.appendTo(that.$body) // don't move modals dom position
      }

      that.$element
        .show()
        .scrollTop(0)

      that.adjustDialog()

      if (transition) {
        that.$element[0].offsetWidth // force reflow
      }

      that.$element.addClass('in')

      that.enforceFocus()

      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })

      transition ?
        that.$dialog // wait for modal to slide in
          .one('bsTransitionEnd', function () {
            that.$element.trigger('focus').trigger(e)
          })
          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
        that.$element.trigger('focus').trigger(e)
    })
  }

  Modal.prototype.hide = function (e) {
    if (e) e.preventDefault()

    e = $.Event('hide.bs.modal')

    this.$element.trigger(e)

    if (!this.isShown || e.isDefaultPrevented()) return

    this.isShown = false

    this.escape()
    this.resize()

    $(document).off('focusin.bs.modal')

    this.$element
      .removeClass('in')
      .off('click.dismiss.bs.modal')
      .off('mouseup.dismiss.bs.modal')

    this.$dialog.off('mousedown.dismiss.bs.modal')

    $.support.transition && this.$element.hasClass('fade') ?
      this.$element
        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
      this.hideModal()
  }

  Modal.prototype.enforceFocus = function () {
    $(document)
      .off('focusin.bs.modal') // guard against infinite focus loop
      .on('focusin.bs.modal', $.proxy(function (e) {
        if (document !== e.target &&
          this.$element[0] !== e.target &&
          !this.$element.has(e.target).length) {
          this.$element.trigger('focus')
        }
      }, this))
  }

  Modal.prototype.escape = function () {
    if (this.isShown && this.options.keyboard) {
      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
        e.which == 27 && this.hide()
      }, this))
    } else if (!this.isShown) {
      this.$element.off('keydown.dismiss.bs.modal')
    }
  }

  Modal.prototype.resize = function () {
    if (this.isShown) {
      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
    } else {
      $(window).off('resize.bs.modal')
    }
  }

  Modal.prototype.hideModal = function () {
    var that = this
    this.$element.hide()
    this.backdrop(function () {
      that.$body.removeClass('modal-open')
      that.resetAdjustments()
      that.resetScrollbar()
      that.$element.trigger('hidden.bs.modal')
    })
  }

  Modal.prototype.removeBackdrop = function () {
    this.$backdrop && this.$backdrop.remove()
    this.$backdrop = null
  }

  Modal.prototype.backdrop = function (callback) {
    var that = this
    var animate = this.$element.hasClass('fade') ? 'fade' : ''

    if (this.isShown && this.options.backdrop) {
      var doAnimate = $.support.transition && animate

      this.$backdrop = $(document.createElement('div'))
        .addClass('modal-backdrop ' + animate)
        .appendTo(this.$body)

      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
        if (this.ignoreBackdropClick) {
          this.ignoreBackdropClick = false
          return
        }
        if (e.target !== e.currentTarget) return
        this.options.backdrop == 'static'
          ? this.$element[0].focus()
          : this.hide()
      }, this))

      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow

      this.$backdrop.addClass('in')

      if (!callback) return

      doAnimate ?
        this.$backdrop
          .one('bsTransitionEnd', callback)
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
        callback()

    } else if (!this.isShown && this.$backdrop) {
      this.$backdrop.removeClass('in')

      var callbackRemove = function () {
        that.removeBackdrop()
        callback && callback()
      }
      $.support.transition && this.$element.hasClass('fade') ?
        this.$backdrop
          .one('bsTransitionEnd', callbackRemove)
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
        callbackRemove()

    } else if (callback) {
      callback()
    }
  }

  // these following methods are used to handle overflowing modals

  Modal.prototype.handleUpdate = function () {
    this.adjustDialog()
  }

  Modal.prototype.adjustDialog = function () {
    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight

    this.$element.css({
      paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
    })
  }

  Modal.prototype.resetAdjustments = function () {
    this.$element.css({
      paddingLeft: '',
      paddingRight: ''
    })
  }

  Modal.prototype.checkScrollbar = function () {
    var fullWindowWidth = window.innerWidth
    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
      var documentElementRect = document.documentElement.getBoundingClientRect()
      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
    }
    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
    this.scrollbarWidth = this.measureScrollbar()
  }

  Modal.prototype.setScrollbar = function () {
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
    this.originalBodyPad = document.body.style.paddingRight || ''
    var scrollbarWidth = this.scrollbarWidth
    if (this.bodyIsOverflowing) {
      this.$body.css('padding-right', bodyPad + scrollbarWidth)
      $(this.fixedContent).each(function (index, element) {
        var actualPadding = element.style.paddingRight
        var calculatedPadding = $(element).css('padding-right')
        $(element)
          .data('padding-right', actualPadding)
          .css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
      })
    }
  }

  Modal.prototype.resetScrollbar = function () {
    this.$body.css('padding-right', this.originalBodyPad)
    $(this.fixedContent).each(function (index, element) {
      var padding = $(element).data('padding-right')
      $(element).removeData('padding-right')
      element.style.paddingRight = padding ? padding : ''
    })
  }

  Modal.prototype.measureScrollbar = function () { // thx walsh
    var scrollDiv = document.createElement('div')
    scrollDiv.className = 'modal-scrollbar-measure'
    this.$body.append(scrollDiv)
    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
    this.$body[0].removeChild(scrollDiv)
    return scrollbarWidth
  }


  // MODAL PLUGIN DEFINITION
  // =======================

  function Plugin(option, _relatedTarget) {
    return this.each(function () {
      var $this = $(this)
      var data = $this.data('bs.modal')
      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)

      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
      if (typeof option == 'string') data[option](_relatedTarget)
      else if (options.show) data.show(_relatedTarget)
    })
  }

  var old = $.fn.modal

  $.fn.modal = Plugin
  $.fn.modal.Constructor = Modal


  // MODAL NO CONFLICT
  // =================

  $.fn.modal.noConflict = function () {
    $.fn.modal = old
    return this
  }


  // MODAL DATA-API
  // ==============

  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
    var $this = $(this)
    var href = $this.attr('href')
    var target = $this.attr('data-target') ||
      (href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7

    var $target = $(document).find(target)
    var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())

    if ($this.is('a')) e.preventDefault()

    $target.one('show.bs.modal', function (showEvent) {
      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
      $target.one('hidden.bs.modal', function () {
        $this.is(':visible') && $this.trigger('focus')
      })
    })
    Plugin.call($target, option, this)
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: tooltip.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#tooltip
 * Inspired by the original jQuery.tipsy by Jason Frame
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */

+function ($) {
  'use strict';

  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']

  var uriAttrs = [
    'background',
    'cite',
    'href',
    'itemtype',
    'longdesc',
    'poster',
    'src',
    'xlink:href'
  ]

  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i

  var DefaultWhitelist = {
    // Global attributes allowed on any supplied element below.
    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
    a: ['target', 'href', 'title', 'rel'],
    area: [],
    b: [],
    br: [],
    col: [],
    code: [],
    div: [],
    em: [],
    hr: [],
    h1: [],
    h2: [],
    h3: [],
    h4: [],
    h5: [],
    h6: [],
    i: [],
    img: ['src', 'alt', 'title', 'width', 'height'],
    li: [],
    ol: [],
    p: [],
    pre: [],
    s: [],
    small: [],
    span: [],
    sub: [],
    sup: [],
    strong: [],
    u: [],
    ul: []
  }

  /**
   * A pattern that recognizes a commonly useful subset of URLs that are safe.
   *
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
   */
  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi

  /**
   * A pattern that matches safe data URLs. Only matches image, video and audio types.
   *
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
   */
  var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i

  function allowedAttribute(attr, allowedAttributeList) {
    var attrName = attr.nodeName.toLowerCase()

    if ($.inArray(attrName, allowedAttributeList) !== -1) {
      if ($.inArray(attrName, uriAttrs) !== -1) {
        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
      }

      return true
    }

    var regExp = $(allowedAttributeList).filter(function (index, value) {
      return value instanceof RegExp
    })

    // Check if a regular expression validates the attribute.
    for (var i = 0, l = regExp.length; i < l; i++) {
      if (attrName.match(regExp[i])) {
        return true
      }
    }

    return false
  }

  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
    if (unsafeHtml.length === 0) {
      return unsafeHtml
    }

    if (sanitizeFn && typeof sanitizeFn === 'function') {
      return sanitizeFn(unsafeHtml)
    }

    // IE 8 and below don't support createHTMLDocument
    if (!document.implementation || !document.implementation.createHTMLDocument) {
      return unsafeHtml
    }

    var createdDocument = document.implementation.createHTMLDocument('sanitization')
    createdDocument.body.innerHTML = unsafeHtml

    var whitelistKeys = $.map(whiteList, function (el, i) { return i })
    var elements = $(createdDocument.body).find('*')

    for (var i = 0, len = elements.length; i < len; i++) {
      var el = elements[i]
      var elName = el.nodeName.toLowerCase()

      if ($.inArray(elName, whitelistKeys) === -1) {
        el.parentNode.removeChild(el)

        continue
      }

      var attributeList = $.map(el.attributes, function (el) { return el })
      var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])

      for (var j = 0, len2 = attributeList.length; j < len2; j++) {
        if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
          el.removeAttribute(attributeList[j].nodeName)
        }
      }
    }

    return createdDocument.body.innerHTML
  }

  // TOOLTIP PUBLIC CLASS DEFINITION
  // ===============================

  var Tooltip = function (element, options) {
    this.type       = null
    this.options    = null
    this.enabled    = null
    this.timeout    = null
    this.hoverState = null
    this.$element   = null
    this.inState    = null

    this.init('tooltip', element, options)
  }

  Tooltip.VERSION  = '3.4.1'

  Tooltip.TRANSITION_DURATION = 150

  Tooltip.DEFAULTS = {
    animation: true,
    placement: 'top',
    selector: false,
    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
    trigger: 'hover focus',
    title: '',
    delay: 0,
    html: false,
    container: false,
    viewport: {
      selector: 'body',
      padding: 0
    },
    sanitize : true,
    sanitizeFn : null,
    whiteList : DefaultWhitelist
  }

  Tooltip.prototype.init = function (type, element, options) {
    this.enabled   = true
    this.type      = type
    this.$element  = $(element)
    this.options   = this.getOptions(options)
    this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
    this.inState   = { click: false, hover: false, focus: false }

    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
    }

    var triggers = this.options.trigger.split(' ')

    for (var i = triggers.length; i--;) {
      var trigger = triggers[i]

      if (trigger == 'click') {
        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
      } else if (trigger != 'manual') {
        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'

        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
      }
    }

    this.options.selector ?
      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
      this.fixTitle()
  }

  Tooltip.prototype.getDefaults = function () {
    return Tooltip.DEFAULTS
  }

  Tooltip.prototype.getOptions = function (options) {
    var dataAttributes = this.$element.data()

    for (var dataAttr in dataAttributes) {
      if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
        delete dataAttributes[dataAttr]
      }
    }

    options = $.extend({}, this.getDefaults(), dataAttributes, options)

    if (options.delay && typeof options.delay == 'number') {
      options.delay = {
        show: options.delay,
        hide: options.delay
      }
    }

    if (options.sanitize) {
      options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
    }

    return options
  }

  Tooltip.prototype.getDelegateOptions = function () {
    var options  = {}
    var defaults = this.getDefaults()

    this._options && $.each(this._options, function (key, value) {
      if (defaults[key] != value) options[key] = value
    })

    return options
  }

  Tooltip.prototype.enter = function (obj) {
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget).data('bs.' + this.type)

    if (!self) {
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
      $(obj.currentTarget).data('bs.' + this.type, self)
    }

    if (obj instanceof $.Event) {
      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
    }

    if (self.tip().hasClass('in') || self.hoverState == 'in') {
      self.hoverState = 'in'
      return
    }

    clearTimeout(self.timeout)

    self.hoverState = 'in'

    if (!self.options.delay || !self.options.delay.show) return self.show()

    self.timeout = setTimeout(function () {
      if (self.hoverState == 'in') self.show()
    }, self.options.delay.show)
  }

  Tooltip.prototype.isInStateTrue = function () {
    for (var key in this.inState) {
      if (this.inState[key]) return true
    }

    return false
  }

  Tooltip.prototype.leave = function (obj) {
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget).data('bs.' + this.type)

    if (!self) {
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
      $(obj.currentTarget).data('bs.' + this.type, self)
    }

    if (obj instanceof $.Event) {
      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
    }

    if (self.isInStateTrue()) return

    clearTimeout(self.timeout)

    self.hoverState = 'out'

    if (!self.options.delay || !self.options.delay.hide) return self.hide()

    self.timeout = setTimeout(function () {
      if (self.hoverState == 'out') self.hide()
    }, self.options.delay.hide)
  }

  Tooltip.prototype.show = function () {
    var e = $.Event('show.bs.' + this.type)

    if (this.hasContent() && this.enabled) {
      this.$element.trigger(e)

      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
      if (e.isDefaultPrevented() || !inDom) return
      var that = this

      var $tip = this.tip()

      var tipId = this.getUID(this.type)

      this.setContent()
      $tip.attr('id', tipId)
      this.$element.attr('aria-describedby', tipId)

      if (this.options.animation) $tip.addClass('fade')

      var placement = typeof this.options.placement == 'function' ?
        this.options.placement.call(this, $tip[0], this.$element[0]) :
        this.options.placement

      var autoToken = /\s?auto?\s?/i
      var autoPlace = autoToken.test(placement)
      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'

      $tip
        .detach()
        .css({ top: 0, left: 0, display: 'block' })
        .addClass(placement)
        .data('bs.' + this.type, this)

      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
      this.$element.trigger('inserted.bs.' + this.type)

      var pos          = this.getPosition()
      var actualWidth  = $tip[0].offsetWidth
      var actualHeight = $tip[0].offsetHeight

      if (autoPlace) {
        var orgPlacement = placement
        var viewportDim = this.getPosition(this.$viewport)

        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
                    placement

        $tip
          .removeClass(orgPlacement)
          .addClass(placement)
      }

      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)

      this.applyPlacement(calculatedOffset, placement)

      var complete = function () {
        var prevHoverState = that.hoverState
        that.$element.trigger('shown.bs.' + that.type)
        that.hoverState = null

        if (prevHoverState == 'out') that.leave(that)
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        $tip
          .one('bsTransitionEnd', complete)
          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
        complete()
    }
  }

  Tooltip.prototype.applyPlacement = function (offset, placement) {
    var $tip   = this.tip()
    var width  = $tip[0].offsetWidth
    var height = $tip[0].offsetHeight

    // manually read margins because getBoundingClientRect includes difference
    var marginTop = parseInt($tip.css('margin-top'), 10)
    var marginLeft = parseInt($tip.css('margin-left'), 10)

    // we must check for NaN for ie 8/9
    if (isNaN(marginTop))  marginTop  = 0
    if (isNaN(marginLeft)) marginLeft = 0

    offset.top  += marginTop
    offset.left += marginLeft

    // $.fn.offset doesn't round pixel values
    // so we use setOffset directly with our own function B-0
    $.offset.setOffset($tip[0], $.extend({
      using: function (props) {
        $tip.css({
          top: Math.round(props.top),
          left: Math.round(props.left)
        })
      }
    }, offset), 0)

    $tip.addClass('in')

    // check to see if placing tip in new offset caused the tip to resize itself
    var actualWidth  = $tip[0].offsetWidth
    var actualHeight = $tip[0].offsetHeight

    if (placement == 'top' && actualHeight != height) {
      offset.top = offset.top + height - actualHeight
    }

    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)

    if (delta.left) offset.left += delta.left
    else offset.top += delta.top

    var isVertical          = /top|bottom/.test(placement)
    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'

    $tip.offset(offset)
    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
  }

  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
    this.arrow()
      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
      .css(isVertical ? 'top' : 'left', '')
  }

  Tooltip.prototype.setContent = function () {
    var $tip  = this.tip()
    var title = this.getTitle()

    if (this.options.html) {
      if (this.options.sanitize) {
        title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
      }

      $tip.find('.tooltip-inner').html(title)
    } else {
      $tip.find('.tooltip-inner').text(title)
    }

    $tip.removeClass('fade in top bottom left right')
  }

  Tooltip.prototype.hide = function (callback) {
    var that = this
    var $tip = $(this.$tip)
    var e    = $.Event('hide.bs.' + this.type)

    function complete() {
      if (that.hoverState != 'in') $tip.detach()
      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
        that.$element
          .removeAttr('aria-describedby')
          .trigger('hidden.bs.' + that.type)
      }
      callback && callback()
    }

    this.$element.trigger(e)

    if (e.isDefaultPrevented()) return

    $tip.removeClass('in')

    $.support.transition && $tip.hasClass('fade') ?
      $tip
        .one('bsTransitionEnd', complete)
        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
      complete()

    this.hoverState = null

    return this
  }

  Tooltip.prototype.fixTitle = function () {
    var $e = this.$element
    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
    }
  }

  Tooltip.prototype.hasContent = function () {
    return this.getTitle()
  }

  Tooltip.prototype.getPosition = function ($element) {
    $element   = $element || this.$element

    var el     = $element[0]
    var isBody = el.tagName == 'BODY'

    var elRect    = el.getBoundingClientRect()
    if (elRect.width == null) {
      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
    }
    var isSvg = window.SVGElement && el instanceof window.SVGElement
    // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
    // See https://github.com/twbs/bootstrap/issues/20280
    var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null

    return $.extend({}, elRect, scroll, outerDims, elOffset)
  }

  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }

  }

  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
    var delta = { top: 0, left: 0 }
    if (!this.$viewport) return delta

    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
    var viewportDimensions = this.getPosition(this.$viewport)

    if (/right|left/.test(placement)) {
      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
      if (topEdgeOffset < viewportDimensions.top) { // top overflow
        delta.top = viewportDimensions.top - topEdgeOffset
      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
      }
    } else {
      var leftEdgeOffset  = pos.left - viewportPadding
      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
        delta.left = viewportDimensions.left - leftEdgeOffset
      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
      }
    }

    return delta
  }

  Tooltip.prototype.getTitle = function () {
    var title
    var $e = this.$element
    var o  = this.options

    title = $e.attr('data-original-title')
      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)

    return title
  }

  Tooltip.prototype.getUID = function (prefix) {
    do prefix += ~~(Math.random() * 1000000)
    while (document.getElementById(prefix))
    return prefix
  }

  Tooltip.prototype.tip = function () {
    if (!this.$tip) {
      this.$tip = $(this.options.template)
      if (this.$tip.length != 1) {
        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
      }
    }
    return this.$tip
  }

  Tooltip.prototype.arrow = function () {
    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
  }

  Tooltip.prototype.enable = function () {
    this.enabled = true
  }

  Tooltip.prototype.disable = function () {
    this.enabled = false
  }

  Tooltip.prototype.toggleEnabled = function () {
    this.enabled = !this.enabled
  }

  Tooltip.prototype.toggle = function (e) {
    var self = this
    if (e) {
      self = $(e.currentTarget).data('bs.' + this.type)
      if (!self) {
        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
        $(e.currentTarget).data('bs.' + this.type, self)
      }
    }

    if (e) {
      self.inState.click = !self.inState.click
      if (self.isInStateTrue()) self.enter(self)
      else self.leave(self)
    } else {
      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
    }
  }

  Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
      if (that.$tip) {
        that.$tip.detach()
      }
      that.$tip = null
      that.$arrow = null
      that.$viewport = null
      that.$element = null
    })
  }

  Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
    return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
  }

  // TOOLTIP PLUGIN DEFINITION
  // =========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.tooltip')
      var options = typeof option == 'object' && option

      if (!data && /destroy|hide/.test(option)) return
      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.tooltip

  $.fn.tooltip             = Plugin
  $.fn.tooltip.Constructor = Tooltip


  // TOOLTIP NO CONFLICT
  // ===================

  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
    return this
  }

}(jQuery);

/* ========================================================================
 * Bootstrap: popover.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#popovers
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // POPOVER PUBLIC CLASS DEFINITION
  // ===============================

  var Popover = function (element, options) {
    this.init('popover', element, options)
  }

  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')

  Popover.VERSION  = '3.4.1'

  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
    placement: 'right',
    trigger: 'click',
    content: '',
    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
  })


  // NOTE: POPOVER EXTENDS tooltip.js
  // ================================

  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)

  Popover.prototype.constructor = Popover

  Popover.prototype.getDefaults = function () {
    return Popover.DEFAULTS
  }

  Popover.prototype.setContent = function () {
    var $tip    = this.tip()
    var title   = this.getTitle()
    var content = this.getContent()

    if (this.options.html) {
      var typeContent = typeof content

      if (this.options.sanitize) {
        title = this.sanitizeHtml(title)

        if (typeContent === 'string') {
          content = this.sanitizeHtml(content)
        }
      }

      $tip.find('.popover-title').html(title)
      $tip.find('.popover-content').children().detach().end()[
        typeContent === 'string' ? 'html' : 'append'
      ](content)
    } else {
      $tip.find('.popover-title').text(title)
      $tip.find('.popover-content').children().detach().end().text(content)
    }

    $tip.removeClass('fade top bottom left right in')

    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
    // this manually by checking the contents.
    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
  }

  Popover.prototype.hasContent = function () {
    return this.getTitle() || this.getContent()
  }

  Popover.prototype.getContent = function () {
    var $e = this.$element
    var o  = this.options

    return $e.attr('data-content')
      || (typeof o.content == 'function' ?
        o.content.call($e[0]) :
        o.content)
  }

  Popover.prototype.arrow = function () {
    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
  }


  // POPOVER PLUGIN DEFINITION
  // =========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.popover')
      var options = typeof option == 'object' && option

      if (!data && /destroy|hide/.test(option)) return
      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.popover

  $.fn.popover             = Plugin
  $.fn.popover.Constructor = Popover


  // POPOVER NO CONFLICT
  // ===================

  $.fn.popover.noConflict = function () {
    $.fn.popover = old
    return this
  }

}(jQuery);

/* ========================================================================
 * Bootstrap: scrollspy.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#scrollspy
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // SCROLLSPY CLASS DEFINITION
  // ==========================

  function ScrollSpy(element, options) {
    this.$body          = $(document.body)
    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
    this.selector       = (this.options.target || '') + ' .nav li > a'
    this.offsets        = []
    this.targets        = []
    this.activeTarget   = null
    this.scrollHeight   = 0

    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
    this.refresh()
    this.process()
  }

  ScrollSpy.VERSION  = '3.4.1'

  ScrollSpy.DEFAULTS = {
    offset: 10
  }

  ScrollSpy.prototype.getScrollHeight = function () {
    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
  }

  ScrollSpy.prototype.refresh = function () {
    var that          = this
    var offsetMethod  = 'offset'
    var offsetBase    = 0

    this.offsets      = []
    this.targets      = []
    this.scrollHeight = this.getScrollHeight()

    if (!$.isWindow(this.$scrollElement[0])) {
      offsetMethod = 'position'
      offsetBase   = this.$scrollElement.scrollTop()
    }

    this.$body
      .find(this.selector)
      .map(function () {
        var $el   = $(this)
        var href  = $el.data('target') || $el.attr('href')
        var $href = /^#./.test(href) && $(href)

        return ($href
          && $href.length
          && $href.is(':visible')
          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
      })
      .sort(function (a, b) { return a[0] - b[0] })
      .each(function () {
        that.offsets.push(this[0])
        that.targets.push(this[1])
      })
  }

  ScrollSpy.prototype.process = function () {
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
    var scrollHeight = this.getScrollHeight()
    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
    var offsets      = this.offsets
    var targets      = this.targets
    var activeTarget = this.activeTarget
    var i

    if (this.scrollHeight != scrollHeight) {
      this.refresh()
    }

    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
    }

    if (activeTarget && scrollTop < offsets[0]) {
      this.activeTarget = null
      return this.clear()
    }

    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
        && this.activate(targets[i])
    }
  }

  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target

    this.clear()

    var selector = this.selector +
      '[data-target="' + target + '"],' +
      this.selector + '[href="' + target + '"]'

    var active = $(selector)
      .parents('li')
      .addClass('active')

    if (active.parent('.dropdown-menu').length) {
      active = active
        .closest('li.dropdown')
        .addClass('active')
    }

    active.trigger('activate.bs.scrollspy')
  }

  ScrollSpy.prototype.clear = function () {
    $(this.selector)
      .parentsUntil(this.options.target, '.active')
      .removeClass('active')
  }


  // SCROLLSPY PLUGIN DEFINITION
  // ===========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.scrollspy')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.scrollspy

  $.fn.scrollspy             = Plugin
  $.fn.scrollspy.Constructor = ScrollSpy


  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
  }


  // SCROLLSPY DATA-API
  // ==================

  $(window).on('load.bs.scrollspy.data-api', function () {
    $('[data-spy="scroll"]').each(function () {
      var $spy = $(this)
      Plugin.call($spy, $spy.data())
    })
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: tab.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#tabs
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // TAB CLASS DEFINITION
  // ====================

  var Tab = function (element) {
    // jscs:disable requireDollarBeforejQueryAssignment
    this.element = $(element)
    // jscs:enable requireDollarBeforejQueryAssignment
  }

  Tab.VERSION = '3.4.1'

  Tab.TRANSITION_DURATION = 150

  Tab.prototype.show = function () {
    var $this    = this.element
    var $ul      = $this.closest('ul:not(.dropdown-menu)')
    var selector = $this.data('target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    if ($this.parent('li').hasClass('active')) return

    var $previous = $ul.find('.active:last a')
    var hideEvent = $.Event('hide.bs.tab', {
      relatedTarget: $this[0]
    })
    var showEvent = $.Event('show.bs.tab', {
      relatedTarget: $previous[0]
    })

    $previous.trigger(hideEvent)
    $this.trigger(showEvent)

    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return

    var $target = $(document).find(selector)

    this.activate($this.closest('li'), $ul)
    this.activate($target, $target.parent(), function () {
      $previous.trigger({
        type: 'hidden.bs.tab',
        relatedTarget: $this[0]
      })
      $this.trigger({
        type: 'shown.bs.tab',
        relatedTarget: $previous[0]
      })
    })
  }

  Tab.prototype.activate = function (element, container, callback) {
    var $active    = container.find('> .active')
    var transition = callback
      && $.support.transition
      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)

    function next() {
      $active
        .removeClass('active')
        .find('> .dropdown-menu > .active')
        .removeClass('active')
        .end()
        .find('[data-toggle="tab"]')
        .attr('aria-expanded', false)

      element
        .addClass('active')
        .find('[data-toggle="tab"]')
        .attr('aria-expanded', true)

      if (transition) {
        element[0].offsetWidth // reflow for transition
        element.addClass('in')
      } else {
        element.removeClass('fade')
      }

      if (element.parent('.dropdown-menu').length) {
        element
          .closest('li.dropdown')
          .addClass('active')
          .end()
          .find('[data-toggle="tab"]')
          .attr('aria-expanded', true)
      }

      callback && callback()
    }

    $active.length && transition ?
      $active
        .one('bsTransitionEnd', next)
        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
      next()

    $active.removeClass('in')
  }


  // TAB PLUGIN DEFINITION
  // =====================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.tab')

      if (!data) $this.data('bs.tab', (data = new Tab(this)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.tab

  $.fn.tab             = Plugin
  $.fn.tab.Constructor = Tab


  // TAB NO CONFLICT
  // ===============

  $.fn.tab.noConflict = function () {
    $.fn.tab = old
    return this
  }


  // TAB DATA-API
  // ============

  var clickHandler = function (e) {
    e.preventDefault()
    Plugin.call($(this), 'show')
  }

  $(document)
    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)

}(jQuery);

/* ========================================================================
 * Bootstrap: affix.js v3.4.1
 * https://getbootstrap.com/docs/3.4/javascript/#affix
 * ========================================================================
 * Copyright 2011-2019 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // AFFIX CLASS DEFINITION
  // ======================

  var Affix = function (element, options) {
    this.options = $.extend({}, Affix.DEFAULTS, options)

    var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)

    this.$target = target
      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))

    this.$element     = $(element)
    this.affixed      = null
    this.unpin        = null
    this.pinnedOffset = null

    this.checkPosition()
  }

  Affix.VERSION  = '3.4.1'

  Affix.RESET    = 'affix affix-top affix-bottom'

  Affix.DEFAULTS = {
    offset: 0,
    target: window
  }

  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
    var scrollTop    = this.$target.scrollTop()
    var position     = this.$element.offset()
    var targetHeight = this.$target.height()

    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false

    if (this.affixed == 'bottom') {
      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
    }

    var initializing   = this.affixed == null
    var colliderTop    = initializing ? scrollTop : position.top
    var colliderHeight = initializing ? targetHeight : height

    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'

    return false
  }

  Affix.prototype.getPinnedOffset = function () {
    if (this.pinnedOffset) return this.pinnedOffset
    this.$element.removeClass(Affix.RESET).addClass('affix')
    var scrollTop = this.$target.scrollTop()
    var position  = this.$element.offset()
    return (this.pinnedOffset = position.top - scrollTop)
  }

  Affix.prototype.checkPositionWithEventLoop = function () {
    setTimeout($.proxy(this.checkPosition, this), 1)
  }

  Affix.prototype.checkPosition = function () {
    if (!this.$element.is(':visible')) return

    var height       = this.$element.height()
    var offset       = this.options.offset
    var offsetTop    = offset.top
    var offsetBottom = offset.bottom
    var scrollHeight = Math.max($(document).height(), $(document.body).height())

    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)

    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)

    if (this.affixed != affix) {
      if (this.unpin != null) this.$element.css('top', '')

      var affixType = 'affix' + (affix ? '-' + affix : '')
      var e         = $.Event(affixType + '.bs.affix')

      this.$element.trigger(e)

      if (e.isDefaultPrevented()) return

      this.affixed = affix
      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null

      this.$element
        .removeClass(Affix.RESET)
        .addClass(affixType)
        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
    }

    if (affix == 'bottom') {
      this.$element.offset({
        top: scrollHeight - height - offsetBottom
      })
    }
  }


  // AFFIX PLUGIN DEFINITION
  // =======================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.affix')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.affix

  $.fn.affix             = Plugin
  $.fn.affix.Constructor = Affix


  // AFFIX NO CONFLICT
  // =================

  $.fn.affix.noConflict = function () {
    $.fn.affix = old
    return this
  }


  // AFFIX DATA-API
  // ==============

  $(window).on('load', function () {
    $('[data-spy="affix"]').each(function () {
      var $spy = $(this)
      var data = $spy.data()

      data.offset = data.offset || {}

      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
      if (data.offsetTop    != null) data.offset.top    = data.offsetTop

      Plugin.call($spy, data)
    })
  })

}(jQuery);

/*!
 * ApexCharts v3.54.1
 * (c) 2018-2024 ApexCharts
 * Released under the MIT License.
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ApexCharts = factory());
})(this, (function () { 'use strict';

  function _arrayLikeToArray(r, a) {
    (null == a || a > r.length) && (a = r.length);
    for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
    return n;
  }
  function _arrayWithHoles(r) {
    if (Array.isArray(r)) return r;
  }
  function _arrayWithoutHoles(r) {
    if (Array.isArray(r)) return _arrayLikeToArray(r);
  }
  function _assertThisInitialized(e) {
    if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    return e;
  }
  function _classCallCheck(a, n) {
    if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
  }
  function _defineProperties(e, r) {
    for (var t = 0; t < r.length; t++) {
      var o = r[t];
      o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
    }
  }
  function _createClass(e, r, t) {
    return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
      writable: !1
    }), e;
  }
  function _createForOfIteratorHelper(r, e) {
    var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
    if (!t) {
      if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
        t && (r = t);
        var n = 0,
          F = function () {};
        return {
          s: F,
          n: function () {
            return n >= r.length ? {
              done: !0
            } : {
              done: !1,
              value: r[n++]
            };
          },
          e: function (r) {
            throw r;
          },
          f: F
        };
      }
      throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
    }
    var o,
      a = !0,
      u = !1;
    return {
      s: function () {
        t = t.call(r);
      },
      n: function () {
        var r = t.next();
        return a = r.done, r;
      },
      e: function (r) {
        u = !0, o = r;
      },
      f: function () {
        try {
          a || null == t.return || t.return();
        } finally {
          if (u) throw o;
        }
      }
    };
  }
  function _createSuper(t) {
    var r = _isNativeReflectConstruct();
    return function () {
      var e,
        o = _getPrototypeOf(t);
      if (r) {
        var s = _getPrototypeOf(this).constructor;
        e = Reflect.construct(o, arguments, s);
      } else e = o.apply(this, arguments);
      return _possibleConstructorReturn(this, e);
    };
  }
  function _defineProperty(e, r, t) {
    return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
      value: t,
      enumerable: !0,
      configurable: !0,
      writable: !0
    }) : e[r] = t, e;
  }
  function _getPrototypeOf(t) {
    return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
      return t.__proto__ || Object.getPrototypeOf(t);
    }, _getPrototypeOf(t);
  }
  function _inherits(t, e) {
    if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
    t.prototype = Object.create(e && e.prototype, {
      constructor: {
        value: t,
        writable: !0,
        configurable: !0
      }
    }), Object.defineProperty(t, "prototype", {
      writable: !1
    }), e && _setPrototypeOf(t, e);
  }
  function _isNativeReflectConstruct() {
    try {
      var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
    } catch (t) {}
    return (_isNativeReflectConstruct = function () {
      return !!t;
    })();
  }
  function _iterableToArray(r) {
    if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
  }
  function _iterableToArrayLimit(r, l) {
    var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
    if (null != t) {
      var e,
        n,
        i,
        u,
        a = [],
        f = !0,
        o = !1;
      try {
        if (i = (t = t.call(r)).next, 0 === l) {
          if (Object(t) !== t) return;
          f = !1;
        } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
      } catch (r) {
        o = !0, n = r;
      } finally {
        try {
          if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
        } finally {
          if (o) throw n;
        }
      }
      return a;
    }
  }
  function _nonIterableRest() {
    throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }
  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }
  function ownKeys(e, r) {
    var t = Object.keys(e);
    if (Object.getOwnPropertySymbols) {
      var o = Object.getOwnPropertySymbols(e);
      r && (o = o.filter(function (r) {
        return Object.getOwnPropertyDescriptor(e, r).enumerable;
      })), t.push.apply(t, o);
    }
    return t;
  }
  function _objectSpread2(e) {
    for (var r = 1; r < arguments.length; r++) {
      var t = null != arguments[r] ? arguments[r] : {};
      r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
        _defineProperty(e, r, t[r]);
      }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
        Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
      });
    }
    return e;
  }
  function _possibleConstructorReturn(t, e) {
    if (e && ("object" == typeof e || "function" == typeof e)) return e;
    if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
    return _assertThisInitialized(t);
  }
  function _setPrototypeOf(t, e) {
    return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
      return t.__proto__ = e, t;
    }, _setPrototypeOf(t, e);
  }
  function _slicedToArray(r, e) {
    return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
  }
  function _toConsumableArray(r) {
    return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();
  }
  function _toPrimitive(t, r) {
    if ("object" != typeof t || !t) return t;
    var e = t[Symbol.toPrimitive];
    if (void 0 !== e) {
      var i = e.call(t, r || "default");
      if ("object" != typeof i) return i;
      throw new TypeError("@@toPrimitive must return a primitive value.");
    }
    return ("string" === r ? String : Number)(t);
  }
  function _toPropertyKey(t) {
    var i = _toPrimitive(t, "string");
    return "symbol" == typeof i ? i : i + "";
  }
  function _typeof(o) {
    "@babel/helpers - typeof";

    return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
      return typeof o;
    } : function (o) {
      return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
    }, _typeof(o);
  }
  function _unsupportedIterableToArray(r, a) {
    if (r) {
      if ("string" == typeof r) return _arrayLikeToArray(r, a);
      var t = {}.toString.call(r).slice(8, -1);
      return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
    }
  }

  /*
   ** Generic functions which are not dependent on ApexCharts
   */
  var Utils$1 = /*#__PURE__*/function () {
    function Utils() {
      _classCallCheck(this, Utils);
    }
    _createClass(Utils, [{
      key: "shadeRGBColor",
      value: function shadeRGBColor(percent, color) {
        var f = color.split(','),
          t = percent < 0 ? 0 : 255,
          p = percent < 0 ? percent * -1 : percent,
          R = parseInt(f[0].slice(4), 10),
          G = parseInt(f[1], 10),
          B = parseInt(f[2], 10);
        return 'rgb(' + (Math.round((t - R) * p) + R) + ',' + (Math.round((t - G) * p) + G) + ',' + (Math.round((t - B) * p) + B) + ')';
      }
    }, {
      key: "shadeHexColor",
      value: function shadeHexColor(percent, color) {
        var f = parseInt(color.slice(1), 16),
          t = percent < 0 ? 0 : 255,
          p = percent < 0 ? percent * -1 : percent,
          R = f >> 16,
          G = f >> 8 & 0x00ff,
          B = f & 0x0000ff;
        return '#' + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1);
      }

      // beautiful color shading blending code
      // http://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors
    }, {
      key: "shadeColor",
      value: function shadeColor(p, color) {
        if (Utils.isColorHex(color)) {
          return this.shadeHexColor(p, color);
        } else {
          return this.shadeRGBColor(p, color);
        }
      }
    }], [{
      key: "bind",
      value: function bind(fn, me) {
        return function () {
          return fn.apply(me, arguments);
        };
      }
    }, {
      key: "isObject",
      value: function isObject(item) {
        return item && _typeof(item) === 'object' && !Array.isArray(item) && item != null;
      }

      // Type checking that works across different window objects
    }, {
      key: "is",
      value: function is(type, val) {
        return Object.prototype.toString.call(val) === '[object ' + type + ']';
      }
    }, {
      key: "listToArray",
      value: function listToArray(list) {
        var i,
          array = [];
        for (i = 0; i < list.length; i++) {
          array[i] = list[i];
        }
        return array;
      }

      // to extend defaults with user options
      // credit: http://stackoverflow.com/questions/27936772/deep-object-merging-in-es6-es7#answer-34749873
    }, {
      key: "extend",
      value: function extend(target, source) {
        var _this = this;
        if (typeof Object.assign !== 'function') {
          (function () {
            Object.assign = function (target) {

              // We must check against these specific cases.
              if (target === undefined || target === null) {
                throw new TypeError('Cannot convert undefined or null to object');
              }
              var output = Object(target);
              for (var index = 1; index < arguments.length; index++) {
                var _source = arguments[index];
                if (_source !== undefined && _source !== null) {
                  for (var nextKey in _source) {
                    if (_source.hasOwnProperty(nextKey)) {
                      output[nextKey] = _source[nextKey];
                    }
                  }
                }
              }
              return output;
            };
          })();
        }
        var output = Object.assign({}, target);
        if (this.isObject(target) && this.isObject(source)) {
          Object.keys(source).forEach(function (key) {
            if (_this.isObject(source[key])) {
              if (!(key in target)) {
                Object.assign(output, _defineProperty({}, key, source[key]));
              } else {
                output[key] = _this.extend(target[key], source[key]);
              }
            } else {
              Object.assign(output, _defineProperty({}, key, source[key]));
            }
          });
        }
        return output;
      }
    }, {
      key: "extendArray",
      value: function extendArray(arrToExtend, resultArr) {
        var extendedArr = [];
        arrToExtend.map(function (item) {
          extendedArr.push(Utils.extend(resultArr, item));
        });
        arrToExtend = extendedArr;
        return arrToExtend;
      }

      // If month counter exceeds 12, it starts again from 1
    }, {
      key: "monthMod",
      value: function monthMod(month) {
        return month % 12;
      }
    }, {
      key: "clone",
      value: function clone(source) {
        if (Utils.is('Array', source)) {
          var cloneResult = [];
          for (var i = 0; i < source.length; i++) {
            cloneResult[i] = this.clone(source[i]);
          }
          return cloneResult;
        } else if (Utils.is('Null', source)) {
          // fixes an issue where null values were converted to {}
          return null;
        } else if (Utils.is('Date', source)) {
          return source;
        } else if (_typeof(source) === 'object') {
          var _cloneResult = {};
          for (var prop in source) {
            if (source.hasOwnProperty(prop)) {
              _cloneResult[prop] = this.clone(source[prop]);
            }
          }
          return _cloneResult;
        } else {
          return source;
        }
      }
    }, {
      key: "log10",
      value: function log10(x) {
        return Math.log(x) / Math.LN10;
      }
    }, {
      key: "roundToBase10",
      value: function roundToBase10(x) {
        return Math.pow(10, Math.floor(Math.log10(x)));
      }
    }, {
      key: "roundToBase",
      value: function roundToBase(x, base) {
        return Math.pow(base, Math.floor(Math.log(x) / Math.log(base)));
      }
    }, {
      key: "parseNumber",
      value: function parseNumber(val) {
        if (val === null) return val;
        return parseFloat(val);
      }
    }, {
      key: "stripNumber",
      value: function stripNumber(num) {
        var precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;
        return Number.isInteger(num) ? num : parseFloat(num.toPrecision(precision));
      }
    }, {
      key: "randomId",
      value: function randomId() {
        return (Math.random() + 1).toString(36).substring(4);
      }
    }, {
      key: "noExponents",
      value: function noExponents(val) {
        var data = String(val).split(/[eE]/);
        if (data.length === 1) return data[0];
        var z = '',
          sign = val < 0 ? '-' : '',
          str = data[0].replace('.', ''),
          mag = Number(data[1]) + 1;
        if (mag < 0) {
          z = sign + '0.';
          while (mag++) {
            z += '0';
          }
          return z + str.replace(/^-/, '');
        }
        mag -= str.length;
        while (mag--) {
          z += '0';
        }
        return str + z;
      }
    }, {
      key: "getDimensions",
      value: function getDimensions(el) {
        var computedStyle = getComputedStyle(el, null);
        var elementHeight = el.clientHeight;
        var elementWidth = el.clientWidth;
        elementHeight -= parseFloat(computedStyle.paddingTop) + parseFloat(computedStyle.paddingBottom);
        elementWidth -= parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight);
        return [elementWidth, elementHeight];
      }
    }, {
      key: "getBoundingClientRect",
      value: function getBoundingClientRect(element) {
        var rect = element.getBoundingClientRect();
        return {
          top: rect.top,
          right: rect.right,
          bottom: rect.bottom,
          left: rect.left,
          width: element.clientWidth,
          height: element.clientHeight,
          x: rect.left,
          y: rect.top
        };
      }
    }, {
      key: "getLargestStringFromArr",
      value: function getLargestStringFromArr(arr) {
        return arr.reduce(function (a, b) {
          if (Array.isArray(b)) {
            b = b.reduce(function (aa, bb) {
              return aa.length > bb.length ? aa : bb;
            });
          }
          return a.length > b.length ? a : b;
        }, 0);
      }

      // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb#answer-12342275
    }, {
      key: "hexToRgba",
      value: function hexToRgba() {
        var hex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '#999999';
        var opacity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.6;
        if (hex.substring(0, 1) !== '#') {
          hex = '#999999';
        }
        var h = hex.replace('#', '');
        h = h.match(new RegExp('(.{' + h.length / 3 + '})', 'g'));
        for (var i = 0; i < h.length; i++) {
          h[i] = parseInt(h[i].length === 1 ? h[i] + h[i] : h[i], 16);
        }
        if (typeof opacity !== 'undefined') h.push(opacity);
        return 'rgba(' + h.join(',') + ')';
      }
    }, {
      key: "getOpacityFromRGBA",
      value: function getOpacityFromRGBA(rgba) {
        return parseFloat(rgba.replace(/^.*,(.+)\)/, '$1'));
      }
    }, {
      key: "rgb2hex",
      value: function rgb2hex(rgb) {
        rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
        return rgb && rgb.length === 4 ? '#' + ('0' + parseInt(rgb[1], 10).toString(16)).slice(-2) + ('0' + parseInt(rgb[2], 10).toString(16)).slice(-2) + ('0' + parseInt(rgb[3], 10).toString(16)).slice(-2) : '';
      }
    }, {
      key: "isColorHex",
      value: function isColorHex(color) {
        return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)|(^#[0-9A-F]{8}$)/i.test(color);
      }
    }, {
      key: "getPolygonPos",
      value: function getPolygonPos(size, dataPointsLen) {
        var dotsArray = [];
        var angle = Math.PI * 2 / dataPointsLen;
        for (var i = 0; i < dataPointsLen; i++) {
          var curPos = {};
          curPos.x = size * Math.sin(i * angle);
          curPos.y = -size * Math.cos(i * angle);
          dotsArray.push(curPos);
        }
        return dotsArray;
      }
    }, {
      key: "polarToCartesian",
      value: function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
        var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
        return {
          x: centerX + radius * Math.cos(angleInRadians),
          y: centerY + radius * Math.sin(angleInRadians)
        };
      }
    }, {
      key: "escapeString",
      value: function escapeString(str) {
        var escapeWith = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'x';
        var newStr = str.toString().slice();
        newStr = newStr.replace(/[` ~!@#$%^&*()|+\=?;:'",.<>{}[\]\\/]/gi, escapeWith);
        return newStr;
      }
    }, {
      key: "negToZero",
      value: function negToZero(val) {
        return val < 0 ? 0 : val;
      }
    }, {
      key: "moveIndexInArray",
      value: function moveIndexInArray(arr, old_index, new_index) {
        if (new_index >= arr.length) {
          var k = new_index - arr.length + 1;
          while (k--) {
            arr.push(undefined);
          }
        }
        arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
        return arr;
      }
    }, {
      key: "extractNumber",
      value: function extractNumber(s) {
        return parseFloat(s.replace(/[^\d.]*/g, ''));
      }
    }, {
      key: "findAncestor",
      value: function findAncestor(el, cls) {
        while ((el = el.parentElement) && !el.classList.contains(cls)) {
        }
        return el;
      }
    }, {
      key: "setELstyles",
      value: function setELstyles(el, styles) {
        for (var key in styles) {
          if (styles.hasOwnProperty(key)) {
            el.style.key = styles[key];
          }
        }
      }
      // prevents JS prevision errors when adding
    }, {
      key: "preciseAddition",
      value: function preciseAddition(a, b) {
        var aDecimals = (String(a).split('.')[1] || '').length;
        var bDecimals = (String(b).split('.')[1] || '').length;
        var factor = Math.pow(10, Math.max(aDecimals, bDecimals));
        return (Math.round(a * factor) + Math.round(b * factor)) / factor;
      }
    }, {
      key: "isNumber",
      value: function isNumber(value) {
        return !isNaN(value) && parseFloat(Number(value)) === value && !isNaN(parseInt(value, 10));
      }
    }, {
      key: "isFloat",
      value: function isFloat(n) {
        return Number(n) === n && n % 1 !== 0;
      }
    }, {
      key: "isSafari",
      value: function isSafari() {
        return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
      }
    }, {
      key: "isFirefox",
      value: function isFirefox() {
        return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
      }
    }, {
      key: "isMsEdge",
      value: function isMsEdge() {
        var ua = window.navigator.userAgent;
        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 false;
      }
      //
      // Find the Greatest Common Divisor of two numbers
      //
    }, {
      key: "getGCD",
      value: function getGCD(a, b) {
        var p = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 7;
        var big = Math.pow(10, p - Math.floor(Math.log10(Math.max(a, b))));
        a = Math.round(Math.abs(a) * big);
        b = Math.round(Math.abs(b) * big);
        while (b) {
          var t = b;
          b = a % b;
          a = t;
        }
        return a / big;
      }
    }, {
      key: "getPrimeFactors",
      value: function getPrimeFactors(n) {
        var factors = [];
        var divisor = 2;
        while (n >= 2) {
          if (n % divisor == 0) {
            factors.push(divisor);
            n = n / divisor;
          } else {
            divisor++;
          }
        }
        return factors;
      }
    }, {
      key: "mod",
      value: function mod(a, b) {
        var p = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 7;
        var big = Math.pow(10, p - Math.floor(Math.log10(Math.max(a, b))));
        a = Math.round(Math.abs(a) * big);
        b = Math.round(Math.abs(b) * big);
        return a % b / big;
      }
    }]);
    return Utils;
  }();

  /**
   * ApexCharts Animation Class.
   *
   * @module Animations
   **/
  var Animations = /*#__PURE__*/function () {
    function Animations(ctx) {
      _classCallCheck(this, Animations);
      this.ctx = ctx;
      this.w = ctx.w;
      this.setEasingFunctions();
    }
    _createClass(Animations, [{
      key: "setEasingFunctions",
      value: function setEasingFunctions() {
        var easing;
        if (this.w.globals.easing) return;
        var userDefinedEasing = this.w.config.chart.animations.easing;
        switch (userDefinedEasing) {
          case 'linear':
            {
              easing = '-';
              break;
            }
          case 'easein':
            {
              easing = '<';
              break;
            }
          case 'easeout':
            {
              easing = '>';
              break;
            }
          case 'easeinout':
            {
              easing = '<>';
              break;
            }
          case 'swing':
            {
              easing = function easing(pos) {
                var s = 1.70158;
                var ret = (pos -= 1) * pos * ((s + 1) * pos + s) + 1;
                return ret;
              };
              break;
            }
          case 'bounce':
            {
              easing = function easing(pos) {
                var ret = '';
                if (pos < 1 / 2.75) {
                  ret = 7.5625 * pos * pos;
                } else if (pos < 2 / 2.75) {
                  ret = 7.5625 * (pos -= 1.5 / 2.75) * pos + 0.75;
                } else if (pos < 2.5 / 2.75) {
                  ret = 7.5625 * (pos -= 2.25 / 2.75) * pos + 0.9375;
                } else {
                  ret = 7.5625 * (pos -= 2.625 / 2.75) * pos + 0.984375;
                }
                return ret;
              };
              break;
            }
          case 'elastic':
            {
              easing = function easing(pos) {
                if (pos === !!pos) return pos;
                return Math.pow(2, -10 * pos) * Math.sin((pos - 0.075) * (2 * Math.PI) / 0.3) + 1;
              };
              break;
            }
          default:
            {
              easing = '<>';
            }
        }
        this.w.globals.easing = easing;
      }
    }, {
      key: "animateLine",
      value: function animateLine(el, from, to, speed) {
        el.attr(from).animate(speed).attr(to);
      }

      /*
       ** Animate radius of a circle element
       */
    }, {
      key: "animateMarker",
      value: function animateMarker(el, speed, easing, cb) {
        el.attr({
          opacity: 0
        }).animate(speed, easing).attr({
          opacity: 1
        }).afterAll(function () {
          cb();
        });
      }

      /*
       ** Animate rect properties
       */
    }, {
      key: "animateRect",
      value: function animateRect(el, from, to, speed, fn) {
        el.attr(from).animate(speed).attr(to).afterAll(function () {
          return fn();
        });
      }
    }, {
      key: "animatePathsGradually",
      value: function animatePathsGradually(params) {
        var el = params.el,
          realIndex = params.realIndex,
          j = params.j,
          fill = params.fill,
          pathFrom = params.pathFrom,
          pathTo = params.pathTo,
          speed = params.speed,
          delay = params.delay;
        var me = this;
        var w = this.w;
        var delayFactor = 0;
        if (w.config.chart.animations.animateGradually.enabled) {
          delayFactor = w.config.chart.animations.animateGradually.delay;
        }
        if (w.config.chart.animations.dynamicAnimation.enabled && w.globals.dataChanged && w.config.chart.type !== 'bar') {
          // disabled due to this bug - https://github.com/apexcharts/vue-apexcharts/issues/75
          delayFactor = 0;
        }
        me.morphSVG(el, realIndex, j, w.config.chart.type === 'line' && !w.globals.comboCharts ? 'stroke' : fill, pathFrom, pathTo, speed, delay * delayFactor);
      }
    }, {
      key: "showDelayedElements",
      value: function showDelayedElements() {
        this.w.globals.delayedElements.forEach(function (d) {
          var ele = d.el;
          ele.classList.remove('apexcharts-element-hidden');
          ele.classList.add('apexcharts-hidden-element-shown');
        });
      }
    }, {
      key: "animationCompleted",
      value: function animationCompleted(el) {
        var w = this.w;
        if (w.globals.animationEnded) return;
        w.globals.animationEnded = true;
        this.showDelayedElements();
        if (typeof w.config.chart.events.animationEnd === 'function') {
          w.config.chart.events.animationEnd(this.ctx, {
            el: el,
            w: w
          });
        }
      }

      // SVG.js animation for morphing one path to another
    }, {
      key: "morphSVG",
      value: function morphSVG(el, realIndex, j, fill, pathFrom, pathTo, speed, delay) {
        var _this = this;
        var w = this.w;
        if (!pathFrom) {
          pathFrom = el.attr('pathFrom');
        }
        if (!pathTo) {
          pathTo = el.attr('pathTo');
        }
        var disableAnimationForCorrupPath = function disableAnimationForCorrupPath(path) {
          if (w.config.chart.type === 'radar') {
            // radar chart drops the path to bottom and hence a corrup path looks ugly
            // therefore, disable animation for such a case
            speed = 1;
          }
          return "M 0 ".concat(w.globals.gridHeight);
        };
        if (!pathFrom || pathFrom.indexOf('undefined') > -1 || pathFrom.indexOf('NaN') > -1) {
          pathFrom = disableAnimationForCorrupPath();
        }
        if (!pathTo || pathTo.indexOf('undefined') > -1 || pathTo.indexOf('NaN') > -1) {
          pathTo = disableAnimationForCorrupPath();
        }
        if (!w.globals.shouldAnimate) {
          speed = 1;
        }
        el.plot(pathFrom).animate(1, w.globals.easing, delay).plot(pathFrom).animate(speed, w.globals.easing, delay).plot(pathTo).afterAll(function () {
          // a flag to indicate that the original mount function can return true now as animation finished here

          if (Utils$1.isNumber(j)) {
            if (j === w.globals.series[w.globals.maxValsInArrayIndex].length - 2 && w.globals.shouldAnimate) {
              _this.animationCompleted(el);
            }
          } else if (fill !== 'none' && w.globals.shouldAnimate) {
            if (!w.globals.comboCharts && realIndex === w.globals.series.length - 1 || w.globals.comboCharts) {
              _this.animationCompleted(el);
            }
          }
          _this.showDelayedElements();
        });
      }
    }]);
    return Animations;
  }();

  /**
   * ApexCharts Filters Class for setting hover/active states on the paths.
   *
   * @module Formatters
   **/
  var Filters = /*#__PURE__*/function () {
    function Filters(ctx) {
      _classCallCheck(this, Filters);
      this.ctx = ctx;
      this.w = ctx.w;
    }

    // create a re-usable filter which can be appended other filter effects and applied to multiple elements
    _createClass(Filters, [{
      key: "getDefaultFilter",
      value: function getDefaultFilter(el, i) {
        var w = this.w;
        el.unfilter(true);
        var filter = new window.SVG.Filter();
        filter.size('120%', '180%', '-5%', '-40%');
        if (w.config.states.normal.filter !== 'none') {
          this.applyFilter(el, i, w.config.states.normal.filter.type, w.config.states.normal.filter.value);
        } else {
          if (w.config.chart.dropShadow.enabled) {
            this.dropShadow(el, w.config.chart.dropShadow, i);
          }
        }
      }
    }, {
      key: "addNormalFilter",
      value: function addNormalFilter(el, i) {
        var w = this.w;

        // revert shadow if it was there
        // but, ignore marker as marker don't have dropshadow yet
        if (w.config.chart.dropShadow.enabled && !el.node.classList.contains('apexcharts-marker')) {
          this.dropShadow(el, w.config.chart.dropShadow, i);
        }
      }

      // appends dropShadow to the filter object which can be chained with other filter effects
    }, {
      key: "addLightenFilter",
      value: function addLightenFilter(el, i, attrs) {
        var _this = this;
        var w = this.w;
        var intensity = attrs.intensity;
        el.unfilter(true);
        var filter = new window.SVG.Filter();
        el.filter(function (add) {
          var shadowAttr = w.config.chart.dropShadow;
          if (shadowAttr.enabled) {
            filter = _this.addShadow(add, i, shadowAttr);
          } else {
            filter = add;
          }
          filter.componentTransfer({
            rgb: {
              type: 'linear',
              slope: 1.5,
              intercept: intensity
            }
          });
        });
        el.filterer.node.setAttribute('filterUnits', 'userSpaceOnUse');
        this._scaleFilterSize(el.filterer.node);
      }

      // appends dropShadow to the filter object which can be chained with other filter effects
    }, {
      key: "addDarkenFilter",
      value: function addDarkenFilter(el, i, attrs) {
        var _this2 = this;
        var w = this.w;
        var intensity = attrs.intensity;
        el.unfilter(true);
        var filter = new window.SVG.Filter();
        el.filter(function (add) {
          var shadowAttr = w.config.chart.dropShadow;
          if (shadowAttr.enabled) {
            filter = _this2.addShadow(add, i, shadowAttr);
          } else {
            filter = add;
          }
          filter.componentTransfer({
            rgb: {
              type: 'linear',
              slope: intensity
            }
          });
        });
        el.filterer.node.setAttribute('filterUnits', 'userSpaceOnUse');
        this._scaleFilterSize(el.filterer.node);
      }
    }, {
      key: "applyFilter",
      value: function applyFilter(el, i, filter) {
        var intensity = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0.5;
        switch (filter) {
          case 'none':
            {
              this.addNormalFilter(el, i);
              break;
            }
          case 'lighten':
            {
              this.addLightenFilter(el, i, {
                intensity: intensity
              });
              break;
            }
          case 'darken':
            {
              this.addDarkenFilter(el, i, {
                intensity: intensity
              });
              break;
            }
        }
      }

      // appends dropShadow to the filter object which can be chained with other filter effects
    }, {
      key: "addShadow",
      value: function addShadow(add, i, attrs) {
        var _w$config$chart$dropS;
        var w = this.w;
        var blur = attrs.blur,
          top = attrs.top,
          left = attrs.left,
          color = attrs.color,
          opacity = attrs.opacity;
        if (((_w$config$chart$dropS = w.config.chart.dropShadow.enabledOnSeries) === null || _w$config$chart$dropS === void 0 ? void 0 : _w$config$chart$dropS.length) > 0) {
          if (w.config.chart.dropShadow.enabledOnSeries.indexOf(i) === -1) {
            return add;
          }
        }
        var shadowBlur = add.flood(Array.isArray(color) ? color[i] : color, opacity).composite(add.sourceAlpha, 'in').offset(left, top).gaussianBlur(blur).merge(add.source);
        return add.blend(add.source, shadowBlur);
      }

      // directly adds dropShadow to the element and returns the same element.
      // the only way it is different from the addShadow() function is that addShadow is chainable to other filters, while this function discards all filters and add dropShadow
    }, {
      key: "dropShadow",
      value: function dropShadow(el, attrs) {
        var _w$config$chart$dropS2;
        var i = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        var top = attrs.top,
          left = attrs.left,
          blur = attrs.blur,
          color = attrs.color,
          opacity = attrs.opacity,
          noUserSpaceOnUse = attrs.noUserSpaceOnUse;
        var w = this.w;
        el.unfilter(true);
        if (Utils$1.isMsEdge() && w.config.chart.type === 'radialBar') {
          // in radialbar charts, dropshadow is clipping actual drawing in IE
          return el;
        }
        if (((_w$config$chart$dropS2 = w.config.chart.dropShadow.enabledOnSeries) === null || _w$config$chart$dropS2 === void 0 ? void 0 : _w$config$chart$dropS2.length) > 0) {
          var _w$config$chart$dropS3;
          if (((_w$config$chart$dropS3 = w.config.chart.dropShadow.enabledOnSeries) === null || _w$config$chart$dropS3 === void 0 ? void 0 : _w$config$chart$dropS3.indexOf(i)) === -1) {
            return el;
          }
        }
        color = Array.isArray(color) ? color[i] : color;
        el.filter(function (add) {
          var shadowBlur = null;
          if (Utils$1.isSafari() || Utils$1.isFirefox() || Utils$1.isMsEdge()) {
            // safari/firefox/IE have some alternative way to use this filter
            shadowBlur = add.flood(color, opacity).composite(add.sourceAlpha, 'in').offset(left, top).gaussianBlur(blur);
          } else {
            shadowBlur = add.flood(color, opacity).composite(add.sourceAlpha, 'in').offset(left, top).gaussianBlur(blur).merge(add.source);
          }
          add.blend(add.source, shadowBlur);
        });
        if (!noUserSpaceOnUse) {
          el.filterer.node.setAttribute('filterUnits', 'userSpaceOnUse');
        }
        this._scaleFilterSize(el.filterer.node);
        return el;
      }
    }, {
      key: "setSelectionFilter",
      value: function setSelectionFilter(el, realIndex, dataPointIndex) {
        var w = this.w;
        if (typeof w.globals.selectedDataPoints[realIndex] !== 'undefined') {
          if (w.globals.selectedDataPoints[realIndex].indexOf(dataPointIndex) > -1) {
            el.node.setAttribute('selected', true);
            var activeFilter = w.config.states.active.filter;
            if (activeFilter !== 'none') {
              this.applyFilter(el, realIndex, activeFilter.type, activeFilter.value);
            }
          }
        }
      }
    }, {
      key: "_scaleFilterSize",
      value: function _scaleFilterSize(el) {
        var setAttributes = function setAttributes(attrs) {
          for (var key in attrs) {
            if (attrs.hasOwnProperty(key)) {
              el.setAttribute(key, attrs[key]);
            }
          }
        };
        setAttributes({
          width: '200%',
          height: '200%',
          x: '-50%',
          y: '-50%'
        });
      }
    }]);
    return Filters;
  }();

  /**
   * ApexCharts Graphics Class for all drawing operations.
   *
   * @module Graphics
   **/
  var Graphics = /*#__PURE__*/function () {
    function Graphics(ctx) {
      _classCallCheck(this, Graphics);
      this.ctx = ctx;
      this.w = ctx.w;
    }

    /*****************************************************************************
     *                                                                            *
     *  SVG Path Rounding Function                                                *
     *  Copyright (C) 2014 Yona Appletree                                         *
     *                                                                            *
     *  Licensed under the Apache License, Version 2.0 (the "License");           *
     *  you may not use this file except in compliance with the License.          *
     *  You may obtain a copy of the License at                                   *
     *                                                                            *
     *      http://www.apache.org/licenses/LICENSE-2.0                            *
     *                                                                            *
     *  Unless required by applicable law or agreed to in writing, software       *
     *  distributed under the License is distributed on an "AS IS" BASIS,         *
     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
     *  See the License for the specific language governing permissions and       *
     *  limitations under the License.                                            *
     *                                                                            *
     *****************************************************************************/

    /**
     * SVG Path rounding function. Takes an input path string and outputs a path
     * string where all line-line corners have been rounded. Only supports absolute
     * commands at the moment.
     *
     * @param pathString The SVG input path
     * @param radius The amount to round the corners, either a value in the SVG
     *               coordinate space, or, if useFractionalRadius is true, a value
     *               from 0 to 1.
     * @returns A new SVG path string with the rounding
     */
    _createClass(Graphics, [{
      key: "roundPathCorners",
      value: function roundPathCorners(pathString, radius) {
        if (pathString.indexOf('NaN') > -1) pathString = '';
        function moveTowardsLength(movingPoint, targetPoint, amount) {
          var width = targetPoint.x - movingPoint.x;
          var height = targetPoint.y - movingPoint.y;
          var distance = Math.sqrt(width * width + height * height);
          return moveTowardsFractional(movingPoint, targetPoint, Math.min(1, amount / distance));
        }
        function moveTowardsFractional(movingPoint, targetPoint, fraction) {
          return {
            x: movingPoint.x + (targetPoint.x - movingPoint.x) * fraction,
            y: movingPoint.y + (targetPoint.y - movingPoint.y) * fraction
          };
        }

        // Adjusts the ending position of a command
        function adjustCommand(cmd, newPoint) {
          if (cmd.length > 2) {
            cmd[cmd.length - 2] = newPoint.x;
            cmd[cmd.length - 1] = newPoint.y;
          }
        }

        // Gives an {x, y} object for a command's ending position
        function pointForCommand(cmd) {
          return {
            x: parseFloat(cmd[cmd.length - 2]),
            y: parseFloat(cmd[cmd.length - 1])
          };
        }

        // Split apart the path, handing concatonated letters and numbers
        var pathParts = pathString.split(/[,\s]/).reduce(function (parts, part) {
          var match = part.match('([a-zA-Z])(.+)');
          if (match) {
            parts.push(match[1]);
            parts.push(match[2]);
          } else {
            parts.push(part);
          }
          return parts;
        }, []);

        // Group the commands with their arguments for easier handling
        var commands = pathParts.reduce(function (commands, part) {
          if (parseFloat(part) == part && commands.length) {
            commands[commands.length - 1].push(part);
          } else {
            commands.push([part]);
          }
          return commands;
        }, []);

        // The resulting commands, also grouped
        var resultCommands = [];
        if (commands.length > 1) {
          var startPoint = pointForCommand(commands[0]);

          // Handle the close path case with a "virtual" closing line
          var virtualCloseLine = null;
          if (commands[commands.length - 1][0] == 'Z' && commands[0].length > 2) {
            virtualCloseLine = ['L', startPoint.x, startPoint.y];
            commands[commands.length - 1] = virtualCloseLine;
          }

          // We always use the first command (but it may be mutated)
          resultCommands.push(commands[0]);
          for (var cmdIndex = 1; cmdIndex < commands.length; cmdIndex++) {
            var prevCmd = resultCommands[resultCommands.length - 1];
            var curCmd = commands[cmdIndex];

            // Handle closing case
            var nextCmd = curCmd == virtualCloseLine ? commands[1] : commands[cmdIndex + 1];

            // Nasty logic to decide if this path is a candidite.
            if (nextCmd && prevCmd && prevCmd.length > 2 && curCmd[0] == 'L' && nextCmd.length > 2 && nextCmd[0] == 'L') {
              // Calc the points we're dealing with
              var prevPoint = pointForCommand(prevCmd);
              var curPoint = pointForCommand(curCmd);
              var nextPoint = pointForCommand(nextCmd);

              // The start and end of the cuve are just our point moved towards the previous and next points, respectivly
              var curveStart, curveEnd;
              curveStart = moveTowardsLength(curPoint, prevPoint, radius);
              curveEnd = moveTowardsLength(curPoint, nextPoint, radius);

              // Adjust the current command and add it
              adjustCommand(curCmd, curveStart);
              curCmd.origPoint = curPoint;
              resultCommands.push(curCmd);

              // The curve control points are halfway between the start/end of the curve and
              // the original point
              var startControl = moveTowardsFractional(curveStart, curPoint, 0.5);
              var endControl = moveTowardsFractional(curPoint, curveEnd, 0.5);

              // Create the curve
              var curveCmd = ['C', startControl.x, startControl.y, endControl.x, endControl.y, curveEnd.x, curveEnd.y];
              // Save the original point for fractional calculations
              curveCmd.origPoint = curPoint;
              resultCommands.push(curveCmd);
            } else {
              // Pass through commands that don't qualify
              resultCommands.push(curCmd);
            }
          }

          // Fix up the starting point and restore the close path if the path was orignally closed
          if (virtualCloseLine) {
            var newStartPoint = pointForCommand(resultCommands[resultCommands.length - 1]);
            resultCommands.push(['Z']);
            adjustCommand(resultCommands[0], newStartPoint);
          }
        } else {
          resultCommands = commands;
        }
        return resultCommands.reduce(function (str, c) {
          return str + c.join(' ') + ' ';
        }, '');
      }
    }, {
      key: "drawLine",
      value: function drawLine(x1, y1, x2, y2) {
        var lineColor = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : '#a8a8a8';
        var dashArray = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
        var strokeWidth = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
        var strokeLineCap = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 'butt';
        var w = this.w;
        var line = w.globals.dom.Paper.line().attr({
          x1: x1,
          y1: y1,
          x2: x2,
          y2: y2,
          stroke: lineColor,
          'stroke-dasharray': dashArray,
          'stroke-width': strokeWidth,
          'stroke-linecap': strokeLineCap
        });
        return line;
      }
    }, {
      key: "drawRect",
      value: function drawRect() {
        var x1 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        var y1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
        var x2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        var y2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
        var radius = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
        var color = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : '#fefefe';
        var opacity = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 1;
        var strokeWidth = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
        var strokeColor = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : null;
        var strokeDashArray = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 0;
        var w = this.w;
        var rect = w.globals.dom.Paper.rect();
        rect.attr({
          x: x1,
          y: y1,
          width: x2 > 0 ? x2 : 0,
          height: y2 > 0 ? y2 : 0,
          rx: radius,
          ry: radius,
          opacity: opacity,
          'stroke-width': strokeWidth !== null ? strokeWidth : 0,
          stroke: strokeColor !== null ? strokeColor : 'none',
          'stroke-dasharray': strokeDashArray
        });

        // fix apexcharts.js#1410
        rect.node.setAttribute('fill', color);
        return rect;
      }
    }, {
      key: "drawPolygon",
      value: function drawPolygon(polygonString) {
        var stroke = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '#e1e1e1';
        var strokeWidth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
        var fill = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'none';
        var w = this.w;
        var polygon = w.globals.dom.Paper.polygon(polygonString).attr({
          fill: fill,
          stroke: stroke,
          'stroke-width': strokeWidth
        });
        return polygon;
      }
    }, {
      key: "drawCircle",
      value: function drawCircle(radius) {
        var attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
        var w = this.w;
        if (radius < 0) radius = 0;
        var c = w.globals.dom.Paper.circle(radius * 2);
        if (attrs !== null) {
          c.attr(attrs);
        }
        return c;
      }
    }, {
      key: "drawPath",
      value: function drawPath(_ref) {
        var _ref$d = _ref.d,
          d = _ref$d === void 0 ? '' : _ref$d,
          _ref$stroke = _ref.stroke,
          stroke = _ref$stroke === void 0 ? '#a8a8a8' : _ref$stroke,
          _ref$strokeWidth = _ref.strokeWidth,
          strokeWidth = _ref$strokeWidth === void 0 ? 1 : _ref$strokeWidth,
          fill = _ref.fill,
          _ref$fillOpacity = _ref.fillOpacity,
          fillOpacity = _ref$fillOpacity === void 0 ? 1 : _ref$fillOpacity,
          _ref$strokeOpacity = _ref.strokeOpacity,
          strokeOpacity = _ref$strokeOpacity === void 0 ? 1 : _ref$strokeOpacity,
          classes = _ref.classes,
          _ref$strokeLinecap = _ref.strokeLinecap,
          strokeLinecap = _ref$strokeLinecap === void 0 ? null : _ref$strokeLinecap,
          _ref$strokeDashArray = _ref.strokeDashArray,
          strokeDashArray = _ref$strokeDashArray === void 0 ? 0 : _ref$strokeDashArray;
        var w = this.w;
        if (strokeLinecap === null) {
          strokeLinecap = w.config.stroke.lineCap;
        }
        if (d.indexOf('undefined') > -1 || d.indexOf('NaN') > -1) {
          d = "M 0 ".concat(w.globals.gridHeight);
        }
        var p = w.globals.dom.Paper.path(d).attr({
          fill: fill,
          'fill-opacity': fillOpacity,
          stroke: stroke,
          'stroke-opacity': strokeOpacity,
          'stroke-linecap': strokeLinecap,
          'stroke-width': strokeWidth,
          'stroke-dasharray': strokeDashArray,
          class: classes
        });
        return p;
      }
    }, {
      key: "group",
      value: function group() {
        var attrs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        var w = this.w;
        var g = w.globals.dom.Paper.group();
        if (attrs !== null) {
          g.attr(attrs);
        }
        return g;
      }
    }, {
      key: "move",
      value: function move(x, y) {
        var move = ['M', x, y].join(' ');
        return move;
      }
    }, {
      key: "line",
      value: function line(x, y) {
        var hORv = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
        var line = null;
        if (hORv === null) {
          line = [' L', x, y].join(' ');
        } else if (hORv === 'H') {
          line = [' H', x].join(' ');
        } else if (hORv === 'V') {
          line = [' V', y].join(' ');
        }
        return line;
      }
    }, {
      key: "curve",
      value: function curve(x1, y1, x2, y2, x, y) {
        var curve = ['C', x1, y1, x2, y2, x, y].join(' ');
        return curve;
      }
    }, {
      key: "quadraticCurve",
      value: function quadraticCurve(x1, y1, x, y) {
        var curve = ['Q', x1, y1, x, y].join(' ');
        return curve;
      }
    }, {
      key: "arc",
      value: function arc(rx, ry, axisRotation, largeArcFlag, sweepFlag, x, y) {
        var relative = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
        var coord = 'A';
        if (relative) coord = 'a';
        var arc = [coord, rx, ry, axisRotation, largeArcFlag, sweepFlag, x, y].join(' ');
        return arc;
      }

      /**
       * @memberof Graphics
       * @param {object}
       *  i = series's index
       *  realIndex = realIndex is series's actual index when it was drawn time. After several redraws, the iterating "i" may change in loops, but realIndex doesn't
       *  pathFrom = existing pathFrom to animateTo
       *  pathTo = new Path to which d attr will be animated from pathFrom to pathTo
       *  stroke = line Color
       *  strokeWidth = width of path Line
       *  fill = it can be gradient, single color, pattern or image
       *  animationDelay = how much to delay when starting animation (in milliseconds)
       *  dataChangeSpeed = for dynamic animations, when data changes
       *  className = class attribute to add
       * @return {object} svg.js path object
       **/
    }, {
      key: "renderPaths",
      value: function renderPaths(_ref2) {
        var j = _ref2.j,
          realIndex = _ref2.realIndex,
          pathFrom = _ref2.pathFrom,
          pathTo = _ref2.pathTo,
          stroke = _ref2.stroke,
          strokeWidth = _ref2.strokeWidth,
          strokeLinecap = _ref2.strokeLinecap,
          fill = _ref2.fill,
          animationDelay = _ref2.animationDelay,
          initialSpeed = _ref2.initialSpeed,
          dataChangeSpeed = _ref2.dataChangeSpeed,
          className = _ref2.className,
          chartType = _ref2.chartType,
          _ref2$shouldClipToGri = _ref2.shouldClipToGrid,
          shouldClipToGrid = _ref2$shouldClipToGri === void 0 ? true : _ref2$shouldClipToGri,
          _ref2$bindEventsOnPat = _ref2.bindEventsOnPaths,
          bindEventsOnPaths = _ref2$bindEventsOnPat === void 0 ? true : _ref2$bindEventsOnPat,
          _ref2$drawShadow = _ref2.drawShadow,
          drawShadow = _ref2$drawShadow === void 0 ? true : _ref2$drawShadow;
        var w = this.w;
        var filters = new Filters(this.ctx);
        var anim = new Animations(this.ctx);
        var initialAnim = this.w.config.chart.animations.enabled;
        var dynamicAnim = initialAnim && this.w.config.chart.animations.dynamicAnimation.enabled;
        var d;
        var shouldAnimate = !!(initialAnim && !w.globals.resized || dynamicAnim && w.globals.dataChanged && w.globals.shouldAnimate);
        if (shouldAnimate) {
          d = pathFrom;
        } else {
          d = pathTo;
          w.globals.animationEnded = true;
        }
        var strokeDashArrayOpt = w.config.stroke.dashArray;
        var strokeDashArray = 0;
        if (Array.isArray(strokeDashArrayOpt)) {
          strokeDashArray = strokeDashArrayOpt[realIndex];
        } else {
          strokeDashArray = w.config.stroke.dashArray;
        }
        var el = this.drawPath({
          d: d,
          stroke: stroke,
          strokeWidth: strokeWidth,
          fill: fill,
          fillOpacity: 1,
          classes: className,
          strokeLinecap: strokeLinecap,
          strokeDashArray: strokeDashArray
        });
        el.attr('index', realIndex);
        if (shouldClipToGrid) {
          if (chartType === 'bar' && !w.globals.isHorizontal || w.globals.comboCharts) {
            el.attr({
              'clip-path': "url(#gridRectBarMask".concat(w.globals.cuid, ")")
            });
          } else {
            el.attr({
              'clip-path': "url(#gridRectMask".concat(w.globals.cuid, ")")
            });
          }
        }

        // const defaultFilter = el.filterer

        if (w.config.states.normal.filter.type !== 'none') {
          filters.getDefaultFilter(el, realIndex);
        } else {
          if (w.config.chart.dropShadow.enabled && drawShadow) {
            var shadow = w.config.chart.dropShadow;
            filters.dropShadow(el, shadow, realIndex);
          }
        }
        if (bindEventsOnPaths) {
          el.node.addEventListener('mouseenter', this.pathMouseEnter.bind(this, el));
          el.node.addEventListener('mouseleave', this.pathMouseLeave.bind(this, el));
          el.node.addEventListener('mousedown', this.pathMouseDown.bind(this, el));
        }
        el.attr({
          pathTo: pathTo,
          pathFrom: pathFrom
        });
        var defaultAnimateOpts = {
          el: el,
          j: j,
          realIndex: realIndex,
          pathFrom: pathFrom,
          pathTo: pathTo,
          fill: fill,
          strokeWidth: strokeWidth,
          delay: animationDelay
        };
        if (initialAnim && !w.globals.resized && !w.globals.dataChanged) {
          anim.animatePathsGradually(_objectSpread2(_objectSpread2({}, defaultAnimateOpts), {}, {
            speed: initialSpeed
          }));
        } else {
          if (w.globals.resized || !w.globals.dataChanged) {
            anim.showDelayedElements();
          }
        }
        if (w.globals.dataChanged && dynamicAnim && shouldAnimate) {
          anim.animatePathsGradually(_objectSpread2(_objectSpread2({}, defaultAnimateOpts), {}, {
            speed: dataChangeSpeed
          }));
        }
        return el;
      }
    }, {
      key: "drawPattern",
      value: function drawPattern(style, width, height) {
        var stroke = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '#a8a8a8';
        var strokeWidth = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
        var w = this.w;
        var p = w.globals.dom.Paper.pattern(width, height, function (add) {
          if (style === 'horizontalLines') {
            add.line(0, 0, height, 0).stroke({
              color: stroke,
              width: strokeWidth + 1
            });
          } else if (style === 'verticalLines') {
            add.line(0, 0, 0, width).stroke({
              color: stroke,
              width: strokeWidth + 1
            });
          } else if (style === 'slantedLines') {
            add.line(0, 0, width, height).stroke({
              color: stroke,
              width: strokeWidth
            });
          } else if (style === 'squares') {
            add.rect(width, height).fill('none').stroke({
              color: stroke,
              width: strokeWidth
            });
          } else if (style === 'circles') {
            add.circle(width).fill('none').stroke({
              color: stroke,
              width: strokeWidth
            });
          }
        });
        return p;
      }
    }, {
      key: "drawGradient",
      value: function drawGradient(style, gfrom, gto, opacityFrom, opacityTo) {
        var size = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
        var stops = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
        var colorStops = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
        var i = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;
        var w = this.w;
        var g;
        if (gfrom.length < 9 && gfrom.indexOf('#') === 0) {
          // if the hex contains alpha and is of 9 digit, skip the opacity
          gfrom = Utils$1.hexToRgba(gfrom, opacityFrom);
        }
        if (gto.length < 9 && gto.indexOf('#') === 0) {
          gto = Utils$1.hexToRgba(gto, opacityTo);
        }
        var stop1 = 0;
        var stop2 = 1;
        var stop3 = 1;
        var stop4 = null;
        if (stops !== null) {
          stop1 = typeof stops[0] !== 'undefined' ? stops[0] / 100 : 0;
          stop2 = typeof stops[1] !== 'undefined' ? stops[1] / 100 : 1;
          stop3 = typeof stops[2] !== 'undefined' ? stops[2] / 100 : 1;
          stop4 = typeof stops[3] !== 'undefined' ? stops[3] / 100 : null;
        }
        var radial = !!(w.config.chart.type === 'donut' || w.config.chart.type === 'pie' || w.config.chart.type === 'polarArea' || w.config.chart.type === 'bubble');
        if (colorStops === null || colorStops.length === 0) {
          g = w.globals.dom.Paper.gradient(radial ? 'radial' : 'linear', function (stop) {
            stop.at(stop1, gfrom, opacityFrom);
            stop.at(stop2, gto, opacityTo);
            stop.at(stop3, gto, opacityTo);
            if (stop4 !== null) {
              stop.at(stop4, gfrom, opacityFrom);
            }
          });
        } else {
          g = w.globals.dom.Paper.gradient(radial ? 'radial' : 'linear', function (stop) {
            var gradientStops = Array.isArray(colorStops[i]) ? colorStops[i] : colorStops;
            gradientStops.forEach(function (s) {
              stop.at(s.offset / 100, s.color, s.opacity);
            });
          });
        }
        if (!radial) {
          if (style === 'vertical') {
            g.from(0, 0).to(0, 1);
          } else if (style === 'diagonal') {
            g.from(0, 0).to(1, 1);
          } else if (style === 'horizontal') {
            g.from(0, 1).to(1, 1);
          } else if (style === 'diagonal2') {
            g.from(1, 0).to(0, 1);
          }
        } else {
          var offx = w.globals.gridWidth / 2;
          var offy = w.globals.gridHeight / 2;
          if (w.config.chart.type !== 'bubble') {
            g.attr({
              gradientUnits: 'userSpaceOnUse',
              cx: offx,
              cy: offy,
              r: size
            });
          } else {
            g.attr({
              cx: 0.5,
              cy: 0.5,
              r: 0.8,
              fx: 0.2,
              fy: 0.2
            });
          }
        }
        return g;
      }
    }, {
      key: "getTextBasedOnMaxWidth",
      value: function getTextBasedOnMaxWidth(_ref3) {
        var text = _ref3.text,
          maxWidth = _ref3.maxWidth,
          fontSize = _ref3.fontSize,
          fontFamily = _ref3.fontFamily;
        var tRects = this.getTextRects(text, fontSize, fontFamily);
        var wordWidth = tRects.width / text.length;
        var wordsBasedOnWidth = Math.floor(maxWidth / wordWidth);
        if (maxWidth < tRects.width) {
          return text.slice(0, wordsBasedOnWidth - 3) + '...';
        }
        return text;
      }
    }, {
      key: "drawText",
      value: function drawText(_ref4) {
        var _this = this;
        var x = _ref4.x,
          y = _ref4.y,
          text = _ref4.text,
          textAnchor = _ref4.textAnchor,
          fontSize = _ref4.fontSize,
          fontFamily = _ref4.fontFamily,
          fontWeight = _ref4.fontWeight,
          foreColor = _ref4.foreColor,
          opacity = _ref4.opacity,
          maxWidth = _ref4.maxWidth,
          _ref4$cssClass = _ref4.cssClass,
          cssClass = _ref4$cssClass === void 0 ? '' : _ref4$cssClass,
          _ref4$isPlainText = _ref4.isPlainText,
          isPlainText = _ref4$isPlainText === void 0 ? true : _ref4$isPlainText,
          _ref4$dominantBaselin = _ref4.dominantBaseline,
          dominantBaseline = _ref4$dominantBaselin === void 0 ? 'auto' : _ref4$dominantBaselin;
        var w = this.w;
        if (typeof text === 'undefined') text = '';
        var truncatedText = text;
        if (!textAnchor) {
          textAnchor = 'start';
        }
        if (!foreColor || !foreColor.length) {
          foreColor = w.config.chart.foreColor;
        }
        fontFamily = fontFamily || w.config.chart.fontFamily;
        fontSize = fontSize || '11px';
        fontWeight = fontWeight || 'regular';
        var commonProps = {
          maxWidth: maxWidth,
          fontSize: fontSize,
          fontFamily: fontFamily
        };
        var elText;
        if (Array.isArray(text)) {
          elText = w.globals.dom.Paper.text(function (add) {
            for (var i = 0; i < text.length; i++) {
              truncatedText = text[i];
              if (maxWidth) {
                truncatedText = _this.getTextBasedOnMaxWidth(_objectSpread2({
                  text: text[i]
                }, commonProps));
              }
              i === 0 ? add.tspan(truncatedText) : add.tspan(truncatedText).newLine();
            }
          });
        } else {
          if (maxWidth) {
            truncatedText = this.getTextBasedOnMaxWidth(_objectSpread2({
              text: text
            }, commonProps));
          }
          elText = isPlainText ? w.globals.dom.Paper.plain(text) : w.globals.dom.Paper.text(function (add) {
            return add.tspan(truncatedText);
          });
        }
        elText.attr({
          x: x,
          y: y,
          'text-anchor': textAnchor,
          'dominant-baseline': dominantBaseline,
          'font-size': fontSize,
          'font-family': fontFamily,
          'font-weight': fontWeight,
          fill: foreColor,
          class: 'apexcharts-text ' + cssClass
        });
        elText.node.style.fontFamily = fontFamily;
        elText.node.style.opacity = opacity;
        return elText;
      }
    }, {
      key: "getMarkerPath",
      value: function getMarkerPath(x, y, type, size) {
        var d = '';
        switch (type) {
          case 'cross':
            size = size / 1.4;
            d = "M ".concat(x - size, " ").concat(y - size, " L ").concat(x + size, " ").concat(y + size, "  M ").concat(x - size, " ").concat(y + size, " L ").concat(x + size, " ").concat(y - size);
            break;
          case 'plus':
            size = size / 1.12;
            d = "M ".concat(x - size, " ").concat(y, " L ").concat(x + size, " ").concat(y, "  M ").concat(x, " ").concat(y - size, " L ").concat(x, " ").concat(y + size);
            break;
          case 'star':
          case 'sparkle':
            var points = 5;
            size = size * 1.15;
            if (type === 'sparkle') {
              size = size / 1.1;
              points = 4;
            }
            var step = Math.PI / points;
            for (var i = 0; i <= 2 * points; i++) {
              var angle = i * step;
              var radius = i % 2 === 0 ? size : size / 2;
              var xPos = x + radius * Math.sin(angle);
              var yPos = y - radius * Math.cos(angle);
              d += (i === 0 ? 'M' : 'L') + xPos + ',' + yPos;
            }
            d += 'Z';
            break;
          case 'triangle':
            d = "M ".concat(x, " ").concat(y - size, " \n             L ").concat(x + size, " ").concat(y + size, " \n             L ").concat(x - size, " ").concat(y + size, " \n             Z");
            break;
          case 'square':
          case 'rect':
            size = size / 1.125;
            d = "M ".concat(x - size, " ").concat(y - size, " \n           L ").concat(x + size, " ").concat(y - size, " \n           L ").concat(x + size, " ").concat(y + size, " \n           L ").concat(x - size, " ").concat(y + size, " \n           Z");
            break;
          case 'diamond':
            size = size * 1.05;
            d = "M ".concat(x, " ").concat(y - size, " \n             L ").concat(x + size, " ").concat(y, " \n             L ").concat(x, " ").concat(y + size, " \n             L ").concat(x - size, " ").concat(y, " \n            Z");
            break;
          case 'line':
            size = size / 1.1;
            d = "M ".concat(x - size, " ").concat(y, " \n           L ").concat(x + size, " ").concat(y);
            break;
          case 'circle':
          default:
            size = size * 2;
            d = "M ".concat(x, ", ").concat(y, " \n           m -").concat(size / 2, ", 0 \n           a ").concat(size / 2, ",").concat(size / 2, " 0 1,0 ").concat(size, ",0 \n           a ").concat(size / 2, ",").concat(size / 2, " 0 1,0 -").concat(size, ",0");
            break;
        }
        return d;
      }

      /**
       * @param {number} x - The x-coordinate of the marker
       * @param {number} y - The y-coordinate of the marker.
       * @param {number} size - The size of the marker
       * @param {Object} opts - The options for the marker.
       * @returns {Object} The created marker.
       */
    }, {
      key: "drawMarkerShape",
      value: function drawMarkerShape(x, y, type, size, opts) {
        var path = this.drawPath({
          d: this.getMarkerPath(x, y, type, size, opts),
          stroke: opts.pointStrokeColor,
          strokeDashArray: opts.pointStrokeDashArray,
          strokeWidth: opts.pointStrokeWidth,
          fill: opts.pointFillColor,
          fillOpacity: opts.pointFillOpacity,
          strokeOpacity: opts.pointStrokeOpacity
        });
        path.attr({
          cx: x,
          cy: y,
          shape: opts.shape,
          class: opts.class ? opts.class : ''
        });
        return path;
      }
    }, {
      key: "drawMarker",
      value: function drawMarker(x, y, opts) {
        x = x || 0;
        var size = opts.pSize || 0;
        if (!Utils$1.isNumber(y)) {
          size = 0;
          y = 0;
        }
        return this.drawMarkerShape(x, y, opts === null || opts === void 0 ? void 0 : opts.shape, size, _objectSpread2(_objectSpread2({}, opts), opts.shape === 'line' || opts.shape === 'plus' || opts.shape === 'cross' ? {
          pointStrokeColor: opts.pointFillColor,
          pointStrokeOpacity: opts.pointFillOpacity
        } : {}));
      }
    }, {
      key: "pathMouseEnter",
      value: function pathMouseEnter(path, e) {
        var w = this.w;
        var filters = new Filters(this.ctx);
        var i = parseInt(path.node.getAttribute('index'), 10);
        var j = parseInt(path.node.getAttribute('j'), 10);
        if (typeof w.config.chart.events.dataPointMouseEnter === 'function') {
          w.config.chart.events.dataPointMouseEnter(e, this.ctx, {
            seriesIndex: i,
            dataPointIndex: j,
            w: w
          });
        }
        this.ctx.events.fireEvent('dataPointMouseEnter', [e, this.ctx, {
          seriesIndex: i,
          dataPointIndex: j,
          w: w
        }]);
        if (w.config.states.active.filter.type !== 'none') {
          if (path.node.getAttribute('selected') === 'true') {
            return;
          }
        }
        if (w.config.states.hover.filter.type !== 'none') {
          if (!w.globals.isTouchDevice) {
            var hoverFilter = w.config.states.hover.filter;
            filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value);
          }
        }
      }
    }, {
      key: "pathMouseLeave",
      value: function pathMouseLeave(path, e) {
        var w = this.w;
        var filters = new Filters(this.ctx);
        var i = parseInt(path.node.getAttribute('index'), 10);
        var j = parseInt(path.node.getAttribute('j'), 10);
        if (typeof w.config.chart.events.dataPointMouseLeave === 'function') {
          w.config.chart.events.dataPointMouseLeave(e, this.ctx, {
            seriesIndex: i,
            dataPointIndex: j,
            w: w
          });
        }
        this.ctx.events.fireEvent('dataPointMouseLeave', [e, this.ctx, {
          seriesIndex: i,
          dataPointIndex: j,
          w: w
        }]);
        if (w.config.states.active.filter.type !== 'none') {
          if (path.node.getAttribute('selected') === 'true') {
            return;
          }
        }
        if (w.config.states.hover.filter.type !== 'none') {
          filters.getDefaultFilter(path, i);
        }
      }
    }, {
      key: "pathMouseDown",
      value: function pathMouseDown(path, e) {
        var w = this.w;
        var filters = new Filters(this.ctx);
        var i = parseInt(path.node.getAttribute('index'), 10);
        var j = parseInt(path.node.getAttribute('j'), 10);
        var selected = 'false';
        if (path.node.getAttribute('selected') === 'true') {
          path.node.setAttribute('selected', 'false');
          if (w.globals.selectedDataPoints[i].indexOf(j) > -1) {
            var index = w.globals.selectedDataPoints[i].indexOf(j);
            w.globals.selectedDataPoints[i].splice(index, 1);
          }
        } else {
          if (!w.config.states.active.allowMultipleDataPointsSelection && w.globals.selectedDataPoints.length > 0) {
            w.globals.selectedDataPoints = [];
            var elPaths = w.globals.dom.Paper.select('.apexcharts-series path').members;
            var elCircles = w.globals.dom.Paper.select('.apexcharts-series circle, .apexcharts-series rect').members;
            var deSelect = function deSelect(els) {
              Array.prototype.forEach.call(els, function (el) {
                el.node.setAttribute('selected', 'false');
                filters.getDefaultFilter(el, i);
              });
            };
            deSelect(elPaths);
            deSelect(elCircles);
          }
          path.node.setAttribute('selected', 'true');
          selected = 'true';
          if (typeof w.globals.selectedDataPoints[i] === 'undefined') {
            w.globals.selectedDataPoints[i] = [];
          }
          w.globals.selectedDataPoints[i].push(j);
        }
        if (selected === 'true') {
          var activeFilter = w.config.states.active.filter;
          if (activeFilter !== 'none') {
            filters.applyFilter(path, i, activeFilter.type, activeFilter.value);
          } else {
            // Reapply the hover filter in case it was removed by `deselect`when there is no active filter and it is not a touch device
            if (w.config.states.hover.filter !== 'none') {
              if (!w.globals.isTouchDevice) {
                var hoverFilter = w.config.states.hover.filter;
                filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value);
              }
            }
          }
        } else {
          // If the item was deselected, apply hover state filter if it is not a touch device
          if (w.config.states.active.filter.type !== 'none') {
            if (w.config.states.hover.filter.type !== 'none' && !w.globals.isTouchDevice) {
              var hoverFilter = w.config.states.hover.filter;
              filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value);
            } else {
              filters.getDefaultFilter(path, i);
            }
          }
        }
        if (typeof w.config.chart.events.dataPointSelection === 'function') {
          w.config.chart.events.dataPointSelection(e, this.ctx, {
            selectedDataPoints: w.globals.selectedDataPoints,
            seriesIndex: i,
            dataPointIndex: j,
            w: w
          });
        }
        if (e) {
          this.ctx.events.fireEvent('dataPointSelection', [e, this.ctx, {
            selectedDataPoints: w.globals.selectedDataPoints,
            seriesIndex: i,
            dataPointIndex: j,
            w: w
          }]);
        }
      }
    }, {
      key: "rotateAroundCenter",
      value: function rotateAroundCenter(el) {
        var coord = {};
        if (el && typeof el.getBBox === 'function') {
          coord = el.getBBox();
        }
        var x = coord.x + coord.width / 2;
        var y = coord.y + coord.height / 2;
        return {
          x: x,
          y: y
        };
      }
    }, {
      key: "getTextRects",
      value: function getTextRects(text, fontSize, fontFamily, transform) {
        var useBBox = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
        var w = this.w;
        var virtualText = this.drawText({
          x: -200,
          y: -200,
          text: text,
          textAnchor: 'start',
          fontSize: fontSize,
          fontFamily: fontFamily,
          foreColor: '#fff',
          opacity: 0
        });
        if (transform) {
          virtualText.attr('transform', transform);
        }
        w.globals.dom.Paper.add(virtualText);
        var rect = virtualText.bbox();
        if (!useBBox) {
          rect = virtualText.node.getBoundingClientRect();
        }
        virtualText.remove();
        return {
          width: rect.width,
          height: rect.height
        };
      }

      /**
       * append ... to long text
       * http://stackoverflow.com/questions/9241315/trimming-text-to-a-given-pixel-width-in-svg
       * @memberof Graphics
       **/
    }, {
      key: "placeTextWithEllipsis",
      value: function placeTextWithEllipsis(textObj, textString, width) {
        if (typeof textObj.getComputedTextLength !== 'function') return;
        textObj.textContent = textString;
        if (textString.length > 0) {
          // ellipsis is needed
          if (textObj.getComputedTextLength() >= width / 1.1) {
            for (var x = textString.length - 3; x > 0; x -= 3) {
              if (textObj.getSubStringLength(0, x) <= width / 1.1) {
                textObj.textContent = textString.substring(0, x) + '...';
                return;
              }
            }
            textObj.textContent = '.'; // can't place at all
          }
        }
      }
    }], [{
      key: "setAttrs",
      value: function setAttrs(el, attrs) {
        for (var key in attrs) {
          if (attrs.hasOwnProperty(key)) {
            el.setAttribute(key, attrs[key]);
          }
        }
      }
    }]);
    return Graphics;
  }();

  /*
   ** Util functions which are dependent on ApexCharts instance
   */
  var CoreUtils = /*#__PURE__*/function () {
    function CoreUtils(ctx) {
      _classCallCheck(this, CoreUtils);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(CoreUtils, [{
      key: "getStackedSeriesTotals",
      value:
      /**
       * @memberof CoreUtils
       * returns the sum of all individual values in a multiple stacked series
       * Eg. w.globals.series = [[32,33,43,12], [2,3,5,1]]
       *  @return [34,36,48,13]
       **/
      function getStackedSeriesTotals() {
        var excludedSeriesIndices = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
        var w = this.w;
        var total = [];
        if (w.globals.series.length === 0) return total;
        for (var i = 0; i < w.globals.series[w.globals.maxValsInArrayIndex].length; i++) {
          var t = 0;
          for (var j = 0; j < w.globals.series.length; j++) {
            if (typeof w.globals.series[j][i] !== 'undefined' && excludedSeriesIndices.indexOf(j) === -1) {
              t += w.globals.series[j][i];
            }
          }
          total.push(t);
        }
        return total;
      }

      // get total of the all values inside all series
    }, {
      key: "getSeriesTotalByIndex",
      value: function getSeriesTotalByIndex() {
        var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        if (index === null) {
          // non-plot chart types - pie / donut / circle
          return this.w.config.series.reduce(function (acc, cur) {
            return acc + cur;
          }, 0);
        } else {
          // axis charts - supporting multiple series
          return this.w.globals.series[index].reduce(function (acc, cur) {
            return acc + cur;
          }, 0);
        }
      }

      /**
       * @memberof CoreUtils
       * returns the sum of values in a multiple stacked grouped charts
       * Eg. w.globals.series = [[32,33,43,12], [2,3,5,1], [43, 23, 34, 22]]
       * series 1 and 2 are in a group, while series 3 is in another group
       *  @return [[34, 36, 48, 12], [43, 23, 34, 22]]
       **/
    }, {
      key: "getStackedSeriesTotalsByGroups",
      value: function getStackedSeriesTotalsByGroups() {
        var _this = this;
        var w = this.w;
        var total = [];
        w.globals.seriesGroups.forEach(function (sg) {
          var includedIndexes = [];
          w.config.series.forEach(function (s, si) {
            if (sg.indexOf(w.globals.seriesNames[si]) > -1) {
              includedIndexes.push(si);
            }
          });
          var excludedIndices = w.globals.series.map(function (_, fi) {
            return includedIndexes.indexOf(fi) === -1 ? fi : -1;
          }).filter(function (f) {
            return f !== -1;
          });
          total.push(_this.getStackedSeriesTotals(excludedIndices));
        });
        return total;
      }
    }, {
      key: "setSeriesYAxisMappings",
      value: function setSeriesYAxisMappings() {
        var gl = this.w.globals;
        var cnf = this.w.config;

        // The old config method to map multiple series to a y axis is to
        // include one yaxis config per series but set each yaxis seriesName to the
        // same series name. This relies on indexing equivalence to map series to
        // an axis: series[n] => yaxis[n]. This needs to be retained for compatibility.
        // But we introduce an alternative that explicitly configures yaxis elements
        // with the series that will be referenced to them (seriesName: []). This
        // only requires including the yaxis elements that will be seen on the chart.
        // Old way:
        // ya: s
        // 0: 0
        // 1: 1
        // 2: 1
        // 3: 1
        // 4: 1
        // Axes 0..4 are all scaled and all will be rendered unless the axes are
        // show: false. If the chart is stacked, it's assumed that series 1..4 are
        // the contributing series. This is not particularly intuitive.
        // New way:
        // ya: s
        // 0: [0]
        // 1: [1,2,3,4]
        // If the chart is stacked, it can be assumed that any axis with multiple
        // series is stacked.
        //
        // If this is an old chart and we are being backward compatible, it will be
        // expected that each series is associated with it's corresponding yaxis
        // through their indices, one-to-one.
        // If yaxis.seriesName matches series.name, we have indices yi and si.
        // A name match where yi != si is interpretted as yaxis[yi] and yaxis[si]
        // will both be scaled to fit the combined series[si] and series[yi].
        // Consider series named: S0,S1,S2 and yaxes A0,A1,A2.
        //
        // Example 1: A0 and A1 scaled the same.
        // A0.seriesName: S0
        // A1.seriesName: S0
        // A2.seriesName: S2
        // Then A1 <-> A0
        //
        // Example 2: A0, A1 and A2 all scaled the same.
        // A0.seriesName: S2
        // A1.seriesName: S0
        // A2.seriesName: S1
        // A0 <-> A2, A1 <-> A0, A2 <-> A1 --->>> A0 <-> A1 <-> A2

        var axisSeriesMap = [];
        var seriesYAxisReverseMap = [];
        var unassignedSeriesIndices = [];
        var seriesNameArrayStyle = gl.series.length > cnf.yaxis.length || cnf.yaxis.some(function (a) {
          return Array.isArray(a.seriesName);
        });
        cnf.series.forEach(function (s, i) {
          unassignedSeriesIndices.push(i);
          seriesYAxisReverseMap.push(null);
        });
        cnf.yaxis.forEach(function (yaxe, yi) {
          axisSeriesMap[yi] = [];
        });
        var unassignedYAxisIndices = [];

        // here, we loop through the yaxis array and find the item which has "seriesName" property
        cnf.yaxis.forEach(function (yaxe, yi) {
          var assigned = false;
          // Allow seriesName to be either a string (for backward compatibility),
          // in which case, handle multiple yaxes referencing the same series.
          // or an array of strings so that a yaxis can reference multiple series.
          // Feature request #4237
          if (yaxe.seriesName) {
            var seriesNames = [];
            if (Array.isArray(yaxe.seriesName)) {
              seriesNames = yaxe.seriesName;
            } else {
              seriesNames.push(yaxe.seriesName);
            }
            seriesNames.forEach(function (name) {
              cnf.series.forEach(function (s, si) {
                if (s.name === name) {
                  var remove = si;
                  if (yi === si || seriesNameArrayStyle) {
                    // New style, don't allow series to be double referenced
                    if (!seriesNameArrayStyle || unassignedSeriesIndices.indexOf(si) > -1) {
                      axisSeriesMap[yi].push([yi, si]);
                    } else {
                      console.warn("Series '" + s.name + "' referenced more than once in what looks like the new style." + ' That is, when using either seriesName: [],' + ' or when there are more series than yaxes.');
                    }
                  } else {
                    // The series index refers to the target yaxis and the current
                    // yaxis index refers to the actual referenced series.
                    axisSeriesMap[si].push([si, yi]);
                    remove = yi;
                  }
                  assigned = true;
                  remove = unassignedSeriesIndices.indexOf(remove);
                  if (remove !== -1) {
                    unassignedSeriesIndices.splice(remove, 1);
                  }
                }
              });
            });
          }
          if (!assigned) {
            unassignedYAxisIndices.push(yi);
          }
        });
        axisSeriesMap = axisSeriesMap.map(function (yaxe, yi) {
          var ra = [];
          yaxe.forEach(function (sa) {
            seriesYAxisReverseMap[sa[1]] = sa[0];
            ra.push(sa[1]);
          });
          return ra;
        });

        // All series referenced directly by yaxes have been assigned to those axes.
        // Any series so far unassigned will be assigned to any yaxes that have yet
        // to reference series directly, one-for-one in order of appearance, with
        // all left-over series assigned to either the last unassigned yaxis, or the
        // last yaxis if all have assigned series. This captures the
        // default single and multiaxis config options which simply includes zero,
        // one or as many yaxes as there are series but do not reference them by name.
        var lastUnassignedYAxis = cnf.yaxis.length - 1;
        for (var i = 0; i < unassignedYAxisIndices.length; i++) {
          lastUnassignedYAxis = unassignedYAxisIndices[i];
          axisSeriesMap[lastUnassignedYAxis] = [];
          if (unassignedSeriesIndices) {
            var si = unassignedSeriesIndices[0];
            unassignedSeriesIndices.shift();
            axisSeriesMap[lastUnassignedYAxis].push(si);
            seriesYAxisReverseMap[si] = lastUnassignedYAxis;
          } else {
            break;
          }
        }
        unassignedSeriesIndices.forEach(function (i) {
          axisSeriesMap[lastUnassignedYAxis].push(i);
          seriesYAxisReverseMap[i] = lastUnassignedYAxis;
        });

        // For the old-style seriesName-as-string-only, leave the zero-length yaxis
        // array elements in for compatibility so that series.length == yaxes.length
        // for multi axis charts.
        gl.seriesYAxisMap = axisSeriesMap.map(function (x) {
          return x;
        });
        gl.seriesYAxisReverseMap = seriesYAxisReverseMap.map(function (x) {
          return x;
        });
        // Set default series group names
        gl.seriesYAxisMap.forEach(function (axisSeries, ai) {
          axisSeries.forEach(function (si) {
            // series may be bare until loaded in realtime
            if (cnf.series[si] && cnf.series[si].group === undefined) {
              // A series with no group defined will be named after the axis that
              // referenced it and thus form a group automatically.
              cnf.series[si].group = 'apexcharts-axis-'.concat(ai.toString());
            }
          });
        });
      }
    }, {
      key: "isSeriesNull",
      value: function isSeriesNull() {
        var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        var r = [];
        if (index === null) {
          // non-plot chart types - pie / donut / circle
          r = this.w.config.series.filter(function (d) {
            return d !== null;
          });
        } else {
          // axis charts - supporting multiple series
          r = this.w.config.series[index].data.filter(function (d) {
            return d !== null;
          });
        }
        return r.length === 0;
      }
    }, {
      key: "seriesHaveSameValues",
      value: function seriesHaveSameValues(index) {
        return this.w.globals.series[index].every(function (val, i, arr) {
          return val === arr[0];
        });
      }
    }, {
      key: "getCategoryLabels",
      value: function getCategoryLabels(labels) {
        var w = this.w;
        var catLabels = labels.slice();
        if (w.config.xaxis.convertedCatToNumeric) {
          catLabels = labels.map(function (i, li) {
            return w.config.xaxis.labels.formatter(i - w.globals.minX + 1);
          });
        }
        return catLabels;
      }
      // maxValsInArrayIndex is the index of series[] which has the largest number of items
    }, {
      key: "getLargestSeries",
      value: function getLargestSeries() {
        var w = this.w;
        w.globals.maxValsInArrayIndex = w.globals.series.map(function (a) {
          return a.length;
        }).indexOf(Math.max.apply(Math, w.globals.series.map(function (a) {
          return a.length;
        })));
      }
    }, {
      key: "getLargestMarkerSize",
      value: function getLargestMarkerSize() {
        var w = this.w;
        var size = 0;
        w.globals.markers.size.forEach(function (m) {
          size = Math.max(size, m);
        });
        if (w.config.markers.discrete && w.config.markers.discrete.length) {
          w.config.markers.discrete.forEach(function (m) {
            size = Math.max(size, m.size);
          });
        }
        if (size > 0) {
          if (w.config.markers.hover.size > 0) {
            size = w.config.markers.hover.size;
          } else {
            size += w.config.markers.hover.sizeOffset;
          }
        }
        w.globals.markers.largestSize = size;
        return size;
      }

      /**
       * @memberof Core
       * returns the sum of all values in a series
       * Eg. w.globals.series = [[32,33,43,12], [2,3,5,1]]
       *  @return [120, 11]
       **/
    }, {
      key: "getSeriesTotals",
      value: function getSeriesTotals() {
        var w = this.w;
        w.globals.seriesTotals = w.globals.series.map(function (ser, index) {
          var total = 0;
          if (Array.isArray(ser)) {
            for (var j = 0; j < ser.length; j++) {
              total += ser[j];
            }
          } else {
            // for pie/donuts/gauges
            total += ser;
          }
          return total;
        });
      }
    }, {
      key: "getSeriesTotalsXRange",
      value: function getSeriesTotalsXRange(minX, maxX) {
        var w = this.w;
        var seriesTotalsXRange = w.globals.series.map(function (ser, index) {
          var total = 0;
          for (var j = 0; j < ser.length; j++) {
            if (w.globals.seriesX[index][j] > minX && w.globals.seriesX[index][j] < maxX) {
              total += ser[j];
            }
          }
          return total;
        });
        return seriesTotalsXRange;
      }

      /**
       * @memberof CoreUtils
       * returns the percentage value of all individual values which can be used in a 100% stacked series
       * Eg. w.globals.series = [[32, 33, 43, 12], [2, 3, 5, 1]]
       *  @return [[94.11, 91.66, 89.58, 92.30], [5.88, 8.33, 10.41, 7.7]]
       **/
    }, {
      key: "getPercentSeries",
      value: function getPercentSeries() {
        var w = this.w;
        w.globals.seriesPercent = w.globals.series.map(function (ser, index) {
          var seriesPercent = [];
          if (Array.isArray(ser)) {
            for (var j = 0; j < ser.length; j++) {
              var total = w.globals.stackedSeriesTotals[j];
              var percent = 0;
              if (total) {
                percent = 100 * ser[j] / total;
              }
              seriesPercent.push(percent);
            }
          } else {
            var _total = w.globals.seriesTotals.reduce(function (acc, val) {
              return acc + val;
            }, 0);
            var _percent = 100 * ser / _total;
            seriesPercent.push(_percent);
          }
          return seriesPercent;
        });
      }
    }, {
      key: "getCalculatedRatios",
      value: function getCalculatedRatios() {
        var _this2 = this;
        var w = this.w;
        var gl = w.globals;
        var yRatio = [];
        var invertedYRatio = 0;
        var xRatio = 0;
        var invertedXRatio = 0;
        var zRatio = 0;
        var baseLineY = [];
        var baseLineInvertedY = 0.1;
        var baseLineX = 0;
        gl.yRange = [];
        if (gl.isMultipleYAxis) {
          for (var i = 0; i < gl.minYArr.length; i++) {
            gl.yRange.push(Math.abs(gl.minYArr[i] - gl.maxYArr[i]));
            baseLineY.push(0);
          }
        } else {
          gl.yRange.push(Math.abs(gl.minY - gl.maxY));
        }
        gl.xRange = Math.abs(gl.maxX - gl.minX);
        gl.zRange = Math.abs(gl.maxZ - gl.minZ);

        // multiple y axis
        for (var _i = 0; _i < gl.yRange.length; _i++) {
          yRatio.push(gl.yRange[_i] / gl.gridHeight);
        }
        xRatio = gl.xRange / gl.gridWidth;
        invertedYRatio = gl.yRange / gl.gridWidth;
        invertedXRatio = gl.xRange / gl.gridHeight;
        zRatio = gl.zRange / gl.gridHeight * 16;
        if (!zRatio) {
          zRatio = 1;
        }
        if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) {
          // Negative numbers present in series
          gl.hasNegs = true;
        }

        // Check we have a map as series may still to be added/updated.
        if (w.globals.seriesYAxisReverseMap.length > 0) {
          var scaleBaseLineYScale = function scaleBaseLineYScale(y, i) {
            var yAxis = w.config.yaxis[w.globals.seriesYAxisReverseMap[i]];
            var sign = y < 0 ? -1 : 1;
            y = Math.abs(y);
            if (yAxis.logarithmic) {
              y = _this2.getBaseLog(yAxis.logBase, y);
            }
            return -sign * y / yRatio[i];
          };
          if (gl.isMultipleYAxis) {
            baseLineY = [];
            // baseline variables is the 0 of the yaxis which will be needed when there are negatives
            for (var _i2 = 0; _i2 < yRatio.length; _i2++) {
              baseLineY.push(scaleBaseLineYScale(gl.minYArr[_i2], _i2));
            }
          } else {
            baseLineY = [];
            baseLineY.push(scaleBaseLineYScale(gl.minY, 0));
            if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) {
              baseLineInvertedY = -gl.minY / invertedYRatio; // this is for bar chart
              baseLineX = gl.minX / xRatio;
            }
          }
        } else {
          baseLineY = [];
          baseLineY.push(0);
          baseLineInvertedY = 0;
          baseLineX = 0;
        }
        return {
          yRatio: yRatio,
          invertedYRatio: invertedYRatio,
          zRatio: zRatio,
          xRatio: xRatio,
          invertedXRatio: invertedXRatio,
          baseLineInvertedY: baseLineInvertedY,
          baseLineY: baseLineY,
          baseLineX: baseLineX
        };
      }
    }, {
      key: "getLogSeries",
      value: function getLogSeries(series) {
        var _this3 = this;
        var w = this.w;
        w.globals.seriesLog = series.map(function (s, i) {
          var yAxisIndex = w.globals.seriesYAxisReverseMap[i];
          if (w.config.yaxis[yAxisIndex] && w.config.yaxis[yAxisIndex].logarithmic) {
            return s.map(function (d) {
              if (d === null) return null;
              return _this3.getLogVal(w.config.yaxis[yAxisIndex].logBase, d, i);
            });
          } else {
            return s;
          }
        });
        return w.globals.invalidLogScale ? series : w.globals.seriesLog;
      }
    }, {
      key: "getBaseLog",
      value: function getBaseLog(base, value) {
        return Math.log(value) / Math.log(base);
      }
    }, {
      key: "getLogVal",
      value: function getLogVal(b, d, seriesIndex) {
        if (d <= 0) {
          return 0; // Should be Number.NEGATIVE_INFINITY
        }
        var w = this.w;
        var min_log_val = w.globals.minYArr[seriesIndex] === 0 ? -1 // make sure we dont calculate log of 0
        : this.getBaseLog(b, w.globals.minYArr[seriesIndex]);
        var max_log_val = w.globals.maxYArr[seriesIndex] === 0 ? 0 // make sure we dont calculate log of 0
        : this.getBaseLog(b, w.globals.maxYArr[seriesIndex]);
        var number_of_height_levels = max_log_val - min_log_val;
        if (d < 1) return d / number_of_height_levels;
        var log_height_value = this.getBaseLog(b, d) - min_log_val;
        return log_height_value / number_of_height_levels;
      }
    }, {
      key: "getLogYRatios",
      value: function getLogYRatios(yRatio) {
        var _this4 = this;
        var w = this.w;
        var gl = this.w.globals;
        gl.yLogRatio = yRatio.slice();
        gl.logYRange = gl.yRange.map(function (_, i) {
          var yAxisIndex = w.globals.seriesYAxisReverseMap[i];
          if (w.config.yaxis[yAxisIndex] && _this4.w.config.yaxis[yAxisIndex].logarithmic) {
            var maxY = -Number.MAX_VALUE;
            var minY = Number.MIN_VALUE;
            var range = 1;
            gl.seriesLog.forEach(function (s, si) {
              s.forEach(function (v) {
                if (w.config.yaxis[si] && w.config.yaxis[si].logarithmic) {
                  maxY = Math.max(v, maxY);
                  minY = Math.min(v, minY);
                }
              });
            });
            range = Math.pow(gl.yRange[i], Math.abs(minY - maxY) / gl.yRange[i]);
            gl.yLogRatio[i] = range / gl.gridHeight;
            return range;
          }
        });
        return gl.invalidLogScale ? yRatio.slice() : gl.yLogRatio;
      }

      // Some config objects can be array - and we need to extend them correctly
    }, {
      key: "drawSeriesByGroup",
      value:
      // Series of the same group and type can be stacked together distinct from
      // other series of the same type on the same axis.
      function drawSeriesByGroup(typeSeries, typeGroups, type, chartClass) {
        var w = this.w;
        var graph = [];
        if (typeSeries.series.length > 0) {
          // draw each group separately
          typeGroups.forEach(function (gn) {
            var gs = [];
            var gi = [];
            typeSeries.i.forEach(function (i, ii) {
              if (w.config.series[i].group === gn) {
                gs.push(typeSeries.series[ii]);
                gi.push(i);
              }
            });
            gs.length > 0 && graph.push(chartClass.draw(gs, type, gi));
          });
        }
        return graph;
      }
    }], [{
      key: "checkComboSeries",
      value: function checkComboSeries(series, chartType) {
        var comboCharts = false;
        var comboBarCount = 0;
        var comboCount = 0;
        if (chartType === undefined) {
          chartType = 'line';
        }

        // Check if user specified a type in series that may make us a combo chart.
        // The default type for chart is "line" and the default for series is the
        // chart type, therefore, if the types of all series match the chart type,
        // this should not be considered a combo chart.
        if (series.length && typeof series[0].type !== 'undefined') {
          series.forEach(function (s) {
            if (s.type === 'bar' || s.type === 'column' || s.type === 'candlestick' || s.type === 'boxPlot') {
              comboBarCount++;
            }
            if (typeof s.type !== 'undefined' && s.type !== chartType) {
              comboCount++;
            }
          });
        }
        if (comboCount > 0) {
          comboCharts = true;
        }
        return {
          comboBarCount: comboBarCount,
          comboCharts: comboCharts
        };
      }
    }, {
      key: "extendArrayProps",
      value: function extendArrayProps(configInstance, options, w) {
        var _options, _options2;
        if ((_options = options) !== null && _options !== void 0 && _options.yaxis) {
          options = configInstance.extendYAxis(options, w);
        }
        if ((_options2 = options) !== null && _options2 !== void 0 && _options2.annotations) {
          var _options3, _options3$annotations, _options4, _options4$annotations;
          if (options.annotations.yaxis) {
            options = configInstance.extendYAxisAnnotations(options);
          }
          if ((_options3 = options) !== null && _options3 !== void 0 && (_options3$annotations = _options3.annotations) !== null && _options3$annotations !== void 0 && _options3$annotations.xaxis) {
            options = configInstance.extendXAxisAnnotations(options);
          }
          if ((_options4 = options) !== null && _options4 !== void 0 && (_options4$annotations = _options4.annotations) !== null && _options4$annotations !== void 0 && _options4$annotations.points) {
            options = configInstance.extendPointAnnotations(options);
          }
        }
        return options;
      }
    }]);
    return CoreUtils;
  }();

  var Helpers$4 = /*#__PURE__*/function () {
    function Helpers(annoCtx) {
      _classCallCheck(this, Helpers);
      this.w = annoCtx.w;
      this.annoCtx = annoCtx;
    }
    _createClass(Helpers, [{
      key: "setOrientations",
      value: function setOrientations(anno) {
        var annoIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
        var w = this.w;
        if (anno.label.orientation === 'vertical') {
          var i = annoIndex !== null ? annoIndex : 0;
          var xAnno = w.globals.dom.baseEl.querySelector(".apexcharts-xaxis-annotations .apexcharts-xaxis-annotation-label[rel='".concat(i, "']"));
          if (xAnno !== null) {
            var xAnnoCoord = xAnno.getBoundingClientRect();
            xAnno.setAttribute('x', parseFloat(xAnno.getAttribute('x')) - xAnnoCoord.height + 4);
            var yOffset = anno.label.position === 'top' ? xAnnoCoord.width : -xAnnoCoord.width;
            xAnno.setAttribute('y', parseFloat(xAnno.getAttribute('y')) + yOffset);
            var _this$annoCtx$graphic = this.annoCtx.graphics.rotateAroundCenter(xAnno),
              x = _this$annoCtx$graphic.x,
              y = _this$annoCtx$graphic.y;
            xAnno.setAttribute('transform', "rotate(-90 ".concat(x, " ").concat(y, ")"));
          }
        }
      }
    }, {
      key: "addBackgroundToAnno",
      value: function addBackgroundToAnno(annoEl, anno) {
        var w = this.w;
        if (!annoEl || !anno.label.text || !String(anno.label.text).trim()) {
          return null;
        }
        var elGridRect = w.globals.dom.baseEl.querySelector('.apexcharts-grid').getBoundingClientRect();
        var coords = annoEl.getBoundingClientRect();
        var _anno$label$style$pad = anno.label.style.padding,
          pleft = _anno$label$style$pad.left,
          pright = _anno$label$style$pad.right,
          ptop = _anno$label$style$pad.top,
          pbottom = _anno$label$style$pad.bottom;
        if (anno.label.orientation === 'vertical') {
          var _ref = [pleft, pright, ptop, pbottom];
          ptop = _ref[0];
          pbottom = _ref[1];
          pleft = _ref[2];
          pright = _ref[3];
        }
        var x1 = coords.left - elGridRect.left - pleft;
        var y1 = coords.top - elGridRect.top - ptop;
        var elRect = this.annoCtx.graphics.drawRect(x1 - w.globals.barPadForNumericAxis, y1, coords.width + pleft + pright, coords.height + ptop + pbottom, anno.label.borderRadius, anno.label.style.background, 1, anno.label.borderWidth, anno.label.borderColor, 0);
        if (anno.id) {
          elRect.node.classList.add(anno.id);
        }
        return elRect;
      }
    }, {
      key: "annotationsBackground",
      value: function annotationsBackground() {
        var _this = this;
        var w = this.w;
        var add = function add(anno, i, type) {
          var annoLabel = w.globals.dom.baseEl.querySelector(".apexcharts-".concat(type, "-annotations .apexcharts-").concat(type, "-annotation-label[rel='").concat(i, "']"));
          if (annoLabel) {
            var parent = annoLabel.parentNode;
            var elRect = _this.addBackgroundToAnno(annoLabel, anno);
            if (elRect) {
              parent.insertBefore(elRect.node, annoLabel);
              if (anno.label.mouseEnter) {
                elRect.node.addEventListener('mouseenter', anno.label.mouseEnter.bind(_this, anno));
              }
              if (anno.label.mouseLeave) {
                elRect.node.addEventListener('mouseleave', anno.label.mouseLeave.bind(_this, anno));
              }
              if (anno.label.click) {
                elRect.node.addEventListener('click', anno.label.click.bind(_this, anno));
              }
            }
          }
        };
        w.config.annotations.xaxis.forEach(function (anno, i) {
          return add(anno, i, 'xaxis');
        });
        w.config.annotations.yaxis.forEach(function (anno, i) {
          return add(anno, i, 'yaxis');
        });
        w.config.annotations.points.forEach(function (anno, i) {
          return add(anno, i, 'point');
        });
      }
    }, {
      key: "getY1Y2",
      value: function getY1Y2(type, anno) {
        var w = this.w;
        var y = type === 'y1' ? anno.y : anno.y2;
        var yP;
        var clipped = false;
        if (this.annoCtx.invertAxis) {
          var labels = w.config.xaxis.convertedCatToNumeric ? w.globals.categoryLabels : w.globals.labels;
          var catIndex = labels.indexOf(y);
          var xLabel = w.globals.dom.baseEl.querySelector(".apexcharts-yaxis-texts-g text:nth-child(".concat(catIndex + 1, ")"));
          yP = xLabel ? parseFloat(xLabel.getAttribute('y')) : (w.globals.gridHeight / labels.length - 1) * (catIndex + 1) - w.globals.barHeight;
          if (anno.seriesIndex !== undefined && w.globals.barHeight) {
            yP -= w.globals.barHeight / 2 * (w.globals.series.length - 1) - w.globals.barHeight * anno.seriesIndex;
          }
        } else {
          var _w$config$yaxis$anno$;
          var seriesIndex = w.globals.seriesYAxisMap[anno.yAxisIndex][0];
          var yPos = w.config.yaxis[anno.yAxisIndex].logarithmic ? new CoreUtils(this.annoCtx.ctx).getLogVal(w.config.yaxis[anno.yAxisIndex].logBase, y, seriesIndex) / w.globals.yLogRatio[seriesIndex] : (y - w.globals.minYArr[seriesIndex]) / (w.globals.yRange[seriesIndex] / w.globals.gridHeight);
          yP = w.globals.gridHeight - Math.min(Math.max(yPos, 0), w.globals.gridHeight);
          clipped = yPos > w.globals.gridHeight || yPos < 0;
          if (anno.marker && (anno.y === undefined || anno.y === null)) {
            yP = 0;
          }
          if ((_w$config$yaxis$anno$ = w.config.yaxis[anno.yAxisIndex]) !== null && _w$config$yaxis$anno$ !== void 0 && _w$config$yaxis$anno$.reversed) {
            yP = yPos;
          }
        }
        if (typeof y === 'string' && y.includes('px')) {
          yP = parseFloat(y);
        }
        return {
          yP: yP,
          clipped: clipped
        };
      }
    }, {
      key: "getX1X2",
      value: function getX1X2(type, anno) {
        var w = this.w;
        var x = type === 'x1' ? anno.x : anno.x2;
        var min = this.annoCtx.invertAxis ? w.globals.minY : w.globals.minX;
        var max = this.annoCtx.invertAxis ? w.globals.maxY : w.globals.maxX;
        var range = this.annoCtx.invertAxis ? w.globals.yRange[0] : w.globals.xRange;
        var clipped = false;
        var xP = this.annoCtx.inversedReversedAxis ? (max - x) / (range / w.globals.gridWidth) : (x - min) / (range / w.globals.gridWidth);
        if ((w.config.xaxis.type === 'category' || w.config.xaxis.convertedCatToNumeric) && !this.annoCtx.invertAxis && !w.globals.dataFormatXNumeric) {
          if (!w.config.chart.sparkline.enabled) {
            xP = this.getStringX(x);
          }
        }
        if (typeof x === 'string' && x.includes('px')) {
          xP = parseFloat(x);
        }
        if ((x === undefined || x === null) && anno.marker) {
          xP = w.globals.gridWidth;
        }
        if (anno.seriesIndex !== undefined && w.globals.barWidth && !this.annoCtx.invertAxis) {
          xP -= w.globals.barWidth / 2 * (w.globals.series.length - 1) - w.globals.barWidth * anno.seriesIndex;
        }
        if (xP > w.globals.gridWidth) {
          xP = w.globals.gridWidth;
          clipped = true;
        } else if (xP < 0) {
          xP = 0;
          clipped = true;
        }
        return {
          x: xP,
          clipped: clipped
        };
      }
    }, {
      key: "getStringX",
      value: function getStringX(x) {
        var w = this.w;
        var rX = x;
        if (w.config.xaxis.convertedCatToNumeric && w.globals.categoryLabels.length) {
          x = w.globals.categoryLabels.indexOf(x) + 1;
        }
        var catIndex = w.globals.labels.map(function (item) {
          return Array.isArray(item) ? item.join(' ') : item;
        }).indexOf(x);
        var xLabel = w.globals.dom.baseEl.querySelector(".apexcharts-xaxis-texts-g text:nth-child(".concat(catIndex + 1, ")"));
        if (xLabel) {
          rX = parseFloat(xLabel.getAttribute('x'));
        }
        return rX;
      }
    }]);
    return Helpers;
  }();

  var XAnnotations = /*#__PURE__*/function () {
    function XAnnotations(annoCtx) {
      _classCallCheck(this, XAnnotations);
      this.w = annoCtx.w;
      this.annoCtx = annoCtx;
      this.invertAxis = this.annoCtx.invertAxis;
      this.helpers = new Helpers$4(this.annoCtx);
    }
    _createClass(XAnnotations, [{
      key: "addXaxisAnnotation",
      value: function addXaxisAnnotation(anno, parent, index) {
        var w = this.w;
        var result = this.helpers.getX1X2('x1', anno);
        var x1 = result.x;
        var clipX1 = result.clipped;
        var clipX2 = true;
        var x2;
        var text = anno.label.text;
        var strokeDashArray = anno.strokeDashArray;
        if (!Utils$1.isNumber(x1)) return;
        if (anno.x2 === null || typeof anno.x2 === 'undefined') {
          if (!clipX1) {
            var line = this.annoCtx.graphics.drawLine(x1 + anno.offsetX,
            // x1
            0 + anno.offsetY,
            // y1
            x1 + anno.offsetX,
            // x2
            w.globals.gridHeight + anno.offsetY,
            // y2
            anno.borderColor,
            // lineColor
            strokeDashArray,
            //dashArray
            anno.borderWidth);
            parent.appendChild(line.node);
            if (anno.id) {
              line.node.classList.add(anno.id);
            }
          }
        } else {
          var _result = this.helpers.getX1X2('x2', anno);
          x2 = _result.x;
          clipX2 = _result.clipped;
          if (!(clipX1 && clipX2)) {
            if (x2 < x1) {
              var temp = x1;
              x1 = x2;
              x2 = temp;
            }
            var rect = this.annoCtx.graphics.drawRect(x1 + anno.offsetX,
            // x1
            0 + anno.offsetY,
            // y1
            x2 - x1,
            // x2
            w.globals.gridHeight + anno.offsetY,
            // y2
            0,
            // radius
            anno.fillColor,
            // color
            anno.opacity,
            // opacity,
            1,
            // strokeWidth
            anno.borderColor,
            // strokeColor
            strokeDashArray // stokeDashArray
            );
            rect.node.classList.add('apexcharts-annotation-rect');
            rect.attr('clip-path', "url(#gridRectMask".concat(w.globals.cuid, ")"));
            parent.appendChild(rect.node);
            if (anno.id) {
              rect.node.classList.add(anno.id);
            }
          }
        }
        if (!(clipX1 && clipX2)) {
          var textRects = this.annoCtx.graphics.getTextRects(text, parseFloat(anno.label.style.fontSize));
          var textY = anno.label.position === 'top' ? 4 : anno.label.position === 'center' ? w.globals.gridHeight / 2 + (anno.label.orientation === 'vertical' ? textRects.width / 2 : 0) : w.globals.gridHeight;
          var elText = this.annoCtx.graphics.drawText({
            x: x1 + anno.label.offsetX,
            y: textY + anno.label.offsetY - (anno.label.orientation === 'vertical' ? anno.label.position === 'top' ? textRects.width / 2 - 12 : -textRects.width / 2 : 0),
            text: text,
            textAnchor: anno.label.textAnchor,
            fontSize: anno.label.style.fontSize,
            fontFamily: anno.label.style.fontFamily,
            fontWeight: anno.label.style.fontWeight,
            foreColor: anno.label.style.color,
            cssClass: "apexcharts-xaxis-annotation-label ".concat(anno.label.style.cssClass, " ").concat(anno.id ? anno.id : '')
          });
          elText.attr({
            rel: index
          });
          parent.appendChild(elText.node);

          // after placing the annotations on svg, set any vertically placed annotations
          this.annoCtx.helpers.setOrientations(anno, index);
        }
      }
    }, {
      key: "drawXAxisAnnotations",
      value: function drawXAxisAnnotations() {
        var _this = this;
        var w = this.w;
        var elg = this.annoCtx.graphics.group({
          class: 'apexcharts-xaxis-annotations'
        });
        w.config.annotations.xaxis.map(function (anno, index) {
          _this.addXaxisAnnotation(anno, elg.node, index);
        });
        return elg;
      }
    }]);
    return XAnnotations;
  }();

  /**
   * DateTime Class to manipulate datetime values.
   *
   * @module DateTime
   **/
  var DateTime = /*#__PURE__*/function () {
    function DateTime(ctx) {
      _classCallCheck(this, DateTime);
      this.ctx = ctx;
      this.w = ctx.w;
      this.months31 = [1, 3, 5, 7, 8, 10, 12];
      this.months30 = [2, 4, 6, 9, 11];
      this.daysCntOfYear = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
    }
    _createClass(DateTime, [{
      key: "isValidDate",
      value: function isValidDate(date) {
        if (typeof date === 'number') {
          return false; // don't test for timestamps
        }
        return !isNaN(this.parseDate(date));
      }
    }, {
      key: "getTimeStamp",
      value: function getTimeStamp(dateStr) {
        if (!Date.parse(dateStr)) {
          return dateStr;
        }
        var utc = this.w.config.xaxis.labels.datetimeUTC;
        return !utc ? new Date(dateStr).getTime() : new Date(new Date(dateStr).toISOString().substr(0, 25)).getTime();
      }
    }, {
      key: "getDate",
      value: function getDate(timestamp) {
        var utc = this.w.config.xaxis.labels.datetimeUTC;
        return utc ? new Date(new Date(timestamp).toUTCString()) : new Date(timestamp);
      }
    }, {
      key: "parseDate",
      value: function parseDate(dateStr) {
        var parsed = Date.parse(dateStr);
        if (!isNaN(parsed)) {
          return this.getTimeStamp(dateStr);
        }
        var output = Date.parse(dateStr.replace(/-/g, '/').replace(/[a-z]+/gi, ' '));
        output = this.getTimeStamp(output);
        return output;
      }

      // This fixes the difference of x-axis labels between chrome/safari
      // Fixes #1726, #1544, #1485, #1255
    }, {
      key: "parseDateWithTimezone",
      value: function parseDateWithTimezone(dateStr) {
        return Date.parse(dateStr.replace(/-/g, '/').replace(/[a-z]+/gi, ' '));
      }

      // http://stackoverflow.com/questions/14638018/current-time-formatting-with-javascript#answer-14638191
    }, {
      key: "formatDate",
      value: function formatDate(date, format) {
        var locale = this.w.globals.locale;
        var utc = this.w.config.xaxis.labels.datetimeUTC;
        var MMMM = ['\x00'].concat(_toConsumableArray(locale.months));
        var MMM = ['\x01'].concat(_toConsumableArray(locale.shortMonths));
        var dddd = ['\x02'].concat(_toConsumableArray(locale.days));
        var ddd = ['\x03'].concat(_toConsumableArray(locale.shortDays));
        function ii(i, len) {
          var s = i + '';
          len = len || 2;
          while (s.length < len) {
            s = '0' + s;
          }
          return s;
        }
        var y = utc ? date.getUTCFullYear() : date.getFullYear();
        format = format.replace(/(^|[^\\])yyyy+/g, '$1' + y);
        format = format.replace(/(^|[^\\])yy/g, '$1' + y.toString().substr(2, 2));
        format = format.replace(/(^|[^\\])y/g, '$1' + y);
        var M = (utc ? date.getUTCMonth() : date.getMonth()) + 1;
        format = format.replace(/(^|[^\\])MMMM+/g, '$1' + MMMM[0]);
        format = format.replace(/(^|[^\\])MMM/g, '$1' + MMM[0]);
        format = format.replace(/(^|[^\\])MM/g, '$1' + ii(M));
        format = format.replace(/(^|[^\\])M/g, '$1' + M);
        var d = utc ? date.getUTCDate() : date.getDate();
        format = format.replace(/(^|[^\\])dddd+/g, '$1' + dddd[0]);
        format = format.replace(/(^|[^\\])ddd/g, '$1' + ddd[0]);
        format = format.replace(/(^|[^\\])dd/g, '$1' + ii(d));
        format = format.replace(/(^|[^\\])d/g, '$1' + d);
        var H = utc ? date.getUTCHours() : date.getHours();
        format = format.replace(/(^|[^\\])HH+/g, '$1' + ii(H));
        format = format.replace(/(^|[^\\])H/g, '$1' + H);
        var h = H > 12 ? H - 12 : H === 0 ? 12 : H;
        format = format.replace(/(^|[^\\])hh+/g, '$1' + ii(h));
        format = format.replace(/(^|[^\\])h/g, '$1' + h);
        var m = utc ? date.getUTCMinutes() : date.getMinutes();
        format = format.replace(/(^|[^\\])mm+/g, '$1' + ii(m));
        format = format.replace(/(^|[^\\])m/g, '$1' + m);
        var s = utc ? date.getUTCSeconds() : date.getSeconds();
        format = format.replace(/(^|[^\\])ss+/g, '$1' + ii(s));
        format = format.replace(/(^|[^\\])s/g, '$1' + s);
        var f = utc ? date.getUTCMilliseconds() : date.getMilliseconds();
        format = format.replace(/(^|[^\\])fff+/g, '$1' + ii(f, 3));
        f = Math.round(f / 10);
        format = format.replace(/(^|[^\\])ff/g, '$1' + ii(f));
        f = Math.round(f / 10);
        format = format.replace(/(^|[^\\])f/g, '$1' + f);
        var T = H < 12 ? 'AM' : 'PM';
        format = format.replace(/(^|[^\\])TT+/g, '$1' + T);
        format = format.replace(/(^|[^\\])T/g, '$1' + T.charAt(0));
        var t = T.toLowerCase();
        format = format.replace(/(^|[^\\])tt+/g, '$1' + t);
        format = format.replace(/(^|[^\\])t/g, '$1' + t.charAt(0));
        var tz = -date.getTimezoneOffset();
        var K = utc || !tz ? 'Z' : tz > 0 ? '+' : '-';
        if (!utc) {
          tz = Math.abs(tz);
          var tzHrs = Math.floor(tz / 60);
          var tzMin = tz % 60;
          K += ii(tzHrs) + ':' + ii(tzMin);
        }
        format = format.replace(/(^|[^\\])K/g, '$1' + K);
        var day = (utc ? date.getUTCDay() : date.getDay()) + 1;
        format = format.replace(new RegExp(dddd[0], 'g'), dddd[day]);
        format = format.replace(new RegExp(ddd[0], 'g'), ddd[day]);
        format = format.replace(new RegExp(MMMM[0], 'g'), MMMM[M]);
        format = format.replace(new RegExp(MMM[0], 'g'), MMM[M]);
        format = format.replace(/\\(.)/g, '$1');
        return format;
      }
    }, {
      key: "getTimeUnitsfromTimestamp",
      value: function getTimeUnitsfromTimestamp(minX, maxX, utc) {
        var w = this.w;
        if (w.config.xaxis.min !== undefined) {
          minX = w.config.xaxis.min;
        }
        if (w.config.xaxis.max !== undefined) {
          maxX = w.config.xaxis.max;
        }
        var tsMin = this.getDate(minX);
        var tsMax = this.getDate(maxX);
        var minD = this.formatDate(tsMin, 'yyyy MM dd HH mm ss fff').split(' ');
        var maxD = this.formatDate(tsMax, 'yyyy MM dd HH mm ss fff').split(' ');
        return {
          minMillisecond: parseInt(minD[6], 10),
          maxMillisecond: parseInt(maxD[6], 10),
          minSecond: parseInt(minD[5], 10),
          maxSecond: parseInt(maxD[5], 10),
          minMinute: parseInt(minD[4], 10),
          maxMinute: parseInt(maxD[4], 10),
          minHour: parseInt(minD[3], 10),
          maxHour: parseInt(maxD[3], 10),
          minDate: parseInt(minD[2], 10),
          maxDate: parseInt(maxD[2], 10),
          minMonth: parseInt(minD[1], 10) - 1,
          maxMonth: parseInt(maxD[1], 10) - 1,
          minYear: parseInt(minD[0], 10),
          maxYear: parseInt(maxD[0], 10)
        };
      }
    }, {
      key: "isLeapYear",
      value: function isLeapYear(year) {
        return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
      }
    }, {
      key: "calculcateLastDaysOfMonth",
      value: function calculcateLastDaysOfMonth(month, year, subtract) {
        var days = this.determineDaysOfMonths(month, year);

        // whatever days we get, subtract the number of days asked
        return days - subtract;
      }
    }, {
      key: "determineDaysOfYear",
      value: function determineDaysOfYear(year) {
        var days = 365;
        if (this.isLeapYear(year)) {
          days = 366;
        }
        return days;
      }
    }, {
      key: "determineRemainingDaysOfYear",
      value: function determineRemainingDaysOfYear(year, month, date) {
        var dayOfYear = this.daysCntOfYear[month] + date;
        if (month > 1 && this.isLeapYear()) dayOfYear++;
        return dayOfYear;
      }
    }, {
      key: "determineDaysOfMonths",
      value: function determineDaysOfMonths(month, year) {
        var days = 30;
        month = Utils$1.monthMod(month);
        switch (true) {
          case this.months30.indexOf(month) > -1:
            if (month === 2) {
              if (this.isLeapYear(year)) {
                days = 29;
              } else {
                days = 28;
              }
            }
            break;
          case this.months31.indexOf(month) > -1:
            days = 31;
            break;
          default:
            days = 31;
            break;
        }
        return days;
      }
    }]);
    return DateTime;
  }();

  /**
   * ApexCharts Formatter Class for setting value formatters for axes as well as tooltips.
   *
   * @module Formatters
   **/
  var Formatters = /*#__PURE__*/function () {
    function Formatters(ctx) {
      _classCallCheck(this, Formatters);
      this.ctx = ctx;
      this.w = ctx.w;
      this.tooltipKeyFormat = 'dd MMM';
    }
    _createClass(Formatters, [{
      key: "xLabelFormat",
      value: function xLabelFormat(fn, val, timestamp, opts) {
        var w = this.w;
        if (w.config.xaxis.type === 'datetime') {
          if (w.config.xaxis.labels.formatter === undefined) {
            // if user has not specified a custom formatter, use the default tooltip.x.format
            if (w.config.tooltip.x.formatter === undefined) {
              var datetimeObj = new DateTime(this.ctx);
              return datetimeObj.formatDate(datetimeObj.getDate(val), w.config.tooltip.x.format);
            }
          }
        }
        return fn(val, timestamp, opts);
      }
    }, {
      key: "defaultGeneralFormatter",
      value: function defaultGeneralFormatter(val) {
        if (Array.isArray(val)) {
          return val.map(function (v) {
            return v;
          });
        } else {
          return val;
        }
      }
    }, {
      key: "defaultYFormatter",
      value: function defaultYFormatter(v, yaxe, i) {
        var w = this.w;
        if (Utils$1.isNumber(v)) {
          if (w.globals.yValueDecimal !== 0) {
            v = v.toFixed(yaxe.decimalsInFloat !== undefined ? yaxe.decimalsInFloat : w.globals.yValueDecimal);
          } else {
            // We have an integer value but the label is not an integer. We can
            // deduce this is due to the number of ticks exceeding the even lower
            // integer range. Add an additional decimal place only in this case.
            var f = v.toFixed(0);
            // Do not change the == to ===
            v = v == f ? f : v.toFixed(1);
          }
        }
        return v;
      }
    }, {
      key: "setLabelFormatters",
      value: function setLabelFormatters() {
        var _this = this;
        var w = this.w;
        w.globals.xaxisTooltipFormatter = function (val) {
          return _this.defaultGeneralFormatter(val);
        };
        w.globals.ttKeyFormatter = function (val) {
          return _this.defaultGeneralFormatter(val);
        };
        w.globals.ttZFormatter = function (val) {
          return val;
        };
        w.globals.legendFormatter = function (val) {
          return _this.defaultGeneralFormatter(val);
        };

        // formatter function will always overwrite format property
        if (w.config.xaxis.labels.formatter !== undefined) {
          w.globals.xLabelFormatter = w.config.xaxis.labels.formatter;
        } else {
          w.globals.xLabelFormatter = function (val) {
            if (Utils$1.isNumber(val)) {
              if (!w.config.xaxis.convertedCatToNumeric && w.config.xaxis.type === 'numeric') {
                if (Utils$1.isNumber(w.config.xaxis.decimalsInFloat)) {
                  return val.toFixed(w.config.xaxis.decimalsInFloat);
                } else {
                  var diff = w.globals.maxX - w.globals.minX;
                  if (diff > 0 && diff < 100) {
                    return val.toFixed(1);
                  }
                  return val.toFixed(0);
                }
              }
              if (w.globals.isBarHorizontal) {
                var range = w.globals.maxY - w.globals.minYArr;
                if (range < 4) {
                  return val.toFixed(1);
                }
              }
              return val.toFixed(0);
            }
            return val;
          };
        }
        if (typeof w.config.tooltip.x.formatter === 'function') {
          w.globals.ttKeyFormatter = w.config.tooltip.x.formatter;
        } else {
          w.globals.ttKeyFormatter = w.globals.xLabelFormatter;
        }
        if (typeof w.config.xaxis.tooltip.formatter === 'function') {
          w.globals.xaxisTooltipFormatter = w.config.xaxis.tooltip.formatter;
        }
        if (Array.isArray(w.config.tooltip.y)) {
          w.globals.ttVal = w.config.tooltip.y;
        } else {
          if (w.config.tooltip.y.formatter !== undefined) {
            w.globals.ttVal = w.config.tooltip.y;
          }
        }
        if (w.config.tooltip.z.formatter !== undefined) {
          w.globals.ttZFormatter = w.config.tooltip.z.formatter;
        }

        // legend formatter - if user wants to append any global values of series to legend text
        if (w.config.legend.formatter !== undefined) {
          w.globals.legendFormatter = w.config.legend.formatter;
        }

        // formatter function will always overwrite format property
        w.config.yaxis.forEach(function (yaxe, i) {
          if (yaxe.labels.formatter !== undefined) {
            w.globals.yLabelFormatters[i] = yaxe.labels.formatter;
          } else {
            w.globals.yLabelFormatters[i] = function (val) {
              if (!w.globals.xyCharts) return val;
              if (Array.isArray(val)) {
                return val.map(function (v) {
                  return _this.defaultYFormatter(v, yaxe, i);
                });
              } else {
                return _this.defaultYFormatter(val, yaxe, i);
              }
            };
          }
        });
        return w.globals;
      }
    }, {
      key: "heatmapLabelFormatters",
      value: function heatmapLabelFormatters() {
        var w = this.w;
        if (w.config.chart.type === 'heatmap') {
          w.globals.yAxisScale[0].result = w.globals.seriesNames.slice();

          //  get the longest string from the labels array and also apply label formatter to it
          var longest = w.globals.seriesNames.reduce(function (a, b) {
            return a.length > b.length ? a : b;
          }, 0);
          w.globals.yAxisScale[0].niceMax = longest;
          w.globals.yAxisScale[0].niceMin = longest;
        }
      }
    }]);
    return Formatters;
  }();

  var AxesUtils = /*#__PURE__*/function () {
    function AxesUtils(ctx) {
      _classCallCheck(this, AxesUtils);
      this.ctx = ctx;
      this.w = ctx.w;
    }

    // Based on the formatter function, get the label text and position
    _createClass(AxesUtils, [{
      key: "getLabel",
      value: function getLabel(labels, timescaleLabels, x, i) {
        var drawnLabels = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [];
        var fontSize = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : '12px';
        var isLeafGroup = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : true;
        var w = this.w;
        var rawLabel = typeof labels[i] === 'undefined' ? '' : labels[i];
        var label = rawLabel;
        var xlbFormatter = w.globals.xLabelFormatter;
        var customFormatter = w.config.xaxis.labels.formatter;
        var isBold = false;
        var xFormat = new Formatters(this.ctx);
        var timestamp = rawLabel;
        if (isLeafGroup) {
          label = xFormat.xLabelFormat(xlbFormatter, rawLabel, timestamp, {
            i: i,
            dateFormatter: new DateTime(this.ctx).formatDate,
            w: w
          });
          if (customFormatter !== undefined) {
            label = customFormatter(rawLabel, labels[i], {
              i: i,
              dateFormatter: new DateTime(this.ctx).formatDate,
              w: w
            });
          }
        }
        var determineHighestUnit = function determineHighestUnit(unit) {
          var highestUnit = null;
          timescaleLabels.forEach(function (t) {
            if (t.unit === 'month') {
              highestUnit = 'year';
            } else if (t.unit === 'day') {
              highestUnit = 'month';
            } else if (t.unit === 'hour') {
              highestUnit = 'day';
            } else if (t.unit === 'minute') {
              highestUnit = 'hour';
            }
          });
          return highestUnit === unit;
        };
        if (timescaleLabels.length > 0) {
          isBold = determineHighestUnit(timescaleLabels[i].unit);
          x = timescaleLabels[i].position;
          label = timescaleLabels[i].value;
        } else {
          if (w.config.xaxis.type === 'datetime' && customFormatter === undefined) {
            label = '';
          }
        }
        if (typeof label === 'undefined') label = '';
        label = Array.isArray(label) ? label : label.toString();
        var graphics = new Graphics(this.ctx);
        var textRect = {};
        if (w.globals.rotateXLabels && isLeafGroup) {
          textRect = graphics.getTextRects(label, parseInt(fontSize, 10), null, "rotate(".concat(w.config.xaxis.labels.rotate, " 0 0)"), false);
        } else {
          textRect = graphics.getTextRects(label, parseInt(fontSize, 10));
        }
        var allowDuplicatesInTimeScale = !w.config.xaxis.labels.showDuplicates && this.ctx.timeScale;
        if (!Array.isArray(label) && (String(label) === 'NaN' || drawnLabels.indexOf(label) >= 0 && allowDuplicatesInTimeScale)) {
          label = '';
        }
        return {
          x: x,
          text: label,
          textRect: textRect,
          isBold: isBold
        };
      }
    }, {
      key: "checkLabelBasedOnTickamount",
      value: function checkLabelBasedOnTickamount(i, label, labelsLen) {
        var w = this.w;
        var ticks = w.config.xaxis.tickAmount;
        if (ticks === 'dataPoints') ticks = Math.round(w.globals.gridWidth / 120);
        if (ticks > labelsLen) return label;
        var tickMultiple = Math.round(labelsLen / (ticks + 1));
        if (i % tickMultiple === 0) {
          return label;
        } else {
          label.text = '';
        }
        return label;
      }
    }, {
      key: "checkForOverflowingLabels",
      value: function checkForOverflowingLabels(i, label, labelsLen, drawnLabels, drawnLabelsRects) {
        var w = this.w;
        if (i === 0) {
          // check if first label is being truncated
          if (w.globals.skipFirstTimelinelabel) {
            label.text = '';
          }
        }
        if (i === labelsLen - 1) {
          // check if last label is being truncated
          if (w.globals.skipLastTimelinelabel) {
            label.text = '';
          }
        }
        if (w.config.xaxis.labels.hideOverlappingLabels && drawnLabels.length > 0) {
          var prev = drawnLabelsRects[drawnLabelsRects.length - 1];
          if (label.x < prev.textRect.width / (w.globals.rotateXLabels ? Math.abs(w.config.xaxis.labels.rotate) / 12 : 1.01) + prev.x) {
            label.text = '';
          }
        }
        return label;
      }
    }, {
      key: "checkForReversedLabels",
      value: function checkForReversedLabels(i, labels) {
        var w = this.w;
        if (w.config.yaxis[i] && w.config.yaxis[i].reversed) {
          labels.reverse();
        }
        return labels;
      }
    }, {
      key: "yAxisAllSeriesCollapsed",
      value: function yAxisAllSeriesCollapsed(index) {
        var gl = this.w.globals;
        return !gl.seriesYAxisMap[index].some(function (si) {
          return gl.collapsedSeriesIndices.indexOf(si) === -1;
        });
      }

      // Method to translate annotation.yAxisIndex values from
      // seriesName-as-a-string values to seriesName-as-an-array values (old style
      // series mapping to new style).
    }, {
      key: "translateYAxisIndex",
      value: function translateYAxisIndex(index) {
        var w = this.w;
        var gl = w.globals;
        var yaxis = w.config.yaxis;
        var newStyle = gl.series.length > yaxis.length || yaxis.some(function (a) {
          return Array.isArray(a.seriesName);
        });
        if (newStyle) {
          return index;
        } else {
          return gl.seriesYAxisReverseMap[index];
        }
      }
    }, {
      key: "isYAxisHidden",
      value: function isYAxisHidden(index) {
        var w = this.w;
        var yaxis = w.config.yaxis[index];
        if (!yaxis.show || this.yAxisAllSeriesCollapsed(index)) {
          return true;
        }
        if (!yaxis.showForNullSeries) {
          var seriesIndices = w.globals.seriesYAxisMap[index];
          var coreUtils = new CoreUtils(this.ctx);
          return seriesIndices.every(function (si) {
            return coreUtils.isSeriesNull(si);
          });
        }
        return false;
      }

      // get the label color for y-axis
      // realIndex is the actual series index, while i is the tick Index
    }, {
      key: "getYAxisForeColor",
      value: function getYAxisForeColor(yColors, realIndex) {
        var w = this.w;
        if (Array.isArray(yColors) && w.globals.yAxisScale[realIndex]) {
          this.ctx.theme.pushExtraColors(yColors, w.globals.yAxisScale[realIndex].result.length, false);
        }
        return yColors;
      }
    }, {
      key: "drawYAxisTicks",
      value: function drawYAxisTicks(x, tickAmount, axisBorder, axisTicks, realIndex, labelsDivider, elYaxis) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);

        // initial label position = 0;
        var tY = w.globals.translateY + w.config.yaxis[realIndex].labels.offsetY;
        if (w.globals.isBarHorizontal) {
          tY = 0;
        } else if (w.config.chart.type === 'heatmap') {
          tY += labelsDivider / 2;
        }
        if (axisTicks.show && tickAmount > 0) {
          if (w.config.yaxis[realIndex].opposite === true) x = x + axisTicks.width;
          for (var i = tickAmount; i >= 0; i--) {
            var elTick = graphics.drawLine(x + axisBorder.offsetX - axisTicks.width + axisTicks.offsetX, tY + axisTicks.offsetY, x + axisBorder.offsetX + axisTicks.offsetX, tY + axisTicks.offsetY, axisTicks.color);
            elYaxis.add(elTick);
            tY += labelsDivider;
          }
        }
      }
    }]);
    return AxesUtils;
  }();

  var YAnnotations = /*#__PURE__*/function () {
    function YAnnotations(annoCtx) {
      _classCallCheck(this, YAnnotations);
      this.w = annoCtx.w;
      this.annoCtx = annoCtx;
      this.helpers = new Helpers$4(this.annoCtx);
      this.axesUtils = new AxesUtils(this.annoCtx);
    }
    _createClass(YAnnotations, [{
      key: "addYaxisAnnotation",
      value: function addYaxisAnnotation(anno, parent, index) {
        var w = this.w;
        var strokeDashArray = anno.strokeDashArray;
        var result = this.helpers.getY1Y2('y1', anno);
        var y1 = result.yP;
        var clipY1 = result.clipped;
        var y2;
        var clipY2 = true;
        var drawn = false;
        var text = anno.label.text;
        if (anno.y2 === null || typeof anno.y2 === 'undefined') {
          if (!clipY1) {
            drawn = true;
            var line = this.annoCtx.graphics.drawLine(0 + anno.offsetX,
            // x1
            y1 + anno.offsetY,
            // y1
            this._getYAxisAnnotationWidth(anno),
            // x2
            y1 + anno.offsetY,
            // y2
            anno.borderColor,
            // lineColor
            strokeDashArray,
            // dashArray
            anno.borderWidth);
            parent.appendChild(line.node);
            if (anno.id) {
              line.node.classList.add(anno.id);
            }
          }
        } else {
          result = this.helpers.getY1Y2('y2', anno);
          y2 = result.yP;
          clipY2 = result.clipped;
          if (y2 > y1) {
            var temp = y1;
            y1 = y2;
            y2 = temp;
          }
          if (!(clipY1 && clipY2)) {
            drawn = true;
            var rect = this.annoCtx.graphics.drawRect(0 + anno.offsetX,
            // x1
            y2 + anno.offsetY,
            // y1
            this._getYAxisAnnotationWidth(anno),
            // x2
            y1 - y2,
            // y2
            0,
            // radius
            anno.fillColor,
            // color
            anno.opacity,
            // opacity,
            1,
            // strokeWidth
            anno.borderColor,
            // strokeColor
            strokeDashArray // stokeDashArray
            );
            rect.node.classList.add('apexcharts-annotation-rect');
            rect.attr('clip-path', "url(#gridRectMask".concat(w.globals.cuid, ")"));
            parent.appendChild(rect.node);
            if (anno.id) {
              rect.node.classList.add(anno.id);
            }
          }
        }
        if (drawn) {
          var textX = anno.label.position === 'right' ? w.globals.gridWidth : anno.label.position === 'center' ? w.globals.gridWidth / 2 : 0;
          var elText = this.annoCtx.graphics.drawText({
            x: textX + anno.label.offsetX,
            y: (y2 != null ? y2 : y1) + anno.label.offsetY - 3,
            text: text,
            textAnchor: anno.label.textAnchor,
            fontSize: anno.label.style.fontSize,
            fontFamily: anno.label.style.fontFamily,
            fontWeight: anno.label.style.fontWeight,
            foreColor: anno.label.style.color,
            cssClass: "apexcharts-yaxis-annotation-label ".concat(anno.label.style.cssClass, " ").concat(anno.id ? anno.id : '')
          });
          elText.attr({
            rel: index
          });
          parent.appendChild(elText.node);
        }
      }
    }, {
      key: "_getYAxisAnnotationWidth",
      value: function _getYAxisAnnotationWidth(anno) {
        // issue apexcharts.js#2009
        var w = this.w;
        var width = w.globals.gridWidth;
        if (anno.width.indexOf('%') > -1) {
          width = w.globals.gridWidth * parseInt(anno.width, 10) / 100;
        } else {
          width = parseInt(anno.width, 10);
        }
        return width + anno.offsetX;
      }
    }, {
      key: "drawYAxisAnnotations",
      value: function drawYAxisAnnotations() {
        var _this = this;
        var w = this.w;
        var elg = this.annoCtx.graphics.group({
          class: 'apexcharts-yaxis-annotations'
        });
        w.config.annotations.yaxis.forEach(function (anno, index) {
          anno.yAxisIndex = _this.axesUtils.translateYAxisIndex(anno.yAxisIndex);
          if (!(_this.axesUtils.isYAxisHidden(anno.yAxisIndex) && _this.axesUtils.yAxisAllSeriesCollapsed(anno.yAxisIndex))) {
            _this.addYaxisAnnotation(anno, elg.node, index);
          }
        });
        return elg;
      }
    }]);
    return YAnnotations;
  }();

  var PointAnnotations = /*#__PURE__*/function () {
    function PointAnnotations(annoCtx) {
      _classCallCheck(this, PointAnnotations);
      this.w = annoCtx.w;
      this.annoCtx = annoCtx;
      this.helpers = new Helpers$4(this.annoCtx);
    }
    _createClass(PointAnnotations, [{
      key: "addPointAnnotation",
      value: function addPointAnnotation(anno, parent, index) {
        var w = this.w;
        if (w.globals.collapsedSeriesIndices.indexOf(anno.seriesIndex) > -1) {
          return;
        }
        var result = this.helpers.getX1X2('x1', anno);
        var x = result.x;
        var clipX = result.clipped;
        result = this.helpers.getY1Y2('y1', anno);
        var y = result.yP;
        var clipY = result.clipped;
        if (!Utils$1.isNumber(x)) return;
        if (!(clipY || clipX)) {
          var optsPoints = {
            pSize: anno.marker.size,
            pointStrokeWidth: anno.marker.strokeWidth,
            pointFillColor: anno.marker.fillColor,
            pointStrokeColor: anno.marker.strokeColor,
            shape: anno.marker.shape,
            pRadius: anno.marker.radius,
            class: "apexcharts-point-annotation-marker ".concat(anno.marker.cssClass, " ").concat(anno.id ? anno.id : '')
          };
          var point = this.annoCtx.graphics.drawMarker(x + anno.marker.offsetX, y + anno.marker.offsetY, optsPoints);
          parent.appendChild(point.node);
          var text = anno.label.text ? anno.label.text : '';
          var elText = this.annoCtx.graphics.drawText({
            x: x + anno.label.offsetX,
            y: y + anno.label.offsetY - anno.marker.size - parseFloat(anno.label.style.fontSize) / 1.6,
            text: text,
            textAnchor: anno.label.textAnchor,
            fontSize: anno.label.style.fontSize,
            fontFamily: anno.label.style.fontFamily,
            fontWeight: anno.label.style.fontWeight,
            foreColor: anno.label.style.color,
            cssClass: "apexcharts-point-annotation-label ".concat(anno.label.style.cssClass, " ").concat(anno.id ? anno.id : '')
          });
          elText.attr({
            rel: index
          });
          parent.appendChild(elText.node);

          // TODO: deprecate this as we will use custom
          if (anno.customSVG.SVG) {
            var g = this.annoCtx.graphics.group({
              class: 'apexcharts-point-annotations-custom-svg ' + anno.customSVG.cssClass
            });
            g.attr({
              transform: "translate(".concat(x + anno.customSVG.offsetX, ", ").concat(y + anno.customSVG.offsetY, ")")
            });
            g.node.innerHTML = anno.customSVG.SVG;
            parent.appendChild(g.node);
          }
          if (anno.image.path) {
            var imgWidth = anno.image.width ? anno.image.width : 20;
            var imgHeight = anno.image.height ? anno.image.height : 20;
            point = this.annoCtx.addImage({
              x: x + anno.image.offsetX - imgWidth / 2,
              y: y + anno.image.offsetY - imgHeight / 2,
              width: imgWidth,
              height: imgHeight,
              path: anno.image.path,
              appendTo: '.apexcharts-point-annotations'
            });
          }
          if (anno.mouseEnter) {
            point.node.addEventListener('mouseenter', anno.mouseEnter.bind(this, anno));
          }
          if (anno.mouseLeave) {
            point.node.addEventListener('mouseleave', anno.mouseLeave.bind(this, anno));
          }
          if (anno.click) {
            point.node.addEventListener('click', anno.click.bind(this, anno));
          }
        }
      }
    }, {
      key: "drawPointAnnotations",
      value: function drawPointAnnotations() {
        var _this = this;
        var w = this.w;
        var elg = this.annoCtx.graphics.group({
          class: 'apexcharts-point-annotations'
        });
        w.config.annotations.points.map(function (anno, index) {
          _this.addPointAnnotation(anno, elg.node, index);
        });
        return elg;
      }
    }]);
    return PointAnnotations;
  }();

  const name = "en";
  const options = {
  	months: [
  		"January",
  		"February",
  		"March",
  		"April",
  		"May",
  		"June",
  		"July",
  		"August",
  		"September",
  		"October",
  		"November",
  		"December"
  	],
  	shortMonths: [
  		"Jan",
  		"Feb",
  		"Mar",
  		"Apr",
  		"May",
  		"Jun",
  		"Jul",
  		"Aug",
  		"Sep",
  		"Oct",
  		"Nov",
  		"Dec"
  	],
  	days: [
  		"Sunday",
  		"Monday",
  		"Tuesday",
  		"Wednesday",
  		"Thursday",
  		"Friday",
  		"Saturday"
  	],
  	shortDays: [
  		"Sun",
  		"Mon",
  		"Tue",
  		"Wed",
  		"Thu",
  		"Fri",
  		"Sat"
  	],
  	toolbar: {
  		exportToSVG: "Download SVG",
  		exportToPNG: "Download PNG",
  		exportToCSV: "Download CSV",
  		menu: "Menu",
  		selection: "Selection",
  		selectionZoom: "Selection Zoom",
  		zoomIn: "Zoom In",
  		zoomOut: "Zoom Out",
  		pan: "Panning",
  		reset: "Reset Zoom"
  	}
  };
  var en = {
  	name: name,
  	options: options
  };

  var Options = /*#__PURE__*/function () {
    function Options() {
      _classCallCheck(this, Options);
      this.yAxis = {
        show: true,
        showAlways: false,
        showForNullSeries: true,
        seriesName: undefined,
        opposite: false,
        reversed: false,
        logarithmic: false,
        logBase: 10,
        tickAmount: undefined,
        stepSize: undefined,
        forceNiceScale: false,
        max: undefined,
        min: undefined,
        floating: false,
        decimalsInFloat: undefined,
        labels: {
          show: true,
          showDuplicates: false,
          minWidth: 0,
          maxWidth: 160,
          offsetX: 0,
          offsetY: 0,
          align: undefined,
          rotate: 0,
          padding: 20,
          style: {
            colors: [],
            fontSize: '11px',
            fontWeight: 400,
            fontFamily: undefined,
            cssClass: ''
          },
          formatter: undefined
        },
        axisBorder: {
          show: false,
          color: '#e0e0e0',
          width: 1,
          offsetX: 0,
          offsetY: 0
        },
        axisTicks: {
          show: false,
          color: '#e0e0e0',
          width: 6,
          offsetX: 0,
          offsetY: 0
        },
        title: {
          text: undefined,
          rotate: -90,
          offsetY: 0,
          offsetX: 0,
          style: {
            color: undefined,
            fontSize: '11px',
            fontWeight: 900,
            fontFamily: undefined,
            cssClass: ''
          }
        },
        tooltip: {
          enabled: false,
          offsetX: 0
        },
        crosshairs: {
          show: true,
          position: 'front',
          stroke: {
            color: '#b6b6b6',
            width: 1,
            dashArray: 0
          }
        }
      };
      this.pointAnnotation = {
        id: undefined,
        x: 0,
        y: null,
        yAxisIndex: 0,
        seriesIndex: undefined,
        mouseEnter: undefined,
        mouseLeave: undefined,
        click: undefined,
        marker: {
          size: 4,
          fillColor: '#fff',
          strokeWidth: 2,
          strokeColor: '#333',
          shape: 'circle',
          offsetX: 0,
          offsetY: 0,
          // radius: 2, // DEPRECATED
          cssClass: ''
        },
        label: {
          borderColor: '#c2c2c2',
          borderWidth: 1,
          borderRadius: 2,
          text: undefined,
          textAnchor: 'middle',
          offsetX: 0,
          offsetY: 0,
          mouseEnter: undefined,
          mouseLeave: undefined,
          click: undefined,
          style: {
            background: '#fff',
            color: undefined,
            fontSize: '11px',
            fontFamily: undefined,
            fontWeight: 400,
            cssClass: '',
            padding: {
              left: 5,
              right: 5,
              top: 2,
              bottom: 2
            }
          }
        },
        customSVG: {
          // this will be deprecated in the next major version as it is going to be replaced with a better alternative below (image)
          SVG: undefined,
          cssClass: undefined,
          offsetX: 0,
          offsetY: 0
        },
        image: {
          path: undefined,
          width: 20,
          height: 20,
          offsetX: 0,
          offsetY: 0
        }
      };
      this.yAxisAnnotation = {
        id: undefined,
        y: 0,
        y2: null,
        strokeDashArray: 1,
        fillColor: '#c2c2c2',
        borderColor: '#c2c2c2',
        borderWidth: 1,
        opacity: 0.3,
        offsetX: 0,
        offsetY: 0,
        width: '100%',
        yAxisIndex: 0,
        label: {
          borderColor: '#c2c2c2',
          borderWidth: 1,
          borderRadius: 2,
          text: undefined,
          textAnchor: 'end',
          position: 'right',
          offsetX: 0,
          offsetY: -3,
          mouseEnter: undefined,
          mouseLeave: undefined,
          click: undefined,
          style: {
            background: '#fff',
            color: undefined,
            fontSize: '11px',
            fontFamily: undefined,
            fontWeight: 400,
            cssClass: '',
            padding: {
              left: 5,
              right: 5,
              top: 2,
              bottom: 2
            }
          }
        }
      };
      this.xAxisAnnotation = {
        id: undefined,
        x: 0,
        x2: null,
        strokeDashArray: 1,
        fillColor: '#c2c2c2',
        borderColor: '#c2c2c2',
        borderWidth: 1,
        opacity: 0.3,
        offsetX: 0,
        offsetY: 0,
        label: {
          borderColor: '#c2c2c2',
          borderWidth: 1,
          borderRadius: 2,
          text: undefined,
          textAnchor: 'middle',
          orientation: 'vertical',
          position: 'top',
          offsetX: 0,
          offsetY: 0,
          mouseEnter: undefined,
          mouseLeave: undefined,
          click: undefined,
          style: {
            background: '#fff',
            color: undefined,
            fontSize: '11px',
            fontFamily: undefined,
            fontWeight: 400,
            cssClass: '',
            padding: {
              left: 5,
              right: 5,
              top: 2,
              bottom: 2
            }
          }
        }
      };
      this.text = {
        x: 0,
        y: 0,
        text: '',
        textAnchor: 'start',
        foreColor: undefined,
        fontSize: '13px',
        fontFamily: undefined,
        fontWeight: 400,
        appendTo: '.apexcharts-annotations',
        backgroundColor: 'transparent',
        borderColor: '#c2c2c2',
        borderRadius: 0,
        borderWidth: 0,
        paddingLeft: 4,
        paddingRight: 4,
        paddingTop: 2,
        paddingBottom: 2
      };
    }
    _createClass(Options, [{
      key: "init",
      value: function init() {
        return {
          annotations: {
            yaxis: [this.yAxisAnnotation],
            xaxis: [this.xAxisAnnotation],
            points: [this.pointAnnotation],
            texts: [],
            images: [],
            shapes: []
          },
          chart: {
            animations: {
              enabled: true,
              easing: 'easeinout',
              // linear, easeout, easein, easeinout, swing, bounce, elastic
              speed: 800,
              animateGradually: {
                delay: 150,
                enabled: true
              },
              dynamicAnimation: {
                enabled: true,
                speed: 350
              }
            },
            background: '',
            locales: [en],
            defaultLocale: 'en',
            dropShadow: {
              enabled: false,
              enabledOnSeries: undefined,
              top: 2,
              left: 2,
              blur: 4,
              color: '#000',
              opacity: 0.35
            },
            events: {
              animationEnd: undefined,
              beforeMount: undefined,
              mounted: undefined,
              updated: undefined,
              click: undefined,
              mouseMove: undefined,
              mouseLeave: undefined,
              xAxisLabelClick: undefined,
              legendClick: undefined,
              markerClick: undefined,
              selection: undefined,
              dataPointSelection: undefined,
              dataPointMouseEnter: undefined,
              dataPointMouseLeave: undefined,
              beforeZoom: undefined,
              beforeResetZoom: undefined,
              zoomed: undefined,
              scrolled: undefined,
              brushScrolled: undefined
            },
            foreColor: '#373d3f',
            fontFamily: 'Helvetica, Arial, sans-serif',
            height: 'auto',
            parentHeightOffset: 15,
            redrawOnParentResize: true,
            redrawOnWindowResize: true,
            id: undefined,
            group: undefined,
            nonce: undefined,
            offsetX: 0,
            offsetY: 0,
            selection: {
              enabled: false,
              type: 'x',
              // selectedPoints: undefined, // default datapoints that should be selected automatically
              fill: {
                color: '#24292e',
                opacity: 0.1
              },
              stroke: {
                width: 1,
                color: '#24292e',
                opacity: 0.4,
                dashArray: 3
              },
              xaxis: {
                min: undefined,
                max: undefined
              },
              yaxis: {
                min: undefined,
                max: undefined
              }
            },
            sparkline: {
              enabled: false
            },
            brush: {
              enabled: false,
              autoScaleYaxis: true,
              target: undefined,
              targets: undefined
            },
            stacked: false,
            stackOnlyBar: true,
            // mixed chart with stacked bars and line series - incorrect line draw #907
            stackType: 'normal',
            toolbar: {
              show: true,
              offsetX: 0,
              offsetY: 0,
              tools: {
                download: true,
                selection: true,
                zoom: true,
                zoomin: true,
                zoomout: true,
                pan: true,
                reset: true,
                customIcons: []
              },
              export: {
                csv: {
                  filename: undefined,
                  columnDelimiter: ',',
                  headerCategory: 'category',
                  headerValue: 'value',
                  categoryFormatter: undefined,
                  valueFormatter: undefined
                },
                png: {
                  filename: undefined
                },
                svg: {
                  filename: undefined
                },
                scale: undefined,
                width: undefined
              },
              autoSelected: 'zoom' // accepts -> zoom, pan, selection
            },
            type: 'line',
            width: '100%',
            zoom: {
              enabled: true,
              type: 'x',
              autoScaleYaxis: false,
              allowMouseWheelZoom: true,
              zoomedArea: {
                fill: {
                  color: '#90CAF9',
                  opacity: 0.4
                },
                stroke: {
                  color: '#0D47A1',
                  opacity: 0.4,
                  width: 1
                }
              }
            }
          },
          plotOptions: {
            line: {
              isSlopeChart: false
            },
            area: {
              fillTo: 'origin'
            },
            bar: {
              horizontal: false,
              columnWidth: '70%',
              // should be in percent 0 - 100
              barHeight: '70%',
              // should be in percent 0 - 100
              distributed: false,
              borderRadius: 0,
              borderRadiusApplication: 'around',
              // [around, end]
              borderRadiusWhenStacked: 'last',
              // [all, last]
              rangeBarOverlap: true,
              rangeBarGroupRows: false,
              hideZeroBarsWhenGrouped: false,
              isDumbbell: false,
              dumbbellColors: undefined,
              isFunnel: false,
              isFunnel3d: true,
              colors: {
                ranges: [],
                backgroundBarColors: [],
                backgroundBarOpacity: 1,
                backgroundBarRadius: 0
              },
              dataLabels: {
                position: 'top',
                // top, center, bottom
                maxItems: 100,
                hideOverflowingLabels: true,
                orientation: 'horizontal',
                total: {
                  enabled: false,
                  formatter: undefined,
                  offsetX: 0,
                  offsetY: 0,
                  style: {
                    color: '#373d3f',
                    fontSize: '12px',
                    fontFamily: undefined,
                    fontWeight: 600
                  }
                }
              }
            },
            bubble: {
              zScaling: true,
              minBubbleRadius: undefined,
              maxBubbleRadius: undefined
            },
            candlestick: {
              colors: {
                upward: '#00B746',
                downward: '#EF403C'
              },
              wick: {
                useFillColor: true
              }
            },
            boxPlot: {
              colors: {
                upper: '#00E396',
                lower: '#008FFB'
              }
            },
            heatmap: {
              radius: 2,
              enableShades: true,
              shadeIntensity: 0.5,
              reverseNegativeShade: false,
              distributed: false,
              useFillColorAsStroke: false,
              colorScale: {
                inverse: false,
                ranges: [],
                min: undefined,
                max: undefined
              }
            },
            treemap: {
              enableShades: true,
              shadeIntensity: 0.5,
              distributed: false,
              reverseNegativeShade: false,
              useFillColorAsStroke: false,
              borderRadius: 4,
              dataLabels: {
                format: 'scale' // scale | truncate
              },
              colorScale: {
                inverse: false,
                ranges: [],
                min: undefined,
                max: undefined
              }
            },
            radialBar: {
              inverseOrder: false,
              startAngle: 0,
              endAngle: 360,
              offsetX: 0,
              offsetY: 0,
              hollow: {
                margin: 5,
                size: '50%',
                background: 'transparent',
                image: undefined,
                imageWidth: 150,
                imageHeight: 150,
                imageOffsetX: 0,
                imageOffsetY: 0,
                imageClipped: true,
                position: 'front',
                dropShadow: {
                  enabled: false,
                  top: 0,
                  left: 0,
                  blur: 3,
                  color: '#000',
                  opacity: 0.5
                }
              },
              track: {
                show: true,
                startAngle: undefined,
                endAngle: undefined,
                background: '#f2f2f2',
                strokeWidth: '97%',
                opacity: 1,
                margin: 5,
                // margin is in pixels
                dropShadow: {
                  enabled: false,
                  top: 0,
                  left: 0,
                  blur: 3,
                  color: '#000',
                  opacity: 0.5
                }
              },
              dataLabels: {
                show: true,
                name: {
                  show: true,
                  fontSize: '16px',
                  fontFamily: undefined,
                  fontWeight: 600,
                  color: undefined,
                  offsetY: 0,
                  formatter: function formatter(val) {
                    return val;
                  }
                },
                value: {
                  show: true,
                  fontSize: '14px',
                  fontFamily: undefined,
                  fontWeight: 400,
                  color: undefined,
                  offsetY: 16,
                  formatter: function formatter(val) {
                    return val + '%';
                  }
                },
                total: {
                  show: false,
                  label: 'Total',
                  fontSize: '16px',
                  fontWeight: 600,
                  fontFamily: undefined,
                  color: undefined,
                  formatter: function formatter(w) {
                    return w.globals.seriesTotals.reduce(function (a, b) {
                      return a + b;
                    }, 0) / w.globals.series.length + '%';
                  }
                }
              },
              barLabels: {
                enabled: false,
                offsetX: 0,
                offsetY: 0,
                useSeriesColors: true,
                fontFamily: undefined,
                fontWeight: 600,
                fontSize: '16px',
                formatter: function formatter(val) {
                  return val;
                },
                onClick: undefined
              }
            },
            pie: {
              customScale: 1,
              offsetX: 0,
              offsetY: 0,
              startAngle: 0,
              endAngle: 360,
              expandOnClick: true,
              dataLabels: {
                // These are the percentage values which are displayed on slice
                offset: 0,
                // offset by which labels will move outside
                minAngleToShowLabel: 10
              },
              donut: {
                size: '65%',
                background: 'transparent',
                labels: {
                  // These are the inner labels appearing inside donut
                  show: false,
                  name: {
                    show: true,
                    fontSize: '16px',
                    fontFamily: undefined,
                    fontWeight: 600,
                    color: undefined,
                    offsetY: -10,
                    formatter: function formatter(val) {
                      return val;
                    }
                  },
                  value: {
                    show: true,
                    fontSize: '20px',
                    fontFamily: undefined,
                    fontWeight: 400,
                    color: undefined,
                    offsetY: 10,
                    formatter: function formatter(val) {
                      return val;
                    }
                  },
                  total: {
                    show: false,
                    showAlways: false,
                    label: 'Total',
                    fontSize: '16px',
                    fontWeight: 400,
                    fontFamily: undefined,
                    color: undefined,
                    formatter: function formatter(w) {
                      return w.globals.seriesTotals.reduce(function (a, b) {
                        return a + b;
                      }, 0);
                    }
                  }
                }
              }
            },
            polarArea: {
              rings: {
                strokeWidth: 1,
                strokeColor: '#e8e8e8'
              },
              spokes: {
                strokeWidth: 1,
                connectorColors: '#e8e8e8'
              }
            },
            radar: {
              size: undefined,
              offsetX: 0,
              offsetY: 0,
              polygons: {
                // strokeColor: '#e8e8e8', // should be deprecated in the minor version i.e 3.2
                strokeWidth: 1,
                strokeColors: '#e8e8e8',
                connectorColors: '#e8e8e8',
                fill: {
                  colors: undefined
                }
              }
            }
          },
          colors: undefined,
          dataLabels: {
            enabled: true,
            enabledOnSeries: undefined,
            formatter: function formatter(val) {
              return val !== null ? val : '';
            },
            textAnchor: 'middle',
            distributed: false,
            offsetX: 0,
            offsetY: 0,
            style: {
              fontSize: '12px',
              fontFamily: undefined,
              fontWeight: 600,
              colors: undefined
            },
            background: {
              enabled: true,
              foreColor: '#fff',
              borderRadius: 2,
              padding: 4,
              opacity: 0.9,
              borderWidth: 1,
              borderColor: '#fff',
              dropShadow: {
                enabled: false,
                top: 1,
                left: 1,
                blur: 1,
                color: '#000',
                opacity: 0.45
              }
            },
            dropShadow: {
              enabled: false,
              top: 1,
              left: 1,
              blur: 1,
              color: '#000',
              opacity: 0.45
            }
          },
          fill: {
            type: 'solid',
            colors: undefined,
            // array of colors
            opacity: 0.85,
            gradient: {
              shade: 'dark',
              type: 'horizontal',
              shadeIntensity: 0.5,
              gradientToColors: undefined,
              inverseColors: true,
              opacityFrom: 1,
              opacityTo: 1,
              stops: [0, 50, 100],
              colorStops: []
            },
            image: {
              src: [],
              width: undefined,
              // optional
              height: undefined // optional
            },
            pattern: {
              style: 'squares',
              // String | Array of Strings
              width: 6,
              height: 6,
              strokeWidth: 2
            }
          },
          forecastDataPoints: {
            count: 0,
            fillOpacity: 0.5,
            strokeWidth: undefined,
            dashArray: 4
          },
          grid: {
            show: true,
            borderColor: '#e0e0e0',
            strokeDashArray: 0,
            position: 'back',
            xaxis: {
              lines: {
                show: false
              }
            },
            yaxis: {
              lines: {
                show: true
              }
            },
            row: {
              colors: undefined,
              // takes as array which will be repeated on rows
              opacity: 0.5
            },
            column: {
              colors: undefined,
              // takes an array which will be repeated on columns
              opacity: 0.5
            },
            padding: {
              top: 0,
              right: 10,
              bottom: 0,
              left: 12
            }
          },
          labels: [],
          legend: {
            show: true,
            showForSingleSeries: false,
            showForNullSeries: true,
            showForZeroSeries: true,
            floating: false,
            position: 'bottom',
            // whether to position legends in 1 of 4
            // direction - top, bottom, left, right
            horizontalAlign: 'center',
            // when position top/bottom, you can specify whether to align legends left, right or center
            inverseOrder: false,
            fontSize: '12px',
            fontFamily: undefined,
            fontWeight: 400,
            width: undefined,
            height: undefined,
            formatter: undefined,
            tooltipHoverFormatter: undefined,
            offsetX: -20,
            offsetY: 4,
            customLegendItems: [],
            labels: {
              colors: undefined,
              useSeriesColors: false
            },
            markers: {
              size: 7,
              fillColors: undefined,
              strokeWidth: 1,
              shape: undefined,
              offsetX: 0,
              offsetY: 0,
              customHTML: undefined,
              onClick: undefined
            },
            itemMargin: {
              horizontal: 5,
              vertical: 4
            },
            onItemClick: {
              toggleDataSeries: true
            },
            onItemHover: {
              highlightDataSeries: true
            }
          },
          markers: {
            discrete: [],
            size: 0,
            colors: undefined,
            strokeColors: '#fff',
            strokeWidth: 2,
            strokeOpacity: 0.9,
            strokeDashArray: 0,
            fillOpacity: 1,
            shape: 'circle',
            offsetX: 0,
            offsetY: 0,
            showNullDataPoints: true,
            onClick: undefined,
            onDblClick: undefined,
            hover: {
              size: undefined,
              sizeOffset: 3
            }
          },
          noData: {
            text: undefined,
            align: 'center',
            verticalAlign: 'middle',
            offsetX: 0,
            offsetY: 0,
            style: {
              color: undefined,
              fontSize: '14px',
              fontFamily: undefined
            }
          },
          responsive: [],
          // breakpoints should follow ascending order 400, then 700, then 1000
          series: undefined,
          states: {
            normal: {
              filter: {
                type: 'none',
                value: 0
              }
            },
            hover: {
              filter: {
                type: 'lighten',
                value: 0.1
              }
            },
            active: {
              allowMultipleDataPointsSelection: false,
              filter: {
                type: 'darken',
                value: 0.5
              }
            }
          },
          title: {
            text: undefined,
            align: 'left',
            margin: 5,
            offsetX: 0,
            offsetY: 0,
            floating: false,
            style: {
              fontSize: '14px',
              fontWeight: 900,
              fontFamily: undefined,
              color: undefined
            }
          },
          subtitle: {
            text: undefined,
            align: 'left',
            margin: 5,
            offsetX: 0,
            offsetY: 30,
            floating: false,
            style: {
              fontSize: '12px',
              fontWeight: 400,
              fontFamily: undefined,
              color: undefined
            }
          },
          stroke: {
            show: true,
            curve: 'smooth',
            // "smooth" / "straight" / "monotoneCubic" / "stepline" / "linestep"
            lineCap: 'butt',
            // round, butt , square
            width: 2,
            colors: undefined,
            // array of colors
            dashArray: 0,
            // single value or array of values
            fill: {
              type: 'solid',
              colors: undefined,
              // array of colors
              opacity: 0.85,
              gradient: {
                shade: 'dark',
                type: 'horizontal',
                shadeIntensity: 0.5,
                gradientToColors: undefined,
                inverseColors: true,
                opacityFrom: 1,
                opacityTo: 1,
                stops: [0, 50, 100],
                colorStops: []
              }
            }
          },
          tooltip: {
            enabled: true,
            enabledOnSeries: undefined,
            shared: true,
            hideEmptySeries: false,
            followCursor: false,
            // when disabled, the tooltip will show on top of the series instead of mouse position
            intersect: false,
            // when enabled, tooltip will only show when user directly hovers over point
            inverseOrder: false,
            custom: undefined,
            fillSeriesColor: false,
            theme: 'light',
            cssClass: '',
            style: {
              fontSize: '12px',
              fontFamily: undefined
            },
            onDatasetHover: {
              highlightDataSeries: false
            },
            x: {
              // x value
              show: true,
              format: 'dd MMM',
              // dd/MM, dd MMM yy, dd MMM yyyy
              formatter: undefined // a custom user supplied formatter function
            },
            y: {
              formatter: undefined,
              title: {
                formatter: function formatter(seriesName) {
                  return seriesName ? seriesName + ': ' : '';
                }
              }
            },
            z: {
              formatter: undefined,
              title: 'Size: '
            },
            marker: {
              show: true,
              fillColors: undefined
            },
            items: {
              display: 'flex'
            },
            fixed: {
              enabled: false,
              position: 'topRight',
              // topRight, topLeft, bottomRight, bottomLeft
              offsetX: 0,
              offsetY: 0
            }
          },
          xaxis: {
            type: 'category',
            categories: [],
            convertedCatToNumeric: false,
            // internal property which should not be altered outside
            offsetX: 0,
            offsetY: 0,
            overwriteCategories: undefined,
            labels: {
              show: true,
              rotate: -45,
              rotateAlways: false,
              hideOverlappingLabels: true,
              trim: false,
              minHeight: undefined,
              maxHeight: 120,
              showDuplicates: true,
              style: {
                colors: [],
                fontSize: '12px',
                fontWeight: 400,
                fontFamily: undefined,
                cssClass: ''
              },
              offsetX: 0,
              offsetY: 0,
              format: undefined,
              formatter: undefined,
              // custom formatter function which will override format
              datetimeUTC: true,
              datetimeFormatter: {
                year: 'yyyy',
                month: "MMM 'yy",
                day: 'dd MMM',
                hour: 'HH:mm',
                minute: 'HH:mm:ss',
                second: 'HH:mm:ss'
              }
            },
            group: {
              groups: [],
              style: {
                colors: [],
                fontSize: '12px',
                fontWeight: 400,
                fontFamily: undefined,
                cssClass: ''
              }
            },
            axisBorder: {
              show: true,
              color: '#e0e0e0',
              width: '100%',
              height: 1,
              offsetX: 0,
              offsetY: 0
            },
            axisTicks: {
              show: true,
              color: '#e0e0e0',
              height: 6,
              offsetX: 0,
              offsetY: 0
            },
            stepSize: undefined,
            tickAmount: undefined,
            tickPlacement: 'on',
            min: undefined,
            max: undefined,
            range: undefined,
            floating: false,
            decimalsInFloat: undefined,
            position: 'bottom',
            title: {
              text: undefined,
              offsetX: 0,
              offsetY: 0,
              style: {
                color: undefined,
                fontSize: '12px',
                fontWeight: 900,
                fontFamily: undefined,
                cssClass: ''
              }
            },
            crosshairs: {
              show: true,
              width: 1,
              // tickWidth/barWidth or an integer
              position: 'back',
              opacity: 0.9,
              stroke: {
                color: '#b6b6b6',
                width: 1,
                dashArray: 3
              },
              fill: {
                type: 'solid',
                // solid, gradient
                color: '#B1B9C4',
                gradient: {
                  colorFrom: '#D8E3F0',
                  colorTo: '#BED1E6',
                  stops: [0, 100],
                  opacityFrom: 0.4,
                  opacityTo: 0.5
                }
              },
              dropShadow: {
                enabled: false,
                left: 0,
                top: 0,
                blur: 1,
                opacity: 0.4
              }
            },
            tooltip: {
              enabled: true,
              offsetY: 0,
              formatter: undefined,
              style: {
                fontSize: '12px',
                fontFamily: undefined
              }
            }
          },
          yaxis: this.yAxis,
          theme: {
            mode: '',
            palette: 'palette1',
            // If defined, it will overwrite globals.colors variable
            monochrome: {
              // monochrome allows you to select just 1 color and fill out the rest with light/dark shade (intensity can be selected)
              enabled: false,
              color: '#008FFB',
              shadeTo: 'light',
              shadeIntensity: 0.65
            }
          }
        };
      }
    }]);
    return Options;
  }();

  /**
   * ApexCharts Annotations Class for drawing lines/rects on both xaxis and yaxis.
   *
   * @module Annotations
   **/
  var Annotations = /*#__PURE__*/function () {
    function Annotations(ctx) {
      _classCallCheck(this, Annotations);
      this.ctx = ctx;
      this.w = ctx.w;
      this.graphics = new Graphics(this.ctx);
      if (this.w.globals.isBarHorizontal) {
        this.invertAxis = true;
      }
      this.helpers = new Helpers$4(this);
      this.xAxisAnnotations = new XAnnotations(this);
      this.yAxisAnnotations = new YAnnotations(this);
      this.pointsAnnotations = new PointAnnotations(this);
      if (this.w.globals.isBarHorizontal && this.w.config.yaxis[0].reversed) {
        this.inversedReversedAxis = true;
      }
      this.xDivision = this.w.globals.gridWidth / this.w.globals.dataPoints;
    }
    _createClass(Annotations, [{
      key: "drawAxesAnnotations",
      value: function drawAxesAnnotations() {
        var w = this.w;
        if (w.globals.axisCharts && w.globals.dataPoints) {
          // w.globals.dataPoints check added to fix  #1832
          var yAnnotations = this.yAxisAnnotations.drawYAxisAnnotations();
          var xAnnotations = this.xAxisAnnotations.drawXAxisAnnotations();
          var pointAnnotations = this.pointsAnnotations.drawPointAnnotations();
          var initialAnim = w.config.chart.animations.enabled;
          var annoArray = [yAnnotations, xAnnotations, pointAnnotations];
          var annoElArray = [xAnnotations.node, yAnnotations.node, pointAnnotations.node];
          for (var i = 0; i < 3; i++) {
            w.globals.dom.elGraphical.add(annoArray[i]);
            if (initialAnim && !w.globals.resized && !w.globals.dataChanged) {
              // fixes apexcharts/apexcharts.js#685
              if (w.config.chart.type !== 'scatter' && w.config.chart.type !== 'bubble' && w.globals.dataPoints > 1) {
                annoElArray[i].classList.add('apexcharts-element-hidden');
              }
            }
            w.globals.delayedElements.push({
              el: annoElArray[i],
              index: 0
            });
          }

          // background sizes needs to be calculated after text is drawn, so calling them last
          this.helpers.annotationsBackground();
        }
      }
    }, {
      key: "drawImageAnnos",
      value: function drawImageAnnos() {
        var _this = this;
        var w = this.w;
        w.config.annotations.images.map(function (s, index) {
          _this.addImage(s, index);
        });
      }
    }, {
      key: "drawTextAnnos",
      value: function drawTextAnnos() {
        var _this2 = this;
        var w = this.w;
        w.config.annotations.texts.map(function (t, index) {
          _this2.addText(t, index);
        });
      }
    }, {
      key: "addXaxisAnnotation",
      value: function addXaxisAnnotation(anno, parent, index) {
        this.xAxisAnnotations.addXaxisAnnotation(anno, parent, index);
      }
    }, {
      key: "addYaxisAnnotation",
      value: function addYaxisAnnotation(anno, parent, index) {
        this.yAxisAnnotations.addYaxisAnnotation(anno, parent, index);
      }
    }, {
      key: "addPointAnnotation",
      value: function addPointAnnotation(anno, parent, index) {
        this.pointsAnnotations.addPointAnnotation(anno, parent, index);
      }
    }, {
      key: "addText",
      value: function addText(params, index) {
        var x = params.x,
          y = params.y,
          text = params.text,
          textAnchor = params.textAnchor,
          foreColor = params.foreColor,
          fontSize = params.fontSize,
          fontFamily = params.fontFamily,
          fontWeight = params.fontWeight,
          cssClass = params.cssClass,
          backgroundColor = params.backgroundColor,
          borderWidth = params.borderWidth,
          strokeDashArray = params.strokeDashArray,
          borderRadius = params.borderRadius,
          borderColor = params.borderColor,
          _params$appendTo = params.appendTo,
          appendTo = _params$appendTo === void 0 ? '.apexcharts-svg' : _params$appendTo,
          _params$paddingLeft = params.paddingLeft,
          paddingLeft = _params$paddingLeft === void 0 ? 4 : _params$paddingLeft,
          _params$paddingRight = params.paddingRight,
          paddingRight = _params$paddingRight === void 0 ? 4 : _params$paddingRight,
          _params$paddingBottom = params.paddingBottom,
          paddingBottom = _params$paddingBottom === void 0 ? 2 : _params$paddingBottom,
          _params$paddingTop = params.paddingTop,
          paddingTop = _params$paddingTop === void 0 ? 2 : _params$paddingTop;
        var w = this.w;
        var elText = this.graphics.drawText({
          x: x,
          y: y,
          text: text,
          textAnchor: textAnchor || 'start',
          fontSize: fontSize || '12px',
          fontWeight: fontWeight || 'regular',
          fontFamily: fontFamily || w.config.chart.fontFamily,
          foreColor: foreColor || w.config.chart.foreColor,
          cssClass: 'apexcharts-text ' + cssClass ? cssClass : ''
        });
        var parent = w.globals.dom.baseEl.querySelector(appendTo);
        if (parent) {
          parent.appendChild(elText.node);
        }
        var textRect = elText.bbox();
        if (text) {
          var elRect = this.graphics.drawRect(textRect.x - paddingLeft, textRect.y - paddingTop, textRect.width + paddingLeft + paddingRight, textRect.height + paddingBottom + paddingTop, borderRadius, backgroundColor ? backgroundColor : 'transparent', 1, borderWidth, borderColor, strokeDashArray);
          parent.insertBefore(elRect.node, elText.node);
        }
      }
    }, {
      key: "addImage",
      value: function addImage(params, index) {
        var w = this.w;
        var path = params.path,
          _params$x = params.x,
          x = _params$x === void 0 ? 0 : _params$x,
          _params$y = params.y,
          y = _params$y === void 0 ? 0 : _params$y,
          _params$width = params.width,
          width = _params$width === void 0 ? 20 : _params$width,
          _params$height = params.height,
          height = _params$height === void 0 ? 20 : _params$height,
          _params$appendTo2 = params.appendTo,
          appendTo = _params$appendTo2 === void 0 ? '.apexcharts-svg' : _params$appendTo2;
        var img = w.globals.dom.Paper.image(path);
        img.size(width, height).move(x, y);
        var parent = w.globals.dom.baseEl.querySelector(appendTo);
        if (parent) {
          parent.appendChild(img.node);
        }
        return img;
      }

      // The addXaxisAnnotation method requires a parent class, and user calling this method externally on the chart instance may not specify parent, hence a different method
    }, {
      key: "addXaxisAnnotationExternal",
      value: function addXaxisAnnotationExternal(params, pushToMemory, context) {
        this.addAnnotationExternal({
          params: params,
          pushToMemory: pushToMemory,
          context: context,
          type: 'xaxis',
          contextMethod: context.addXaxisAnnotation
        });
        return context;
      }
    }, {
      key: "addYaxisAnnotationExternal",
      value: function addYaxisAnnotationExternal(params, pushToMemory, context) {
        this.addAnnotationExternal({
          params: params,
          pushToMemory: pushToMemory,
          context: context,
          type: 'yaxis',
          contextMethod: context.addYaxisAnnotation
        });
        return context;
      }
    }, {
      key: "addPointAnnotationExternal",
      value: function addPointAnnotationExternal(params, pushToMemory, context) {
        if (typeof this.invertAxis === 'undefined') {
          this.invertAxis = context.w.globals.isBarHorizontal;
        }
        this.addAnnotationExternal({
          params: params,
          pushToMemory: pushToMemory,
          context: context,
          type: 'point',
          contextMethod: context.addPointAnnotation
        });
        return context;
      }
    }, {
      key: "addAnnotationExternal",
      value: function addAnnotationExternal(_ref) {
        var params = _ref.params,
          pushToMemory = _ref.pushToMemory,
          context = _ref.context,
          type = _ref.type,
          contextMethod = _ref.contextMethod;
        var me = context;
        var w = me.w;
        var parent = w.globals.dom.baseEl.querySelector(".apexcharts-".concat(type, "-annotations"));
        var index = parent.childNodes.length + 1;
        var options = new Options();
        var axesAnno = Object.assign({}, type === 'xaxis' ? options.xAxisAnnotation : type === 'yaxis' ? options.yAxisAnnotation : options.pointAnnotation);
        var anno = Utils$1.extend(axesAnno, params);
        switch (type) {
          case 'xaxis':
            this.addXaxisAnnotation(anno, parent, index);
            break;
          case 'yaxis':
            this.addYaxisAnnotation(anno, parent, index);
            break;
          case 'point':
            this.addPointAnnotation(anno, parent, index);
            break;
        }

        // add background
        var axesAnnoLabel = w.globals.dom.baseEl.querySelector(".apexcharts-".concat(type, "-annotations .apexcharts-").concat(type, "-annotation-label[rel='").concat(index, "']"));
        var elRect = this.helpers.addBackgroundToAnno(axesAnnoLabel, anno);
        if (elRect) {
          parent.insertBefore(elRect.node, axesAnnoLabel);
        }
        if (pushToMemory) {
          w.globals.memory.methodsToExec.push({
            context: me,
            id: anno.id ? anno.id : Utils$1.randomId(),
            method: contextMethod,
            label: 'addAnnotation',
            params: params
          });
        }
        return context;
      }
    }, {
      key: "clearAnnotations",
      value: function clearAnnotations(ctx) {
        var w = ctx.w;
        var annos = w.globals.dom.baseEl.querySelectorAll('.apexcharts-yaxis-annotations, .apexcharts-xaxis-annotations, .apexcharts-point-annotations');

        // annotations added externally should be cleared out too
        for (var i = w.globals.memory.methodsToExec.length - 1; i >= 0; i--) {
          if (w.globals.memory.methodsToExec[i].label === 'addText' || w.globals.memory.methodsToExec[i].label === 'addAnnotation') {
            w.globals.memory.methodsToExec.splice(i, 1);
          }
        }
        annos = Utils$1.listToArray(annos);

        // delete the DOM elements
        Array.prototype.forEach.call(annos, function (a) {
          while (a.firstChild) {
            a.removeChild(a.firstChild);
          }
        });
      }
    }, {
      key: "removeAnnotation",
      value: function removeAnnotation(ctx, id) {
        var w = ctx.w;
        var annos = w.globals.dom.baseEl.querySelectorAll(".".concat(id));
        if (annos) {
          w.globals.memory.methodsToExec.map(function (m, i) {
            if (m.id === id) {
              w.globals.memory.methodsToExec.splice(i, 1);
            }
          });
          Array.prototype.forEach.call(annos, function (a) {
            a.parentElement.removeChild(a);
          });
        }
      }
    }]);
    return Annotations;
  }();

  /**
   * ApexCharts Default Class for setting default options for all chart types.
   *
   * @module Defaults
   **/

  var getRangeValues = function getRangeValues(_ref) {
    var _w$config$series$seri;
    var isTimeline = _ref.isTimeline,
      ctx = _ref.ctx,
      seriesIndex = _ref.seriesIndex,
      dataPointIndex = _ref.dataPointIndex,
      y1 = _ref.y1,
      y2 = _ref.y2,
      w = _ref.w;
    var start = w.globals.seriesRangeStart[seriesIndex][dataPointIndex];
    var end = w.globals.seriesRangeEnd[seriesIndex][dataPointIndex];
    var ylabel = w.globals.labels[dataPointIndex];
    var seriesName = w.config.series[seriesIndex].name ? w.config.series[seriesIndex].name : '';
    var yLbFormatter = w.globals.ttKeyFormatter;
    var yLbTitleFormatter = w.config.tooltip.y.title.formatter;
    var opts = {
      w: w,
      seriesIndex: seriesIndex,
      dataPointIndex: dataPointIndex,
      start: start,
      end: end
    };
    if (typeof yLbTitleFormatter === 'function') {
      seriesName = yLbTitleFormatter(seriesName, opts);
    }
    if ((_w$config$series$seri = w.config.series[seriesIndex].data[dataPointIndex]) !== null && _w$config$series$seri !== void 0 && _w$config$series$seri.x) {
      ylabel = w.config.series[seriesIndex].data[dataPointIndex].x;
    }
    if (!isTimeline) {
      if (w.config.xaxis.type === 'datetime') {
        var xFormat = new Formatters(ctx);
        ylabel = xFormat.xLabelFormat(w.globals.ttKeyFormatter, ylabel, ylabel, {
          i: undefined,
          dateFormatter: new DateTime(ctx).formatDate,
          w: w
        });
      }
    }
    if (typeof yLbFormatter === 'function') {
      ylabel = yLbFormatter(ylabel, opts);
    }
    if (Number.isFinite(y1) && Number.isFinite(y2)) {
      start = y1;
      end = y2;
    }
    var startVal = '';
    var endVal = '';
    var color = w.globals.colors[seriesIndex];
    if (w.config.tooltip.x.formatter === undefined) {
      if (w.config.xaxis.type === 'datetime') {
        var datetimeObj = new DateTime(ctx);
        startVal = datetimeObj.formatDate(datetimeObj.getDate(start), w.config.tooltip.x.format);
        endVal = datetimeObj.formatDate(datetimeObj.getDate(end), w.config.tooltip.x.format);
      } else {
        startVal = start;
        endVal = end;
      }
    } else {
      startVal = w.config.tooltip.x.formatter(start);
      endVal = w.config.tooltip.x.formatter(end);
    }
    return {
      start: start,
      end: end,
      startVal: startVal,
      endVal: endVal,
      ylabel: ylabel,
      color: color,
      seriesName: seriesName
    };
  };
  var buildRangeTooltipHTML = function buildRangeTooltipHTML(opts) {
    var color = opts.color,
      seriesName = opts.seriesName,
      ylabel = opts.ylabel,
      start = opts.start,
      end = opts.end,
      seriesIndex = opts.seriesIndex,
      dataPointIndex = opts.dataPointIndex;
    var formatter = opts.ctx.tooltip.tooltipLabels.getFormatters(seriesIndex);
    start = formatter.yLbFormatter(start);
    end = formatter.yLbFormatter(end);
    var val = formatter.yLbFormatter(opts.w.globals.series[seriesIndex][dataPointIndex]);
    var valueHTML = '';
    var rangeValues = "<span class=\"value start-value\">\n  ".concat(start, "\n  </span> <span class=\"separator\">-</span> <span class=\"value end-value\">\n  ").concat(end, "\n  </span>");
    if (opts.w.globals.comboCharts) {
      if (opts.w.config.series[seriesIndex].type === 'rangeArea' || opts.w.config.series[seriesIndex].type === 'rangeBar') {
        valueHTML = rangeValues;
      } else {
        valueHTML = "<span>".concat(val, "</span>");
      }
    } else {
      valueHTML = rangeValues;
    }
    return '<div class="apexcharts-tooltip-rangebar">' + '<div> <span class="series-name" style="color: ' + color + '">' + (seriesName ? seriesName : '') + '</span></div>' + '<div> <span class="category">' + ylabel + ': </span> ' + valueHTML + ' </div>' + '</div>';
  };
  var Defaults = /*#__PURE__*/function () {
    function Defaults(opts) {
      _classCallCheck(this, Defaults);
      this.opts = opts;
    }
    _createClass(Defaults, [{
      key: "hideYAxis",
      value: function hideYAxis() {
        this.opts.yaxis[0].show = false;
        this.opts.yaxis[0].title.text = '';
        this.opts.yaxis[0].axisBorder.show = false;
        this.opts.yaxis[0].axisTicks.show = false;
        this.opts.yaxis[0].floating = true;
      }
    }, {
      key: "line",
      value: function line() {
        return {
          chart: {
            animations: {
              easing: 'swing'
            }
          },
          dataLabels: {
            enabled: false
          },
          stroke: {
            width: 5,
            curve: 'straight'
          },
          markers: {
            size: 0,
            hover: {
              sizeOffset: 6
            }
          },
          xaxis: {
            crosshairs: {
              width: 1
            }
          }
        };
      }
    }, {
      key: "sparkline",
      value: function sparkline(defaults) {
        this.hideYAxis();
        var ret = {
          grid: {
            show: false,
            padding: {
              left: 0,
              right: 0,
              top: 0,
              bottom: 0
            }
          },
          legend: {
            show: false
          },
          xaxis: {
            labels: {
              show: false
            },
            tooltip: {
              enabled: false
            },
            axisBorder: {
              show: false
            },
            axisTicks: {
              show: false
            }
          },
          chart: {
            toolbar: {
              show: false
            },
            zoom: {
              enabled: false
            }
          },
          dataLabels: {
            enabled: false
          }
        };
        return Utils$1.extend(defaults, ret);
      }
    }, {
      key: "slope",
      value: function slope() {
        this.hideYAxis();
        return {
          chart: {
            toolbar: {
              show: false
            },
            zoom: {
              enabled: false
            }
          },
          dataLabels: {
            enabled: true,
            formatter: function formatter(val, opts) {
              var seriesName = opts.w.config.series[opts.seriesIndex].name;
              return val !== null ? seriesName + ': ' + val : '';
            },
            background: {
              enabled: false
            },
            offsetX: -5
          },
          grid: {
            xaxis: {
              lines: {
                show: true
              }
            },
            yaxis: {
              lines: {
                show: false
              }
            }
          },
          xaxis: {
            position: 'top',
            labels: {
              style: {
                fontSize: 14,
                fontWeight: 900
              }
            },
            tooltip: {
              enabled: false
            },
            crosshairs: {
              show: false
            }
          },
          markers: {
            size: 8,
            hover: {
              sizeOffset: 1
            }
          },
          legend: {
            show: false
          },
          tooltip: {
            shared: false,
            intersect: true,
            followCursor: true
          },
          stroke: {
            width: 5,
            curve: 'straight'
          }
        };
      }
    }, {
      key: "bar",
      value: function bar() {
        return {
          chart: {
            stacked: false,
            animations: {
              easing: 'swing'
            }
          },
          plotOptions: {
            bar: {
              dataLabels: {
                position: 'center'
              }
            }
          },
          dataLabels: {
            style: {
              colors: ['#fff']
            },
            background: {
              enabled: false
            }
          },
          stroke: {
            width: 0,
            lineCap: 'round'
          },
          fill: {
            opacity: 0.85
          },
          legend: {
            markers: {
              shape: 'square'
            }
          },
          tooltip: {
            shared: false,
            intersect: true
          },
          xaxis: {
            tooltip: {
              enabled: false
            },
            tickPlacement: 'between',
            crosshairs: {
              width: 'barWidth',
              position: 'back',
              fill: {
                type: 'gradient'
              },
              dropShadow: {
                enabled: false
              },
              stroke: {
                width: 0
              }
            }
          }
        };
      }
    }, {
      key: "funnel",
      value: function funnel() {
        this.hideYAxis();
        return _objectSpread2(_objectSpread2({}, this.bar()), {}, {
          chart: {
            animations: {
              easing: 'linear',
              speed: 800,
              animateGradually: {
                enabled: false
              }
            }
          },
          plotOptions: {
            bar: {
              horizontal: true,
              borderRadiusApplication: 'around',
              borderRadius: 0,
              dataLabels: {
                position: 'center'
              }
            }
          },
          grid: {
            show: false,
            padding: {
              left: 0,
              right: 0
            }
          },
          xaxis: {
            labels: {
              show: false
            },
            tooltip: {
              enabled: false
            },
            axisBorder: {
              show: false
            },
            axisTicks: {
              show: false
            }
          }
        });
      }
    }, {
      key: "candlestick",
      value: function candlestick() {
        var _this = this;
        return {
          stroke: {
            width: 1,
            colors: ['#333']
          },
          fill: {
            opacity: 1
          },
          dataLabels: {
            enabled: false
          },
          tooltip: {
            shared: true,
            custom: function custom(_ref2) {
              var seriesIndex = _ref2.seriesIndex,
                dataPointIndex = _ref2.dataPointIndex,
                w = _ref2.w;
              return _this._getBoxTooltip(w, seriesIndex, dataPointIndex, ['Open', 'High', '', 'Low', 'Close'], 'candlestick');
            }
          },
          states: {
            active: {
              filter: {
                type: 'none'
              }
            }
          },
          xaxis: {
            crosshairs: {
              width: 1
            }
          }
        };
      }
    }, {
      key: "boxPlot",
      value: function boxPlot() {
        var _this2 = this;
        return {
          chart: {
            animations: {
              dynamicAnimation: {
                enabled: false
              }
            }
          },
          stroke: {
            width: 1,
            colors: ['#24292e']
          },
          dataLabels: {
            enabled: false
          },
          tooltip: {
            shared: true,
            custom: function custom(_ref3) {
              var seriesIndex = _ref3.seriesIndex,
                dataPointIndex = _ref3.dataPointIndex,
                w = _ref3.w;
              return _this2._getBoxTooltip(w, seriesIndex, dataPointIndex, ['Minimum', 'Q1', 'Median', 'Q3', 'Maximum'], 'boxPlot');
            }
          },
          markers: {
            size: 7,
            strokeWidth: 1,
            strokeColors: '#111'
          },
          xaxis: {
            crosshairs: {
              width: 1
            }
          }
        };
      }
    }, {
      key: "rangeBar",
      value: function rangeBar() {
        var handleTimelineTooltip = function handleTimelineTooltip(opts) {
          var _getRangeValues = getRangeValues(_objectSpread2(_objectSpread2({}, opts), {}, {
              isTimeline: true
            })),
            color = _getRangeValues.color,
            seriesName = _getRangeValues.seriesName,
            ylabel = _getRangeValues.ylabel,
            startVal = _getRangeValues.startVal,
            endVal = _getRangeValues.endVal;
          return buildRangeTooltipHTML(_objectSpread2(_objectSpread2({}, opts), {}, {
            color: color,
            seriesName: seriesName,
            ylabel: ylabel,
            start: startVal,
            end: endVal
          }));
        };
        var handleRangeColumnTooltip = function handleRangeColumnTooltip(opts) {
          var _getRangeValues2 = getRangeValues(opts),
            color = _getRangeValues2.color,
            seriesName = _getRangeValues2.seriesName,
            ylabel = _getRangeValues2.ylabel,
            start = _getRangeValues2.start,
            end = _getRangeValues2.end;
          return buildRangeTooltipHTML(_objectSpread2(_objectSpread2({}, opts), {}, {
            color: color,
            seriesName: seriesName,
            ylabel: ylabel,
            start: start,
            end: end
          }));
        };
        return {
          chart: {
            animations: {
              animateGradually: false
            }
          },
          stroke: {
            width: 0,
            lineCap: 'square'
          },
          plotOptions: {
            bar: {
              borderRadius: 0,
              dataLabels: {
                position: 'center'
              }
            }
          },
          dataLabels: {
            enabled: false,
            formatter: function formatter(val, _ref4) {
              _ref4.ctx;
                var seriesIndex = _ref4.seriesIndex,
                dataPointIndex = _ref4.dataPointIndex,
                w = _ref4.w;
              var getVal = function getVal() {
                var start = w.globals.seriesRangeStart[seriesIndex][dataPointIndex];
                var end = w.globals.seriesRangeEnd[seriesIndex][dataPointIndex];
                return end - start;
              };
              if (w.globals.comboCharts) {
                if (w.config.series[seriesIndex].type === 'rangeBar' || w.config.series[seriesIndex].type === 'rangeArea') {
                  return getVal();
                } else {
                  return val;
                }
              } else {
                return getVal();
              }
            },
            background: {
              enabled: false
            },
            style: {
              colors: ['#fff']
            }
          },
          markers: {
            size: 10
          },
          tooltip: {
            shared: false,
            followCursor: true,
            custom: function custom(opts) {
              if (opts.w.config.plotOptions && opts.w.config.plotOptions.bar && opts.w.config.plotOptions.bar.horizontal) {
                return handleTimelineTooltip(opts);
              } else {
                return handleRangeColumnTooltip(opts);
              }
            }
          },
          xaxis: {
            tickPlacement: 'between',
            tooltip: {
              enabled: false
            },
            crosshairs: {
              stroke: {
                width: 0
              }
            }
          }
        };
      }
    }, {
      key: "dumbbell",
      value: function dumbbell(opts) {
        var _opts$plotOptions$bar, _opts$plotOptions$bar2;
        if (!((_opts$plotOptions$bar = opts.plotOptions.bar) !== null && _opts$plotOptions$bar !== void 0 && _opts$plotOptions$bar.barHeight)) {
          opts.plotOptions.bar.barHeight = 2;
        }
        if (!((_opts$plotOptions$bar2 = opts.plotOptions.bar) !== null && _opts$plotOptions$bar2 !== void 0 && _opts$plotOptions$bar2.columnWidth)) {
          opts.plotOptions.bar.columnWidth = 2;
        }
        return opts;
      }
    }, {
      key: "area",
      value: function area() {
        return {
          stroke: {
            width: 4,
            fill: {
              type: 'solid',
              gradient: {
                inverseColors: false,
                shade: 'light',
                type: 'vertical',
                opacityFrom: 0.65,
                opacityTo: 0.5,
                stops: [0, 100, 100]
              }
            }
          },
          fill: {
            type: 'gradient',
            gradient: {
              inverseColors: false,
              shade: 'light',
              type: 'vertical',
              opacityFrom: 0.65,
              opacityTo: 0.5,
              stops: [0, 100, 100]
            }
          },
          markers: {
            size: 0,
            hover: {
              sizeOffset: 6
            }
          },
          tooltip: {
            followCursor: false
          }
        };
      }
    }, {
      key: "rangeArea",
      value: function rangeArea() {
        var handleRangeAreaTooltip = function handleRangeAreaTooltip(opts) {
          var _getRangeValues3 = getRangeValues(opts),
            color = _getRangeValues3.color,
            seriesName = _getRangeValues3.seriesName,
            ylabel = _getRangeValues3.ylabel,
            start = _getRangeValues3.start,
            end = _getRangeValues3.end;
          return buildRangeTooltipHTML(_objectSpread2(_objectSpread2({}, opts), {}, {
            color: color,
            seriesName: seriesName,
            ylabel: ylabel,
            start: start,
            end: end
          }));
        };
        return {
          stroke: {
            curve: 'straight',
            width: 0
          },
          fill: {
            type: 'solid',
            opacity: 0.6
          },
          markers: {
            size: 0
          },
          states: {
            hover: {
              filter: {
                type: 'none'
              }
            },
            active: {
              filter: {
                type: 'none'
              }
            }
          },
          tooltip: {
            intersect: false,
            shared: true,
            followCursor: true,
            custom: function custom(opts) {
              return handleRangeAreaTooltip(opts);
            }
          }
        };
      }
    }, {
      key: "brush",
      value: function brush(defaults) {
        var ret = {
          chart: {
            toolbar: {
              autoSelected: 'selection',
              show: false
            },
            zoom: {
              enabled: false
            }
          },
          dataLabels: {
            enabled: false
          },
          stroke: {
            width: 1
          },
          tooltip: {
            enabled: false
          },
          xaxis: {
            tooltip: {
              enabled: false
            }
          }
        };
        return Utils$1.extend(defaults, ret);
      }
    }, {
      key: "stacked100",
      value: function stacked100(opts) {
        opts.dataLabels = opts.dataLabels || {};
        opts.dataLabels.formatter = opts.dataLabels.formatter || undefined;
        var existingDataLabelFormatter = opts.dataLabels.formatter;
        opts.yaxis.forEach(function (yaxe, index) {
          opts.yaxis[index].min = 0;
          opts.yaxis[index].max = 100;
        });
        var isBar = opts.chart.type === 'bar';
        if (isBar) {
          opts.dataLabels.formatter = existingDataLabelFormatter || function (val) {
            if (typeof val === 'number') {
              return val ? val.toFixed(0) + '%' : val;
            }
            return val;
          };
        }
        return opts;
      }
    }, {
      key: "stackedBars",
      value: function stackedBars() {
        var barDefaults = this.bar();
        return _objectSpread2(_objectSpread2({}, barDefaults), {}, {
          plotOptions: _objectSpread2(_objectSpread2({}, barDefaults.plotOptions), {}, {
            bar: _objectSpread2(_objectSpread2({}, barDefaults.plotOptions.bar), {}, {
              borderRadiusApplication: 'end',
              borderRadiusWhenStacked: 'last'
            })
          })
        });
      }

      // This function removes the left and right spacing in chart for line/area/scatter if xaxis type = category for those charts by converting xaxis = numeric. Numeric/Datetime xaxis prevents the unnecessary spacing in the left/right of the chart area
    }, {
      key: "convertCatToNumeric",
      value: function convertCatToNumeric(opts) {
        opts.xaxis.convertedCatToNumeric = true;
        return opts;
      }
    }, {
      key: "convertCatToNumericXaxis",
      value: function convertCatToNumericXaxis(opts, ctx, cats) {
        opts.xaxis.type = 'numeric';
        opts.xaxis.labels = opts.xaxis.labels || {};
        opts.xaxis.labels.formatter = opts.xaxis.labels.formatter || function (val) {
          return Utils$1.isNumber(val) ? Math.floor(val) : val;
        };
        var defaultFormatter = opts.xaxis.labels.formatter;
        var labels = opts.xaxis.categories && opts.xaxis.categories.length ? opts.xaxis.categories : opts.labels;
        if (cats && cats.length) {
          labels = cats.map(function (c) {
            return Array.isArray(c) ? c : String(c);
          });
        }
        if (labels && labels.length) {
          opts.xaxis.labels.formatter = function (val) {
            return Utils$1.isNumber(val) ? defaultFormatter(labels[Math.floor(val) - 1]) : defaultFormatter(val);
          };
        }
        opts.xaxis.categories = [];
        opts.labels = [];
        opts.xaxis.tickAmount = opts.xaxis.tickAmount || 'dataPoints';
        return opts;
      }
    }, {
      key: "bubble",
      value: function bubble() {
        return {
          dataLabels: {
            style: {
              colors: ['#fff']
            }
          },
          tooltip: {
            shared: false,
            intersect: true
          },
          xaxis: {
            crosshairs: {
              width: 0
            }
          },
          fill: {
            type: 'solid',
            gradient: {
              shade: 'light',
              inverse: true,
              shadeIntensity: 0.55,
              opacityFrom: 0.4,
              opacityTo: 0.8
            }
          }
        };
      }
    }, {
      key: "scatter",
      value: function scatter() {
        return {
          dataLabels: {
            enabled: false
          },
          tooltip: {
            shared: false,
            intersect: true
          },
          markers: {
            size: 6,
            strokeWidth: 1,
            hover: {
              sizeOffset: 2
            }
          }
        };
      }
    }, {
      key: "heatmap",
      value: function heatmap() {
        return {
          chart: {
            stacked: false
          },
          fill: {
            opacity: 1
          },
          dataLabels: {
            style: {
              colors: ['#fff']
            }
          },
          stroke: {
            colors: ['#fff']
          },
          tooltip: {
            followCursor: true,
            marker: {
              show: false
            },
            x: {
              show: false
            }
          },
          legend: {
            position: 'top',
            markers: {
              shape: 'square'
            }
          },
          grid: {
            padding: {
              right: 20
            }
          }
        };
      }
    }, {
      key: "treemap",
      value: function treemap() {
        return {
          chart: {
            zoom: {
              enabled: false
            }
          },
          dataLabels: {
            style: {
              fontSize: 14,
              fontWeight: 600,
              colors: ['#fff']
            }
          },
          stroke: {
            show: true,
            width: 2,
            colors: ['#fff']
          },
          legend: {
            show: false
          },
          fill: {
            opacity: 1,
            gradient: {
              stops: [0, 100]
            }
          },
          tooltip: {
            followCursor: true,
            x: {
              show: false
            }
          },
          grid: {
            padding: {
              left: 0,
              right: 0
            }
          },
          xaxis: {
            crosshairs: {
              show: false
            },
            tooltip: {
              enabled: false
            }
          }
        };
      }
    }, {
      key: "pie",
      value: function pie() {
        return {
          chart: {
            toolbar: {
              show: false
            }
          },
          plotOptions: {
            pie: {
              donut: {
                labels: {
                  show: false
                }
              }
            }
          },
          dataLabels: {
            formatter: function formatter(val) {
              return val.toFixed(1) + '%';
            },
            style: {
              colors: ['#fff']
            },
            background: {
              enabled: false
            },
            dropShadow: {
              enabled: true
            }
          },
          stroke: {
            colors: ['#fff']
          },
          fill: {
            opacity: 1,
            gradient: {
              shade: 'light',
              stops: [0, 100]
            }
          },
          tooltip: {
            theme: 'dark',
            fillSeriesColor: true
          },
          legend: {
            position: 'right'
          },
          grid: {
            padding: {
              left: 0,
              right: 0,
              top: 0,
              bottom: 0
            }
          }
        };
      }
    }, {
      key: "donut",
      value: function donut() {
        return {
          chart: {
            toolbar: {
              show: false
            }
          },
          dataLabels: {
            formatter: function formatter(val) {
              return val.toFixed(1) + '%';
            },
            style: {
              colors: ['#fff']
            },
            background: {
              enabled: false
            },
            dropShadow: {
              enabled: true
            }
          },
          stroke: {
            colors: ['#fff']
          },
          fill: {
            opacity: 1,
            gradient: {
              shade: 'light',
              shadeIntensity: 0.35,
              stops: [80, 100],
              opacityFrom: 1,
              opacityTo: 1
            }
          },
          tooltip: {
            theme: 'dark',
            fillSeriesColor: true
          },
          legend: {
            position: 'right'
          },
          grid: {
            padding: {
              left: 0,
              right: 0,
              top: 0,
              bottom: 0
            }
          }
        };
      }
    }, {
      key: "polarArea",
      value: function polarArea() {
        return {
          chart: {
            toolbar: {
              show: false
            }
          },
          dataLabels: {
            formatter: function formatter(val) {
              return val.toFixed(1) + '%';
            },
            enabled: false
          },
          stroke: {
            show: true,
            width: 2
          },
          fill: {
            opacity: 0.7
          },
          tooltip: {
            theme: 'dark',
            fillSeriesColor: true
          },
          legend: {
            position: 'right'
          },
          grid: {
            padding: {
              left: 0,
              right: 0,
              top: 0,
              bottom: 0
            }
          }
        };
      }
    }, {
      key: "radar",
      value: function radar() {
        this.opts.yaxis[0].labels.offsetY = this.opts.yaxis[0].labels.offsetY ? this.opts.yaxis[0].labels.offsetY : 6;
        return {
          dataLabels: {
            enabled: false,
            style: {
              fontSize: '11px'
            }
          },
          stroke: {
            width: 2
          },
          markers: {
            size: 5,
            strokeWidth: 1,
            strokeOpacity: 1
          },
          fill: {
            opacity: 0.2
          },
          tooltip: {
            shared: false,
            intersect: true,
            followCursor: true
          },
          grid: {
            show: false,
            padding: {
              left: 0,
              right: 0,
              top: 0,
              bottom: 0
            }
          },
          xaxis: {
            labels: {
              formatter: function formatter(val) {
                return val;
              },
              style: {
                colors: ['#a8a8a8'],
                fontSize: '11px'
              }
            },
            tooltip: {
              enabled: false
            },
            crosshairs: {
              show: false
            }
          }
        };
      }
    }, {
      key: "radialBar",
      value: function radialBar() {
        return {
          chart: {
            animations: {
              dynamicAnimation: {
                enabled: true,
                speed: 800
              }
            },
            toolbar: {
              show: false
            }
          },
          fill: {
            gradient: {
              shade: 'dark',
              shadeIntensity: 0.4,
              inverseColors: false,
              type: 'diagonal2',
              opacityFrom: 1,
              opacityTo: 1,
              stops: [70, 98, 100]
            }
          },
          legend: {
            show: false,
            position: 'right'
          },
          tooltip: {
            enabled: false,
            fillSeriesColor: true
          },
          grid: {
            padding: {
              left: 0,
              right: 0,
              top: 0,
              bottom: 0
            }
          }
        };
      }
    }, {
      key: "_getBoxTooltip",
      value: function _getBoxTooltip(w, seriesIndex, dataPointIndex, labels, chartType) {
        var o = w.globals.seriesCandleO[seriesIndex][dataPointIndex];
        var h = w.globals.seriesCandleH[seriesIndex][dataPointIndex];
        var m = w.globals.seriesCandleM[seriesIndex][dataPointIndex];
        var l = w.globals.seriesCandleL[seriesIndex][dataPointIndex];
        var c = w.globals.seriesCandleC[seriesIndex][dataPointIndex];
        if (w.config.series[seriesIndex].type && w.config.series[seriesIndex].type !== chartType) {
          return "<div class=\"apexcharts-custom-tooltip\">\n          ".concat(w.config.series[seriesIndex].name ? w.config.series[seriesIndex].name : 'series-' + (seriesIndex + 1), ": <strong>").concat(w.globals.series[seriesIndex][dataPointIndex], "</strong>\n        </div>");
        } else {
          return "<div class=\"apexcharts-tooltip-box apexcharts-tooltip-".concat(w.config.chart.type, "\">") + "<div>".concat(labels[0], ": <span class=\"value\">") + o + '</span></div>' + "<div>".concat(labels[1], ": <span class=\"value\">") + h + '</span></div>' + (m ? "<div>".concat(labels[2], ": <span class=\"value\">") + m + '</span></div>' : '') + "<div>".concat(labels[3], ": <span class=\"value\">") + l + '</span></div>' + "<div>".concat(labels[4], ": <span class=\"value\">") + c + '</span></div>' + '</div>';
        }
      }
    }]);
    return Defaults;
  }();

  /**
   * ApexCharts Config Class for extending user options with pre-defined ApexCharts config.
   *
   * @module Config
   **/
  var Config = /*#__PURE__*/function () {
    function Config(opts) {
      _classCallCheck(this, Config);
      this.opts = opts;
    }
    _createClass(Config, [{
      key: "init",
      value: function init(_ref) {
        var responsiveOverride = _ref.responsiveOverride;
        var opts = this.opts;
        var options = new Options();
        var defaults = new Defaults(opts);
        this.chartType = opts.chart.type;
        opts = this.extendYAxis(opts);
        opts = this.extendAnnotations(opts);
        var config = options.init();
        var newDefaults = {};
        if (opts && _typeof(opts) === 'object') {
          var _opts$plotOptions, _opts$plotOptions$bar, _opts$chart$brush, _opts$plotOptions2, _opts$plotOptions2$li, _opts$plotOptions3, _opts$plotOptions3$ba, _opts$chart$sparkline, _window$Apex$chart, _window$Apex$chart$sp;
          var chartDefaults = {};
          var chartTypes = ['line', 'area', 'bar', 'candlestick', 'boxPlot', 'rangeBar', 'rangeArea', 'bubble', 'scatter', 'heatmap', 'treemap', 'pie', 'polarArea', 'donut', 'radar', 'radialBar'];
          if (chartTypes.indexOf(opts.chart.type) !== -1) {
            chartDefaults = defaults[opts.chart.type]();
          } else {
            chartDefaults = defaults.line();
          }
          if ((_opts$plotOptions = opts.plotOptions) !== null && _opts$plotOptions !== void 0 && (_opts$plotOptions$bar = _opts$plotOptions.bar) !== null && _opts$plotOptions$bar !== void 0 && _opts$plotOptions$bar.isFunnel) {
            chartDefaults = defaults.funnel();
          }
          if (opts.chart.stacked && opts.chart.type === 'bar') {
            chartDefaults = defaults.stackedBars();
          }
          if ((_opts$chart$brush = opts.chart.brush) !== null && _opts$chart$brush !== void 0 && _opts$chart$brush.enabled) {
            chartDefaults = defaults.brush(chartDefaults);
          }
          if ((_opts$plotOptions2 = opts.plotOptions) !== null && _opts$plotOptions2 !== void 0 && (_opts$plotOptions2$li = _opts$plotOptions2.line) !== null && _opts$plotOptions2$li !== void 0 && _opts$plotOptions2$li.isSlopeChart) {
            chartDefaults = defaults.slope();
          }
          if (opts.chart.stacked && opts.chart.stackType === '100%') {
            opts = defaults.stacked100(opts);
          }
          if ((_opts$plotOptions3 = opts.plotOptions) !== null && _opts$plotOptions3 !== void 0 && (_opts$plotOptions3$ba = _opts$plotOptions3.bar) !== null && _opts$plotOptions3$ba !== void 0 && _opts$plotOptions3$ba.isDumbbell) {
            opts = defaults.dumbbell(opts);
          }

          // If user has specified a dark theme, make the tooltip dark too
          this.checkForDarkTheme(window.Apex); // check global window Apex options
          this.checkForDarkTheme(opts); // check locally passed options

          opts.xaxis = opts.xaxis || window.Apex.xaxis || {};

          // an important boolean needs to be set here
          // otherwise all the charts will have this flag set to true window.Apex.xaxis is set globally
          if (!responsiveOverride) {
            opts.xaxis.convertedCatToNumeric = false;
          }
          opts = this.checkForCatToNumericXAxis(this.chartType, chartDefaults, opts);
          if ((_opts$chart$sparkline = opts.chart.sparkline) !== null && _opts$chart$sparkline !== void 0 && _opts$chart$sparkline.enabled || (_window$Apex$chart = window.Apex.chart) !== null && _window$Apex$chart !== void 0 && (_window$Apex$chart$sp = _window$Apex$chart.sparkline) !== null && _window$Apex$chart$sp !== void 0 && _window$Apex$chart$sp.enabled) {
            chartDefaults = defaults.sparkline(chartDefaults);
          }
          newDefaults = Utils$1.extend(config, chartDefaults);
        }

        // config should cascade in this fashion
        // default-config < global-apex-variable-config < user-defined-config

        // get GLOBALLY defined options and merge with the default config
        var mergedWithDefaultConfig = Utils$1.extend(newDefaults, window.Apex);

        // get the merged config and extend with user defined config
        config = Utils$1.extend(mergedWithDefaultConfig, opts);

        // some features are not supported. those mismatches should be handled
        config = this.handleUserInputErrors(config);
        return config;
      }
    }, {
      key: "checkForCatToNumericXAxis",
      value: function checkForCatToNumericXAxis(chartType, chartDefaults, opts) {
        var _opts$plotOptions4, _opts$plotOptions4$ba;
        var defaults = new Defaults(opts);
        var isBarHorizontal = (chartType === 'bar' || chartType === 'boxPlot') && ((_opts$plotOptions4 = opts.plotOptions) === null || _opts$plotOptions4 === void 0 ? void 0 : (_opts$plotOptions4$ba = _opts$plotOptions4.bar) === null || _opts$plotOptions4$ba === void 0 ? void 0 : _opts$plotOptions4$ba.horizontal);
        var unsupportedZoom = chartType === 'pie' || chartType === 'polarArea' || chartType === 'donut' || chartType === 'radar' || chartType === 'radialBar' || chartType === 'heatmap';
        var notNumericXAxis = opts.xaxis.type !== 'datetime' && opts.xaxis.type !== 'numeric';
        var tickPlacement = opts.xaxis.tickPlacement ? opts.xaxis.tickPlacement : chartDefaults.xaxis && chartDefaults.xaxis.tickPlacement;
        if (!isBarHorizontal && !unsupportedZoom && notNumericXAxis && tickPlacement !== 'between') {
          opts = defaults.convertCatToNumeric(opts);
        }
        return opts;
      }
    }, {
      key: "extendYAxis",
      value: function extendYAxis(opts, w) {
        var options = new Options();
        if (typeof opts.yaxis === 'undefined' || !opts.yaxis || Array.isArray(opts.yaxis) && opts.yaxis.length === 0) {
          opts.yaxis = {};
        }

        // extend global yaxis config (only if object is provided / not an array)
        if (opts.yaxis.constructor !== Array && window.Apex.yaxis && window.Apex.yaxis.constructor !== Array) {
          opts.yaxis = Utils$1.extend(opts.yaxis, window.Apex.yaxis);
        }

        // as we can't extend nested object's array with extend, we need to do it first
        // user can provide either an array or object in yaxis config
        if (opts.yaxis.constructor !== Array) {
          // convert the yaxis to array if user supplied object
          opts.yaxis = [Utils$1.extend(options.yAxis, opts.yaxis)];
        } else {
          opts.yaxis = Utils$1.extendArray(opts.yaxis, options.yAxis);
        }
        var isLogY = false;
        opts.yaxis.forEach(function (y) {
          if (y.logarithmic) {
            isLogY = true;
          }
        });
        var series = opts.series;
        if (w && !series) {
          series = w.config.series;
        }

        // A logarithmic chart works correctly when each series has a corresponding y-axis
        // If this is not the case, we manually create yaxis for multi-series log chart
        if (isLogY && series.length !== opts.yaxis.length && series.length) {
          opts.yaxis = series.map(function (s, i) {
            if (!s.name) {
              series[i].name = "series-".concat(i + 1);
            }
            if (opts.yaxis[i]) {
              opts.yaxis[i].seriesName = series[i].name;
              return opts.yaxis[i];
            } else {
              var newYaxis = Utils$1.extend(options.yAxis, opts.yaxis[0]);
              newYaxis.show = false;
              return newYaxis;
            }
          });
        }
        if (isLogY && series.length > 1 && series.length !== opts.yaxis.length) {
          console.warn('A multi-series logarithmic chart should have equal number of series and y-axes');
        }
        return opts;
      }

      // annotations also accepts array, so we need to extend them manually
    }, {
      key: "extendAnnotations",
      value: function extendAnnotations(opts) {
        if (typeof opts.annotations === 'undefined') {
          opts.annotations = {};
          opts.annotations.yaxis = [];
          opts.annotations.xaxis = [];
          opts.annotations.points = [];
        }
        opts = this.extendYAxisAnnotations(opts);
        opts = this.extendXAxisAnnotations(opts);
        opts = this.extendPointAnnotations(opts);
        return opts;
      }
    }, {
      key: "extendYAxisAnnotations",
      value: function extendYAxisAnnotations(opts) {
        var options = new Options();
        opts.annotations.yaxis = Utils$1.extendArray(typeof opts.annotations.yaxis !== 'undefined' ? opts.annotations.yaxis : [], options.yAxisAnnotation);
        return opts;
      }
    }, {
      key: "extendXAxisAnnotations",
      value: function extendXAxisAnnotations(opts) {
        var options = new Options();
        opts.annotations.xaxis = Utils$1.extendArray(typeof opts.annotations.xaxis !== 'undefined' ? opts.annotations.xaxis : [], options.xAxisAnnotation);
        return opts;
      }
    }, {
      key: "extendPointAnnotations",
      value: function extendPointAnnotations(opts) {
        var options = new Options();
        opts.annotations.points = Utils$1.extendArray(typeof opts.annotations.points !== 'undefined' ? opts.annotations.points : [], options.pointAnnotation);
        return opts;
      }
    }, {
      key: "checkForDarkTheme",
      value: function checkForDarkTheme(opts) {
        if (opts.theme && opts.theme.mode === 'dark') {
          if (!opts.tooltip) {
            opts.tooltip = {};
          }
          if (opts.tooltip.theme !== 'light') {
            opts.tooltip.theme = 'dark';
          }
          if (!opts.chart.foreColor) {
            opts.chart.foreColor = '#f6f7f8';
          }
          if (!opts.theme.palette) {
            opts.theme.palette = 'palette4';
          }
        }
      }
    }, {
      key: "handleUserInputErrors",
      value: function handleUserInputErrors(opts) {
        var config = opts;
        // conflicting tooltip option. intersect makes sure to focus on 1 point at a time. Shared cannot be used along with it
        if (config.tooltip.shared && config.tooltip.intersect) {
          throw new Error('tooltip.shared cannot be enabled when tooltip.intersect is true. Turn off any other option by setting it to false.');
        }
        if (config.chart.type === 'bar' && config.plotOptions.bar.horizontal) {
          // No multiple yaxis for bars
          if (config.yaxis.length > 1) {
            throw new Error('Multiple Y Axis for bars are not supported. Switch to column chart by setting plotOptions.bar.horizontal=false');
          }

          // if yaxis is reversed in horizontal bar chart, you should draw the y-axis on right side
          if (config.yaxis[0].reversed) {
            config.yaxis[0].opposite = true;
          }
          config.xaxis.tooltip.enabled = false; // no xaxis tooltip for horizontal bar
          config.yaxis[0].tooltip.enabled = false; // no xaxis tooltip for horizontal bar
          config.chart.zoom.enabled = false; // no zooming for horz bars
        }
        if (config.chart.type === 'bar' || config.chart.type === 'rangeBar') {
          if (config.tooltip.shared) {
            if (config.xaxis.crosshairs.width === 'barWidth' && config.series.length > 1) {
              config.xaxis.crosshairs.width = 'tickWidth';
            }
          }
        }
        if (config.chart.type === 'candlestick' || config.chart.type === 'boxPlot') {
          if (config.yaxis[0].reversed) {
            console.warn("Reversed y-axis in ".concat(config.chart.type, " chart is not supported."));
            config.yaxis[0].reversed = false;
          }
        }
        return config;
      }
    }]);
    return Config;
  }();

  var Globals = /*#__PURE__*/function () {
    function Globals() {
      _classCallCheck(this, Globals);
    }
    _createClass(Globals, [{
      key: "initGlobalVars",
      value: function initGlobalVars(gl) {
        gl.series = []; // the MAIN series array (y values)
        gl.seriesCandleO = [];
        gl.seriesCandleH = [];
        gl.seriesCandleM = [];
        gl.seriesCandleL = [];
        gl.seriesCandleC = [];
        gl.seriesRangeStart = [];
        gl.seriesRangeEnd = [];
        gl.seriesRange = [];
        gl.seriesPercent = [];
        gl.seriesGoals = [];
        gl.seriesX = [];
        gl.seriesZ = [];
        gl.seriesNames = [];
        gl.seriesTotals = [];
        gl.seriesLog = [];
        gl.seriesColors = [];
        gl.stackedSeriesTotals = [];
        gl.seriesXvalues = []; // we will need this in tooltip (it's x position)
        // when we will have unequal x values, we will need
        // some way to get x value depending on mouse pointer
        gl.seriesYvalues = []; // we will need this when deciding which series
        // user hovered on
        gl.labels = [];
        gl.hasXaxisGroups = false;
        gl.groups = [];
        gl.barGroups = [];
        gl.lineGroups = [];
        gl.areaGroups = [];
        gl.hasSeriesGroups = false;
        gl.seriesGroups = [];
        gl.categoryLabels = [];
        gl.timescaleLabels = [];
        gl.noLabelsProvided = false;
        gl.resizeTimer = null;
        gl.selectionResizeTimer = null;
        gl.lastWheelExecution = 0;
        gl.delayedElements = [];
        gl.pointsArray = [];
        gl.dataLabelsRects = [];
        gl.isXNumeric = false;
        gl.skipLastTimelinelabel = false;
        gl.skipFirstTimelinelabel = false;
        gl.isDataXYZ = false;
        gl.isMultiLineX = false;
        gl.isMultipleYAxis = false;
        gl.maxY = -Number.MAX_VALUE;
        gl.minY = Number.MIN_VALUE;
        gl.minYArr = [];
        gl.maxYArr = [];
        gl.maxX = -Number.MAX_VALUE;
        gl.minX = Number.MAX_VALUE;
        gl.initialMaxX = -Number.MAX_VALUE;
        gl.initialMinX = Number.MAX_VALUE;
        gl.maxDate = 0;
        gl.minDate = Number.MAX_VALUE;
        gl.minZ = Number.MAX_VALUE;
        gl.maxZ = -Number.MAX_VALUE;
        gl.minXDiff = Number.MAX_VALUE;
        gl.yAxisScale = [];
        gl.xAxisScale = null;
        gl.xAxisTicksPositions = [];
        gl.yLabelsCoords = [];
        gl.yTitleCoords = [];
        gl.barPadForNumericAxis = 0;
        gl.padHorizontal = 0;
        gl.xRange = 0;
        gl.yRange = [];
        gl.zRange = 0;
        gl.dataPoints = 0;
        gl.xTickAmount = 0;
        gl.multiAxisTickAmount = 0;
      }
    }, {
      key: "globalVars",
      value: function globalVars(config) {
        return {
          chartID: null,
          // chart ID - apexcharts-cuid
          cuid: null,
          // chart ID - random numbers excluding "apexcharts" part
          events: {
            beforeMount: [],
            mounted: [],
            updated: [],
            clicked: [],
            selection: [],
            dataPointSelection: [],
            zoomed: [],
            scrolled: []
          },
          colors: [],
          clientX: null,
          clientY: null,
          fill: {
            colors: []
          },
          stroke: {
            colors: []
          },
          dataLabels: {
            style: {
              colors: []
            }
          },
          radarPolygons: {
            fill: {
              colors: []
            }
          },
          markers: {
            colors: [],
            size: config.markers.size,
            largestSize: 0
          },
          animationEnded: false,
          isTouchDevice: 'ontouchstart' in window || navigator.msMaxTouchPoints,
          isDirty: false,
          // chart has been updated after the initial render. This is different than dataChanged property. isDirty means user manually called some method to update
          isExecCalled: false,
          // whether user updated the chart through the exec method
          initialConfig: null,
          // we will store the first config user has set to go back when user finishes interactions like zooming and come out of it
          initialSeries: [],
          lastXAxis: [],
          lastYAxis: [],
          columnSeries: null,
          labels: [],
          // store the text to draw on x axis
          // Don't mutate the labels, many things including tooltips depends on it!
          timescaleLabels: [],
          // store the timescaleLabels Labels in another variable
          noLabelsProvided: false,
          // if user didn't provide any categories/labels or x values, fallback to 1,2,3,4...
          allSeriesCollapsed: false,
          collapsedSeries: [],
          // when user collapses a series, it goes into this array
          collapsedSeriesIndices: [],
          // this stores the index of the collapsedSeries instead of whole object for quick access
          ancillaryCollapsedSeries: [],
          // when user collapses an "alwaysVisible" series, it goes into this array
          ancillaryCollapsedSeriesIndices: [],
          // this stores the index of the ancillaryCollapsedSeries whose y-axis is always visible
          risingSeries: [],
          // when user re-opens a collapsed series, it goes here
          dataFormatXNumeric: false,
          // boolean value to indicate user has passed numeric x values
          capturedSeriesIndex: -1,
          capturedDataPointIndex: -1,
          selectedDataPoints: [],
          invalidLogScale: false,
          // if a user enabled log scale but the data provided is not valid to generate a log scale, turn on this flag
          ignoreYAxisIndexes: [],
          // when series are being collapsed in multiple y axes, ignore certain index
          maxValsInArrayIndex: 0,
          radialSize: 0,
          selection: undefined,
          zoomEnabled: config.chart.toolbar.autoSelected === 'zoom' && config.chart.toolbar.tools.zoom && config.chart.zoom.enabled,
          panEnabled: config.chart.toolbar.autoSelected === 'pan' && config.chart.toolbar.tools.pan,
          selectionEnabled: config.chart.toolbar.autoSelected === 'selection' && config.chart.toolbar.tools.selection,
          yaxis: null,
          mousedown: false,
          lastClientPosition: {},
          // don't reset this variable this the chart is destroyed. It is used to detect right or left mousemove in panning
          visibleXRange: undefined,
          yValueDecimal: 0,
          // are there floating numbers in the series. If yes, this represent the len of the decimals
          total: 0,
          SVGNS: 'http://www.w3.org/2000/svg',
          // svg namespace
          svgWidth: 0,
          // the whole svg width
          svgHeight: 0,
          // the whole svg height
          noData: false,
          // whether there is any data to display or not
          locale: {},
          // the current locale values will be preserved here for global access
          dom: {},
          // for storing all dom nodes in this particular property
          memory: {
            methodsToExec: []
          },
          shouldAnimate: true,
          skipLastTimelinelabel: false,
          // when last label is cropped, skip drawing it
          skipFirstTimelinelabel: false,
          // when first label is cropped, skip drawing it
          delayedElements: [],
          // element which appear after animation has finished
          axisCharts: true,
          // chart type = line or area or bar
          // (refer them also as plot charts in the code)
          isDataXYZ: false,
          // bool: data was provided in a {[x,y,z]} pattern
          isSlopeChart: config.plotOptions.line.isSlopeChart,
          resized: false,
          // bool: user has resized
          resizeTimer: null,
          // timeout function to make a small delay before
          // drawing when user resized
          comboCharts: false,
          // bool: whether it's a combination of line/column
          dataChanged: false,
          // bool: has data changed dynamically
          previousPaths: [],
          // array: when data is changed, it will animate from
          // previous paths
          allSeriesHasEqualX: true,
          pointsArray: [],
          // store the points positions here to draw later on hover
          // format is - [[x,y],[x,y]... [x,y]]
          dataLabelsRects: [],
          // store the positions of datalabels to prevent collision
          lastDrawnDataLabelsIndexes: [],
          hasNullValues: false,
          // bool: whether series contains null values
          easing: null,
          // function: animation effect to apply
          zoomed: false,
          // whether user has zoomed or not
          gridWidth: 0,
          // drawable width of actual graphs (series paths)
          gridHeight: 0,
          // drawable height of actual graphs (series paths)
          rotateXLabels: false,
          defaultLabels: false,
          xLabelFormatter: undefined,
          // formatter for x axis labels
          yLabelFormatters: [],
          xaxisTooltipFormatter: undefined,
          // formatter for x axis tooltip
          ttKeyFormatter: undefined,
          ttVal: undefined,
          ttZFormatter: undefined,
          LINE_HEIGHT_RATIO: 1.618,
          xAxisLabelsHeight: 0,
          xAxisGroupLabelsHeight: 0,
          xAxisLabelsWidth: 0,
          yAxisLabelsWidth: 0,
          scaleX: 1,
          scaleY: 1,
          translateX: 0,
          translateY: 0,
          translateYAxisX: [],
          yAxisWidths: [],
          translateXAxisY: 0,
          translateXAxisX: 0,
          tooltip: null,
          // Rules for niceScaleAllowedMagMsd:
          // 1) An array of two arrays only ([[],[]]):
          //    * array[0][]: influences labelling of data series that contain only integers
          //       - must contain only integers (or expect ugly ticks)
          //    * array[1][]: influences labelling of data series that contain at least one float
          //       - may contain floats
          //    * both arrays:
          //       - each array[][i] ideally satisfy: 10 mod array[][i] == 0 (or expect ugly ticks)
          //       - to avoid clipping data point keep each array[][i] >= i
          // 2) each array[i][] contains 11 values, for all possible index values 0..10.
          //    array[][0] should not be needed (not proven) but ensures non-zero is returned.
          //
          // Users can effectively force their preferred "magMsd" through stepSize and
          // forceNiceScale. With forceNiceScale: true, stepSize becomes normalizable to the
          // axis's min..max range, which allows users to set stepSize to an integer 1..10, for
          // example, stepSize: 3. This value will be preferred to the value determined through
          // this array. The range-normalized value is checked for consistency with other
          // user defined options and will be ignored if inconsistent.
          niceScaleAllowedMagMsd: [[1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10], [1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10]],
          // Default ticks based on SVG size. These values have high numbers
          // of divisors. The array is indexed using a calculated maxTicks value
          // divided by 2 simply to halve the array size. See Scales.niceScale().
          niceScaleDefaultTicks: [1, 2, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24],
          seriesYAxisMap: [],
          // Given yAxis index, return all series indices belonging to it. Multiple series can be referenced to each yAxis.
          seriesYAxisReverseMap: [] // Given a Series index, return its yAxis index.
        };
      }
    }, {
      key: "init",
      value: function init(config) {
        var globals = this.globalVars(config);
        this.initGlobalVars(globals);
        globals.initialConfig = Utils$1.extend({}, config);
        globals.initialSeries = Utils$1.clone(config.series);
        globals.lastXAxis = Utils$1.clone(globals.initialConfig.xaxis);
        globals.lastYAxis = Utils$1.clone(globals.initialConfig.yaxis);
        return globals;
      }
    }]);
    return Globals;
  }();

  /**
   * ApexCharts Base Class for extending user options with pre-defined ApexCharts config.
   *
   * @module Base
   **/
  var Base = /*#__PURE__*/function () {
    function Base(opts) {
      _classCallCheck(this, Base);
      this.opts = opts;
    }
    _createClass(Base, [{
      key: "init",
      value: function init() {
        var config = new Config(this.opts).init({
          responsiveOverride: false
        });
        var globals = new Globals().init(config);
        var w = {
          config: config,
          globals: globals
        };
        return w;
      }
    }]);
    return Base;
  }();

  /**
   * ApexCharts Fill Class for setting fill options of the paths.
   *
   * @module Fill
   **/
  var Fill = /*#__PURE__*/function () {
    function Fill(ctx) {
      _classCallCheck(this, Fill);
      this.ctx = ctx;
      this.w = ctx.w;
      this.opts = null;
      this.seriesIndex = 0;
      this.patternIDs = [];
    }
    _createClass(Fill, [{
      key: "clippedImgArea",
      value: function clippedImgArea(params) {
        var w = this.w;
        var cnf = w.config;
        var svgW = parseInt(w.globals.gridWidth, 10);
        var svgH = parseInt(w.globals.gridHeight, 10);
        var size = svgW > svgH ? svgW : svgH;
        var fillImg = params.image;
        var imgWidth = 0;
        var imgHeight = 0;
        if (typeof params.width === 'undefined' && typeof params.height === 'undefined') {
          if (cnf.fill.image.width !== undefined && cnf.fill.image.height !== undefined) {
            imgWidth = cnf.fill.image.width + 1;
            imgHeight = cnf.fill.image.height;
          } else {
            imgWidth = size + 1;
            imgHeight = size;
          }
        } else {
          imgWidth = params.width;
          imgHeight = params.height;
        }
        var elPattern = document.createElementNS(w.globals.SVGNS, 'pattern');
        Graphics.setAttrs(elPattern, {
          id: params.patternID,
          patternUnits: params.patternUnits ? params.patternUnits : 'userSpaceOnUse',
          width: imgWidth + 'px',
          height: imgHeight + 'px'
        });
        var elImage = document.createElementNS(w.globals.SVGNS, 'image');
        elPattern.appendChild(elImage);
        elImage.setAttributeNS(window.SVG.xlink, 'href', fillImg);
        Graphics.setAttrs(elImage, {
          x: 0,
          y: 0,
          preserveAspectRatio: 'none',
          width: imgWidth + 'px',
          height: imgHeight + 'px'
        });
        elImage.style.opacity = params.opacity;
        w.globals.dom.elDefs.node.appendChild(elPattern);
      }
    }, {
      key: "getSeriesIndex",
      value: function getSeriesIndex(opts) {
        var w = this.w;
        var cType = w.config.chart.type;
        if ((cType === 'bar' || cType === 'rangeBar') && w.config.plotOptions.bar.distributed || cType === 'heatmap' || cType === 'treemap') {
          this.seriesIndex = opts.seriesNumber;
        } else {
          this.seriesIndex = opts.seriesNumber % w.globals.series.length;
        }
        return this.seriesIndex;
      }
    }, {
      key: "fillPath",
      value: function fillPath(opts) {
        var w = this.w;
        this.opts = opts;
        var cnf = this.w.config;
        var pathFill;
        var patternFill, gradientFill;
        this.seriesIndex = this.getSeriesIndex(opts);
        var fillColors = this.getFillColors();
        var fillColor = fillColors[this.seriesIndex];

        //override fillcolor if user inputted color with data
        if (w.globals.seriesColors[this.seriesIndex] !== undefined) {
          fillColor = w.globals.seriesColors[this.seriesIndex];
        }
        if (typeof fillColor === 'function') {
          fillColor = fillColor({
            seriesIndex: this.seriesIndex,
            dataPointIndex: opts.dataPointIndex,
            value: opts.value,
            w: w
          });
        }
        var fillType = opts.fillType ? opts.fillType : this.getFillType(this.seriesIndex);
        var fillOpacity = Array.isArray(cnf.fill.opacity) ? cnf.fill.opacity[this.seriesIndex] : cnf.fill.opacity;
        if (opts.color) {
          fillColor = opts.color;
        }

        // in case a color is undefined, fallback to white color to prevent runtime error
        if (!fillColor) {
          fillColor = '#fff';
          console.warn('undefined color - ApexCharts');
        }
        var defaultColor = fillColor;
        if (fillColor.indexOf('rgb') === -1) {
          if (fillColor.length < 9) {
            // if the hex contains alpha and is of 9 digit, skip the opacity
            defaultColor = Utils$1.hexToRgba(fillColor, fillOpacity);
          }
        } else {
          if (fillColor.indexOf('rgba') > -1) {
            fillOpacity = Utils$1.getOpacityFromRGBA(fillColor);
          }
        }
        if (opts.opacity) fillOpacity = opts.opacity;
        if (fillType === 'pattern') {
          patternFill = this.handlePatternFill({
            fillConfig: opts.fillConfig,
            patternFill: patternFill,
            fillColor: fillColor,
            fillOpacity: fillOpacity,
            defaultColor: defaultColor
          });
        }
        if (fillType === 'gradient') {
          gradientFill = this.handleGradientFill({
            fillConfig: opts.fillConfig,
            fillColor: fillColor,
            fillOpacity: fillOpacity,
            i: this.seriesIndex
          });
        }
        if (fillType === 'image') {
          var imgSrc = cnf.fill.image.src;
          var patternID = opts.patternID ? opts.patternID : '';
          var patternKey = "pattern".concat(w.globals.cuid).concat(opts.seriesNumber + 1).concat(patternID);
          if (this.patternIDs.indexOf(patternKey) === -1) {
            this.clippedImgArea({
              opacity: fillOpacity,
              image: Array.isArray(imgSrc) ? opts.seriesNumber < imgSrc.length ? imgSrc[opts.seriesNumber] : imgSrc[0] : imgSrc,
              width: opts.width ? opts.width : undefined,
              height: opts.height ? opts.height : undefined,
              patternUnits: opts.patternUnits,
              patternID: patternKey
            });
            this.patternIDs.push(patternKey);
          }
          pathFill = "url(#".concat(patternKey, ")");
        } else if (fillType === 'gradient') {
          pathFill = gradientFill;
        } else if (fillType === 'pattern') {
          pathFill = patternFill;
        } else {
          pathFill = defaultColor;
        }

        // override pattern/gradient if opts.solid is true
        if (opts.solid) {
          pathFill = defaultColor;
        }
        return pathFill;
      }
    }, {
      key: "getFillType",
      value: function getFillType(seriesIndex) {
        var w = this.w;
        if (Array.isArray(w.config.fill.type)) {
          return w.config.fill.type[seriesIndex];
        } else {
          return w.config.fill.type;
        }
      }
    }, {
      key: "getFillColors",
      value: function getFillColors() {
        var w = this.w;
        var cnf = w.config;
        var opts = this.opts;
        var fillColors = [];
        if (w.globals.comboCharts) {
          if (w.config.series[this.seriesIndex].type === 'line') {
            if (Array.isArray(w.globals.stroke.colors)) {
              fillColors = w.globals.stroke.colors;
            } else {
              fillColors.push(w.globals.stroke.colors);
            }
          } else {
            if (Array.isArray(w.globals.fill.colors)) {
              fillColors = w.globals.fill.colors;
            } else {
              fillColors.push(w.globals.fill.colors);
            }
          }
        } else {
          if (cnf.chart.type === 'line') {
            if (Array.isArray(w.globals.stroke.colors)) {
              fillColors = w.globals.stroke.colors;
            } else {
              fillColors.push(w.globals.stroke.colors);
            }
          } else {
            if (Array.isArray(w.globals.fill.colors)) {
              fillColors = w.globals.fill.colors;
            } else {
              fillColors.push(w.globals.fill.colors);
            }
          }
        }

        // colors passed in arguments
        if (typeof opts.fillColors !== 'undefined') {
          fillColors = [];
          if (Array.isArray(opts.fillColors)) {
            fillColors = opts.fillColors.slice();
          } else {
            fillColors.push(opts.fillColors);
          }
        }
        return fillColors;
      }
    }, {
      key: "handlePatternFill",
      value: function handlePatternFill(_ref) {
        var fillConfig = _ref.fillConfig,
          patternFill = _ref.patternFill,
          fillColor = _ref.fillColor,
          fillOpacity = _ref.fillOpacity,
          defaultColor = _ref.defaultColor;
        var fillCnf = this.w.config.fill;
        if (fillConfig) {
          fillCnf = fillConfig;
        }
        var opts = this.opts;
        var graphics = new Graphics(this.ctx);
        var patternStrokeWidth = Array.isArray(fillCnf.pattern.strokeWidth) ? fillCnf.pattern.strokeWidth[this.seriesIndex] : fillCnf.pattern.strokeWidth;
        var patternLineColor = fillColor;
        if (Array.isArray(fillCnf.pattern.style)) {
          if (typeof fillCnf.pattern.style[opts.seriesNumber] !== 'undefined') {
            var pf = graphics.drawPattern(fillCnf.pattern.style[opts.seriesNumber], fillCnf.pattern.width, fillCnf.pattern.height, patternLineColor, patternStrokeWidth, fillOpacity);
            patternFill = pf;
          } else {
            patternFill = defaultColor;
          }
        } else {
          patternFill = graphics.drawPattern(fillCnf.pattern.style, fillCnf.pattern.width, fillCnf.pattern.height, patternLineColor, patternStrokeWidth, fillOpacity);
        }
        return patternFill;
      }
    }, {
      key: "handleGradientFill",
      value: function handleGradientFill(_ref2) {
        var fillColor = _ref2.fillColor,
          fillOpacity = _ref2.fillOpacity,
          fillConfig = _ref2.fillConfig,
          i = _ref2.i;
        var fillCnf = this.w.config.fill;
        if (fillConfig) {
          fillCnf = _objectSpread2(_objectSpread2({}, fillCnf), fillConfig);
        }
        var opts = this.opts;
        var graphics = new Graphics(this.ctx);
        var utils = new Utils$1();
        var type = fillCnf.gradient.type;
        var gradientFrom = fillColor;
        var gradientTo;
        var opacityFrom = fillCnf.gradient.opacityFrom === undefined ? fillOpacity : Array.isArray(fillCnf.gradient.opacityFrom) ? fillCnf.gradient.opacityFrom[i] : fillCnf.gradient.opacityFrom;
        if (gradientFrom.indexOf('rgba') > -1) {
          opacityFrom = Utils$1.getOpacityFromRGBA(gradientFrom);
        }
        var opacityTo = fillCnf.gradient.opacityTo === undefined ? fillOpacity : Array.isArray(fillCnf.gradient.opacityTo) ? fillCnf.gradient.opacityTo[i] : fillCnf.gradient.opacityTo;
        if (fillCnf.gradient.gradientToColors === undefined || fillCnf.gradient.gradientToColors.length === 0) {
          if (fillCnf.gradient.shade === 'dark') {
            gradientTo = utils.shadeColor(parseFloat(fillCnf.gradient.shadeIntensity) * -1, fillColor.indexOf('rgb') > -1 ? Utils$1.rgb2hex(fillColor) : fillColor);
          } else {
            gradientTo = utils.shadeColor(parseFloat(fillCnf.gradient.shadeIntensity), fillColor.indexOf('rgb') > -1 ? Utils$1.rgb2hex(fillColor) : fillColor);
          }
        } else {
          if (fillCnf.gradient.gradientToColors[opts.seriesNumber]) {
            var gToColor = fillCnf.gradient.gradientToColors[opts.seriesNumber];
            gradientTo = gToColor;
            if (gToColor.indexOf('rgba') > -1) {
              opacityTo = Utils$1.getOpacityFromRGBA(gToColor);
            }
          } else {
            gradientTo = fillColor;
          }
        }
        if (fillCnf.gradient.gradientFrom) {
          gradientFrom = fillCnf.gradient.gradientFrom;
        }
        if (fillCnf.gradient.gradientTo) {
          gradientTo = fillCnf.gradient.gradientTo;
        }
        if (fillCnf.gradient.inverseColors) {
          var t = gradientFrom;
          gradientFrom = gradientTo;
          gradientTo = t;
        }
        if (gradientFrom.indexOf('rgb') > -1) {
          gradientFrom = Utils$1.rgb2hex(gradientFrom);
        }
        if (gradientTo.indexOf('rgb') > -1) {
          gradientTo = Utils$1.rgb2hex(gradientTo);
        }
        return graphics.drawGradient(type, gradientFrom, gradientTo, opacityFrom, opacityTo, opts.size, fillCnf.gradient.stops, fillCnf.gradient.colorStops, i);
      }
    }]);
    return Fill;
  }();

  /**
   * ApexCharts Markers Class for drawing points on y values in axes charts.
   *
   * @module Markers
   **/
  var Markers = /*#__PURE__*/function () {
    function Markers(ctx, opts) {
      _classCallCheck(this, Markers);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(Markers, [{
      key: "setGlobalMarkerSize",
      value: function setGlobalMarkerSize() {
        var w = this.w;
        w.globals.markers.size = Array.isArray(w.config.markers.size) ? w.config.markers.size : [w.config.markers.size];
        if (w.globals.markers.size.length > 0) {
          if (w.globals.markers.size.length < w.globals.series.length + 1) {
            for (var i = 0; i <= w.globals.series.length; i++) {
              if (typeof w.globals.markers.size[i] === 'undefined') {
                w.globals.markers.size.push(w.globals.markers.size[0]);
              }
            }
          }
        } else {
          w.globals.markers.size = w.config.series.map(function (s) {
            return w.config.markers.size;
          });
        }
      }
    }, {
      key: "plotChartMarkers",
      value: function plotChartMarkers(pointsPos, seriesIndex, j, pSize) {
        var alwaysDrawMarker = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
        var w = this.w;
        var i = seriesIndex;
        var p = pointsPos;
        var elPointsWrap = null;
        var graphics = new Graphics(this.ctx);
        var point;
        var hasDiscreteMarkers = w.config.markers.discrete && w.config.markers.discrete.length;
        if (w.globals.markers.size[seriesIndex] > 0 || alwaysDrawMarker || hasDiscreteMarkers) {
          elPointsWrap = graphics.group({
            class: alwaysDrawMarker || hasDiscreteMarkers ? '' : 'apexcharts-series-markers'
          });
          elPointsWrap.attr('clip-path', "url(#gridRectMarkerMask".concat(w.globals.cuid, ")"));
        }
        if (Array.isArray(p.x)) {
          for (var q = 0; q < p.x.length; q++) {
            var dataPointIndex = j;

            // a small hack as we have 2 points for the first val to connect it
            if (j === 1 && q === 0) dataPointIndex = 0;
            if (j === 1 && q === 1) dataPointIndex = 1;
            var PointClasses = 'apexcharts-marker';
            if ((w.config.chart.type === 'line' || w.config.chart.type === 'area') && !w.globals.comboCharts && !w.config.tooltip.intersect) {
              PointClasses += ' no-pointer-events';
            }
            var shouldMarkerDraw = Array.isArray(w.config.markers.size) ? w.globals.markers.size[seriesIndex] > 0 : w.config.markers.size > 0;
            if (shouldMarkerDraw || alwaysDrawMarker || hasDiscreteMarkers) {
              if (Utils$1.isNumber(p.y[q])) {
                PointClasses += " w".concat(Utils$1.randomId());
              } else {
                PointClasses = 'apexcharts-nullpoint';
              }
              var opts = this.getMarkerConfig({
                cssClass: PointClasses,
                seriesIndex: seriesIndex,
                dataPointIndex: dataPointIndex
              });
              if (w.config.series[i].data[dataPointIndex]) {
                if (w.config.series[i].data[dataPointIndex].fillColor) {
                  opts.pointFillColor = w.config.series[i].data[dataPointIndex].fillColor;
                }
                if (w.config.series[i].data[dataPointIndex].strokeColor) {
                  opts.pointStrokeColor = w.config.series[i].data[dataPointIndex].strokeColor;
                }
              }
              if (typeof pSize !== 'undefined') {
                opts.pSize = pSize;
              }
              if (p.x[q] < -w.globals.markers.largestSize || p.x[q] > w.globals.gridWidth + w.globals.markers.largestSize || p.y[q] < -w.globals.markers.largestSize || p.y[q] > w.globals.gridHeight + w.globals.markers.largestSize) {
                opts.pSize = 0;
              }
              point = graphics.drawMarker(p.x[q], p.y[q], opts);
              point.attr('rel', dataPointIndex);
              point.attr('j', dataPointIndex);
              point.attr('index', seriesIndex);
              point.node.setAttribute('default-marker-size', opts.pSize);
              var filters = new Filters(this.ctx);
              filters.setSelectionFilter(point, seriesIndex, dataPointIndex);
              this.addEvents(point);
              if (elPointsWrap) {
                elPointsWrap.add(point);
              }
            } else {
              // dynamic array creation - multidimensional
              if (typeof w.globals.pointsArray[seriesIndex] === 'undefined') w.globals.pointsArray[seriesIndex] = [];
              w.globals.pointsArray[seriesIndex].push([p.x[q], p.y[q]]);
            }
          }
        }
        return elPointsWrap;
      }
    }, {
      key: "getMarkerConfig",
      value: function getMarkerConfig(_ref) {
        var cssClass = _ref.cssClass,
          seriesIndex = _ref.seriesIndex,
          _ref$dataPointIndex = _ref.dataPointIndex,
          dataPointIndex = _ref$dataPointIndex === void 0 ? null : _ref$dataPointIndex,
          _ref$radius = _ref.radius,
          radius = _ref$radius === void 0 ? null : _ref$radius,
          _ref$size = _ref.size,
          size = _ref$size === void 0 ? null : _ref$size,
          _ref$strokeWidth = _ref.strokeWidth,
          strokeWidth = _ref$strokeWidth === void 0 ? null : _ref$strokeWidth;
        var w = this.w;
        var pStyle = this.getMarkerStyle(seriesIndex);
        var pSize = size === null ? w.globals.markers.size[seriesIndex] : size;
        var m = w.config.markers;

        // discrete markers is an option where user can specify a particular marker with different shape, size and color

        if (dataPointIndex !== null && m.discrete.length) {
          m.discrete.map(function (marker) {
            if (marker.seriesIndex === seriesIndex && marker.dataPointIndex === dataPointIndex) {
              pStyle.pointStrokeColor = marker.strokeColor;
              pStyle.pointFillColor = marker.fillColor;
              pSize = marker.size;
              pStyle.pointShape = marker.shape;
            }
          });
        }
        return {
          pSize: radius === null ? pSize : radius,
          pRadius: radius !== null ? radius : m.radius,
          pointStrokeWidth: strokeWidth !== null ? strokeWidth : Array.isArray(m.strokeWidth) ? m.strokeWidth[seriesIndex] : m.strokeWidth,
          pointStrokeColor: pStyle.pointStrokeColor,
          pointFillColor: pStyle.pointFillColor,
          shape: pStyle.pointShape || (Array.isArray(m.shape) ? m.shape[seriesIndex] : m.shape),
          class: cssClass,
          pointStrokeOpacity: Array.isArray(m.strokeOpacity) ? m.strokeOpacity[seriesIndex] : m.strokeOpacity,
          pointStrokeDashArray: Array.isArray(m.strokeDashArray) ? m.strokeDashArray[seriesIndex] : m.strokeDashArray,
          pointFillOpacity: Array.isArray(m.fillOpacity) ? m.fillOpacity[seriesIndex] : m.fillOpacity,
          seriesIndex: seriesIndex
        };
      }
    }, {
      key: "addEvents",
      value: function addEvents(marker) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        marker.node.addEventListener('mouseenter', graphics.pathMouseEnter.bind(this.ctx, marker));
        marker.node.addEventListener('mouseleave', graphics.pathMouseLeave.bind(this.ctx, marker));
        marker.node.addEventListener('mousedown', graphics.pathMouseDown.bind(this.ctx, marker));
        marker.node.addEventListener('click', w.config.markers.onClick);
        marker.node.addEventListener('dblclick', w.config.markers.onDblClick);
        marker.node.addEventListener('touchstart', graphics.pathMouseDown.bind(this.ctx, marker), {
          passive: true
        });
      }
    }, {
      key: "getMarkerStyle",
      value: function getMarkerStyle(seriesIndex) {
        var w = this.w;
        var colors = w.globals.markers.colors;
        var strokeColors = w.config.markers.strokeColor || w.config.markers.strokeColors;
        var pointStrokeColor = Array.isArray(strokeColors) ? strokeColors[seriesIndex] : strokeColors;
        var pointFillColor = Array.isArray(colors) ? colors[seriesIndex] : colors;
        return {
          pointStrokeColor: pointStrokeColor,
          pointFillColor: pointFillColor
        };
      }
    }]);
    return Markers;
  }();

  /**
   * ApexCharts Scatter Class.
   * This Class also handles bubbles chart as currently there is no major difference in drawing them,
   * @module Scatter
   **/
  var Scatter = /*#__PURE__*/function () {
    function Scatter(ctx) {
      _classCallCheck(this, Scatter);
      this.ctx = ctx;
      this.w = ctx.w;
      this.initialAnim = this.w.config.chart.animations.enabled;
    }
    _createClass(Scatter, [{
      key: "draw",
      value: function draw(elSeries, j, opts) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var realIndex = opts.realIndex;
        var pointsPos = opts.pointsPos;
        var zRatio = opts.zRatio;
        var elPointsMain = opts.elParent;
        var elPointsWrap = graphics.group({
          class: "apexcharts-series-markers apexcharts-series-".concat(w.config.chart.type)
        });
        elPointsWrap.attr('clip-path', "url(#gridRectMarkerMask".concat(w.globals.cuid, ")"));
        if (Array.isArray(pointsPos.x)) {
          for (var q = 0; q < pointsPos.x.length; q++) {
            var dataPointIndex = j + 1;
            var shouldDraw = true;

            // a small hack as we have 2 points for the first val to connect it
            if (j === 0 && q === 0) dataPointIndex = 0;
            if (j === 0 && q === 1) dataPointIndex = 1;
            var radius = w.globals.markers.size[realIndex];
            if (zRatio !== Infinity) {
              // means we have a bubble
              var bubble = w.config.plotOptions.bubble;
              radius = w.globals.seriesZ[realIndex][dataPointIndex];
              if (bubble.zScaling) {
                radius /= zRatio;
              }
              if (bubble.minBubbleRadius && radius < bubble.minBubbleRadius) {
                radius = bubble.minBubbleRadius;
              }
              if (bubble.maxBubbleRadius && radius > bubble.maxBubbleRadius) {
                radius = bubble.maxBubbleRadius;
              }
            }
            var x = pointsPos.x[q];
            var y = pointsPos.y[q];
            radius = radius || 0;
            if (y === null || typeof w.globals.series[realIndex][dataPointIndex] === 'undefined') {
              shouldDraw = false;
            }
            if (shouldDraw) {
              var point = this.drawPoint(x, y, radius, realIndex, dataPointIndex, j);
              elPointsWrap.add(point);
            }
            elPointsMain.add(elPointsWrap);
          }
        }
      }
    }, {
      key: "drawPoint",
      value: function drawPoint(x, y, radius, realIndex, dataPointIndex, j) {
        var w = this.w;
        var i = realIndex;
        var anim = new Animations(this.ctx);
        var filters = new Filters(this.ctx);
        var fill = new Fill(this.ctx);
        var markers = new Markers(this.ctx);
        var graphics = new Graphics(this.ctx);
        var markerConfig = markers.getMarkerConfig({
          cssClass: 'apexcharts-marker',
          seriesIndex: i,
          dataPointIndex: dataPointIndex,
          radius: w.config.chart.type === 'bubble' || w.globals.comboCharts && w.config.series[realIndex] && w.config.series[realIndex].type === 'bubble' ? radius : null
        });
        var pathFillCircle = fill.fillPath({
          seriesNumber: realIndex,
          dataPointIndex: dataPointIndex,
          color: markerConfig.pointFillColor,
          patternUnits: 'objectBoundingBox',
          value: w.globals.series[realIndex][j]
        });
        var el = graphics.drawMarker(x, y, markerConfig);
        if (w.config.series[i].data[dataPointIndex]) {
          if (w.config.series[i].data[dataPointIndex].fillColor) {
            pathFillCircle = w.config.series[i].data[dataPointIndex].fillColor;
          }
        }
        el.attr({
          fill: pathFillCircle
        });
        if (w.config.chart.dropShadow.enabled) {
          var dropShadow = w.config.chart.dropShadow;
          filters.dropShadow(el, dropShadow, realIndex);
        }
        if (this.initialAnim && !w.globals.dataChanged && !w.globals.resized) {
          var speed = w.config.chart.animations.speed;
          anim.animateMarker(el, speed, w.globals.easing, function () {
            window.setTimeout(function () {
              anim.animationCompleted(el);
            }, 100);
          });
        } else {
          w.globals.animationEnded = true;
        }
        el.attr({
          rel: dataPointIndex,
          j: dataPointIndex,
          index: realIndex,
          'default-marker-size': markerConfig.pSize
        });
        filters.setSelectionFilter(el, realIndex, dataPointIndex);
        markers.addEvents(el);
        el.node.classList.add('apexcharts-marker');
        return el;
      }
    }, {
      key: "centerTextInBubble",
      value: function centerTextInBubble(y) {
        var w = this.w;
        y = y + parseInt(w.config.dataLabels.style.fontSize, 10) / 4;
        return {
          y: y
        };
      }
    }]);
    return Scatter;
  }();

  /**
   * ApexCharts DataLabels Class for drawing dataLabels on Axes based Charts.
   *
   * @module DataLabels
   **/
  var DataLabels = /*#__PURE__*/function () {
    function DataLabels(ctx) {
      _classCallCheck(this, DataLabels);
      this.ctx = ctx;
      this.w = ctx.w;
    }

    // When there are many datalabels to be printed, and some of them overlaps each other in the same series, this method will take care of that
    // Also, when datalabels exceeds the drawable area and get clipped off, we need to adjust and move some pixels to make them visible again
    _createClass(DataLabels, [{
      key: "dataLabelsCorrection",
      value: function dataLabelsCorrection(x, y, val, i, dataPointIndex, alwaysDrawDataLabel, fontSize) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var drawnextLabel = false; //

        var textRects = graphics.getTextRects(val, fontSize);
        var width = textRects.width;
        var height = textRects.height;
        if (y < 0) y = 0;
        if (y > w.globals.gridHeight + height) y = w.globals.gridHeight + height / 2;

        // first value in series, so push an empty array
        if (typeof w.globals.dataLabelsRects[i] === 'undefined') w.globals.dataLabelsRects[i] = [];

        // then start pushing actual rects in that sub-array
        w.globals.dataLabelsRects[i].push({
          x: x,
          y: y,
          width: width,
          height: height
        });
        var len = w.globals.dataLabelsRects[i].length - 2;
        var lastDrawnIndex = typeof w.globals.lastDrawnDataLabelsIndexes[i] !== 'undefined' ? w.globals.lastDrawnDataLabelsIndexes[i][w.globals.lastDrawnDataLabelsIndexes[i].length - 1] : 0;
        if (typeof w.globals.dataLabelsRects[i][len] !== 'undefined') {
          var lastDataLabelRect = w.globals.dataLabelsRects[i][lastDrawnIndex];
          if (
          // next label forward and x not intersecting
          x > lastDataLabelRect.x + lastDataLabelRect.width || y > lastDataLabelRect.y + lastDataLabelRect.height || y + height < lastDataLabelRect.y || x + width < lastDataLabelRect.x // next label is going to be drawn backwards
          ) {
            // the 2 indexes don't override, so OK to draw next label
            drawnextLabel = true;
          }
        }
        if (dataPointIndex === 0 || alwaysDrawDataLabel) {
          drawnextLabel = true;
        }
        return {
          x: x,
          y: y,
          textRects: textRects,
          drawnextLabel: drawnextLabel
        };
      }
    }, {
      key: "drawDataLabel",
      value: function drawDataLabel(_ref) {
        var _this = this;
        var type = _ref.type,
          pos = _ref.pos,
          i = _ref.i,
          j = _ref.j,
          isRangeStart = _ref.isRangeStart,
          _ref$strokeWidth = _ref.strokeWidth,
          strokeWidth = _ref$strokeWidth === void 0 ? 2 : _ref$strokeWidth;
        // this method handles line, area, bubble, scatter charts as those charts contains markers/points which have pre-defined x/y positions
        // all other charts like radar / bars / heatmaps will define their own drawDataLabel routine
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var dataLabelsConfig = w.config.dataLabels;
        var x = 0;
        var y = 0;
        var dataPointIndex = j;
        var elDataLabelsWrap = null;
        var seriesCollapsed = w.globals.collapsedSeriesIndices.indexOf(i) !== -1;
        if (seriesCollapsed || !dataLabelsConfig.enabled || !Array.isArray(pos.x)) {
          return elDataLabelsWrap;
        }
        elDataLabelsWrap = graphics.group({
          class: 'apexcharts-data-labels'
        });
        for (var q = 0; q < pos.x.length; q++) {
          x = pos.x[q] + dataLabelsConfig.offsetX;
          y = pos.y[q] + dataLabelsConfig.offsetY + strokeWidth;
          if (!isNaN(x)) {
            // a small hack as we have 2 points for the first val to connect it
            if (j === 1 && q === 0) dataPointIndex = 0;
            if (j === 1 && q === 1) dataPointIndex = 1;
            var val = w.globals.series[i][dataPointIndex];
            if (type === 'rangeArea') {
              if (isRangeStart) {
                val = w.globals.seriesRangeStart[i][dataPointIndex];
              } else {
                val = w.globals.seriesRangeEnd[i][dataPointIndex];
              }
            }
            var text = '';
            var getText = function getText(v) {
              return w.config.dataLabels.formatter(v, {
                ctx: _this.ctx,
                seriesIndex: i,
                dataPointIndex: dataPointIndex,
                w: w
              });
            };
            if (w.config.chart.type === 'bubble') {
              val = w.globals.seriesZ[i][dataPointIndex];
              text = getText(val);
              y = pos.y[q];
              var scatter = new Scatter(this.ctx);
              var centerTextInBubbleCoords = scatter.centerTextInBubble(y, i, dataPointIndex);
              y = centerTextInBubbleCoords.y;
            } else {
              if (typeof val !== 'undefined') {
                text = getText(val);
              }
            }
            var textAnchor = w.config.dataLabels.textAnchor;
            if (w.globals.isSlopeChart) {
              if (dataPointIndex === 0) {
                textAnchor = 'end';
              } else if (dataPointIndex === w.config.series[i].data.length - 1) {
                textAnchor = 'start';
              } else {
                textAnchor = 'middle';
              }
            }
            this.plotDataLabelsText({
              x: x,
              y: y,
              text: text,
              i: i,
              j: dataPointIndex,
              parent: elDataLabelsWrap,
              offsetCorrection: true,
              dataLabelsConfig: w.config.dataLabels,
              textAnchor: textAnchor
            });
          }
        }
        return elDataLabelsWrap;
      }
    }, {
      key: "plotDataLabelsText",
      value: function plotDataLabelsText(opts) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var x = opts.x,
          y = opts.y,
          i = opts.i,
          j = opts.j,
          text = opts.text,
          textAnchor = opts.textAnchor,
          fontSize = opts.fontSize,
          parent = opts.parent,
          dataLabelsConfig = opts.dataLabelsConfig,
          color = opts.color,
          alwaysDrawDataLabel = opts.alwaysDrawDataLabel,
          offsetCorrection = opts.offsetCorrection,
          className = opts.className;
        var dataLabelText = null;
        if (Array.isArray(w.config.dataLabels.enabledOnSeries)) {
          if (w.config.dataLabels.enabledOnSeries.indexOf(i) < 0) {
            return dataLabelText;
          }
        }
        var correctedLabels = {
          x: x,
          y: y,
          drawnextLabel: true,
          textRects: null
        };
        if (offsetCorrection) {
          correctedLabels = this.dataLabelsCorrection(x, y, text, i, j, alwaysDrawDataLabel, parseInt(dataLabelsConfig.style.fontSize, 10));
        }

        // when zoomed, we don't need to correct labels offsets,
        // but if normally, labels get cropped, correct them
        if (!w.globals.zoomed) {
          x = correctedLabels.x;
          y = correctedLabels.y;
        }
        if (correctedLabels.textRects) {
          // fixes #2264
          if (x < -20 - correctedLabels.textRects.width || x > w.globals.gridWidth + correctedLabels.textRects.width + 30) {
            // datalabels fall outside drawing area, so draw a blank label
            text = '';
          }
        }
        var dataLabelColor = w.globals.dataLabels.style.colors[i];
        if ((w.config.chart.type === 'bar' || w.config.chart.type === 'rangeBar') && w.config.plotOptions.bar.distributed || w.config.dataLabels.distributed) {
          dataLabelColor = w.globals.dataLabels.style.colors[j];
        }
        if (typeof dataLabelColor === 'function') {
          dataLabelColor = dataLabelColor({
            series: w.globals.series,
            seriesIndex: i,
            dataPointIndex: j,
            w: w
          });
        }
        if (color) {
          dataLabelColor = color;
        }
        var offX = dataLabelsConfig.offsetX;
        var offY = dataLabelsConfig.offsetY;
        if (w.config.chart.type === 'bar' || w.config.chart.type === 'rangeBar') {
          // for certain chart types, we handle offsets while calculating datalabels pos
          // why? because bars/column may have negative values and based on that
          // offsets becomes reversed
          offX = 0;
          offY = 0;
        }
        if (w.globals.isSlopeChart) {
          if (j !== 0) {
            offX = dataLabelsConfig.offsetX * -2 + 5;
          }
          if (j !== 0 && j !== w.config.series[i].data.length - 1) {
            offX = 0;
          }
        }
        if (correctedLabels.drawnextLabel) {
          dataLabelText = graphics.drawText({
            width: 100,
            height: parseInt(dataLabelsConfig.style.fontSize, 10),
            x: x + offX,
            y: y + offY,
            foreColor: dataLabelColor,
            textAnchor: textAnchor || dataLabelsConfig.textAnchor,
            text: text,
            fontSize: fontSize || dataLabelsConfig.style.fontSize,
            fontFamily: dataLabelsConfig.style.fontFamily,
            fontWeight: dataLabelsConfig.style.fontWeight || 'normal'
          });
          dataLabelText.attr({
            class: className || 'apexcharts-datalabel',
            cx: x,
            cy: y
          });
          if (dataLabelsConfig.dropShadow.enabled) {
            var textShadow = dataLabelsConfig.dropShadow;
            var filters = new Filters(this.ctx);
            filters.dropShadow(dataLabelText, textShadow);
          }
          parent.add(dataLabelText);
          if (typeof w.globals.lastDrawnDataLabelsIndexes[i] === 'undefined') {
            w.globals.lastDrawnDataLabelsIndexes[i] = [];
          }
          w.globals.lastDrawnDataLabelsIndexes[i].push(j);
        }
        return dataLabelText;
      }
    }, {
      key: "addBackgroundToDataLabel",
      value: function addBackgroundToDataLabel(el, coords) {
        var w = this.w;
        var bCnf = w.config.dataLabels.background;
        var paddingH = bCnf.padding;
        var paddingV = bCnf.padding / 2;
        var width = coords.width;
        var height = coords.height;
        var graphics = new Graphics(this.ctx);
        var elRect = graphics.drawRect(coords.x - paddingH, coords.y - paddingV / 2, width + paddingH * 2, height + paddingV, bCnf.borderRadius, w.config.chart.background === 'transparent' || !w.config.chart.background ? '#fff' : w.config.chart.background, bCnf.opacity, bCnf.borderWidth, bCnf.borderColor);
        if (bCnf.dropShadow.enabled) {
          var filters = new Filters(this.ctx);
          filters.dropShadow(elRect, bCnf.dropShadow);
        }
        return elRect;
      }
    }, {
      key: "dataLabelsBackground",
      value: function dataLabelsBackground() {
        var w = this.w;
        if (w.config.chart.type === 'bubble') return;
        var elDataLabels = w.globals.dom.baseEl.querySelectorAll('.apexcharts-datalabels text');
        for (var i = 0; i < elDataLabels.length; i++) {
          var el = elDataLabels[i];
          var coords = el.getBBox();
          var elRect = null;
          if (coords.width && coords.height) {
            elRect = this.addBackgroundToDataLabel(el, coords);
          }
          if (elRect) {
            el.parentNode.insertBefore(elRect.node, el);
            var background = el.getAttribute('fill');
            var shouldAnim = w.config.chart.animations.enabled && !w.globals.resized && !w.globals.dataChanged;
            if (shouldAnim) {
              elRect.animate().attr({
                fill: background
              });
            } else {
              elRect.attr({
                fill: background
              });
            }
            el.setAttribute('fill', w.config.dataLabels.background.foreColor);
          }
        }
      }
    }, {
      key: "bringForward",
      value: function bringForward() {
        var w = this.w;
        var elDataLabelsNodes = w.globals.dom.baseEl.querySelectorAll('.apexcharts-datalabels');
        var elSeries = w.globals.dom.baseEl.querySelector('.apexcharts-plot-series:last-child');
        for (var i = 0; i < elDataLabelsNodes.length; i++) {
          if (elSeries) {
            elSeries.insertBefore(elDataLabelsNodes[i], elSeries.nextSibling);
          }
        }
      }
    }]);
    return DataLabels;
  }();

  /**
   * ApexCharts Series Class for interaction with the Series of the chart.
   *
   * @module Series
   **/
  var Series = /*#__PURE__*/function () {
    function Series(ctx) {
      _classCallCheck(this, Series);
      this.ctx = ctx;
      this.w = ctx.w;
      this.legendInactiveClass = 'legend-mouseover-inactive';
    }
    _createClass(Series, [{
      key: "getAllSeriesEls",
      value: function getAllSeriesEls() {
        return this.w.globals.dom.baseEl.getElementsByClassName("apexcharts-series");
      }
    }, {
      key: "getSeriesByName",
      value: function getSeriesByName(seriesName) {
        return this.w.globals.dom.baseEl.querySelector(".apexcharts-inner .apexcharts-series[seriesName='".concat(Utils$1.escapeString(seriesName), "']"));
      }
    }, {
      key: "isSeriesHidden",
      value: function isSeriesHidden(seriesName) {
        var targetElement = this.getSeriesByName(seriesName);
        var realIndex = parseInt(targetElement.getAttribute('data:realIndex'), 10);
        var isHidden = targetElement.classList.contains('apexcharts-series-collapsed');
        return {
          isHidden: isHidden,
          realIndex: realIndex
        };
      }
    }, {
      key: "addCollapsedClassToSeries",
      value: function addCollapsedClassToSeries(elSeries, index) {
        var w = this.w;
        function iterateOnAllCollapsedSeries(series) {
          for (var cs = 0; cs < series.length; cs++) {
            if (series[cs].index === index) {
              elSeries.node.classList.add('apexcharts-series-collapsed');
            }
          }
        }
        iterateOnAllCollapsedSeries(w.globals.collapsedSeries);
        iterateOnAllCollapsedSeries(w.globals.ancillaryCollapsedSeries);
      }
    }, {
      key: "toggleSeries",
      value: function toggleSeries(seriesName) {
        var isSeriesHidden = this.isSeriesHidden(seriesName);
        this.ctx.legend.legendHelpers.toggleDataSeries(isSeriesHidden.realIndex, isSeriesHidden.isHidden);
        return isSeriesHidden.isHidden;
      }
    }, {
      key: "showSeries",
      value: function showSeries(seriesName) {
        var isSeriesHidden = this.isSeriesHidden(seriesName);
        if (isSeriesHidden.isHidden) {
          this.ctx.legend.legendHelpers.toggleDataSeries(isSeriesHidden.realIndex, true);
        }
      }
    }, {
      key: "hideSeries",
      value: function hideSeries(seriesName) {
        var isSeriesHidden = this.isSeriesHidden(seriesName);
        if (!isSeriesHidden.isHidden) {
          this.ctx.legend.legendHelpers.toggleDataSeries(isSeriesHidden.realIndex, false);
        }
      }
    }, {
      key: "resetSeries",
      value: function resetSeries() {
        var shouldUpdateChart = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
        var shouldResetZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var shouldResetCollapsed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
        var w = this.w;
        var series = Utils$1.clone(w.globals.initialSeries);
        w.globals.previousPaths = [];
        if (shouldResetCollapsed) {
          w.globals.collapsedSeries = [];
          w.globals.ancillaryCollapsedSeries = [];
          w.globals.collapsedSeriesIndices = [];
          w.globals.ancillaryCollapsedSeriesIndices = [];
        } else {
          series = this.emptyCollapsedSeries(series);
        }
        w.config.series = series;
        if (shouldUpdateChart) {
          if (shouldResetZoom) {
            w.globals.zoomed = false;
            this.ctx.updateHelpers.revertDefaultAxisMinMax();
          }
          this.ctx.updateHelpers._updateSeries(series, w.config.chart.animations.dynamicAnimation.enabled);
        }
      }
    }, {
      key: "emptyCollapsedSeries",
      value: function emptyCollapsedSeries(series) {
        var w = this.w;
        for (var i = 0; i < series.length; i++) {
          if (w.globals.collapsedSeriesIndices.indexOf(i) > -1) {
            series[i].data = [];
          }
        }
        return series;
      }
    }, {
      key: "highlightSeries",
      value: function highlightSeries(seriesName) {
        var w = this.w;
        var targetElement = this.getSeriesByName(seriesName);
        var realIndex = parseInt(targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute('data:realIndex'), 10);
        var allSeriesEls = w.globals.dom.baseEl.querySelectorAll(".apexcharts-series, .apexcharts-datalabels, .apexcharts-yaxis");
        var seriesEl = null;
        var dataLabelEl = null;
        var yaxisEl = null;
        if (w.globals.axisCharts || w.config.chart.type === 'radialBar') {
          if (w.globals.axisCharts) {
            seriesEl = w.globals.dom.baseEl.querySelector(".apexcharts-series[data\\:realIndex='".concat(realIndex, "']"));
            dataLabelEl = w.globals.dom.baseEl.querySelector(".apexcharts-datalabels[data\\:realIndex='".concat(realIndex, "']"));
            var yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex];
            yaxisEl = w.globals.dom.baseEl.querySelector(".apexcharts-yaxis[rel='".concat(yaxisIndex, "']"));
          } else {
            seriesEl = w.globals.dom.baseEl.querySelector(".apexcharts-series[rel='".concat(realIndex + 1, "']"));
          }
        } else {
          seriesEl = w.globals.dom.baseEl.querySelector(".apexcharts-series[rel='".concat(realIndex + 1, "'] path"));
        }
        for (var se = 0; se < allSeriesEls.length; se++) {
          allSeriesEls[se].classList.add(this.legendInactiveClass);
        }
        if (seriesEl) {
          if (!w.globals.axisCharts) {
            seriesEl.parentNode.classList.remove(this.legendInactiveClass);
          }
          seriesEl.classList.remove(this.legendInactiveClass);
          if (dataLabelEl !== null) {
            dataLabelEl.classList.remove(this.legendInactiveClass);
          }
          if (yaxisEl !== null) {
            yaxisEl.classList.remove(this.legendInactiveClass);
          }
        } else {
          for (var _se = 0; _se < allSeriesEls.length; _se++) {
            allSeriesEls[_se].classList.remove(this.legendInactiveClass);
          }
        }
      }
    }, {
      key: "toggleSeriesOnHover",
      value: function toggleSeriesOnHover(e, targetElement) {
        var w = this.w;
        if (!targetElement) targetElement = e.target;
        var allSeriesEls = w.globals.dom.baseEl.querySelectorAll(".apexcharts-series, .apexcharts-datalabels, .apexcharts-yaxis");
        if (e.type === 'mousemove') {
          var realIndex = parseInt(targetElement.getAttribute('rel'), 10) - 1;
          this.highlightSeries(w.globals.seriesNames[realIndex]);
        } else if (e.type === 'mouseout') {
          for (var se = 0; se < allSeriesEls.length; se++) {
            allSeriesEls[se].classList.remove(this.legendInactiveClass);
          }
        }
      }
    }, {
      key: "highlightRangeInSeries",
      value: function highlightRangeInSeries(e, targetElement) {
        var _this = this;
        var w = this.w;
        var allHeatMapElements = w.globals.dom.baseEl.getElementsByClassName('apexcharts-heatmap-rect');
        var activeInactive = function activeInactive(action) {
          for (var i = 0; i < allHeatMapElements.length; i++) {
            allHeatMapElements[i].classList[action](_this.legendInactiveClass);
          }
        };
        var removeInactiveClassFromHoveredRange = function removeInactiveClassFromHoveredRange(range, rangeMax) {
          for (var i = 0; i < allHeatMapElements.length; i++) {
            var val = Number(allHeatMapElements[i].getAttribute('val'));
            if (val >= range.from && (val < range.to || range.to === rangeMax && val === rangeMax)) {
              allHeatMapElements[i].classList.remove(_this.legendInactiveClass);
            }
          }
        };
        if (e.type === 'mousemove') {
          var seriesCnt = parseInt(targetElement.getAttribute('rel'), 10) - 1;
          activeInactive('add');
          var ranges = w.config.plotOptions.heatmap.colorScale.ranges;
          var range = ranges[seriesCnt];
          var rangeMax = ranges.reduce(function (acc, cur) {
            return Math.max(acc, cur.to);
          }, 0);
          removeInactiveClassFromHoveredRange(range, rangeMax);
        } else if (e.type === 'mouseout') {
          activeInactive('remove');
        }
      }
    }, {
      key: "getActiveConfigSeriesIndex",
      value: function getActiveConfigSeriesIndex() {
        var order = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'asc';
        var chartTypes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
        var w = this.w;
        var activeIndex = 0;
        if (w.config.series.length > 1) {
          // active series flag is required to know if user has not deactivated via legend click
          var activeSeriesIndex = w.config.series.map(function (s, index) {
            var checkChartType = function checkChartType() {
              if (w.globals.comboCharts) {
                return chartTypes.length === 0 || chartTypes.length && chartTypes.indexOf(w.config.series[index].type) > -1;
              }
              return true;
            };
            var hasData = s.data && s.data.length > 0 && w.globals.collapsedSeriesIndices.indexOf(index) === -1;
            return hasData && checkChartType() ? index : -1;
          });
          for (var a = order === 'asc' ? 0 : activeSeriesIndex.length - 1; order === 'asc' ? a < activeSeriesIndex.length : a >= 0; order === 'asc' ? a++ : a--) {
            if (activeSeriesIndex[a] !== -1) {
              activeIndex = activeSeriesIndex[a];
              break;
            }
          }
        }
        return activeIndex;
      }
    }, {
      key: "getBarSeriesIndices",
      value: function getBarSeriesIndices() {
        var w = this.w;
        if (w.globals.comboCharts) {
          return this.w.config.series.map(function (s, i) {
            return s.type === 'bar' || s.type === 'column' ? i : -1;
          }).filter(function (i) {
            return i !== -1;
          });
        }
        return this.w.config.series.map(function (s, i) {
          return i;
        });
      }
    }, {
      key: "getPreviousPaths",
      value: function getPreviousPaths() {
        var w = this.w;
        w.globals.previousPaths = [];
        function pushPaths(seriesEls, i, type) {
          var paths = seriesEls[i].childNodes;
          var dArr = {
            type: type,
            paths: [],
            realIndex: seriesEls[i].getAttribute('data:realIndex')
          };
          for (var j = 0; j < paths.length; j++) {
            if (paths[j].hasAttribute('pathTo')) {
              var d = paths[j].getAttribute('pathTo');
              dArr.paths.push({
                d: d
              });
            }
          }
          w.globals.previousPaths.push(dArr);
        }
        var getPaths = function getPaths(chartType) {
          return w.globals.dom.baseEl.querySelectorAll(".apexcharts-".concat(chartType, "-series .apexcharts-series"));
        };
        var chartTypes = ['line', 'area', 'bar', 'rangebar', 'rangeArea', 'candlestick', 'radar'];
        chartTypes.forEach(function (type) {
          var paths = getPaths(type);
          for (var p = 0; p < paths.length; p++) {
            pushPaths(paths, p, type);
          }
        });
        this.handlePrevBubbleScatterPaths('bubble');
        this.handlePrevBubbleScatterPaths('scatter');
        var heatTreeSeries = w.globals.dom.baseEl.querySelectorAll(".apexcharts-".concat(w.config.chart.type, " .apexcharts-series"));
        if (heatTreeSeries.length > 0) {
          var _loop = function _loop(h) {
            var seriesEls = w.globals.dom.baseEl.querySelectorAll(".apexcharts-".concat(w.config.chart.type, " .apexcharts-series[data\\:realIndex='").concat(h, "'] rect"));
            var dArr = [];
            var _loop2 = function _loop2(i) {
              var getAttr = function getAttr(x) {
                return seriesEls[i].getAttribute(x);
              };
              var rect = {
                x: parseFloat(getAttr('x')),
                y: parseFloat(getAttr('y')),
                width: parseFloat(getAttr('width')),
                height: parseFloat(getAttr('height'))
              };
              dArr.push({
                rect: rect,
                color: seriesEls[i].getAttribute('color')
              });
            };
            for (var i = 0; i < seriesEls.length; i++) {
              _loop2(i);
            }
            w.globals.previousPaths.push(dArr);
          };
          for (var h = 0; h < heatTreeSeries.length; h++) {
            _loop(h);
          }
        }
        if (!w.globals.axisCharts) {
          // for non-axis charts (i.e., circular charts, pathFrom is not usable. We need whole series)
          w.globals.previousPaths = w.globals.series;
        }
      }
    }, {
      key: "handlePrevBubbleScatterPaths",
      value: function handlePrevBubbleScatterPaths(type) {
        var w = this.w;
        var paths = w.globals.dom.baseEl.querySelectorAll(".apexcharts-".concat(type, "-series .apexcharts-series"));
        if (paths.length > 0) {
          for (var s = 0; s < paths.length; s++) {
            var seriesEls = w.globals.dom.baseEl.querySelectorAll(".apexcharts-".concat(type, "-series .apexcharts-series[data\\:realIndex='").concat(s, "'] circle"));
            var dArr = [];
            for (var i = 0; i < seriesEls.length; i++) {
              dArr.push({
                x: seriesEls[i].getAttribute('cx'),
                y: seriesEls[i].getAttribute('cy'),
                r: seriesEls[i].getAttribute('r')
              });
            }
            w.globals.previousPaths.push(dArr);
          }
        }
      }
    }, {
      key: "clearPreviousPaths",
      value: function clearPreviousPaths() {
        var w = this.w;
        w.globals.previousPaths = [];
        w.globals.allSeriesCollapsed = false;
      }
    }, {
      key: "handleNoData",
      value: function handleNoData() {
        var w = this.w;
        var me = this;
        var noDataOpts = w.config.noData;
        var graphics = new Graphics(me.ctx);
        var x = w.globals.svgWidth / 2;
        var y = w.globals.svgHeight / 2;
        var textAnchor = 'middle';
        w.globals.noData = true;
        w.globals.animationEnded = true;
        if (noDataOpts.align === 'left') {
          x = 10;
          textAnchor = 'start';
        } else if (noDataOpts.align === 'right') {
          x = w.globals.svgWidth - 10;
          textAnchor = 'end';
        }
        if (noDataOpts.verticalAlign === 'top') {
          y = 50;
        } else if (noDataOpts.verticalAlign === 'bottom') {
          y = w.globals.svgHeight - 50;
        }
        x = x + noDataOpts.offsetX;
        y = y + parseInt(noDataOpts.style.fontSize, 10) + 2 + noDataOpts.offsetY;
        if (noDataOpts.text !== undefined && noDataOpts.text !== '') {
          var titleText = graphics.drawText({
            x: x,
            y: y,
            text: noDataOpts.text,
            textAnchor: textAnchor,
            fontSize: noDataOpts.style.fontSize,
            fontFamily: noDataOpts.style.fontFamily,
            foreColor: noDataOpts.style.color,
            opacity: 1,
            class: 'apexcharts-text-nodata'
          });
          w.globals.dom.Paper.add(titleText);
        }
      }

      // When user clicks on legends, the collapsed series is filled with [0,0,0,...,0]
      // This is because we don't want to alter the series' length as it is used at many places
    }, {
      key: "setNullSeriesToZeroValues",
      value: function setNullSeriesToZeroValues(series) {
        var w = this.w;
        for (var sl = 0; sl < series.length; sl++) {
          if (series[sl].length === 0) {
            for (var j = 0; j < series[w.globals.maxValsInArrayIndex].length; j++) {
              series[sl].push(0);
            }
          }
        }
        return series;
      }
    }, {
      key: "hasAllSeriesEqualX",
      value: function hasAllSeriesEqualX() {
        var equalLen = true;
        var w = this.w;
        var filteredSerX = this.filteredSeriesX();
        for (var i = 0; i < filteredSerX.length - 1; i++) {
          if (filteredSerX[i][0] !== filteredSerX[i + 1][0]) {
            equalLen = false;
            break;
          }
        }
        w.globals.allSeriesHasEqualX = equalLen;
        return equalLen;
      }
    }, {
      key: "filteredSeriesX",
      value: function filteredSeriesX() {
        var w = this.w;
        var filteredSeriesX = w.globals.seriesX.map(function (ser) {
          return ser.length > 0 ? ser : [];
        });
        return filteredSeriesX;
      }
    }]);
    return Series;
  }();

  var Data = /*#__PURE__*/function () {
    function Data(ctx) {
      _classCallCheck(this, Data);
      this.ctx = ctx;
      this.w = ctx.w;
      this.twoDSeries = [];
      this.threeDSeries = [];
      this.twoDSeriesX = [];
      this.seriesGoals = [];
      this.coreUtils = new CoreUtils(this.ctx);
    }
    _createClass(Data, [{
      key: "isMultiFormat",
      value: function isMultiFormat() {
        return this.isFormatXY() || this.isFormat2DArray();
      }

      // given format is [{x, y}, {x, y}]
    }, {
      key: "isFormatXY",
      value: function isFormatXY() {
        var series = this.w.config.series.slice();
        var sr = new Series(this.ctx);
        this.activeSeriesIndex = sr.getActiveConfigSeriesIndex();
        if (typeof series[this.activeSeriesIndex].data !== 'undefined' && series[this.activeSeriesIndex].data.length > 0 && series[this.activeSeriesIndex].data[0] !== null && typeof series[this.activeSeriesIndex].data[0].x !== 'undefined' && series[this.activeSeriesIndex].data[0] !== null) {
          return true;
        }
      }

      // given format is [[x, y], [x, y]]
    }, {
      key: "isFormat2DArray",
      value: function isFormat2DArray() {
        var series = this.w.config.series.slice();
        var sr = new Series(this.ctx);
        this.activeSeriesIndex = sr.getActiveConfigSeriesIndex();
        if (typeof series[this.activeSeriesIndex].data !== 'undefined' && series[this.activeSeriesIndex].data.length > 0 && typeof series[this.activeSeriesIndex].data[0] !== 'undefined' && series[this.activeSeriesIndex].data[0] !== null && series[this.activeSeriesIndex].data[0].constructor === Array) {
          return true;
        }
      }
    }, {
      key: "handleFormat2DArray",
      value: function handleFormat2DArray(ser, i) {
        var cnf = this.w.config;
        var gl = this.w.globals;
        var isBoxPlot = cnf.chart.type === 'boxPlot' || cnf.series[i].type === 'boxPlot';
        for (var j = 0; j < ser[i].data.length; j++) {
          if (typeof ser[i].data[j][1] !== 'undefined') {
            if (Array.isArray(ser[i].data[j][1]) && ser[i].data[j][1].length === 4 && !isBoxPlot) {
              // candlestick nested ohlc format
              this.twoDSeries.push(Utils$1.parseNumber(ser[i].data[j][1][3]));
            } else if (ser[i].data[j].length >= 5) {
              // candlestick non-nested ohlc format
              this.twoDSeries.push(Utils$1.parseNumber(ser[i].data[j][4]));
            } else {
              this.twoDSeries.push(Utils$1.parseNumber(ser[i].data[j][1]));
            }
            gl.dataFormatXNumeric = true;
          }
          if (cnf.xaxis.type === 'datetime') {
            // if timestamps are provided and xaxis type is datetime,

            var ts = new Date(ser[i].data[j][0]);
            ts = new Date(ts).getTime();
            this.twoDSeriesX.push(ts);
          } else {
            this.twoDSeriesX.push(ser[i].data[j][0]);
          }
        }
        for (var _j = 0; _j < ser[i].data.length; _j++) {
          if (typeof ser[i].data[_j][2] !== 'undefined') {
            this.threeDSeries.push(ser[i].data[_j][2]);
            gl.isDataXYZ = true;
          }
        }
      }
    }, {
      key: "handleFormatXY",
      value: function handleFormatXY(ser, i) {
        var cnf = this.w.config;
        var gl = this.w.globals;
        var dt = new DateTime(this.ctx);
        var activeI = i;
        if (gl.collapsedSeriesIndices.indexOf(i) > -1) {
          // fix #368
          activeI = this.activeSeriesIndex;
        }

        // get series
        for (var j = 0; j < ser[i].data.length; j++) {
          if (typeof ser[i].data[j].y !== 'undefined') {
            if (Array.isArray(ser[i].data[j].y)) {
              this.twoDSeries.push(Utils$1.parseNumber(ser[i].data[j].y[ser[i].data[j].y.length - 1]));
            } else {
              this.twoDSeries.push(Utils$1.parseNumber(ser[i].data[j].y));
            }
          }
          if (typeof ser[i].data[j].goals !== 'undefined' && Array.isArray(ser[i].data[j].goals)) {
            if (typeof this.seriesGoals[i] === 'undefined') {
              this.seriesGoals[i] = [];
            }
            this.seriesGoals[i].push(ser[i].data[j].goals);
          } else {
            if (typeof this.seriesGoals[i] === 'undefined') {
              this.seriesGoals[i] = [];
            }
            this.seriesGoals[i].push(null);
          }
        }

        // get seriesX
        for (var _j2 = 0; _j2 < ser[activeI].data.length; _j2++) {
          var isXString = typeof ser[activeI].data[_j2].x === 'string';
          var isXArr = Array.isArray(ser[activeI].data[_j2].x);
          var isXDate = !isXArr && !!dt.isValidDate(ser[activeI].data[_j2].x);
          if (isXString || isXDate) {
            // user supplied '01/01/2017' or a date string (a JS date object is not supported)
            if (isXString || cnf.xaxis.convertedCatToNumeric) {
              var isRangeColumn = gl.isBarHorizontal && gl.isRangeData;
              if (cnf.xaxis.type === 'datetime' && !isRangeColumn) {
                this.twoDSeriesX.push(dt.parseDate(ser[activeI].data[_j2].x));
              } else {
                // a category and not a numeric x value
                this.fallbackToCategory = true;
                this.twoDSeriesX.push(ser[activeI].data[_j2].x);
                if (!isNaN(ser[activeI].data[_j2].x) && this.w.config.xaxis.type !== 'category' && typeof ser[activeI].data[_j2].x !== 'string') {
                  gl.isXNumeric = true;
                }
              }
            } else {
              if (cnf.xaxis.type === 'datetime') {
                this.twoDSeriesX.push(dt.parseDate(ser[activeI].data[_j2].x.toString()));
              } else {
                gl.dataFormatXNumeric = true;
                gl.isXNumeric = true;
                this.twoDSeriesX.push(parseFloat(ser[activeI].data[_j2].x));
              }
            }
          } else if (isXArr) {
            // a multiline label described in array format
            this.fallbackToCategory = true;
            this.twoDSeriesX.push(ser[activeI].data[_j2].x);
          } else {
            // a numeric value in x property
            gl.isXNumeric = true;
            gl.dataFormatXNumeric = true;
            this.twoDSeriesX.push(ser[activeI].data[_j2].x);
          }
        }
        if (ser[i].data[0] && typeof ser[i].data[0].z !== 'undefined') {
          for (var t = 0; t < ser[i].data.length; t++) {
            this.threeDSeries.push(ser[i].data[t].z);
          }
          gl.isDataXYZ = true;
        }
      }
    }, {
      key: "handleRangeData",
      value: function handleRangeData(ser, i) {
        var gl = this.w.globals;
        var range = {};
        if (this.isFormat2DArray()) {
          range = this.handleRangeDataFormat('array', ser, i);
        } else if (this.isFormatXY()) {
          range = this.handleRangeDataFormat('xy', ser, i);
        }

        // Fix: RangeArea Chart: hide all series results in a crash #3984
        gl.seriesRangeStart.push(range.start === undefined ? [] : range.start);
        gl.seriesRangeEnd.push(range.end === undefined ? [] : range.end);
        gl.seriesRange.push(range.rangeUniques);

        // check for overlaps to avoid clashes in a timeline chart
        gl.seriesRange.forEach(function (sr, si) {
          if (sr) {
            sr.forEach(function (sarr, sarri) {
              sarr.y.forEach(function (arr, arri) {
                for (var sri = 0; sri < sarr.y.length; sri++) {
                  if (arri !== sri) {
                    var range1y1 = arr.y1;
                    var range1y2 = arr.y2;
                    var range2y1 = sarr.y[sri].y1;
                    var range2y2 = sarr.y[sri].y2;
                    if (range1y1 <= range2y2 && range2y1 <= range1y2) {
                      if (sarr.overlaps.indexOf(arr.rangeName) < 0) {
                        sarr.overlaps.push(arr.rangeName);
                      }
                      if (sarr.overlaps.indexOf(sarr.y[sri].rangeName) < 0) {
                        sarr.overlaps.push(sarr.y[sri].rangeName);
                      }
                    }
                  }
                }
              });
            });
          }
        });
        return range;
      }
    }, {
      key: "handleCandleStickBoxData",
      value: function handleCandleStickBoxData(ser, i) {
        var gl = this.w.globals;
        var ohlc = {};
        if (this.isFormat2DArray()) {
          ohlc = this.handleCandleStickBoxDataFormat('array', ser, i);
        } else if (this.isFormatXY()) {
          ohlc = this.handleCandleStickBoxDataFormat('xy', ser, i);
        }
        gl.seriesCandleO[i] = ohlc.o;
        gl.seriesCandleH[i] = ohlc.h;
        gl.seriesCandleM[i] = ohlc.m;
        gl.seriesCandleL[i] = ohlc.l;
        gl.seriesCandleC[i] = ohlc.c;
        return ohlc;
      }
    }, {
      key: "handleRangeDataFormat",
      value: function handleRangeDataFormat(format, ser, i) {
        var rangeStart = [];
        var rangeEnd = [];
        var uniqueKeys = ser[i].data.filter(function (thing, index, self) {
          return index === self.findIndex(function (t) {
            return t.x === thing.x;
          });
        }).map(function (r, index) {
          return {
            x: r.x,
            overlaps: [],
            y: []
          };
        });
        if (format === 'array') {
          for (var j = 0; j < ser[i].data.length; j++) {
            if (Array.isArray(ser[i].data[j])) {
              rangeStart.push(ser[i].data[j][1][0]);
              rangeEnd.push(ser[i].data[j][1][1]);
            } else {
              rangeStart.push(ser[i].data[j]);
              rangeEnd.push(ser[i].data[j]);
            }
          }
        } else if (format === 'xy') {
          var _loop = function _loop(_j3) {
            var isDataPoint2D = Array.isArray(ser[i].data[_j3].y);
            var id = Utils$1.randomId();
            var x = ser[i].data[_j3].x;
            var y = {
              y1: isDataPoint2D ? ser[i].data[_j3].y[0] : ser[i].data[_j3].y,
              y2: isDataPoint2D ? ser[i].data[_j3].y[1] : ser[i].data[_j3].y,
              rangeName: id
            };

            // CAUTION: mutating config object by adding a new property
            // TODO: As this is specifically for timeline rangebar charts, update the docs mentioning the series only supports xy format
            ser[i].data[_j3].rangeName = id;
            var uI = uniqueKeys.findIndex(function (t) {
              return t.x === x;
            });
            uniqueKeys[uI].y.push(y);
            rangeStart.push(y.y1);
            rangeEnd.push(y.y2);
          };
          for (var _j3 = 0; _j3 < ser[i].data.length; _j3++) {
            _loop(_j3);
          }
        }
        return {
          start: rangeStart,
          end: rangeEnd,
          rangeUniques: uniqueKeys
        };
      }
    }, {
      key: "handleCandleStickBoxDataFormat",
      value: function handleCandleStickBoxDataFormat(format, ser, i) {
        var w = this.w;
        var isBoxPlot = w.config.chart.type === 'boxPlot' || w.config.series[i].type === 'boxPlot';
        var serO = [];
        var serH = [];
        var serM = [];
        var serL = [];
        var serC = [];
        if (format === 'array') {
          if (isBoxPlot && ser[i].data[0].length === 6 || !isBoxPlot && ser[i].data[0].length === 5) {
            for (var j = 0; j < ser[i].data.length; j++) {
              serO.push(ser[i].data[j][1]);
              serH.push(ser[i].data[j][2]);
              if (isBoxPlot) {
                serM.push(ser[i].data[j][3]);
                serL.push(ser[i].data[j][4]);
                serC.push(ser[i].data[j][5]);
              } else {
                serL.push(ser[i].data[j][3]);
                serC.push(ser[i].data[j][4]);
              }
            }
          } else {
            for (var _j4 = 0; _j4 < ser[i].data.length; _j4++) {
              if (Array.isArray(ser[i].data[_j4][1])) {
                serO.push(ser[i].data[_j4][1][0]);
                serH.push(ser[i].data[_j4][1][1]);
                if (isBoxPlot) {
                  serM.push(ser[i].data[_j4][1][2]);
                  serL.push(ser[i].data[_j4][1][3]);
                  serC.push(ser[i].data[_j4][1][4]);
                } else {
                  serL.push(ser[i].data[_j4][1][2]);
                  serC.push(ser[i].data[_j4][1][3]);
                }
              }
            }
          }
        } else if (format === 'xy') {
          for (var _j5 = 0; _j5 < ser[i].data.length; _j5++) {
            if (Array.isArray(ser[i].data[_j5].y)) {
              serO.push(ser[i].data[_j5].y[0]);
              serH.push(ser[i].data[_j5].y[1]);
              if (isBoxPlot) {
                serM.push(ser[i].data[_j5].y[2]);
                serL.push(ser[i].data[_j5].y[3]);
                serC.push(ser[i].data[_j5].y[4]);
              } else {
                serL.push(ser[i].data[_j5].y[2]);
                serC.push(ser[i].data[_j5].y[3]);
              }
            }
          }
        }
        return {
          o: serO,
          h: serH,
          m: serM,
          l: serL,
          c: serC
        };
      }
    }, {
      key: "parseDataAxisCharts",
      value: function parseDataAxisCharts(ser) {
        var _this = this;
        var ctx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.ctx;
        var cnf = this.w.config;
        var gl = this.w.globals;
        var dt = new DateTime(ctx);
        var xlabels = cnf.labels.length > 0 ? cnf.labels.slice() : cnf.xaxis.categories.slice();
        gl.isRangeBar = cnf.chart.type === 'rangeBar' && gl.isBarHorizontal;
        gl.hasXaxisGroups = cnf.xaxis.type === 'category' && cnf.xaxis.group.groups.length > 0;
        if (gl.hasXaxisGroups) {
          gl.groups = cnf.xaxis.group.groups;
        }
        ser.forEach(function (s, i) {
          if (s.name !== undefined) {
            gl.seriesNames.push(s.name);
          } else {
            gl.seriesNames.push('series-' + parseInt(i + 1, 10));
          }
        });
        this.coreUtils.setSeriesYAxisMappings();
        // At this point, every series that didn't have a user defined group name
        // has been given a name according to the yaxis the series is referenced by.
        // This fits the existing behaviour where all series associated with an axis
        // are defacto presented as a single group. It is now formalised.
        var buckets = [];
        var groups = _toConsumableArray(new Set(cnf.series.map(function (s) {
          return s.group;
        })));
        cnf.series.forEach(function (s, i) {
          var index = groups.indexOf(s.group);
          if (!buckets[index]) buckets[index] = [];
          buckets[index].push(gl.seriesNames[i]);
        });
        gl.seriesGroups = buckets;
        var handleDates = function handleDates() {
          for (var j = 0; j < xlabels.length; j++) {
            if (typeof xlabels[j] === 'string') {
              // user provided date strings
              var isDate = dt.isValidDate(xlabels[j]);
              if (isDate) {
                _this.twoDSeriesX.push(dt.parseDate(xlabels[j]));
              } else {
                throw new Error('You have provided invalid Date format. Please provide a valid JavaScript Date');
              }
            } else {
              // user provided timestamps
              _this.twoDSeriesX.push(xlabels[j]);
            }
          }
        };
        for (var i = 0; i < ser.length; i++) {
          this.twoDSeries = [];
          this.twoDSeriesX = [];
          this.threeDSeries = [];
          if (typeof ser[i].data === 'undefined') {
            console.error("It is a possibility that you may have not included 'data' property in series.");
            return;
          }
          if (cnf.chart.type === 'rangeBar' || cnf.chart.type === 'rangeArea' || ser[i].type === 'rangeBar' || ser[i].type === 'rangeArea') {
            gl.isRangeData = true;
            if (cnf.chart.type === 'rangeBar' || cnf.chart.type === 'rangeArea') {
              this.handleRangeData(ser, i);
            }
          }
          if (this.isMultiFormat()) {
            if (this.isFormat2DArray()) {
              this.handleFormat2DArray(ser, i);
            } else if (this.isFormatXY()) {
              this.handleFormatXY(ser, i);
            }
            if (cnf.chart.type === 'candlestick' || ser[i].type === 'candlestick' || cnf.chart.type === 'boxPlot' || ser[i].type === 'boxPlot') {
              this.handleCandleStickBoxData(ser, i);
            }
            gl.series.push(this.twoDSeries);
            gl.labels.push(this.twoDSeriesX);
            gl.seriesX.push(this.twoDSeriesX);
            gl.seriesGoals = this.seriesGoals;
            if (i === this.activeSeriesIndex && !this.fallbackToCategory) {
              gl.isXNumeric = true;
            }
          } else {
            if (cnf.xaxis.type === 'datetime') {
              // user didn't supplied [{x,y}] or [[x,y]], but single array in data.
              // Also labels/categories were supplied differently
              gl.isXNumeric = true;
              handleDates();
              gl.seriesX.push(this.twoDSeriesX);
            } else if (cnf.xaxis.type === 'numeric') {
              gl.isXNumeric = true;
              if (xlabels.length > 0) {
                this.twoDSeriesX = xlabels;
                gl.seriesX.push(this.twoDSeriesX);
              }
            }
            gl.labels.push(this.twoDSeriesX);
            var singleArray = ser[i].data.map(function (d) {
              return Utils$1.parseNumber(d);
            });
            gl.series.push(singleArray);
          }
          gl.seriesZ.push(this.threeDSeries);

          // overrided default color if user inputs color with series data
          if (ser[i].color !== undefined) {
            gl.seriesColors.push(ser[i].color);
          } else {
            gl.seriesColors.push(undefined);
          }
        }
        return this.w;
      }
    }, {
      key: "parseDataNonAxisCharts",
      value: function parseDataNonAxisCharts(ser) {
        var gl = this.w.globals;
        var cnf = this.w.config;
        gl.series = ser.slice();
        gl.seriesNames = cnf.labels.slice();
        for (var i = 0; i < gl.series.length; i++) {
          if (gl.seriesNames[i] === undefined) {
            gl.seriesNames.push('series-' + (i + 1));
          }
        }
        return this.w;
      }

      /** User possibly set string categories in xaxis.categories or labels prop
       * Or didn't set xaxis labels at all - in which case we manually do it.
       * If user passed series data as [[3, 2], [4, 5]] or [{ x: 3, y: 55 }],
       * this shouldn't be called
       * @param {array} ser - the series which user passed to the config
       */
    }, {
      key: "handleExternalLabelsData",
      value: function handleExternalLabelsData(ser) {
        var cnf = this.w.config;
        var gl = this.w.globals;
        if (cnf.xaxis.categories.length > 0) {
          // user provided labels in xaxis.category prop
          gl.labels = cnf.xaxis.categories;
        } else if (cnf.labels.length > 0) {
          // user provided labels in labels props
          gl.labels = cnf.labels.slice();
        } else if (this.fallbackToCategory) {
          // user provided labels in x prop in [{ x: 3, y: 55 }] data, and those labels are already stored in gl.labels[0], so just re-arrange the gl.labels array
          gl.labels = gl.labels[0];
          if (gl.seriesRange.length) {
            gl.seriesRange.map(function (srt) {
              srt.forEach(function (sr) {
                if (gl.labels.indexOf(sr.x) < 0 && sr.x) {
                  gl.labels.push(sr.x);
                }
              });
            });
            // remove duplicate x-axis labels
            gl.labels = Array.from(new Set(gl.labels.map(JSON.stringify)), JSON.parse);
          }
          if (cnf.xaxis.convertedCatToNumeric) {
            var defaults = new Defaults(cnf);
            defaults.convertCatToNumericXaxis(cnf, this.ctx, gl.seriesX[0]);
            this._generateExternalLabels(ser);
          }
        } else {
          this._generateExternalLabels(ser);
        }
      }
    }, {
      key: "_generateExternalLabels",
      value: function _generateExternalLabels(ser) {
        var gl = this.w.globals;
        var cnf = this.w.config;
        // user didn't provided any labels, fallback to 1-2-3-4-5
        var labelArr = [];
        if (gl.axisCharts) {
          if (gl.series.length > 0) {
            if (this.isFormatXY()) {
              // in case there is a combo chart (boxplot/scatter)
              // and there are duplicated x values, we need to eliminate duplicates
              var seriesDataFiltered = cnf.series.map(function (serie, s) {
                return serie.data.filter(function (v, i, a) {
                  return a.findIndex(function (t) {
                    return t.x === v.x;
                  }) === i;
                });
              });
              var len = seriesDataFiltered.reduce(function (p, c, i, a) {
                return a[p].length > c.length ? p : i;
              }, 0);
              for (var i = 0; i < seriesDataFiltered[len].length; i++) {
                labelArr.push(i + 1);
              }
            } else {
              for (var _i = 0; _i < gl.series[gl.maxValsInArrayIndex].length; _i++) {
                labelArr.push(_i + 1);
              }
            }
          }
          gl.seriesX = [];
          // create gl.seriesX as it will be used in calculations of x positions
          for (var _i2 = 0; _i2 < ser.length; _i2++) {
            gl.seriesX.push(labelArr);
          }

          // turn on the isXNumeric flag to allow minX and maxX to function properly
          if (!this.w.globals.isBarHorizontal) {
            gl.isXNumeric = true;
          }
        }

        // no series to pull labels from, put a 0-10 series
        // possibly, user collapsed all series. Hence we can't work with above calc
        if (labelArr.length === 0) {
          labelArr = gl.axisCharts ? [] : gl.series.map(function (gls, glsi) {
            return glsi + 1;
          });
          for (var _i3 = 0; _i3 < ser.length; _i3++) {
            gl.seriesX.push(labelArr);
          }
        }

        // Finally, pass the labelArr in gl.labels which will be printed on x-axis
        gl.labels = labelArr;
        if (cnf.xaxis.convertedCatToNumeric) {
          gl.categoryLabels = labelArr.map(function (l) {
            return cnf.xaxis.labels.formatter(l);
          });
        }

        // Turn on this global flag to indicate no labels were provided by user
        gl.noLabelsProvided = true;
      }

      // Segregate user provided data into appropriate vars
    }, {
      key: "parseData",
      value: function parseData(ser) {
        var w = this.w;
        var cnf = w.config;
        var gl = w.globals;
        this.excludeCollapsedSeriesInYAxis();

        // If we detected string in X prop of series, we fallback to category x-axis
        this.fallbackToCategory = false;
        this.ctx.core.resetGlobals();
        this.ctx.core.isMultipleY();
        if (gl.axisCharts) {
          // axisCharts includes line / area / column / scatter
          this.parseDataAxisCharts(ser);
          this.coreUtils.getLargestSeries();
        } else {
          // non-axis charts are pie / donut
          this.parseDataNonAxisCharts(ser);
        }

        // set Null values to 0 in all series when user hides/shows some series
        if (cnf.chart.stacked) {
          var series = new Series(this.ctx);
          gl.series = series.setNullSeriesToZeroValues(gl.series);
        }
        this.coreUtils.getSeriesTotals();
        if (gl.axisCharts) {
          gl.stackedSeriesTotals = this.coreUtils.getStackedSeriesTotals();
          gl.stackedSeriesTotalsByGroups = this.coreUtils.getStackedSeriesTotalsByGroups();
        }
        this.coreUtils.getPercentSeries();
        if (!gl.dataFormatXNumeric && (!gl.isXNumeric || cnf.xaxis.type === 'numeric' && cnf.labels.length === 0 && cnf.xaxis.categories.length === 0)) {
          // x-axis labels couldn't be detected; hence try searching every option in config
          this.handleExternalLabelsData(ser);
        }

        // check for multiline xaxis
        var catLabels = this.coreUtils.getCategoryLabels(gl.labels);
        for (var l = 0; l < catLabels.length; l++) {
          if (Array.isArray(catLabels[l])) {
            gl.isMultiLineX = true;
            break;
          }
        }
      }
    }, {
      key: "excludeCollapsedSeriesInYAxis",
      value: function excludeCollapsedSeriesInYAxis() {
        var w = this.w;
        // Post revision 3.46.0 there is no longer a strict one-to-one
        // correspondence between series and Y axes.
        // An axis can be ignored only while all series referenced by it
        // are collapsed.
        var yAxisIndexes = [];
        w.globals.seriesYAxisMap.forEach(function (yAxisArr, yi) {
          var collapsedCount = 0;
          yAxisArr.forEach(function (seriesIndex) {
            if (w.globals.collapsedSeriesIndices.indexOf(seriesIndex) !== -1) {
              collapsedCount++;
            }
          });
          // It's possible to have a yaxis that doesn't reference any series yet,
          // eg, because there are no series' yet, so don't list it as ignored
          // prematurely.
          if (collapsedCount > 0 && collapsedCount == yAxisArr.length) {
            yAxisIndexes.push(yi);
          }
        });
        w.globals.ignoreYAxisIndexes = yAxisIndexes.map(function (x) {
          return x;
        });
      }
    }]);
    return Data;
  }();

  var Exports = /*#__PURE__*/function () {
    function Exports(ctx) {
      _classCallCheck(this, Exports);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(Exports, [{
      key: "scaleSvgNode",
      value: function scaleSvgNode(svg, scale) {
        // get current both width and height of the svg
        var svgWidth = parseFloat(svg.getAttributeNS(null, 'width'));
        var svgHeight = parseFloat(svg.getAttributeNS(null, 'height'));
        // set new width and height based on the scale
        svg.setAttributeNS(null, 'width', svgWidth * scale);
        svg.setAttributeNS(null, 'height', svgHeight * scale);
        svg.setAttributeNS(null, 'viewBox', '0 0 ' + svgWidth + ' ' + svgHeight);
      }
    }, {
      key: "getSvgString",
      value: function getSvgString() {
        var _this = this;
        return new Promise(function (resolve) {
          var w = _this.w;
          var width = w.config.chart.toolbar.export.width;
          var scale = w.config.chart.toolbar.export.scale || width / w.globals.svgWidth;
          if (!scale) {
            scale = 1; // if no scale is specified, don't scale...
          }
          var svgString = _this.w.globals.dom.Paper.svg();

          // clone the svg node so it remains intact in the UI
          var svgNode = _this.w.globals.dom.Paper.node.cloneNode(true);

          // in case the scale is different than 1, the svg needs to be rescaled

          if (scale !== 1) {
            // scale the image
            _this.scaleSvgNode(svgNode, scale);
          }
          // Convert image URLs to base64
          _this.convertImagesToBase64(svgNode).then(function () {
            svgString = new XMLSerializer().serializeToString(svgNode);
            resolve(svgString.replace(/&nbsp;/g, '&#160;'));
          });
        });
      }
    }, {
      key: "convertImagesToBase64",
      value: function convertImagesToBase64(svgNode) {
        var _this2 = this;
        var images = svgNode.getElementsByTagName('image');
        var promises = Array.from(images).map(function (img) {
          var href = img.getAttributeNS('http://www.w3.org/1999/xlink', 'href');
          if (href && !href.startsWith('data:')) {
            return _this2.getBase64FromUrl(href).then(function (base64) {
              img.setAttributeNS('http://www.w3.org/1999/xlink', 'href', base64);
            }).catch(function (error) {
              console.error('Error converting image to base64:', error);
            });
          }
          return Promise.resolve();
        });
        return Promise.all(promises);
      }
    }, {
      key: "getBase64FromUrl",
      value: function getBase64FromUrl(url) {
        return new Promise(function (resolve, reject) {
          var img = new Image();
          img.crossOrigin = 'Anonymous';
          img.onload = function () {
            var canvas = document.createElement('canvas');
            canvas.width = img.width;
            canvas.height = img.height;
            var ctx = canvas.getContext('2d');
            ctx.drawImage(img, 0, 0);
            resolve(canvas.toDataURL());
          };
          img.onerror = reject;
          img.src = url;
        });
      }
    }, {
      key: "cleanup",
      value: function cleanup() {
        var w = this.w;

        // hide some elements to avoid printing them on exported svg
        var xcrosshairs = w.globals.dom.baseEl.getElementsByClassName('apexcharts-xcrosshairs');
        var ycrosshairs = w.globals.dom.baseEl.getElementsByClassName('apexcharts-ycrosshairs');
        var zoomSelectionRects = w.globals.dom.baseEl.querySelectorAll('.apexcharts-zoom-rect, .apexcharts-selection-rect');
        Array.prototype.forEach.call(zoomSelectionRects, function (z) {
          z.setAttribute('width', 0);
        });
        if (xcrosshairs && xcrosshairs[0]) {
          xcrosshairs[0].setAttribute('x', -500);
          xcrosshairs[0].setAttribute('x1', -500);
          xcrosshairs[0].setAttribute('x2', -500);
        }
        if (ycrosshairs && ycrosshairs[0]) {
          ycrosshairs[0].setAttribute('y', -100);
          ycrosshairs[0].setAttribute('y1', -100);
          ycrosshairs[0].setAttribute('y2', -100);
        }
      }
    }, {
      key: "svgUrl",
      value: function svgUrl() {
        var _this3 = this;
        return new Promise(function (resolve) {
          _this3.cleanup();
          _this3.getSvgString().then(function (svgData) {
            var svgBlob = new Blob([svgData], {
              type: 'image/svg+xml;charset=utf-8'
            });
            resolve(URL.createObjectURL(svgBlob));
          });
        });
      }
    }, {
      key: "dataURI",
      value: function dataURI(options) {
        var _this4 = this;
        return new Promise(function (resolve) {
          var w = _this4.w;
          var scale = options ? options.scale || options.width / w.globals.svgWidth : 1;
          _this4.cleanup();
          var canvas = document.createElement('canvas');
          canvas.width = w.globals.svgWidth * scale;
          canvas.height = parseInt(w.globals.dom.elWrap.style.height, 10) * scale; // because of resizeNonAxisCharts

          var canvasBg = w.config.chart.background === 'transparent' || !w.config.chart.background ? '#fff' : w.config.chart.background;
          var ctx = canvas.getContext('2d');
          ctx.fillStyle = canvasBg;
          ctx.fillRect(0, 0, canvas.width * scale, canvas.height * scale);
          _this4.getSvgString().then(function (svgData) {
            var svgUrl = 'data:image/svg+xml,' + encodeURIComponent(svgData);
            var img = new Image();
            img.crossOrigin = 'anonymous';
            img.onload = function () {
              ctx.drawImage(img, 0, 0);
              if (canvas.msToBlob) {
                // Microsoft Edge can't navigate to data urls, so we return the blob instead
                var blob = canvas.msToBlob();
                resolve({
                  blob: blob
                });
              } else {
                var imgURI = canvas.toDataURL('image/png');
                resolve({
                  imgURI: imgURI
                });
              }
            };
            img.src = svgUrl;
          });
        });
      }
    }, {
      key: "exportToSVG",
      value: function exportToSVG() {
        var _this5 = this;
        this.svgUrl().then(function (url) {
          _this5.triggerDownload(url, _this5.w.config.chart.toolbar.export.svg.filename, '.svg');
        });
      }
    }, {
      key: "exportToPng",
      value: function exportToPng() {
        var _this6 = this;
        var scale = this.w.config.chart.toolbar.export.scale;
        var width = this.w.config.chart.toolbar.export.width;
        var option = scale ? {
          scale: scale
        } : width ? {
          width: width
        } : undefined;
        this.dataURI(option).then(function (_ref) {
          var imgURI = _ref.imgURI,
            blob = _ref.blob;
          if (blob) {
            navigator.msSaveOrOpenBlob(blob, _this6.w.globals.chartID + '.png');
          } else {
            _this6.triggerDownload(imgURI, _this6.w.config.chart.toolbar.export.png.filename, '.png');
          }
        });
      }
    }, {
      key: "exportToCSV",
      value: function exportToCSV(_ref2) {
        var _this7 = this;
        var series = _ref2.series,
          fileName = _ref2.fileName,
          _ref2$columnDelimiter = _ref2.columnDelimiter,
          columnDelimiter = _ref2$columnDelimiter === void 0 ? ',' : _ref2$columnDelimiter,
          _ref2$lineDelimiter = _ref2.lineDelimiter,
          lineDelimiter = _ref2$lineDelimiter === void 0 ? '\n' : _ref2$lineDelimiter;
        var w = this.w;
        if (!series) series = w.config.series;
        var columns = [];
        var rows = [];
        var result = '';
        var universalBOM = "\uFEFF";
        var gSeries = w.globals.series.map(function (s, i) {
          return w.globals.collapsedSeriesIndices.indexOf(i) === -1 ? s : [];
        });
        var getFormattedCategory = function getFormattedCategory(cat) {
          if (typeof w.config.chart.toolbar.export.csv.categoryFormatter === 'function') {
            return w.config.chart.toolbar.export.csv.categoryFormatter(cat);
          }
          if (w.config.xaxis.type === 'datetime' && String(cat).length >= 10) {
            return new Date(cat).toDateString();
          }
          return Utils$1.isNumber(cat) ? cat : cat.split(columnDelimiter).join('');
        };
        var getFormattedValue = function getFormattedValue(value) {
          return typeof w.config.chart.toolbar.export.csv.valueFormatter === 'function' ? w.config.chart.toolbar.export.csv.valueFormatter(value) : value;
        };
        var seriesMaxDataLength = Math.max.apply(Math, _toConsumableArray(series.map(function (s) {
          return s.data ? s.data.length : 0;
        })));
        var dataFormat = new Data(this.ctx);
        var axesUtils = new AxesUtils(this.ctx);
        var getCat = function getCat(i) {
          var cat = '';

          // pie / donut/ radial
          if (!w.globals.axisCharts) {
            cat = w.config.labels[i];
          } else {
            // xy charts

            // non datetime
            if (w.config.xaxis.type === 'category' || w.config.xaxis.convertedCatToNumeric) {
              if (w.globals.isBarHorizontal) {
                var lbFormatter = w.globals.yLabelFormatters[0];
                var sr = new Series(_this7.ctx);
                var activeSeries = sr.getActiveConfigSeriesIndex();
                cat = lbFormatter(w.globals.labels[i], {
                  seriesIndex: activeSeries,
                  dataPointIndex: i,
                  w: w
                });
              } else {
                cat = axesUtils.getLabel(w.globals.labels, w.globals.timescaleLabels, 0, i).text;
              }
            }

            // datetime, but labels specified in categories or labels
            if (w.config.xaxis.type === 'datetime') {
              if (w.config.xaxis.categories.length) {
                cat = w.config.xaxis.categories[i];
              } else if (w.config.labels.length) {
                cat = w.config.labels[i];
              }
            }
          }

          // let the caller know the current category is null. this can happen for example
          // when dealing with line charts having inconsistent time series data
          if (cat === null) return 'nullvalue';
          if (Array.isArray(cat)) {
            cat = cat.join(' ');
          }
          return Utils$1.isNumber(cat) ? cat : cat.split(columnDelimiter).join('');
        };

        // Fix https://github.com/apexcharts/apexcharts.js/issues/3365
        var getEmptyDataForCsvColumn = function getEmptyDataForCsvColumn() {
          return _toConsumableArray(Array(seriesMaxDataLength)).map(function () {
            return '';
          });
        };
        var handleAxisRowsColumns = function handleAxisRowsColumns(s, sI) {
          if (columns.length && sI === 0) {
            // It's the first series.  Go ahead and create the first row with header information.
            rows.push(columns.join(columnDelimiter));
          }
          if (s.data) {
            // Use the data we have, or generate a properly sized empty array with empty data if some data is missing.
            s.data = s.data.length && s.data || getEmptyDataForCsvColumn();
            for (var i = 0; i < s.data.length; i++) {
              // Reset the columns array so that we can start building columns for this row.
              columns = [];
              var cat = getCat(i);

              // current category is null, let's move on to the next one
              if (cat === 'nullvalue') continue;
              if (!cat) {
                if (dataFormat.isFormatXY()) {
                  cat = series[sI].data[i].x;
                } else if (dataFormat.isFormat2DArray()) {
                  cat = series[sI].data[i] ? series[sI].data[i][0] : '';
                }
              }
              if (sI === 0) {
                // It's the first series.  Also handle the category.
                columns.push(getFormattedCategory(cat));
                for (var ci = 0; ci < w.globals.series.length; ci++) {
                  var _series$ci$data$i;
                  var value = dataFormat.isFormatXY() ? (_series$ci$data$i = series[ci].data[i]) === null || _series$ci$data$i === void 0 ? void 0 : _series$ci$data$i.y : gSeries[ci][i];
                  columns.push(getFormattedValue(value));
                }
              }
              if (w.config.chart.type === 'candlestick' || s.type && s.type === 'candlestick') {
                columns.pop();
                columns.push(w.globals.seriesCandleO[sI][i]);
                columns.push(w.globals.seriesCandleH[sI][i]);
                columns.push(w.globals.seriesCandleL[sI][i]);
                columns.push(w.globals.seriesCandleC[sI][i]);
              }
              if (w.config.chart.type === 'boxPlot' || s.type && s.type === 'boxPlot') {
                columns.pop();
                columns.push(w.globals.seriesCandleO[sI][i]);
                columns.push(w.globals.seriesCandleH[sI][i]);
                columns.push(w.globals.seriesCandleM[sI][i]);
                columns.push(w.globals.seriesCandleL[sI][i]);
                columns.push(w.globals.seriesCandleC[sI][i]);
              }
              if (w.config.chart.type === 'rangeBar') {
                columns.pop();
                columns.push(w.globals.seriesRangeStart[sI][i]);
                columns.push(w.globals.seriesRangeEnd[sI][i]);
              }
              if (columns.length) {
                rows.push(columns.join(columnDelimiter));
              }
            }
          }
        };
        var handleUnequalXValues = function handleUnequalXValues() {
          var categories = new Set();
          var data = {};
          series.forEach(function (s, sI) {
            s === null || s === void 0 ? void 0 : s.data.forEach(function (dataItem) {
              var cat, value;
              if (dataFormat.isFormatXY()) {
                cat = dataItem.x;
                value = dataItem.y;
              } else if (dataFormat.isFormat2DArray()) {
                cat = dataItem[0];
                value = dataItem[1];
              } else {
                return;
              }
              if (!data[cat]) {
                data[cat] = Array(series.length).fill('');
              }
              data[cat][sI] = getFormattedValue(value);
              categories.add(cat);
            });
          });
          if (columns.length) {
            rows.push(columns.join(columnDelimiter));
          }
          Array.from(categories).sort().forEach(function (cat) {
            rows.push([getFormattedCategory(cat), data[cat].join(columnDelimiter)]);
          });
        };
        columns.push(w.config.chart.toolbar.export.csv.headerCategory);
        if (w.config.chart.type === 'boxPlot') {
          columns.push('minimum');
          columns.push('q1');
          columns.push('median');
          columns.push('q3');
          columns.push('maximum');
        } else if (w.config.chart.type === 'candlestick') {
          columns.push('open');
          columns.push('high');
          columns.push('low');
          columns.push('close');
        } else if (w.config.chart.type === 'rangeBar') {
          columns.push('minimum');
          columns.push('maximum');
        } else {
          series.map(function (s, sI) {
            var sname = (s.name ? s.name : "series-".concat(sI)) + '';
            if (w.globals.axisCharts) {
              columns.push(sname.split(columnDelimiter).join('') ? sname.split(columnDelimiter).join('') : "series-".concat(sI));
            }
          });
        }
        if (!w.globals.axisCharts) {
          columns.push(w.config.chart.toolbar.export.csv.headerValue);
          rows.push(columns.join(columnDelimiter));
        }
        if (!w.globals.allSeriesHasEqualX && w.globals.axisCharts && !w.config.xaxis.categories.length && !w.config.labels.length) {
          handleUnequalXValues();
        } else {
          series.map(function (s, sI) {
            if (w.globals.axisCharts) {
              handleAxisRowsColumns(s, sI);
            } else {
              columns = [];
              columns.push(getFormattedCategory(w.globals.labels[sI]));
              columns.push(getFormattedValue(gSeries[sI]));
              rows.push(columns.join(columnDelimiter));
            }
          });
        }
        result += rows.join(lineDelimiter);
        this.triggerDownload('data:text/csv; charset=utf-8,' + encodeURIComponent(universalBOM + result), fileName ? fileName : w.config.chart.toolbar.export.csv.filename, '.csv');
      }
    }, {
      key: "triggerDownload",
      value: function triggerDownload(href, filename, ext) {
        var downloadLink = document.createElement('a');
        downloadLink.href = href;
        downloadLink.download = (filename ? filename : this.w.globals.chartID) + ext;
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
      }
    }]);
    return Exports;
  }();

  /**
   * ApexCharts XAxis Class for drawing X-Axis.
   *
   * @module XAxis
   **/
  var XAxis = /*#__PURE__*/function () {
    function XAxis(ctx, elgrid) {
      _classCallCheck(this, XAxis);
      this.ctx = ctx;
      this.elgrid = elgrid;
      this.w = ctx.w;
      var w = this.w;
      this.axesUtils = new AxesUtils(ctx);
      this.xaxisLabels = w.globals.labels.slice();
      if (w.globals.timescaleLabels.length > 0 && !w.globals.isBarHorizontal) {
        //  timeline labels are there and chart is not rangeabr timeline
        this.xaxisLabels = w.globals.timescaleLabels.slice();
      }
      if (w.config.xaxis.overwriteCategories) {
        this.xaxisLabels = w.config.xaxis.overwriteCategories;
      }
      this.drawnLabels = [];
      this.drawnLabelsRects = [];
      if (w.config.xaxis.position === 'top') {
        this.offY = 0;
      } else {
        this.offY = w.globals.gridHeight;
      }
      this.offY = this.offY + w.config.xaxis.axisBorder.offsetY;
      this.isCategoryBarHorizontal = w.config.chart.type === 'bar' && w.config.plotOptions.bar.horizontal;
      this.xaxisFontSize = w.config.xaxis.labels.style.fontSize;
      this.xaxisFontFamily = w.config.xaxis.labels.style.fontFamily;
      this.xaxisForeColors = w.config.xaxis.labels.style.colors;
      this.xaxisBorderWidth = w.config.xaxis.axisBorder.width;
      if (this.isCategoryBarHorizontal) {
        this.xaxisBorderWidth = w.config.yaxis[0].axisBorder.width.toString();
      }
      if (this.xaxisBorderWidth.indexOf('%') > -1) {
        this.xaxisBorderWidth = w.globals.gridWidth * parseInt(this.xaxisBorderWidth, 10) / 100;
      } else {
        this.xaxisBorderWidth = parseInt(this.xaxisBorderWidth, 10);
      }
      this.xaxisBorderHeight = w.config.xaxis.axisBorder.height;

      // For bars, we will only consider single y xais,
      // as we are not providing multiple yaxis for bar charts
      this.yaxis = w.config.yaxis[0];
    }
    _createClass(XAxis, [{
      key: "drawXaxis",
      value: function drawXaxis() {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var elXaxis = graphics.group({
          class: 'apexcharts-xaxis',
          transform: "translate(".concat(w.config.xaxis.offsetX, ", ").concat(w.config.xaxis.offsetY, ")")
        });
        var elXaxisTexts = graphics.group({
          class: 'apexcharts-xaxis-texts-g',
          transform: "translate(".concat(w.globals.translateXAxisX, ", ").concat(w.globals.translateXAxisY, ")")
        });
        elXaxis.add(elXaxisTexts);
        var labels = [];
        for (var i = 0; i < this.xaxisLabels.length; i++) {
          labels.push(this.xaxisLabels[i]);
        }
        this.drawXAxisLabelAndGroup(true, graphics, elXaxisTexts, labels, w.globals.isXNumeric, function (i, colWidth) {
          return colWidth;
        });
        if (w.globals.hasXaxisGroups) {
          var labelsGroup = w.globals.groups;
          labels = [];
          for (var _i = 0; _i < labelsGroup.length; _i++) {
            labels.push(labelsGroup[_i].title);
          }
          var overwriteStyles = {};
          if (w.config.xaxis.group.style) {
            overwriteStyles.xaxisFontSize = w.config.xaxis.group.style.fontSize;
            overwriteStyles.xaxisFontFamily = w.config.xaxis.group.style.fontFamily;
            overwriteStyles.xaxisForeColors = w.config.xaxis.group.style.colors;
            overwriteStyles.fontWeight = w.config.xaxis.group.style.fontWeight;
            overwriteStyles.cssClass = w.config.xaxis.group.style.cssClass;
          }
          this.drawXAxisLabelAndGroup(false, graphics, elXaxisTexts, labels, false, function (i, colWidth) {
            return labelsGroup[i].cols * colWidth;
          }, overwriteStyles);
        }
        if (w.config.xaxis.title.text !== undefined) {
          var elXaxisTitle = graphics.group({
            class: 'apexcharts-xaxis-title'
          });
          var elXAxisTitleText = graphics.drawText({
            x: w.globals.gridWidth / 2 + w.config.xaxis.title.offsetX,
            y: this.offY + parseFloat(this.xaxisFontSize) + (w.config.xaxis.position === 'bottom' ? w.globals.xAxisLabelsHeight : -w.globals.xAxisLabelsHeight - 10) + w.config.xaxis.title.offsetY,
            text: w.config.xaxis.title.text,
            textAnchor: 'middle',
            fontSize: w.config.xaxis.title.style.fontSize,
            fontFamily: w.config.xaxis.title.style.fontFamily,
            fontWeight: w.config.xaxis.title.style.fontWeight,
            foreColor: w.config.xaxis.title.style.color,
            cssClass: 'apexcharts-xaxis-title-text ' + w.config.xaxis.title.style.cssClass
          });
          elXaxisTitle.add(elXAxisTitleText);
          elXaxis.add(elXaxisTitle);
        }
        if (w.config.xaxis.axisBorder.show) {
          var offX = w.globals.barPadForNumericAxis;
          var elHorzLine = graphics.drawLine(w.globals.padHorizontal + w.config.xaxis.axisBorder.offsetX - offX, this.offY, this.xaxisBorderWidth + offX, this.offY, w.config.xaxis.axisBorder.color, 0, this.xaxisBorderHeight);
          if (this.elgrid && this.elgrid.elGridBorders && w.config.grid.show) {
            this.elgrid.elGridBorders.add(elHorzLine);
          } else {
            elXaxis.add(elHorzLine);
          }
        }
        return elXaxis;
      }
    }, {
      key: "drawXAxisLabelAndGroup",
      value: function drawXAxisLabelAndGroup(isLeafGroup, graphics, elXaxisTexts, labels, isXNumeric, colWidthCb) {
        var _this = this;
        var overwriteStyles = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
        var drawnLabels = [];
        var drawnLabelsRects = [];
        var w = this.w;
        var xaxisFontSize = overwriteStyles.xaxisFontSize || this.xaxisFontSize;
        var xaxisFontFamily = overwriteStyles.xaxisFontFamily || this.xaxisFontFamily;
        var xaxisForeColors = overwriteStyles.xaxisForeColors || this.xaxisForeColors;
        var fontWeight = overwriteStyles.fontWeight || w.config.xaxis.labels.style.fontWeight;
        var cssClass = overwriteStyles.cssClass || w.config.xaxis.labels.style.cssClass;
        var colWidth;

        // initial x Position (keep adding column width in the loop)
        var xPos = w.globals.padHorizontal;
        var labelsLen = labels.length;

        /**
         * labelsLen can be different (whether you are drawing x-axis labels or x-axis group labels)
         * hence, we introduce dataPoints to be consistent.
         * Also, in datetime/numeric xaxis, dataPoints can be misleading, so we resort to labelsLen for such xaxis type
         */
        var dataPoints = w.config.xaxis.type === 'category' ? w.globals.dataPoints : labelsLen;

        // when all series are collapsed, fixes #3381
        if (dataPoints === 0 && labelsLen > dataPoints) dataPoints = labelsLen;
        if (isXNumeric) {
          var len = dataPoints > 1 ? dataPoints - 1 : dataPoints;
          colWidth = w.globals.gridWidth / Math.min(len, labelsLen - 1);
          xPos = xPos + colWidthCb(0, colWidth) / 2 + w.config.xaxis.labels.offsetX;
        } else {
          colWidth = w.globals.gridWidth / dataPoints;
          xPos = xPos + colWidthCb(0, colWidth) + w.config.xaxis.labels.offsetX;
        }
        var _loop = function _loop(i) {
          var x = xPos - colWidthCb(i, colWidth) / 2 + w.config.xaxis.labels.offsetX;
          if (i === 0 && labelsLen === 1 && colWidth / 2 === xPos && dataPoints === 1) {
            // single datapoint
            x = w.globals.gridWidth / 2;
          }
          var label = _this.axesUtils.getLabel(labels, w.globals.timescaleLabels, x, i, drawnLabels, xaxisFontSize, isLeafGroup);
          var offsetYCorrection = 28;
          if (w.globals.rotateXLabels && isLeafGroup) {
            offsetYCorrection = 22;
          }
          if (w.config.xaxis.title.text && w.config.xaxis.position === 'top') {
            offsetYCorrection += parseFloat(w.config.xaxis.title.style.fontSize) + 2;
          }
          if (!isLeafGroup) {
            offsetYCorrection = offsetYCorrection + parseFloat(xaxisFontSize) + (w.globals.xAxisLabelsHeight - w.globals.xAxisGroupLabelsHeight) + (w.globals.rotateXLabels ? 10 : 0);
          }
          var isCategoryTickAmounts = typeof w.config.xaxis.tickAmount !== 'undefined' && w.config.xaxis.tickAmount !== 'dataPoints' && w.config.xaxis.type !== 'datetime';
          if (isCategoryTickAmounts) {
            label = _this.axesUtils.checkLabelBasedOnTickamount(i, label, labelsLen);
          } else {
            label = _this.axesUtils.checkForOverflowingLabels(i, label, labelsLen, drawnLabels, drawnLabelsRects);
          }
          var getCatForeColor = function getCatForeColor() {
            return isLeafGroup && w.config.xaxis.convertedCatToNumeric ? xaxisForeColors[w.globals.minX + i - 1] : xaxisForeColors[i];
          };
          if (w.config.xaxis.labels.show) {
            var elText = graphics.drawText({
              x: label.x,
              y: _this.offY + w.config.xaxis.labels.offsetY + offsetYCorrection - (w.config.xaxis.position === 'top' ? w.globals.xAxisHeight + w.config.xaxis.axisTicks.height - 2 : 0),
              text: label.text,
              textAnchor: 'middle',
              fontWeight: label.isBold ? 600 : fontWeight,
              fontSize: xaxisFontSize,
              fontFamily: xaxisFontFamily,
              foreColor: Array.isArray(xaxisForeColors) ? getCatForeColor() : xaxisForeColors,
              isPlainText: false,
              cssClass: (isLeafGroup ? 'apexcharts-xaxis-label ' : 'apexcharts-xaxis-group-label ') + cssClass
            });
            elXaxisTexts.add(elText);
            elText.on('click', function (e) {
              if (typeof w.config.chart.events.xAxisLabelClick === 'function') {
                var opts = Object.assign({}, w, {
                  labelIndex: i
                });
                w.config.chart.events.xAxisLabelClick(e, _this.ctx, opts);
              }
            });
            if (isLeafGroup) {
              var elTooltipTitle = document.createElementNS(w.globals.SVGNS, 'title');
              elTooltipTitle.textContent = Array.isArray(label.text) ? label.text.join(' ') : label.text;
              elText.node.appendChild(elTooltipTitle);
              if (label.text !== '') {
                drawnLabels.push(label.text);
                drawnLabelsRects.push(label);
              }
            }
          }
          if (i < labelsLen - 1) {
            xPos = xPos + colWidthCb(i + 1, colWidth);
          }
        };
        for (var i = 0; i <= labelsLen - 1; i++) {
          _loop(i);
        }
      }

      // this actually becomes the vertical axis (for bar charts)
    }, {
      key: "drawXaxisInversed",
      value: function drawXaxisInversed(realIndex) {
        var _this2 = this;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var translateYAxisX = w.config.yaxis[0].opposite ? w.globals.translateYAxisX[realIndex] : 0;
        var elYaxis = graphics.group({
          class: 'apexcharts-yaxis apexcharts-xaxis-inversed',
          rel: realIndex
        });
        var elYaxisTexts = graphics.group({
          class: 'apexcharts-yaxis-texts-g apexcharts-xaxis-inversed-texts-g',
          transform: 'translate(' + translateYAxisX + ', 0)'
        });
        elYaxis.add(elYaxisTexts);
        var colHeight;

        // initial x Position (keep adding column width in the loop)
        var yPos;
        var labels = [];
        if (w.config.yaxis[realIndex].show) {
          for (var i = 0; i < this.xaxisLabels.length; i++) {
            labels.push(this.xaxisLabels[i]);
          }
        }
        colHeight = w.globals.gridHeight / labels.length;
        yPos = -(colHeight / 2.2);
        var lbFormatter = w.globals.yLabelFormatters[0];
        var ylabels = w.config.yaxis[0].labels;
        if (ylabels.show) {
          var _loop2 = function _loop2(_i2) {
            var label = typeof labels[_i2] === 'undefined' ? '' : labels[_i2];
            label = lbFormatter(label, {
              seriesIndex: realIndex,
              dataPointIndex: _i2,
              w: w
            });
            var yColors = _this2.axesUtils.getYAxisForeColor(ylabels.style.colors, realIndex);
            var getForeColor = function getForeColor() {
              return Array.isArray(yColors) ? yColors[_i2] : yColors;
            };
            var multiY = 0;
            if (Array.isArray(label)) {
              multiY = label.length / 2 * parseInt(ylabels.style.fontSize, 10);
            }
            var offsetX = ylabels.offsetX - 15;
            var textAnchor = 'end';
            if (_this2.yaxis.opposite) {
              textAnchor = 'start';
            }
            if (w.config.yaxis[0].labels.align === 'left') {
              offsetX = ylabels.offsetX;
              textAnchor = 'start';
            } else if (w.config.yaxis[0].labels.align === 'center') {
              offsetX = ylabels.offsetX;
              textAnchor = 'middle';
            } else if (w.config.yaxis[0].labels.align === 'right') {
              textAnchor = 'end';
            }
            var elLabel = graphics.drawText({
              x: offsetX,
              y: yPos + colHeight + ylabels.offsetY - multiY,
              text: label,
              textAnchor: textAnchor,
              foreColor: getForeColor(),
              fontSize: ylabels.style.fontSize,
              fontFamily: ylabels.style.fontFamily,
              fontWeight: ylabels.style.fontWeight,
              isPlainText: false,
              cssClass: 'apexcharts-yaxis-label ' + ylabels.style.cssClass,
              maxWidth: ylabels.maxWidth
            });
            elYaxisTexts.add(elLabel);
            elLabel.on('click', function (e) {
              if (typeof w.config.chart.events.xAxisLabelClick === 'function') {
                var opts = Object.assign({}, w, {
                  labelIndex: _i2
                });
                w.config.chart.events.xAxisLabelClick(e, _this2.ctx, opts);
              }
            });
            var elTooltipTitle = document.createElementNS(w.globals.SVGNS, 'title');
            elTooltipTitle.textContent = Array.isArray(label) ? label.join(' ') : label;
            elLabel.node.appendChild(elTooltipTitle);
            if (w.config.yaxis[realIndex].labels.rotate !== 0) {
              var labelRotatingCenter = graphics.rotateAroundCenter(elLabel.node);
              elLabel.node.setAttribute('transform', "rotate(".concat(w.config.yaxis[realIndex].labels.rotate, " 0 ").concat(labelRotatingCenter.y, ")"));
            }
            yPos = yPos + colHeight;
          };
          for (var _i2 = 0; _i2 <= labels.length - 1; _i2++) {
            _loop2(_i2);
          }
        }
        if (w.config.yaxis[0].title.text !== undefined) {
          var elXaxisTitle = graphics.group({
            class: 'apexcharts-yaxis-title apexcharts-xaxis-title-inversed',
            transform: 'translate(' + translateYAxisX + ', 0)'
          });
          var elXAxisTitleText = graphics.drawText({
            x: w.config.yaxis[0].title.offsetX,
            y: w.globals.gridHeight / 2 + w.config.yaxis[0].title.offsetY,
            text: w.config.yaxis[0].title.text,
            textAnchor: 'middle',
            foreColor: w.config.yaxis[0].title.style.color,
            fontSize: w.config.yaxis[0].title.style.fontSize,
            fontWeight: w.config.yaxis[0].title.style.fontWeight,
            fontFamily: w.config.yaxis[0].title.style.fontFamily,
            cssClass: 'apexcharts-yaxis-title-text ' + w.config.yaxis[0].title.style.cssClass
          });
          elXaxisTitle.add(elXAxisTitleText);
          elYaxis.add(elXaxisTitle);
        }
        var offX = 0;
        if (this.isCategoryBarHorizontal && w.config.yaxis[0].opposite) {
          offX = w.globals.gridWidth;
        }
        var axisBorder = w.config.xaxis.axisBorder;
        if (axisBorder.show) {
          var elVerticalLine = graphics.drawLine(w.globals.padHorizontal + axisBorder.offsetX + offX, 1 + axisBorder.offsetY, w.globals.padHorizontal + axisBorder.offsetX + offX, w.globals.gridHeight + axisBorder.offsetY, axisBorder.color, 0);
          if (this.elgrid && this.elgrid.elGridBorders && w.config.grid.show) {
            this.elgrid.elGridBorders.add(elVerticalLine);
          } else {
            elYaxis.add(elVerticalLine);
          }
        }
        if (w.config.yaxis[0].axisTicks.show) {
          this.axesUtils.drawYAxisTicks(offX, labels.length, w.config.yaxis[0].axisBorder, w.config.yaxis[0].axisTicks, 0, colHeight, elYaxis);
        }
        return elYaxis;
      }
    }, {
      key: "drawXaxisTicks",
      value: function drawXaxisTicks(x1, y2, appendToElement) {
        var w = this.w;
        var x2 = x1;
        if (x1 < 0 || x1 - 2 > w.globals.gridWidth) return;
        var y1 = this.offY + w.config.xaxis.axisTicks.offsetY;
        y2 = y2 + y1 + w.config.xaxis.axisTicks.height;
        if (w.config.xaxis.position === 'top') {
          y2 = y1 - w.config.xaxis.axisTicks.height;
        }
        if (w.config.xaxis.axisTicks.show) {
          var graphics = new Graphics(this.ctx);
          var line = graphics.drawLine(x1 + w.config.xaxis.axisTicks.offsetX, y1 + w.config.xaxis.offsetY, x2 + w.config.xaxis.axisTicks.offsetX, y2 + w.config.xaxis.offsetY, w.config.xaxis.axisTicks.color);

          // we are not returning anything, but appending directly to the element passed in param
          appendToElement.add(line);
          line.node.classList.add('apexcharts-xaxis-tick');
        }
      }
    }, {
      key: "getXAxisTicksPositions",
      value: function getXAxisTicksPositions() {
        var w = this.w;
        var xAxisTicksPositions = [];
        var xCount = this.xaxisLabels.length;
        var x1 = w.globals.padHorizontal;
        if (w.globals.timescaleLabels.length > 0) {
          for (var i = 0; i < xCount; i++) {
            x1 = this.xaxisLabels[i].position;
            xAxisTicksPositions.push(x1);
          }
        } else {
          var xCountForCategoryCharts = xCount;
          for (var _i3 = 0; _i3 < xCountForCategoryCharts; _i3++) {
            var x1Count = xCountForCategoryCharts;
            if (w.globals.isXNumeric && w.config.chart.type !== 'bar') {
              x1Count -= 1;
            }
            x1 = x1 + w.globals.gridWidth / x1Count;
            xAxisTicksPositions.push(x1);
          }
        }
        return xAxisTicksPositions;
      }

      // to rotate x-axis labels or to put ... for longer text in xaxis
    }, {
      key: "xAxisLabelCorrections",
      value: function xAxisLabelCorrections() {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var xAxis = w.globals.dom.baseEl.querySelector('.apexcharts-xaxis-texts-g');
        var xAxisTexts = w.globals.dom.baseEl.querySelectorAll('.apexcharts-xaxis-texts-g text:not(.apexcharts-xaxis-group-label)');
        var yAxisTextsInversed = w.globals.dom.baseEl.querySelectorAll('.apexcharts-yaxis-inversed text');
        var xAxisTextsInversed = w.globals.dom.baseEl.querySelectorAll('.apexcharts-xaxis-inversed-texts-g text tspan');
        if (w.globals.rotateXLabels || w.config.xaxis.labels.rotateAlways) {
          for (var xat = 0; xat < xAxisTexts.length; xat++) {
            var textRotatingCenter = graphics.rotateAroundCenter(xAxisTexts[xat]);
            textRotatingCenter.y = textRotatingCenter.y - 1; // + tickWidth/4;
            textRotatingCenter.x = textRotatingCenter.x + 1;
            xAxisTexts[xat].setAttribute('transform', "rotate(".concat(w.config.xaxis.labels.rotate, " ").concat(textRotatingCenter.x, " ").concat(textRotatingCenter.y, ")"));
            xAxisTexts[xat].setAttribute('text-anchor', "end");
            var offsetHeight = 10;
            xAxis.setAttribute('transform', "translate(0, ".concat(-offsetHeight, ")"));
            var tSpan = xAxisTexts[xat].childNodes;
            if (w.config.xaxis.labels.trim) {
              Array.prototype.forEach.call(tSpan, function (ts) {
                graphics.placeTextWithEllipsis(ts, ts.textContent, w.globals.xAxisLabelsHeight - (w.config.legend.position === 'bottom' ? 20 : 10));
              });
            }
          }
        } else {
          (function () {
            var width = w.globals.gridWidth / (w.globals.labels.length + 1);
            for (var _xat = 0; _xat < xAxisTexts.length; _xat++) {
              var _tSpan = xAxisTexts[_xat].childNodes;
              if (w.config.xaxis.labels.trim && w.config.xaxis.type !== 'datetime') {
                Array.prototype.forEach.call(_tSpan, function (ts) {
                  graphics.placeTextWithEllipsis(ts, ts.textContent, width);
                });
              }
            }
          })();
        }
        if (yAxisTextsInversed.length > 0) {
          // truncate rotated y axis in bar chart (x axis)
          var firstLabelPosX = yAxisTextsInversed[yAxisTextsInversed.length - 1].getBBox();
          var lastLabelPosX = yAxisTextsInversed[0].getBBox();
          if (firstLabelPosX.x < -20) {
            yAxisTextsInversed[yAxisTextsInversed.length - 1].parentNode.removeChild(yAxisTextsInversed[yAxisTextsInversed.length - 1]);
          }
          if (lastLabelPosX.x + lastLabelPosX.width > w.globals.gridWidth && !w.globals.isBarHorizontal) {
            yAxisTextsInversed[0].parentNode.removeChild(yAxisTextsInversed[0]);
          }

          // truncate rotated x axis in bar chart (y axis)
          for (var _xat2 = 0; _xat2 < xAxisTextsInversed.length; _xat2++) {
            graphics.placeTextWithEllipsis(xAxisTextsInversed[_xat2], xAxisTextsInversed[_xat2].textContent, w.config.yaxis[0].labels.maxWidth - (w.config.yaxis[0].title.text ? parseFloat(w.config.yaxis[0].title.style.fontSize) * 2 : 0) - 15);
          }
        }
      }

      // renderXAxisBands() {
      //   let w = this.w;

      //   let plotBand = document.createElementNS(w.globals.SVGNS, 'rect')
      //   w.globals.dom.elGraphical.add(plotBand)
      // }
    }]);
    return XAxis;
  }();

  /**
   * ApexCharts Grid Class for drawing Cartesian Grid.
   *
   * @module Grid
   **/
  var Grid = /*#__PURE__*/function () {
    function Grid(ctx) {
      _classCallCheck(this, Grid);
      this.ctx = ctx;
      this.w = ctx.w;
      var w = this.w;
      this.xaxisLabels = w.globals.labels.slice();
      this.axesUtils = new AxesUtils(ctx);
      this.isRangeBar = w.globals.seriesRange.length && w.globals.isBarHorizontal;
      if (w.globals.timescaleLabels.length > 0) {
        //  timescaleLabels labels are there
        this.xaxisLabels = w.globals.timescaleLabels.slice();
      }
    }
    _createClass(Grid, [{
      key: "drawGridArea",
      value: function drawGridArea() {
        var elGrid = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        if (!elGrid) {
          elGrid = graphics.group({
            class: 'apexcharts-grid'
          });
        }
        var elVerticalLine = graphics.drawLine(w.globals.padHorizontal, 1, w.globals.padHorizontal, w.globals.gridHeight, 'transparent');
        var elHorzLine = graphics.drawLine(w.globals.padHorizontal, w.globals.gridHeight, w.globals.gridWidth, w.globals.gridHeight, 'transparent');
        elGrid.add(elHorzLine);
        elGrid.add(elVerticalLine);
        return elGrid;
      }
    }, {
      key: "drawGrid",
      value: function drawGrid() {
        var gl = this.w.globals;
        if (gl.axisCharts) {
          var elgrid = this.renderGrid();
          this.drawGridArea(elgrid.el);
          return elgrid;
        }
        return null;
      }
    }, {
      key: "createGridMask",
      value: function createGridMask() {
        var w = this.w;
        var gl = w.globals;
        var graphics = new Graphics(this.ctx);
        var strokeSize = Array.isArray(w.config.stroke.width) ? Math.max.apply(Math, _toConsumableArray(w.config.stroke.width)) : w.config.stroke.width;
        var createClipPath = function createClipPath(id) {
          var clipPath = document.createElementNS(gl.SVGNS, 'clipPath');
          clipPath.setAttribute('id', id);
          return clipPath;
        };
        gl.dom.elGridRectMask = createClipPath("gridRectMask".concat(gl.cuid));
        gl.dom.elGridRectBarMask = createClipPath("gridRectBarMask".concat(gl.cuid));
        gl.dom.elGridRectMarkerMask = createClipPath("gridRectMarkerMask".concat(gl.cuid));
        gl.dom.elForecastMask = createClipPath("forecastMask".concat(gl.cuid));
        gl.dom.elNonForecastMask = createClipPath("nonForecastMask".concat(gl.cuid));
        var hasBar = ['bar', 'rangeBar', 'candlestick', 'boxPlot'].includes(w.config.chart.type) || w.globals.comboBarCount > 0;
        var barWidthLeft = 0;
        var barWidthRight = 0;
        if (hasBar && w.globals.isXNumeric && !w.globals.isBarHorizontal) {
          barWidthLeft = Math.max(w.config.grid.padding.left, gl.barPadForNumericAxis);
          barWidthRight = Math.max(w.config.grid.padding.right, gl.barPadForNumericAxis);
        }
        gl.dom.elGridRect = graphics.drawRect(0, 0, gl.gridWidth, gl.gridHeight, 0, '#fff');
        gl.dom.elGridRectBar = graphics.drawRect(-strokeSize / 2 - barWidthLeft - 2, -strokeSize / 2 - 2, gl.gridWidth + strokeSize + barWidthRight + barWidthLeft + 4, gl.gridHeight + strokeSize + 4, 0, '#fff');
        var markerSize = w.globals.markers.largestSize;
        gl.dom.elGridRectMarker = graphics.drawRect(-markerSize, -markerSize, gl.gridWidth + markerSize * 2, gl.gridHeight + markerSize * 2, 0, '#fff');
        gl.dom.elGridRectMask.appendChild(gl.dom.elGridRect.node);
        gl.dom.elGridRectBarMask.appendChild(gl.dom.elGridRectBar.node);
        gl.dom.elGridRectMarkerMask.appendChild(gl.dom.elGridRectMarker.node);
        var defs = gl.dom.baseEl.querySelector('defs');
        defs.appendChild(gl.dom.elGridRectMask);
        defs.appendChild(gl.dom.elGridRectBarMask);
        defs.appendChild(gl.dom.elGridRectMarkerMask);
        defs.appendChild(gl.dom.elForecastMask);
        defs.appendChild(gl.dom.elNonForecastMask);
      }
    }, {
      key: "_drawGridLines",
      value: function _drawGridLines(_ref) {
        var i = _ref.i,
          x1 = _ref.x1,
          y1 = _ref.y1,
          x2 = _ref.x2,
          y2 = _ref.y2,
          xCount = _ref.xCount,
          parent = _ref.parent;
        var w = this.w;
        var shouldDraw = function shouldDraw() {
          if (i === 0 && w.globals.skipFirstTimelinelabel) return false;
          if (i === xCount - 1 && w.globals.skipLastTimelinelabel && !w.config.xaxis.labels.formatter) return false;
          if (w.config.chart.type === 'radar') return false;
          return true;
        };
        if (shouldDraw()) {
          if (w.config.grid.xaxis.lines.show) {
            this._drawGridLine({
              i: i,
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2,
              xCount: xCount,
              parent: parent
            });
          }
          var y_2 = 0;
          if (w.globals.hasXaxisGroups && w.config.xaxis.tickPlacement === 'between') {
            var groups = w.globals.groups;
            if (groups) {
              var gacc = 0;
              for (var gi = 0; gacc < i && gi < groups.length; gi++) {
                gacc += groups[gi].cols;
              }
              if (gacc === i) {
                y_2 = w.globals.xAxisLabelsHeight * 0.6;
              }
            }
          }
          var xAxis = new XAxis(this.ctx);
          xAxis.drawXaxisTicks(x1, y_2, w.globals.dom.elGraphical);
        }
      }
    }, {
      key: "_drawGridLine",
      value: function _drawGridLine(_ref2) {
        var i = _ref2.i,
          x1 = _ref2.x1,
          y1 = _ref2.y1,
          x2 = _ref2.x2,
          y2 = _ref2.y2,
          xCount = _ref2.xCount,
          parent = _ref2.parent;
        var w = this.w;
        var isHorzLine = parent.node.classList.contains('apexcharts-gridlines-horizontal');
        var offX = w.globals.barPadForNumericAxis;
        var excludeBorders = y1 === 0 && y2 === 0 || x1 === 0 && x2 === 0 || y1 === w.globals.gridHeight && y2 === w.globals.gridHeight || w.globals.isBarHorizontal && (i === 0 || i === xCount - 1);
        var graphics = new Graphics(this);
        var line = graphics.drawLine(x1 - (isHorzLine ? offX : 0), y1, x2 + (isHorzLine ? offX : 0), y2, w.config.grid.borderColor, w.config.grid.strokeDashArray);
        line.node.classList.add('apexcharts-gridline');
        if (excludeBorders && w.config.grid.show) {
          this.elGridBorders.add(line);
        } else {
          parent.add(line);
        }
      }
    }, {
      key: "_drawGridBandRect",
      value: function _drawGridBandRect(_ref3) {
        var c = _ref3.c,
          x1 = _ref3.x1,
          y1 = _ref3.y1,
          x2 = _ref3.x2,
          y2 = _ref3.y2,
          type = _ref3.type;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var offX = w.globals.barPadForNumericAxis;
        var color = w.config.grid[type].colors[c];
        var rect = graphics.drawRect(x1 - (type === 'row' ? offX : 0), y1, x2 + (type === 'row' ? offX * 2 : 0), y2, 0, color, w.config.grid[type].opacity);
        this.elg.add(rect);
        rect.attr('clip-path', "url(#gridRectMask".concat(w.globals.cuid, ")"));
        rect.node.classList.add("apexcharts-grid-".concat(type));
      }
    }, {
      key: "_drawXYLines",
      value: function _drawXYLines(_ref4) {
        var _this = this;
        var xCount = _ref4.xCount,
          tickAmount = _ref4.tickAmount;
        var w = this.w;
        var datetimeLines = function datetimeLines(_ref5) {
          var xC = _ref5.xC,
            x1 = _ref5.x1,
            y1 = _ref5.y1,
            x2 = _ref5.x2,
            y2 = _ref5.y2;
          for (var i = 0; i < xC; i++) {
            x1 = _this.xaxisLabels[i].position;
            x2 = _this.xaxisLabels[i].position;
            _this._drawGridLines({
              i: i,
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2,
              xCount: xCount,
              parent: _this.elgridLinesV
            });
          }
        };
        var categoryLines = function categoryLines(_ref6) {
          var xC = _ref6.xC,
            x1 = _ref6.x1,
            y1 = _ref6.y1,
            x2 = _ref6.x2,
            y2 = _ref6.y2;
          for (var i = 0; i < xC + (w.globals.isXNumeric ? 0 : 1); i++) {
            if (i === 0 && xC === 1 && w.globals.dataPoints === 1) {
              x1 = w.globals.gridWidth / 2;
              x2 = x1;
            }
            _this._drawGridLines({
              i: i,
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2,
              xCount: xCount,
              parent: _this.elgridLinesV
            });
            x1 += w.globals.gridWidth / (w.globals.isXNumeric ? xC - 1 : xC);
            x2 = x1;
          }
        };
        if (w.config.grid.xaxis.lines.show || w.config.xaxis.axisTicks.show) {
          var x1 = w.globals.padHorizontal;
          var y1 = 0;
          var x2;
          var y2 = w.globals.gridHeight;
          if (w.globals.timescaleLabels.length) {
            datetimeLines({
              xC: xCount,
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2
            });
          } else {
            if (w.globals.isXNumeric) {
              xCount = w.globals.xAxisScale.result.length;
            }
            categoryLines({
              xC: xCount,
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2
            });
          }
        }
        if (w.config.grid.yaxis.lines.show) {
          var _x = 0;
          var _y = 0;
          var _y2 = 0;
          var _x2 = w.globals.gridWidth;
          var tA = tickAmount + 1;
          if (this.isRangeBar) {
            tA = w.globals.labels.length;
          }
          for (var i = 0; i < tA + (this.isRangeBar ? 1 : 0); i++) {
            this._drawGridLine({
              i: i,
              xCount: tA + (this.isRangeBar ? 1 : 0),
              x1: _x,
              y1: _y,
              x2: _x2,
              y2: _y2,
              parent: this.elgridLinesH
            });
            _y += w.globals.gridHeight / (this.isRangeBar ? tA : tickAmount);
            _y2 = _y;
          }
        }
      }
    }, {
      key: "_drawInvertedXYLines",
      value: function _drawInvertedXYLines(_ref7) {
        var xCount = _ref7.xCount;
        var w = this.w;
        if (w.config.grid.xaxis.lines.show || w.config.xaxis.axisTicks.show) {
          var x1 = w.globals.padHorizontal;
          var y1 = 0;
          var x2;
          var y2 = w.globals.gridHeight;
          for (var i = 0; i < xCount + 1; i++) {
            if (w.config.grid.xaxis.lines.show) {
              this._drawGridLine({
                i: i,
                xCount: xCount + 1,
                x1: x1,
                y1: y1,
                x2: x2,
                y2: y2,
                parent: this.elgridLinesV
              });
            }
            var xAxis = new XAxis(this.ctx);
            xAxis.drawXaxisTicks(x1, 0, w.globals.dom.elGraphical);
            x1 += w.globals.gridWidth / xCount;
            x2 = x1;
          }
        }
        if (w.config.grid.yaxis.lines.show) {
          var _x3 = 0;
          var _y3 = 0;
          var _y4 = 0;
          var _x4 = w.globals.gridWidth;
          for (var _i = 0; _i < w.globals.dataPoints + 1; _i++) {
            this._drawGridLine({
              i: _i,
              xCount: w.globals.dataPoints + 1,
              x1: _x3,
              y1: _y3,
              x2: _x4,
              y2: _y4,
              parent: this.elgridLinesH
            });
            _y3 += w.globals.gridHeight / w.globals.dataPoints;
            _y4 = _y3;
          }
        }
      }
    }, {
      key: "renderGrid",
      value: function renderGrid() {
        var w = this.w;
        var gl = w.globals;
        var graphics = new Graphics(this.ctx);
        this.elg = graphics.group({
          class: 'apexcharts-grid'
        });
        this.elgridLinesH = graphics.group({
          class: 'apexcharts-gridlines-horizontal'
        });
        this.elgridLinesV = graphics.group({
          class: 'apexcharts-gridlines-vertical'
        });
        this.elGridBorders = graphics.group({
          class: 'apexcharts-grid-borders'
        });
        this.elg.add(this.elgridLinesH);
        this.elg.add(this.elgridLinesV);
        if (!w.config.grid.show) {
          this.elgridLinesV.hide();
          this.elgridLinesH.hide();
          this.elGridBorders.hide();
        }
        var gridAxisIndex = 0;
        while (gridAxisIndex < gl.seriesYAxisMap.length && gl.ignoreYAxisIndexes.includes(gridAxisIndex)) {
          gridAxisIndex++;
        }
        if (gridAxisIndex === gl.seriesYAxisMap.length) {
          gridAxisIndex = 0;
        }
        var yTickAmount = gl.yAxisScale[gridAxisIndex].result.length - 1;
        var xCount;
        if (!gl.isBarHorizontal || this.isRangeBar) {
          xCount = this.xaxisLabels.length;
          if (this.isRangeBar) {
            var _gl$yAxisScale, _gl$yAxisScale$gridAx, _gl$yAxisScale$gridAx2;
            yTickAmount = gl.labels.length;
            if (w.config.xaxis.tickAmount && w.config.xaxis.labels.formatter) {
              xCount = w.config.xaxis.tickAmount;
            }
            if (((_gl$yAxisScale = gl.yAxisScale) === null || _gl$yAxisScale === void 0 ? void 0 : (_gl$yAxisScale$gridAx = _gl$yAxisScale[gridAxisIndex]) === null || _gl$yAxisScale$gridAx === void 0 ? void 0 : (_gl$yAxisScale$gridAx2 = _gl$yAxisScale$gridAx.result) === null || _gl$yAxisScale$gridAx2 === void 0 ? void 0 : _gl$yAxisScale$gridAx2.length) > 0 && w.config.xaxis.type !== 'datetime') {
              xCount = gl.yAxisScale[gridAxisIndex].result.length - 1;
            }
          }
          this._drawXYLines({
            xCount: xCount,
            tickAmount: yTickAmount
          });
        } else {
          xCount = yTickAmount;

          // for horizontal bar chart, get the xaxis tickamount
          yTickAmount = gl.xTickAmount;
          this._drawInvertedXYLines({
            xCount: xCount,
            tickAmount: yTickAmount
          });
        }
        this.drawGridBands(xCount, yTickAmount);
        return {
          el: this.elg,
          elGridBorders: this.elGridBorders,
          xAxisTickWidth: gl.gridWidth / xCount
        };
      }
    }, {
      key: "drawGridBands",
      value: function drawGridBands(xCount, tickAmount) {
        var _this2 = this,
          _w$config$grid$row$co,
          _w$config$grid$column;
        var w = this.w;
        var drawBands = function drawBands(type, count, x1, y1, x2, y2) {
          for (var i = 0, c = 0; i < count; i++, c++) {
            if (c >= w.config.grid[type].colors.length) {
              c = 0;
            }
            _this2._drawGridBandRect({
              c: c,
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2,
              type: type
            });
            y1 += w.globals.gridHeight / tickAmount;
          }
        };
        if (((_w$config$grid$row$co = w.config.grid.row.colors) === null || _w$config$grid$row$co === void 0 ? void 0 : _w$config$grid$row$co.length) > 0) {
          drawBands('row', tickAmount, 0, 0, w.globals.gridWidth, w.globals.gridHeight / tickAmount);
        }
        if (((_w$config$grid$column = w.config.grid.column.colors) === null || _w$config$grid$column === void 0 ? void 0 : _w$config$grid$column.length) > 0) {
          var xc = !w.globals.isBarHorizontal && w.config.xaxis.tickPlacement === 'on' && (w.config.xaxis.type === 'category' || w.config.xaxis.convertedCatToNumeric) ? xCount - 1 : xCount;
          if (w.globals.isXNumeric) {
            xc = w.globals.xAxisScale.result.length - 1;
          }
          var x1 = w.globals.padHorizontal;
          var y1 = 0;
          var x2 = w.globals.padHorizontal + w.globals.gridWidth / xc;
          var y2 = w.globals.gridHeight;
          for (var i = 0, c = 0; i < xCount; i++, c++) {
            if (c >= w.config.grid.column.colors.length) {
              c = 0;
            }
            if (w.config.xaxis.type === 'datetime') {
              var _this$xaxisLabels;
              x1 = this.xaxisLabels[i].position;
              x2 = (((_this$xaxisLabels = this.xaxisLabels[i + 1]) === null || _this$xaxisLabels === void 0 ? void 0 : _this$xaxisLabels.position) || w.globals.gridWidth) - this.xaxisLabels[i].position;
            }
            this._drawGridBandRect({
              c: c,
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2,
              type: 'column'
            });
            x1 += w.globals.gridWidth / xc;
          }
        }
      }
    }]);
    return Grid;
  }();

  var Scales = /*#__PURE__*/function () {
    function Scales(ctx) {
      _classCallCheck(this, Scales);
      this.ctx = ctx;
      this.w = ctx.w;
      this.coreUtils = new CoreUtils(this.ctx);
    }

    // http://stackoverflow.com/questions/326679/choosing-an-attractive-linear-scale-for-a-graphs-y-axis
    // This routine creates the Y axis values for a graph.
    _createClass(Scales, [{
      key: "niceScale",
      value: function niceScale(yMin, yMax) {
        var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
        // Calculate Min amd Max graphical labels and graph
        // increments.
        //
        // Output will be an array of the Y axis values that
        // encompass the Y values.
        var jsPrecision = 1e-11; // JS precision errors
        var w = this.w;
        var gl = w.globals;
        var axisCnf;
        var maxTicks;
        var gotMin;
        var gotMax;
        if (gl.isBarHorizontal) {
          axisCnf = w.config.xaxis;
          // The most ticks we can fit into the svg chart dimensions
          maxTicks = Math.max((gl.svgWidth - 100) / 25, 2); // Guestimate
        } else {
          axisCnf = w.config.yaxis[index];
          maxTicks = Math.max((gl.svgHeight - 100) / 15, 2);
        }
        if (!Utils$1.isNumber(maxTicks)) {
          maxTicks = 10;
        }
        gotMin = axisCnf.min !== undefined && axisCnf.min !== null;
        gotMax = axisCnf.max !== undefined && axisCnf.min !== null;
        var gotStepSize = axisCnf.stepSize !== undefined && axisCnf.stepSize !== null;
        var gotTickAmount = axisCnf.tickAmount !== undefined && axisCnf.tickAmount !== null;
        var ticks = gotTickAmount ? axisCnf.tickAmount : gl.niceScaleDefaultTicks[Math.min(Math.round(maxTicks / 2), gl.niceScaleDefaultTicks.length - 1)];

        // In case we have a multi axis chart:
        // Ensure subsequent series start with the same tickAmount as series[0],
        // because the tick lines are drawn based on series[0]. This does not
        // override user defined options for any yaxis.
        if (gl.isMultipleYAxis && !gotTickAmount && gl.multiAxisTickAmount > 0) {
          ticks = gl.multiAxisTickAmount;
          gotTickAmount = true;
        }
        if (ticks === 'dataPoints') {
          ticks = gl.dataPoints - 1;
        } else {
          // Ensure ticks is an integer
          ticks = Math.abs(Math.round(ticks));
        }
        if (yMin === Number.MIN_VALUE && yMax === 0 || !Utils$1.isNumber(yMin) && !Utils$1.isNumber(yMax) || yMin === Number.MIN_VALUE && yMax === -Number.MAX_VALUE) {
          // when all values are 0
          yMin = Utils$1.isNumber(axisCnf.min) ? axisCnf.min : 0;
          yMax = Utils$1.isNumber(axisCnf.max) ? axisCnf.max : yMin + ticks;
          gl.allSeriesCollapsed = false;
        }
        if (yMin > yMax) {
          // if somehow due to some wrong config, user sent max less than min,
          // adjust the min/max again
          console.warn('axis.min cannot be greater than axis.max: swapping min and max');
          var temp = yMax;
          yMax = yMin;
          yMin = temp;
        } else if (yMin === yMax) {
          // If yMin and yMax are identical, then
          // adjust the yMin and yMax values to actually
          // make a graph. Also avoids division by zero errors.
          yMin = yMin === 0 ? 0 : yMin - 1; // choose an integer in case yValueDecimals=0
          yMax = yMax === 0 ? 2 : yMax + 1; // choose an integer in case yValueDecimals=0
        }
        var result = [];
        if (ticks < 1) {
          ticks = 1;
        }
        var tiks = ticks;

        // Determine Range
        var range = Math.abs(yMax - yMin);

        // Snap min or max to zero if close
        var proximityRatio = 0.15;
        if (!gotMin && yMin > 0 && yMin / range < proximityRatio) {
          yMin = 0;
          gotMin = true;
        }
        if (!gotMax && yMax < 0 && -yMax / range < proximityRatio) {
          yMax = 0;
          gotMax = true;
        }
        range = Math.abs(yMax - yMin);

        // Calculate a pretty step value based on ticks

        // Initial stepSize
        var stepSize = range / tiks;
        var niceStep = stepSize;
        var mag = Math.floor(Math.log10(niceStep));
        var magPow = Math.pow(10, mag);
        // ceil() is used below in conjunction with the values populating
        // niceScaleAllowedMagMsd[][] to ensure that (niceStep * tiks)
        // produces a range that doesn't clip data points after stretching
        // the raw range out a little to match the prospective new range.
        var magMsd = Math.ceil(niceStep / magPow);
        // See globals.js for info on what niceScaleAllowedMagMsd does
        magMsd = gl.niceScaleAllowedMagMsd[gl.yValueDecimal === 0 ? 0 : 1][magMsd];
        niceStep = magMsd * magPow;

        // Initial stepSize
        stepSize = niceStep;

        // Get step value
        if (gl.isBarHorizontal && axisCnf.stepSize && axisCnf.type !== 'datetime') {
          stepSize = axisCnf.stepSize;
          gotStepSize = true;
        } else if (gotStepSize) {
          stepSize = axisCnf.stepSize;
        }
        if (gotStepSize) {
          if (axisCnf.forceNiceScale) {
            // Check that given stepSize is sane with respect to the range.
            //
            // The user can, by setting forceNiceScale = true,
            // define a stepSize that will be scaled to a useful value before
            // it's checked for consistency.
            //
            // If, for example, the range = 4 and the user defined stepSize = 8
            // (or 8000 or 0.0008, etc), then stepSize is inapplicable as
            // it is. Reducing it to 0.8 will fit with 5 ticks.
            //
            var stepMag = Math.floor(Math.log10(stepSize));
            stepSize *= Math.pow(10, mag - stepMag);
          }
        }

        // Start applying some rules
        if (gotMin && gotMax) {
          var crudeStep = range / tiks;
          // min and max (range) cannot be changed
          if (gotTickAmount) {
            if (gotStepSize) {
              if (Utils$1.mod(range, stepSize) != 0) {
                // stepSize conflicts with range
                var gcdStep = Utils$1.getGCD(stepSize, crudeStep);
                // gcdStep is a multiple of range because crudeStep is a multiple.
                // gcdStep is also a multiple of stepSize, so it partially honoured
                // All three could be equal, which would be very nice
                // if the computed stepSize generates too many ticks they will be
                // reduced later, unless the number is prime, in which case,
                // the chart will display all of them or just one (plus the X axis)
                // depending on svg dimensions. Setting forceNiceScale: true will force
                // the display of at least the default number of ticks.
                if (crudeStep / gcdStep < 10) {
                  stepSize = gcdStep;
                } else {
                  // stepSize conflicts and no reasonable adjustment, but must
                  // honour tickAmount
                  stepSize = crudeStep;
                }
              } else {
                // stepSize fits
                if (Utils$1.mod(stepSize, crudeStep) == 0) {
                  // crudeStep is a multiple of stepSize, or vice versa
                  // but we know that crudeStep will generate tickAmount ticks
                  stepSize = crudeStep;
                } else {
                  // stepSize conflicts with tickAmount
                  // if the user is setting up a multi-axis chart and wants
                  // synced axis ticks then they should not define stepSize
                  // or ensure there is no conflict between any of their options
                  // on any axis.
                  crudeStep = stepSize;
                  // De-prioritizing ticks from now on
                  gotTickAmount = false;
                }
              }
            } else {
              // no user stepSize, honour tickAmount
              stepSize = crudeStep;
            }
          } else {
            // default ticks in use, tiks can change
            if (gotStepSize) {
              if (Utils$1.mod(range, stepSize) == 0) {
                // user stepSize fits
                crudeStep = stepSize;
              } else {
                stepSize = crudeStep;
              }
            } else {
              // no user stepSize
              if (Utils$1.mod(range, stepSize) == 0) {
                // generated nice stepSize fits
                crudeStep = stepSize;
              } else {
                tiks = Math.ceil(range / stepSize);
                crudeStep = range / tiks;
                var _gcdStep = Utils$1.getGCD(range, stepSize);
                if (range / _gcdStep < maxTicks) {
                  crudeStep = _gcdStep;
                }
                stepSize = crudeStep;
              }
            }
          }
          tiks = Math.round(range / stepSize);
        } else {
          // Snap range to ticks
          if (!gotMin && !gotMax) {
            if (gl.isMultipleYAxis && gotTickAmount) {
              // Ensure graph doesn't clip.
              var tMin = stepSize * Math.floor(yMin / stepSize);
              var tMax = tMin + stepSize * tiks;
              if (tMax < yMax) {
                stepSize *= 2;
              }
              yMin = tMin;
              tMax = yMax;
              yMax = yMin + stepSize * tiks;
              // Snap min or max to zero if possible
              range = Math.abs(yMax - yMin);
              if (yMin > 0 && yMin < Math.abs(tMax - yMax)) {
                yMin = 0;
                yMax = stepSize * tiks;
              }
              if (yMax < 0 && -yMax < Math.abs(tMin - yMin)) {
                yMax = 0;
                yMin = -stepSize * tiks;
              }
            } else {
              yMin = stepSize * Math.floor(yMin / stepSize);
              yMax = stepSize * Math.ceil(yMax / stepSize);
            }
          } else if (gotMax) {
            if (gotTickAmount) {
              yMin = yMax - stepSize * tiks;
            } else {
              var yMinPrev = yMin;
              yMin = stepSize * Math.floor(yMin / stepSize);
              if (Math.abs(yMax - yMin) / Utils$1.getGCD(range, stepSize) > maxTicks) {
                // Use default ticks to compute yMin then shrinkwrap
                yMin = yMax - stepSize * ticks;
                yMin += stepSize * Math.floor((yMinPrev - yMin) / stepSize);
              }
            }
          } else if (gotMin) {
            if (gotTickAmount) {
              yMax = yMin + stepSize * tiks;
            } else {
              var yMaxPrev = yMax;
              yMax = stepSize * Math.ceil(yMax / stepSize);
              if (Math.abs(yMax - yMin) / Utils$1.getGCD(range, stepSize) > maxTicks) {
                // Use default ticks to compute yMin then shrinkwrap
                yMax = yMin + stepSize * ticks;
                yMax += stepSize * Math.ceil((yMaxPrev - yMax) / stepSize);
              }
            }
          }
          range = Math.abs(yMax - yMin);
          // Final check and possible adjustment of stepSize to prevent
          // overriding the user's min or max choice.
          stepSize = Utils$1.getGCD(range, stepSize);
          tiks = Math.round(range / stepSize);
        }

        // Shrinkwrap ticks to the range
        if (!gotTickAmount && !(gotMin || gotMax)) {
          tiks = Math.ceil((range - jsPrecision) / (stepSize + jsPrecision));
          // No user tickAmount, or min or max, we are free to adjust to avoid a
          // prime number. This helps when reducing ticks for small svg dimensions.
          if (tiks > 16 && Utils$1.getPrimeFactors(tiks).length < 2) {
            tiks++;
          }
        }

        // Prune tiks down to range if series is all integers. Since tiks > range,
        // range is very low (< 10 or so). Skip this step if gotTickAmount is true
        // because either the user set tickAmount or the chart is multiscale and
        // this axis is not determining the number of grid lines.
        if (!gotTickAmount && axisCnf.forceNiceScale && gl.yValueDecimal === 0 && tiks > range) {
          tiks = range;
          stepSize = Math.round(range / tiks);
        }
        if (tiks > maxTicks && (!(gotTickAmount || gotStepSize) || axisCnf.forceNiceScale)) {
          // Reduce the number of ticks nicely if chart svg dimensions shrink too far.
          // The reduced tick set should always be a subset of the full set.
          //
          // This following products of prime factors method works as follows:
          // We compute the prime factors of the full tick count (tiks), then all the
          // possible products of those factors in order from smallest to biggest,
          // until we find a product P such that: tiks/P < maxTicks.
          //
          // Example:
          // Computing products of the prime factors of 30.
          //
          //   tiks | pf  |  1     2     3      4      5      6  <-- compute order
          //   --------------------------------------------------
          //     30 |  5  |              5             5      5  <-- Multiply all
          //        |  3  |        3            3      3      3  <-- primes in each
          //        |  2  |  2                  2             2  <-- column = P
          //   --------------------------------------------------
          //                15    10     6      5      2      1  <-- tiks/P
          //
          //   tiks = 30 has prime factors [2, 3, 5]
          //   The loop below computes the products [2,3,5,6,15,30].
          //   The last product of P = 2*3*5 is skipped since 30/P = 1.
          //   This yields tiks/P = [15,10,6,5,2,1], checked in order until
          //   tiks/P < maxTicks.
          //
          //   Pros:
          //      1) The ticks in the reduced set are always members of the
          //         full set of ticks.
          //   Cons:
          //      1) None: if tiks is prime, we get all or one, nothing between, so
          //      the worst case is to display all, which is the status quo. Really
          //      only a problem visually for larger tick numbers, say, > 7.
          //
          var pf = Utils$1.getPrimeFactors(tiks);
          var last = pf.length - 1;
          var tt = tiks;
          reduceLoop: for (var xFactors = 0; xFactors < last; xFactors++) {
            for (var lowest = 0; lowest <= last - xFactors; lowest++) {
              var stop = Math.min(lowest + xFactors, last);
              var t = tt;
              var div = 1;
              for (var next = lowest; next <= stop; next++) {
                div *= pf[next];
              }
              t /= div;
              if (t < maxTicks) {
                tt = t;
                break reduceLoop;
              }
            }
          }
          if (tt === tiks) {
            // Could not reduce ticks at all, go all in and display just the
            // X axis and one tick.
            stepSize = range;
          } else {
            stepSize = range / tt;
          }
          tiks = Math.round(range / stepSize);
        }

        // Record final tiks for use by other series that call niceScale().
        // Note: some don't, like logarithmicScale(), etc.
        if (gl.isMultipleYAxis && gl.multiAxisTickAmount == 0 && gl.ignoreYAxisIndexes.indexOf(index) < 0) {
          gl.multiAxisTickAmount = tiks;
        }

        // build Y label array.

        var val = yMin - stepSize;
        // Ensure we don't under/over shoot due to JS precision errors.
        // This also fixes (amongst others):
        // https://github.com/apexcharts/apexcharts.js/issues/430
        var err = stepSize * jsPrecision;
        do {
          val += stepSize;
          result.push(Utils$1.stripNumber(val, 7));
        } while (yMax - val > err);
        return {
          result: result,
          niceMin: result[0],
          niceMax: result[result.length - 1]
        };
      }
    }, {
      key: "linearScale",
      value: function linearScale(yMin, yMax) {
        var ticks = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
        var index = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
        var step = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined;
        var range = Math.abs(yMax - yMin);
        var result = [];
        if (yMin === yMax) {
          result = [yMin];
          return {
            result: result,
            niceMin: result[0],
            niceMax: result[result.length - 1]
          };
        }
        ticks = this._adjustTicksForSmallRange(ticks, index, range);
        if (ticks === 'dataPoints') {
          ticks = this.w.globals.dataPoints - 1;
        }
        if (!step) {
          step = range / ticks;
        }
        step = Math.round((step + Number.EPSILON) * 10) / 10;
        if (ticks === Number.MAX_VALUE) {
          ticks = 5;
          step = 1;
        }
        var v = yMin;
        while (ticks >= 0) {
          result.push(v);
          v = Utils$1.preciseAddition(v, step);
          ticks -= 1;
        }
        return {
          result: result,
          niceMin: result[0],
          niceMax: result[result.length - 1]
        };
      }
    }, {
      key: "logarithmicScaleNice",
      value: function logarithmicScaleNice(yMin, yMax, base) {
        // Basic validation to avoid for loop starting at -inf.
        if (yMax <= 0) yMax = Math.max(yMin, base);
        if (yMin <= 0) yMin = Math.min(yMax, base);
        var logs = [];

        // Get powers of base for our max and min
        var logMax = Math.ceil(Math.log(yMax) / Math.log(base) + 1);
        var logMin = Math.floor(Math.log(yMin) / Math.log(base));
        for (var i = logMin; i < logMax; i++) {
          logs.push(Math.pow(base, i));
        }
        return {
          result: logs,
          niceMin: logs[0],
          niceMax: logs[logs.length - 1]
        };
      }
    }, {
      key: "logarithmicScale",
      value: function logarithmicScale(yMin, yMax, base) {
        // Basic validation to avoid for loop starting at -inf.
        if (yMax <= 0) yMax = Math.max(yMin, base);
        if (yMin <= 0) yMin = Math.min(yMax, base);
        var logs = [];

        // Get the logarithmic range.
        var logMax = Math.log(yMax) / Math.log(base);
        var logMin = Math.log(yMin) / Math.log(base);

        // Get the exact logarithmic range.
        // (This is the exact number of multiples of the base there are between yMin and yMax).
        var logRange = logMax - logMin;

        // Round the logarithmic range to get the number of ticks we will create.
        // If the chosen min/max values are multiples of each other WRT the base, this will be neat.
        // If the chosen min/max aren't, we will at least still provide USEFUL ticks.
        var ticks = Math.round(logRange);

        // Get the logarithmic spacing between ticks.
        var logTickSpacing = logRange / ticks;

        // Create as many ticks as there is range in the logs.
        for (var i = 0, logTick = logMin; i < ticks; i++, logTick += logTickSpacing) {
          logs.push(Math.pow(base, logTick));
        }

        // Add a final tick at the yMax.
        logs.push(Math.pow(base, logMax));
        return {
          result: logs,
          niceMin: yMin,
          niceMax: yMax
        };
      }
    }, {
      key: "_adjustTicksForSmallRange",
      value: function _adjustTicksForSmallRange(ticks, index, range) {
        var newTicks = ticks;
        if (typeof index !== 'undefined' && this.w.config.yaxis[index].labels.formatter && this.w.config.yaxis[index].tickAmount === undefined) {
          var formattedVal = Number(this.w.config.yaxis[index].labels.formatter(1));
          if (Utils$1.isNumber(formattedVal) && this.w.globals.yValueDecimal === 0) {
            newTicks = Math.ceil(range);
          }
        }
        return newTicks < ticks ? newTicks : ticks;
      }
    }, {
      key: "setYScaleForIndex",
      value: function setYScaleForIndex(index, minY, maxY) {
        var gl = this.w.globals;
        var cnf = this.w.config;
        var y = gl.isBarHorizontal ? cnf.xaxis : cnf.yaxis[index];
        if (typeof gl.yAxisScale[index] === 'undefined') {
          gl.yAxisScale[index] = [];
        }
        var range = Math.abs(maxY - minY);
        if (y.logarithmic && range <= 5) {
          gl.invalidLogScale = true;
        }
        if (y.logarithmic && range > 5) {
          gl.allSeriesCollapsed = false;
          gl.yAxisScale[index] = y.forceNiceScale ? this.logarithmicScaleNice(minY, maxY, y.logBase) : this.logarithmicScale(minY, maxY, y.logBase);
        } else {
          if (maxY === -Number.MAX_VALUE || !Utils$1.isNumber(maxY) || minY === Number.MAX_VALUE || !Utils$1.isNumber(minY)) {
            // no data in the chart.
            // Either all series collapsed or user passed a blank array.
            // Show the user's yaxis with their scale options but with a range.
            gl.yAxisScale[index] = this.niceScale(Number.MIN_VALUE, 0, index);
          } else {
            // there is some data. Turn off the allSeriesCollapsed flag
            gl.allSeriesCollapsed = false;
            gl.yAxisScale[index] = this.niceScale(minY, maxY, index);
          }
        }
      }
    }, {
      key: "setXScale",
      value: function setXScale(minX, maxX) {
        var w = this.w;
        var gl = w.globals;
        var diff = Math.abs(maxX - minX);
        if (maxX === -Number.MAX_VALUE || !Utils$1.isNumber(maxX)) {
          // no data in the chart. Either all series collapsed or user passed a blank array
          gl.xAxisScale = this.linearScale(0, 10, 10);
        } else {
          var ticks = gl.xTickAmount + 1;
          if (diff < 10 && diff > 1) {
            ticks = diff;
          }
          gl.xAxisScale = this.linearScale(minX, maxX, ticks, 0, w.config.xaxis.stepSize);
        }
        return gl.xAxisScale;
      }
    }, {
      key: "scaleMultipleYAxes",
      value: function scaleMultipleYAxes() {
        var _this = this;
        var cnf = this.w.config;
        var gl = this.w.globals;
        this.coreUtils.setSeriesYAxisMappings();
        var axisSeriesMap = gl.seriesYAxisMap;
        var minYArr = gl.minYArr;
        var maxYArr = gl.maxYArr;

        // Compute min..max for each yaxis
        gl.allSeriesCollapsed = true;
        gl.barGroups = [];
        axisSeriesMap.forEach(function (axisSeries, ai) {
          var groupNames = [];
          axisSeries.forEach(function (as) {
            var group = cnf.series[as].group;
            if (groupNames.indexOf(group) < 0) {
              groupNames.push(group);
            }
          });
          if (axisSeries.length > 0) {
            (function () {
              var minY = Number.MAX_VALUE;
              var maxY = -Number.MAX_VALUE;
              var lowestY = minY;
              var highestY = maxY;
              var seriesType;
              var seriesGroupName;
              if (cnf.chart.stacked) {
                (function () {
                  // Series' on this axis with the same group name will be stacked.
                  // Sum series in each group separately
                  var mapSeries = new Array(gl.dataPoints).fill(0);
                  var sumSeries = [];
                  var posSeries = [];
                  var negSeries = [];
                  groupNames.forEach(function () {
                    sumSeries.push(mapSeries.map(function () {
                      return Number.MIN_VALUE;
                    }));
                    posSeries.push(mapSeries.map(function () {
                      return Number.MIN_VALUE;
                    }));
                    negSeries.push(mapSeries.map(function () {
                      return Number.MIN_VALUE;
                    }));
                  });
                  var _loop = function _loop(i) {
                    // Assume chart type but the first series that has a type overrides.
                    if (!seriesType && cnf.series[axisSeries[i]].type) {
                      seriesType = cnf.series[axisSeries[i]].type;
                    }
                    // Sum all series for this yaxis at each corresponding datapoint
                    // For bar and column charts we need to keep positive and negative
                    // values separate, for each group separately.
                    var si = axisSeries[i];
                    if (cnf.series[si].group) {
                      seriesGroupName = cnf.series[si].group;
                    } else {
                      seriesGroupName = 'axis-'.concat(ai);
                    }
                    var collapsed = !(gl.collapsedSeriesIndices.indexOf(si) < 0 && gl.ancillaryCollapsedSeriesIndices.indexOf(si) < 0);
                    if (!collapsed) {
                      gl.allSeriesCollapsed = false;
                      groupNames.forEach(function (gn, gni) {
                        // Undefined group names will be grouped together as their own
                        // group.
                        if (cnf.series[si].group === gn) {
                          for (var j = 0; j < gl.series[si].length; j++) {
                            var val = gl.series[si][j];
                            if (val >= 0) {
                              posSeries[gni][j] += val;
                            } else {
                              negSeries[gni][j] += val;
                            }
                            sumSeries[gni][j] += val;
                            // For non bar-like series' we need these point max/min values.
                            lowestY = Math.min(lowestY, val);
                            highestY = Math.max(highestY, val);
                          }
                        }
                      });
                    }
                    if (seriesType === 'bar' || seriesType === 'column') {
                      gl.barGroups.push(seriesGroupName);
                    }
                  };
                  for (var i = 0; i < axisSeries.length; i++) {
                    _loop(i);
                  }
                  if (!seriesType) {
                    seriesType = cnf.chart.type;
                  }
                  if (seriesType === 'bar' || seriesType === 'column') {
                    groupNames.forEach(function (gn, gni) {
                      minY = Math.min(minY, Math.min.apply(null, negSeries[gni]));
                      maxY = Math.max(maxY, Math.max.apply(null, posSeries[gni]));
                    });
                  } else {
                    groupNames.forEach(function (gn, gni) {
                      lowestY = Math.min(lowestY, Math.min.apply(null, sumSeries[gni]));
                      highestY = Math.max(highestY, Math.max.apply(null, sumSeries[gni]));
                    });
                    minY = lowestY;
                    maxY = highestY;
                  }
                  if (minY === Number.MIN_VALUE && maxY === Number.MIN_VALUE) {
                    // No series data
                    maxY = -Number.MAX_VALUE;
                  }
                })();
              } else {
                for (var i = 0; i < axisSeries.length; i++) {
                  var si = axisSeries[i];
                  minY = Math.min(minY, minYArr[si]);
                  maxY = Math.max(maxY, maxYArr[si]);
                  var collapsed = !(gl.collapsedSeriesIndices.indexOf(si) < 0 && gl.ancillaryCollapsedSeriesIndices.indexOf(si) < 0);
                  if (!collapsed) {
                    gl.allSeriesCollapsed = false;
                  }
                }
              }
              if (cnf.yaxis[ai].min !== undefined) {
                if (typeof cnf.yaxis[ai].min === 'function') {
                  minY = cnf.yaxis[ai].min(minY);
                } else {
                  minY = cnf.yaxis[ai].min;
                }
              }
              if (cnf.yaxis[ai].max !== undefined) {
                if (typeof cnf.yaxis[ai].max === 'function') {
                  maxY = cnf.yaxis[ai].max(maxY);
                } else {
                  maxY = cnf.yaxis[ai].max;
                }
              }
              gl.barGroups = gl.barGroups.filter(function (v, i, a) {
                return a.indexOf(v) === i;
              });
              // Set the scale for this yaxis
              _this.setYScaleForIndex(ai, minY, maxY);
              // Set individual series min and max to nice values
              axisSeries.forEach(function (si) {
                minYArr[si] = gl.yAxisScale[ai].niceMin;
                maxYArr[si] = gl.yAxisScale[ai].niceMax;
              });
            })();
          } else {
            // No series referenced by this yaxis
            _this.setYScaleForIndex(ai, 0, -Number.MAX_VALUE);
          }
        });
      }
    }]);
    return Scales;
  }();

  /**
   * Range is used to generates values between min and max.
   *
   * @module Range
   **/
  var Range = /*#__PURE__*/function () {
    function Range(ctx) {
      _classCallCheck(this, Range);
      this.ctx = ctx;
      this.w = ctx.w;
      this.scales = new Scales(ctx);
    }
    _createClass(Range, [{
      key: "init",
      value: function init() {
        this.setYRange();
        this.setXRange();
        this.setZRange();
      }
    }, {
      key: "getMinYMaxY",
      value: function getMinYMaxY(startingSeriesIndex) {
        var lowestY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Number.MAX_VALUE;
        var highestY = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -Number.MAX_VALUE;
        var endingSeriesIndex = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
        var cnf = this.w.config;
        var gl = this.w.globals;
        var maxY = -Number.MAX_VALUE;
        var minY = Number.MIN_VALUE;
        if (endingSeriesIndex === null) {
          endingSeriesIndex = startingSeriesIndex + 1;
        }
        var series = gl.series;
        var seriesMin = series;
        var seriesMax = series;
        if (cnf.chart.type === 'candlestick') {
          seriesMin = gl.seriesCandleL;
          seriesMax = gl.seriesCandleH;
        } else if (cnf.chart.type === 'boxPlot') {
          seriesMin = gl.seriesCandleO;
          seriesMax = gl.seriesCandleC;
        } else if (gl.isRangeData) {
          seriesMin = gl.seriesRangeStart;
          seriesMax = gl.seriesRangeEnd;
        }
        var autoScaleYaxis = false;
        if (gl.seriesX.length >= endingSeriesIndex) {
          var _gl$brushSource;
          // Eventually brushSource will be set if the current chart is a target.
          // That is, after the appropriate event causes us to update.
          var brush = (_gl$brushSource = gl.brushSource) === null || _gl$brushSource === void 0 ? void 0 : _gl$brushSource.w.config.chart.brush;
          if (cnf.chart.zoom.enabled && cnf.chart.zoom.autoScaleYaxis || brush !== null && brush !== void 0 && brush.enabled && brush !== null && brush !== void 0 && brush.autoScaleYaxis) {
            autoScaleYaxis = true;
          }
        }
        for (var i = startingSeriesIndex; i < endingSeriesIndex; i++) {
          gl.dataPoints = Math.max(gl.dataPoints, series[i].length);
          var seriesType = cnf.series[i].type;
          if (gl.categoryLabels.length) {
            gl.dataPoints = gl.categoryLabels.filter(function (label) {
              return typeof label !== 'undefined';
            }).length;
          }
          if (gl.labels.length && cnf.xaxis.type !== 'datetime' && gl.series.reduce(function (a, c) {
            return a + c.length;
          }, 0) !== 0) {
            // the condition cnf.xaxis.type !== 'datetime' fixes #3897 and #3905
            gl.dataPoints = Math.max(gl.dataPoints, gl.labels.length);
          }
          var firstXIndex = 0;
          var lastXIndex = series[i].length - 1;
          if (autoScaleYaxis) {
            // Scale the Y axis to the min..max within the possibly zoomed X axis domain.
            if (cnf.xaxis.min) {
              for (; firstXIndex < lastXIndex && gl.seriesX[i][firstXIndex] < cnf.xaxis.min; firstXIndex++) {}
            }
            if (cnf.xaxis.max) {
              for (; lastXIndex > firstXIndex && gl.seriesX[i][lastXIndex] > cnf.xaxis.max; lastXIndex--) {}
            }
          }
          for (var j = firstXIndex; j <= lastXIndex && j < gl.series[i].length; j++) {
            var val = series[i][j];
            if (val !== null && Utils$1.isNumber(val)) {
              if (typeof seriesMax[i][j] !== 'undefined') {
                maxY = Math.max(maxY, seriesMax[i][j]);
                lowestY = Math.min(lowestY, seriesMax[i][j]);
              }
              if (typeof seriesMin[i][j] !== 'undefined') {
                lowestY = Math.min(lowestY, seriesMin[i][j]);
                highestY = Math.max(highestY, seriesMin[i][j]);
              }

              // These series arrays are dual purpose:
              // Array      : CandleO, CandleH, CandleM, CandleL, CandleC
              // Candlestick: O        H                 L        C
              // Boxplot    : Min      Q1       Median   Q3       Max
              switch (seriesType) {
                case 'candlestick':
                  {
                    if (typeof gl.seriesCandleC[i][j] !== 'undefined') {
                      maxY = Math.max(maxY, gl.seriesCandleH[i][j]);
                      lowestY = Math.min(lowestY, gl.seriesCandleL[i][j]);
                    }
                  }
                  break;
                case 'boxPlot':
                  {
                    if (typeof gl.seriesCandleC[i][j] !== 'undefined') {
                      maxY = Math.max(maxY, gl.seriesCandleC[i][j]);
                      lowestY = Math.min(lowestY, gl.seriesCandleO[i][j]);
                    }
                  }
                  break;
              }

              // there is a combo chart and the specified series in not either
              // candlestick, boxplot, or rangeArea/rangeBar; find the max there.
              if (seriesType && seriesType !== 'candlestick' && seriesType !== 'boxPlot' && seriesType !== 'rangeArea' && seriesType !== 'rangeBar') {
                maxY = Math.max(maxY, gl.series[i][j]);
                lowestY = Math.min(lowestY, gl.series[i][j]);
              }
              highestY = maxY;
              if (gl.seriesGoals[i] && gl.seriesGoals[i][j] && Array.isArray(gl.seriesGoals[i][j])) {
                gl.seriesGoals[i][j].forEach(function (g) {
                  if (minY !== Number.MIN_VALUE) {
                    minY = Math.min(minY, g.value);
                    lowestY = minY;
                  }
                  maxY = Math.max(maxY, g.value);
                  highestY = maxY;
                });
              }
              if (Utils$1.isFloat(val)) {
                val = Utils$1.noExponents(val);
                gl.yValueDecimal = Math.max(gl.yValueDecimal, val.toString().split('.')[1].length);
              }
              if (minY > seriesMin[i][j] && seriesMin[i][j] < 0) {
                minY = seriesMin[i][j];
              }
            } else {
              gl.hasNullValues = true;
            }
          }
          if (seriesType === 'bar' || seriesType === 'column') {
            if (minY < 0 && maxY < 0) {
              // all negative values in a bar series, hence make the max to 0
              maxY = 0;
              highestY = Math.max(highestY, 0);
            }
            if (minY === Number.MIN_VALUE) {
              minY = 0;
              lowestY = Math.min(lowestY, 0);
            }
          }
        }
        if (cnf.chart.type === 'rangeBar' && gl.seriesRangeStart.length && gl.isBarHorizontal) {
          minY = lowestY;
        }
        if (cnf.chart.type === 'bar') {
          if (minY < 0 && maxY < 0) {
            // all negative values in a bar chart, hence make the max to 0
            maxY = 0;
          }
          if (minY === Number.MIN_VALUE) {
            minY = 0;
          }
        }
        return {
          minY: minY,
          maxY: maxY,
          lowestY: lowestY,
          highestY: highestY
        };
      }
    }, {
      key: "setYRange",
      value: function setYRange() {
        var gl = this.w.globals;
        var cnf = this.w.config;
        gl.maxY = -Number.MAX_VALUE;
        gl.minY = Number.MIN_VALUE;
        var lowestYInAllSeries = Number.MAX_VALUE;
        var minYMaxY;
        if (gl.isMultipleYAxis) {
          // we need to get minY and maxY for multiple y axis
          lowestYInAllSeries = Number.MAX_VALUE;
          for (var i = 0; i < gl.series.length; i++) {
            minYMaxY = this.getMinYMaxY(i);
            gl.minYArr[i] = minYMaxY.lowestY;
            gl.maxYArr[i] = minYMaxY.highestY;
            lowestYInAllSeries = Math.min(lowestYInAllSeries, minYMaxY.lowestY);
          }
        }

        // and then, get the minY and maxY from all series
        minYMaxY = this.getMinYMaxY(0, lowestYInAllSeries, null, gl.series.length);
        if (cnf.chart.type === 'bar') {
          gl.minY = minYMaxY.minY;
          gl.maxY = minYMaxY.maxY;
        } else {
          gl.minY = minYMaxY.lowestY;
          gl.maxY = minYMaxY.highestY;
        }
        lowestYInAllSeries = minYMaxY.lowestY;
        if (cnf.chart.stacked) {
          this._setStackedMinMax();
        }

        // if the numbers are too big, reduce the range
        // for eg, if number is between 100000-110000, putting 0 as the lowest
        // value is not so good idea. So change the gl.minY for
        // line/area/scatter/candlesticks/boxPlot/vertical rangebar
        if (cnf.chart.type === 'line' || cnf.chart.type === 'area' || cnf.chart.type === 'scatter' || cnf.chart.type === 'candlestick' || cnf.chart.type === 'boxPlot' || cnf.chart.type === 'rangeBar' && !gl.isBarHorizontal) {
          if (gl.minY === Number.MIN_VALUE && lowestYInAllSeries !== -Number.MAX_VALUE && lowestYInAllSeries !== gl.maxY // single value possibility
          ) {
            gl.minY = lowestYInAllSeries;
          }
        } else {
          gl.minY = gl.minY !== Number.MIN_VALUE ? Math.min(minYMaxY.minY, gl.minY) : minYMaxY.minY;
        }
        cnf.yaxis.forEach(function (yaxe, index) {
          // override all min/max values by user defined values (y axis)
          if (yaxe.max !== undefined) {
            if (typeof yaxe.max === 'number') {
              gl.maxYArr[index] = yaxe.max;
            } else if (typeof yaxe.max === 'function') {
              // fixes apexcharts.js/issues/2098
              gl.maxYArr[index] = yaxe.max(gl.isMultipleYAxis ? gl.maxYArr[index] : gl.maxY);
            }

            // gl.maxY is for single y-axis chart, it will be ignored in multi-yaxis
            gl.maxY = gl.maxYArr[index];
          }
          if (yaxe.min !== undefined) {
            if (typeof yaxe.min === 'number') {
              gl.minYArr[index] = yaxe.min;
            } else if (typeof yaxe.min === 'function') {
              // fixes apexcharts.js/issues/2098
              gl.minYArr[index] = yaxe.min(gl.isMultipleYAxis ? gl.minYArr[index] === Number.MIN_VALUE ? 0 : gl.minYArr[index] : gl.minY);
            }
            // gl.minY is for single y-axis chart, it will be ignored in multi-yaxis
            gl.minY = gl.minYArr[index];
          }
        });

        // for horizontal bar charts, we need to check xaxis min/max as user may have specified there
        if (gl.isBarHorizontal) {
          var minmax = ['min', 'max'];
          minmax.forEach(function (m) {
            if (cnf.xaxis[m] !== undefined && typeof cnf.xaxis[m] === 'number') {
              m === 'min' ? gl.minY = cnf.xaxis[m] : gl.maxY = cnf.xaxis[m];
            }
          });
        }
        if (gl.isMultipleYAxis) {
          this.scales.scaleMultipleYAxes();
          gl.minY = lowestYInAllSeries;
        } else {
          this.scales.setYScaleForIndex(0, gl.minY, gl.maxY);
          gl.minY = gl.yAxisScale[0].niceMin;
          gl.maxY = gl.yAxisScale[0].niceMax;
          gl.minYArr[0] = gl.minY;
          gl.maxYArr[0] = gl.maxY;
        }
        gl.barGroups = [];
        gl.lineGroups = [];
        gl.areaGroups = [];
        cnf.series.forEach(function (s) {
          var type = s.type || cnf.chart.type;
          switch (type) {
            case 'bar':
            case 'column':
              gl.barGroups.push(s.group);
              break;
            case 'line':
              gl.lineGroups.push(s.group);
              break;
            case 'area':
              gl.areaGroups.push(s.group);
              break;
          }
        });
        // Uniquify the group names in each stackable chart type.
        gl.barGroups = gl.barGroups.filter(function (v, i, a) {
          return a.indexOf(v) === i;
        });
        gl.lineGroups = gl.lineGroups.filter(function (v, i, a) {
          return a.indexOf(v) === i;
        });
        gl.areaGroups = gl.areaGroups.filter(function (v, i, a) {
          return a.indexOf(v) === i;
        });
        return {
          minY: gl.minY,
          maxY: gl.maxY,
          minYArr: gl.minYArr,
          maxYArr: gl.maxYArr,
          yAxisScale: gl.yAxisScale
        };
      }
    }, {
      key: "setXRange",
      value: function setXRange() {
        var gl = this.w.globals;
        var cnf = this.w.config;
        var isXNumeric = cnf.xaxis.type === 'numeric' || cnf.xaxis.type === 'datetime' || cnf.xaxis.type === 'category' && !gl.noLabelsProvided || gl.noLabelsProvided || gl.isXNumeric;
        var getInitialMinXMaxX = function getInitialMinXMaxX() {
          for (var i = 0; i < gl.series.length; i++) {
            if (gl.labels[i]) {
              for (var j = 0; j < gl.labels[i].length; j++) {
                if (gl.labels[i][j] !== null && Utils$1.isNumber(gl.labels[i][j])) {
                  gl.maxX = Math.max(gl.maxX, gl.labels[i][j]);
                  gl.initialMaxX = Math.max(gl.maxX, gl.labels[i][j]);
                  gl.minX = Math.min(gl.minX, gl.labels[i][j]);
                  gl.initialMinX = Math.min(gl.minX, gl.labels[i][j]);
                }
              }
            }
          }
        };
        // minX maxX starts here
        if (gl.isXNumeric) {
          getInitialMinXMaxX();
        }
        if (gl.noLabelsProvided) {
          if (cnf.xaxis.categories.length === 0) {
            gl.maxX = gl.labels[gl.labels.length - 1];
            gl.initialMaxX = gl.labels[gl.labels.length - 1];
            gl.minX = 1;
            gl.initialMinX = 1;
          }
        }
        if (gl.isXNumeric || gl.noLabelsProvided || gl.dataFormatXNumeric) {
          var ticks = 10;
          if (cnf.xaxis.tickAmount === undefined) {
            ticks = Math.round(gl.svgWidth / 150);

            // no labels provided and total number of dataPoints is less than 30
            if (cnf.xaxis.type === 'numeric' && gl.dataPoints < 30) {
              ticks = gl.dataPoints - 1;
            }

            // this check is for when ticks exceeds total datapoints and that would result in duplicate labels
            if (ticks > gl.dataPoints && gl.dataPoints !== 0) {
              ticks = gl.dataPoints - 1;
            }
          } else if (cnf.xaxis.tickAmount === 'dataPoints') {
            if (gl.series.length > 1) {
              ticks = gl.series[gl.maxValsInArrayIndex].length - 1;
            }
            if (gl.isXNumeric) {
              var diff = gl.maxX - gl.minX;
              if (diff < 30) {
                ticks = diff - 1;
              }
            }
          } else {
            ticks = cnf.xaxis.tickAmount;
          }
          gl.xTickAmount = ticks;

          // override all min/max values by user defined values (x axis)
          if (cnf.xaxis.max !== undefined && typeof cnf.xaxis.max === 'number') {
            gl.maxX = cnf.xaxis.max;
          }
          if (cnf.xaxis.min !== undefined && typeof cnf.xaxis.min === 'number') {
            gl.minX = cnf.xaxis.min;
          }

          // if range is provided, adjust the new minX
          if (cnf.xaxis.range !== undefined) {
            gl.minX = gl.maxX - cnf.xaxis.range;
          }
          if (gl.minX !== Number.MAX_VALUE && gl.maxX !== -Number.MAX_VALUE) {
            if (cnf.xaxis.convertedCatToNumeric && !gl.dataFormatXNumeric) {
              var catScale = [];
              for (var i = gl.minX - 1; i < gl.maxX; i++) {
                catScale.push(i + 1);
              }
              gl.xAxisScale = {
                result: catScale,
                niceMin: catScale[0],
                niceMax: catScale[catScale.length - 1]
              };
            } else {
              gl.xAxisScale = this.scales.setXScale(gl.minX, gl.maxX);
            }
          } else {
            gl.xAxisScale = this.scales.linearScale(0, ticks, ticks, 0, cnf.xaxis.stepSize);
            if (gl.noLabelsProvided && gl.labels.length > 0) {
              gl.xAxisScale = this.scales.linearScale(1, gl.labels.length, ticks - 1, 0, cnf.xaxis.stepSize);

              // this is the only place seriesX is again mutated
              gl.seriesX = gl.labels.slice();
            }
          }
          // we will still store these labels as the count for this will be different (to draw grid and labels placement)
          if (isXNumeric) {
            gl.labels = gl.xAxisScale.result.slice();
          }
        }
        if (gl.isBarHorizontal && gl.labels.length) {
          gl.xTickAmount = gl.labels.length;
        }

        // single dataPoint
        this._handleSingleDataPoint();

        // minimum x difference to calculate bar width in numeric bars
        this._getMinXDiff();
        return {
          minX: gl.minX,
          maxX: gl.maxX
        };
      }
    }, {
      key: "setZRange",
      value: function setZRange() {
        // minZ, maxZ starts here
        var gl = this.w.globals;
        if (!gl.isDataXYZ) return;
        for (var i = 0; i < gl.series.length; i++) {
          if (typeof gl.seriesZ[i] !== 'undefined') {
            for (var j = 0; j < gl.seriesZ[i].length; j++) {
              if (gl.seriesZ[i][j] !== null && Utils$1.isNumber(gl.seriesZ[i][j])) {
                gl.maxZ = Math.max(gl.maxZ, gl.seriesZ[i][j]);
                gl.minZ = Math.min(gl.minZ, gl.seriesZ[i][j]);
              }
            }
          }
        }
      }
    }, {
      key: "_handleSingleDataPoint",
      value: function _handleSingleDataPoint() {
        var gl = this.w.globals;
        var cnf = this.w.config;
        if (gl.minX === gl.maxX) {
          var datetimeObj = new DateTime(this.ctx);
          if (cnf.xaxis.type === 'datetime') {
            var newMinX = datetimeObj.getDate(gl.minX);
            if (cnf.xaxis.labels.datetimeUTC) {
              newMinX.setUTCDate(newMinX.getUTCDate() - 2);
            } else {
              newMinX.setDate(newMinX.getDate() - 2);
            }
            gl.minX = new Date(newMinX).getTime();
            var newMaxX = datetimeObj.getDate(gl.maxX);
            if (cnf.xaxis.labels.datetimeUTC) {
              newMaxX.setUTCDate(newMaxX.getUTCDate() + 2);
            } else {
              newMaxX.setDate(newMaxX.getDate() + 2);
            }
            gl.maxX = new Date(newMaxX).getTime();
          } else if (cnf.xaxis.type === 'numeric' || cnf.xaxis.type === 'category' && !gl.noLabelsProvided) {
            gl.minX = gl.minX - 2;
            gl.initialMinX = gl.minX;
            gl.maxX = gl.maxX + 2;
            gl.initialMaxX = gl.maxX;
          }
        }
      }
    }, {
      key: "_getMinXDiff",
      value: function _getMinXDiff() {
        var gl = this.w.globals;
        if (gl.isXNumeric) {
          // get the least x diff if numeric x axis is present
          gl.seriesX.forEach(function (sX, i) {
            if (sX.length === 1) {
              // a small hack to prevent overlapping multiple bars when there is just 1 datapoint in bar series.
              // fix #811
              sX.push(gl.seriesX[gl.maxValsInArrayIndex][gl.seriesX[gl.maxValsInArrayIndex].length - 1]);
            }

            // fix #983 (clone the array to avoid side effects)
            var seriesX = sX.slice();
            seriesX.sort(function (a, b) {
              return a - b;
            });
            seriesX.forEach(function (s, j) {
              if (j > 0) {
                var xDiff = s - seriesX[j - 1];
                if (xDiff > 0) {
                  gl.minXDiff = Math.min(xDiff, gl.minXDiff);
                }
              }
            });
            if (gl.dataPoints === 1 || gl.minXDiff === Number.MAX_VALUE) {
              // fixes apexcharts.js #1221
              gl.minXDiff = 0.5;
            }
          });
        }
      }
    }, {
      key: "_setStackedMinMax",
      value: function _setStackedMinMax() {
        var _this = this;
        var gl = this.w.globals;
        // for stacked charts, we calculate each series's parallel values.
        // i.e, series[0][j] + series[1][j] .... [series[i.length][j]]
        // and get the max out of it

        if (!gl.series.length) return;
        var seriesGroups = gl.seriesGroups;
        if (!seriesGroups.length) {
          seriesGroups = [this.w.globals.seriesNames.map(function (name) {
            return name;
          })];
        }
        var stackedPoss = {};
        var stackedNegs = {};
        seriesGroups.forEach(function (group) {
          stackedPoss[group] = [];
          stackedNegs[group] = [];
          var indicesOfSeriesInGroup = _this.w.config.series.map(function (serie, si) {
            return group.indexOf(gl.seriesNames[si]) > -1 ? si : null;
          }).filter(function (f) {
            return f !== null;
          });
          indicesOfSeriesInGroup.forEach(function (i) {
            for (var j = 0; j < gl.series[gl.maxValsInArrayIndex].length; j++) {
              var _this$w$config$series, _this$w$config$series2, _this$w$config$series3, _this$w$config$series4;
              if (typeof stackedPoss[group][j] === 'undefined') {
                stackedPoss[group][j] = 0;
                stackedNegs[group][j] = 0;
              }
              var stackSeries = _this.w.config.chart.stacked && !gl.comboCharts || _this.w.config.chart.stacked && gl.comboCharts && (!_this.w.config.chart.stackOnlyBar || ((_this$w$config$series = _this.w.config.series) === null || _this$w$config$series === void 0 ? void 0 : (_this$w$config$series2 = _this$w$config$series[i]) === null || _this$w$config$series2 === void 0 ? void 0 : _this$w$config$series2.type) === 'bar' || ((_this$w$config$series3 = _this.w.config.series) === null || _this$w$config$series3 === void 0 ? void 0 : (_this$w$config$series4 = _this$w$config$series3[i]) === null || _this$w$config$series4 === void 0 ? void 0 : _this$w$config$series4.type) === 'column');
              if (stackSeries) {
                if (gl.series[i][j] !== null && Utils$1.isNumber(gl.series[i][j])) {
                  gl.series[i][j] > 0 ? stackedPoss[group][j] += parseFloat(gl.series[i][j]) + 0.0001 : stackedNegs[group][j] += parseFloat(gl.series[i][j]);
                }
              }
            }
          });
        });
        Object.entries(stackedPoss).forEach(function (_ref) {
          var _ref2 = _slicedToArray(_ref, 1),
            key = _ref2[0];
          stackedPoss[key].forEach(function (_, stgi) {
            gl.maxY = Math.max(gl.maxY, stackedPoss[key][stgi]);
            gl.minY = Math.min(gl.minY, stackedNegs[key][stgi]);
          });
        });
      }
    }]);
    return Range;
  }();

  /**
   * ApexCharts YAxis Class for drawing Y-Axis.
   *
   * @module YAxis
   **/
  var YAxis = /*#__PURE__*/function () {
    function YAxis(ctx, elgrid) {
      _classCallCheck(this, YAxis);
      this.ctx = ctx;
      this.elgrid = elgrid;
      this.w = ctx.w;
      var w = this.w;
      this.xaxisFontSize = w.config.xaxis.labels.style.fontSize;
      this.axisFontFamily = w.config.xaxis.labels.style.fontFamily;
      this.xaxisForeColors = w.config.xaxis.labels.style.colors;
      this.isCategoryBarHorizontal = w.config.chart.type === 'bar' && w.config.plotOptions.bar.horizontal;
      this.xAxisoffX = w.config.xaxis.position === 'bottom' ? w.globals.gridHeight : 0;
      this.drawnLabels = [];
      this.axesUtils = new AxesUtils(ctx);
    }
    _createClass(YAxis, [{
      key: "drawYaxis",
      value: function drawYaxis(realIndex) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var yaxisStyle = w.config.yaxis[realIndex].labels.style;
        var yaxisFontSize = yaxisStyle.fontSize,
          yaxisFontFamily = yaxisStyle.fontFamily,
          yaxisFontWeight = yaxisStyle.fontWeight;
        var elYaxis = graphics.group({
          class: 'apexcharts-yaxis',
          rel: realIndex,
          transform: "translate(".concat(w.globals.translateYAxisX[realIndex], ", 0)")
        });
        if (this.axesUtils.isYAxisHidden(realIndex)) return elYaxis;
        var elYaxisTexts = graphics.group({
          class: 'apexcharts-yaxis-texts-g'
        });
        elYaxis.add(elYaxisTexts);
        var tickAmount = w.globals.yAxisScale[realIndex].result.length - 1;
        var labelsDivider = w.globals.gridHeight / tickAmount;
        var lbFormatter = w.globals.yLabelFormatters[realIndex];
        var labels = this.axesUtils.checkForReversedLabels(realIndex, w.globals.yAxisScale[realIndex].result.slice());
        if (w.config.yaxis[realIndex].labels.show) {
          var lY = w.globals.translateY + w.config.yaxis[realIndex].labels.offsetY;
          if (w.globals.isBarHorizontal) lY = 0;else if (w.config.chart.type === 'heatmap') lY -= labelsDivider / 2;
          lY += parseInt(yaxisFontSize, 10) / 3;
          for (var i = tickAmount; i >= 0; i--) {
            var val = lbFormatter(labels[i], i, w);
            var xPad = w.config.yaxis[realIndex].labels.padding;
            if (w.config.yaxis[realIndex].opposite && w.config.yaxis.length !== 0) xPad *= -1;
            var textAnchor = this.getTextAnchor(w.config.yaxis[realIndex].labels.align, w.config.yaxis[realIndex].opposite);
            var yColors = this.axesUtils.getYAxisForeColor(yaxisStyle.colors, realIndex);
            var foreColor = Array.isArray(yColors) ? yColors[i] : yColors;
            var existingYLabels = Utils$1.listToArray(w.globals.dom.baseEl.querySelectorAll(".apexcharts-yaxis[rel='".concat(realIndex, "'] .apexcharts-yaxis-label tspan"))).map(function (label) {
              return label.textContent;
            });
            var label = graphics.drawText({
              x: xPad,
              y: lY,
              text: existingYLabels.includes(val) && !w.config.yaxis[realIndex].labels.showDuplicates ? '' : val,
              textAnchor: textAnchor,
              fontSize: yaxisFontSize,
              fontFamily: yaxisFontFamily,
              fontWeight: yaxisFontWeight,
              maxWidth: w.config.yaxis[realIndex].labels.maxWidth,
              foreColor: foreColor,
              isPlainText: false,
              cssClass: "apexcharts-yaxis-label ".concat(yaxisStyle.cssClass)
            });
            elYaxisTexts.add(label);
            this.addTooltip(label, val);
            if (w.config.yaxis[realIndex].labels.rotate !== 0) {
              this.rotateLabel(graphics, label, firstLabel, w.config.yaxis[realIndex].labels.rotate);
            }
            lY += labelsDivider;
          }
        }
        this.addYAxisTitle(graphics, elYaxis, realIndex);
        this.addAxisBorder(graphics, elYaxis, realIndex, tickAmount, labelsDivider);
        return elYaxis;
      }
    }, {
      key: "getTextAnchor",
      value: function getTextAnchor(align, opposite) {
        if (align === 'left') return 'start';
        if (align === 'center') return 'middle';
        if (align === 'right') return 'end';
        return opposite ? 'start' : 'end';
      }
    }, {
      key: "addTooltip",
      value: function addTooltip(label, val) {
        var elTooltipTitle = document.createElementNS(this.w.globals.SVGNS, 'title');
        elTooltipTitle.textContent = Array.isArray(val) ? val.join(' ') : val;
        label.node.appendChild(elTooltipTitle);
      }
    }, {
      key: "rotateLabel",
      value: function rotateLabel(graphics, label, firstLabel, rotate) {
        var firstLabelCenter = graphics.rotateAroundCenter(firstLabel.node);
        var labelCenter = graphics.rotateAroundCenter(label.node);
        label.node.setAttribute('transform', "rotate(".concat(rotate, " ").concat(firstLabelCenter.x, " ").concat(labelCenter.y, ")"));
      }
    }, {
      key: "addYAxisTitle",
      value: function addYAxisTitle(graphics, elYaxis, realIndex) {
        var w = this.w;
        if (w.config.yaxis[realIndex].title.text !== undefined) {
          var elYaxisTitle = graphics.group({
            class: 'apexcharts-yaxis-title'
          });
          var x = w.config.yaxis[realIndex].opposite ? w.globals.translateYAxisX[realIndex] : 0;
          var elYAxisTitleText = graphics.drawText({
            x: x,
            y: w.globals.gridHeight / 2 + w.globals.translateY + w.config.yaxis[realIndex].title.offsetY,
            text: w.config.yaxis[realIndex].title.text,
            textAnchor: 'end',
            foreColor: w.config.yaxis[realIndex].title.style.color,
            fontSize: w.config.yaxis[realIndex].title.style.fontSize,
            fontWeight: w.config.yaxis[realIndex].title.style.fontWeight,
            fontFamily: w.config.yaxis[realIndex].title.style.fontFamily,
            cssClass: "apexcharts-yaxis-title-text ".concat(w.config.yaxis[realIndex].title.style.cssClass)
          });
          elYaxisTitle.add(elYAxisTitleText);
          elYaxis.add(elYaxisTitle);
        }
      }
    }, {
      key: "addAxisBorder",
      value: function addAxisBorder(graphics, elYaxis, realIndex, tickAmount, labelsDivider) {
        var w = this.w;
        var axisBorder = w.config.yaxis[realIndex].axisBorder;
        var x = 31 + axisBorder.offsetX;
        if (w.config.yaxis[realIndex].opposite) x = -31 - axisBorder.offsetX;
        if (axisBorder.show) {
          var elVerticalLine = graphics.drawLine(x, w.globals.translateY + axisBorder.offsetY - 2, x, w.globals.gridHeight + w.globals.translateY + axisBorder.offsetY + 2, axisBorder.color, 0, axisBorder.width);
          elYaxis.add(elVerticalLine);
        }
        if (w.config.yaxis[realIndex].axisTicks.show) {
          this.axesUtils.drawYAxisTicks(x, tickAmount, axisBorder, w.config.yaxis[realIndex].axisTicks, realIndex, labelsDivider, elYaxis);
        }
      }
    }, {
      key: "drawYaxisInversed",
      value: function drawYaxisInversed(realIndex) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var elXaxis = graphics.group({
          class: 'apexcharts-xaxis apexcharts-yaxis-inversed'
        });
        var elXaxisTexts = graphics.group({
          class: 'apexcharts-xaxis-texts-g',
          transform: "translate(".concat(w.globals.translateXAxisX, ", ").concat(w.globals.translateXAxisY, ")")
        });
        elXaxis.add(elXaxisTexts);
        var tickAmount = w.globals.yAxisScale[realIndex].result.length - 1;
        var labelsDivider = w.globals.gridWidth / tickAmount + 0.1;
        var l = labelsDivider + w.config.xaxis.labels.offsetX;
        var lbFormatter = w.globals.xLabelFormatter;
        var labels = this.axesUtils.checkForReversedLabels(realIndex, w.globals.yAxisScale[realIndex].result.slice());
        var timescaleLabels = w.globals.timescaleLabels;
        if (timescaleLabels.length > 0) {
          this.xaxisLabels = timescaleLabels.slice();
          labels = timescaleLabels.slice();
          tickAmount = labels.length;
        }
        if (w.config.xaxis.labels.show) {
          for (var i = timescaleLabels.length ? 0 : tickAmount; timescaleLabels.length ? i < timescaleLabels.length : i >= 0; timescaleLabels.length ? i++ : i--) {
            var val = lbFormatter(labels[i], i, w);
            var x = w.globals.gridWidth + w.globals.padHorizontal - (l - labelsDivider + w.config.xaxis.labels.offsetX);
            if (timescaleLabels.length) {
              var label = this.axesUtils.getLabel(labels, timescaleLabels, x, i, this.drawnLabels, this.xaxisFontSize);
              x = label.x;
              val = label.text;
              this.drawnLabels.push(label.text);
              if (i === 0 && w.globals.skipFirstTimelinelabel) val = '';
              if (i === labels.length - 1 && w.globals.skipLastTimelinelabel) val = '';
            }
            var elTick = graphics.drawText({
              x: x,
              y: this.xAxisoffX + w.config.xaxis.labels.offsetY + 30 - (w.config.xaxis.position === 'top' ? w.globals.xAxisHeight + w.config.xaxis.axisTicks.height - 2 : 0),
              text: val,
              textAnchor: 'middle',
              foreColor: Array.isArray(this.xaxisForeColors) ? this.xaxisForeColors[realIndex] : this.xaxisForeColors,
              fontSize: this.xaxisFontSize,
              fontFamily: this.xaxisFontFamily,
              fontWeight: w.config.xaxis.labels.style.fontWeight,
              isPlainText: false,
              cssClass: "apexcharts-xaxis-label ".concat(w.config.xaxis.labels.style.cssClass)
            });
            elXaxisTexts.add(elTick);
            elTick.tspan(val);
            this.addTooltip(elTick, val);
            l += labelsDivider;
          }
        }
        this.inversedYAxisTitleText(elXaxis);
        this.inversedYAxisBorder(elXaxis);
        return elXaxis;
      }
    }, {
      key: "inversedYAxisBorder",
      value: function inversedYAxisBorder(parent) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var axisBorder = w.config.xaxis.axisBorder;
        if (axisBorder.show) {
          var lineCorrection = 0;
          if (w.config.chart.type === 'bar' && w.globals.isXNumeric) lineCorrection -= 15;
          var elHorzLine = graphics.drawLine(w.globals.padHorizontal + lineCorrection + axisBorder.offsetX, this.xAxisoffX, w.globals.gridWidth, this.xAxisoffX, axisBorder.color, 0, axisBorder.height);
          if (this.elgrid && this.elgrid.elGridBorders && w.config.grid.show) {
            this.elgrid.elGridBorders.add(elHorzLine);
          } else {
            parent.add(elHorzLine);
          }
        }
      }
    }, {
      key: "inversedYAxisTitleText",
      value: function inversedYAxisTitleText(parent) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        if (w.config.xaxis.title.text !== undefined) {
          var elYaxisTitle = graphics.group({
            class: 'apexcharts-xaxis-title apexcharts-yaxis-title-inversed'
          });
          var elYAxisTitleText = graphics.drawText({
            x: w.globals.gridWidth / 2 + w.config.xaxis.title.offsetX,
            y: this.xAxisoffX + parseFloat(this.xaxisFontSize) + parseFloat(w.config.xaxis.title.style.fontSize) + w.config.xaxis.title.offsetY + 20,
            text: w.config.xaxis.title.text,
            textAnchor: 'middle',
            fontSize: w.config.xaxis.title.style.fontSize,
            fontFamily: w.config.xaxis.title.style.fontFamily,
            fontWeight: w.config.xaxis.title.style.fontWeight,
            foreColor: w.config.xaxis.title.style.color,
            cssClass: "apexcharts-xaxis-title-text ".concat(w.config.xaxis.title.style.cssClass)
          });
          elYaxisTitle.add(elYAxisTitleText);
          parent.add(elYaxisTitle);
        }
      }
    }, {
      key: "yAxisTitleRotate",
      value: function yAxisTitleRotate(realIndex, yAxisOpposite) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var elYAxisLabelsWrap = w.globals.dom.baseEl.querySelector(".apexcharts-yaxis[rel='".concat(realIndex, "'] .apexcharts-yaxis-texts-g"));
        var yAxisLabelsCoord = elYAxisLabelsWrap ? elYAxisLabelsWrap.getBoundingClientRect() : {
          width: 0,
          height: 0
        };
        var yAxisTitle = w.globals.dom.baseEl.querySelector(".apexcharts-yaxis[rel='".concat(realIndex, "'] .apexcharts-yaxis-title text"));
        var yAxisTitleCoord = yAxisTitle ? yAxisTitle.getBoundingClientRect() : {
          width: 0,
          height: 0
        };
        if (yAxisTitle) {
          var x = this.xPaddingForYAxisTitle(realIndex, yAxisLabelsCoord, yAxisTitleCoord, yAxisOpposite);
          yAxisTitle.setAttribute('x', x.xPos - (yAxisOpposite ? 10 : 0));
          var titleRotatingCenter = graphics.rotateAroundCenter(yAxisTitle);
          yAxisTitle.setAttribute('transform', "rotate(".concat(yAxisOpposite ? w.config.yaxis[realIndex].title.rotate * -1 : w.config.yaxis[realIndex].title.rotate, " ").concat(titleRotatingCenter.x, " ").concat(titleRotatingCenter.y, ")"));
        }
      }
    }, {
      key: "xPaddingForYAxisTitle",
      value: function xPaddingForYAxisTitle(realIndex, yAxisLabelsCoord, yAxisTitleCoord, yAxisOpposite) {
        var w = this.w;
        var x = 0;
        var padd = 10;
        if (w.config.yaxis[realIndex].title.text === undefined || realIndex < 0) {
          return {
            xPos: x,
            padd: 0
          };
        }
        if (yAxisOpposite) {
          x = yAxisLabelsCoord.width + w.config.yaxis[realIndex].title.offsetX + yAxisTitleCoord.width / 2 + padd / 2;
        } else {
          x = yAxisLabelsCoord.width * -1 + w.config.yaxis[realIndex].title.offsetX + padd / 2 + yAxisTitleCoord.width / 2;
          if (w.globals.isBarHorizontal) {
            padd = 25;
            x = yAxisLabelsCoord.width * -1 - w.config.yaxis[realIndex].title.offsetX - padd;
          }
        }
        return {
          xPos: x,
          padd: padd
        };
      }
    }, {
      key: "setYAxisXPosition",
      value: function setYAxisXPosition(yaxisLabelCoords, yTitleCoords) {
        var w = this.w;
        var xLeft = 0;
        var xRight = 0;
        var leftOffsetX = 18;
        var rightOffsetX = 1;
        if (w.config.yaxis.length > 1) this.multipleYs = true;
        w.config.yaxis.forEach(function (yaxe, index) {
          var shouldNotDrawAxis = w.globals.ignoreYAxisIndexes.includes(index) || !yaxe.show || yaxe.floating || yaxisLabelCoords[index].width === 0;
          var axisWidth = yaxisLabelCoords[index].width + yTitleCoords[index].width;
          if (!yaxe.opposite) {
            xLeft = w.globals.translateX - leftOffsetX;
            if (!shouldNotDrawAxis) leftOffsetX += axisWidth + 20;
            w.globals.translateYAxisX[index] = xLeft + yaxe.labels.offsetX;
          } else {
            if (w.globals.isBarHorizontal) {
              xRight = w.globals.gridWidth + w.globals.translateX - 1;
              w.globals.translateYAxisX[index] = xRight - yaxe.labels.offsetX;
            } else {
              xRight = w.globals.gridWidth + w.globals.translateX + rightOffsetX;
              if (!shouldNotDrawAxis) rightOffsetX += axisWidth + 20;
              w.globals.translateYAxisX[index] = xRight - yaxe.labels.offsetX + 20;
            }
          }
        });
      }
    }, {
      key: "setYAxisTextAlignments",
      value: function setYAxisTextAlignments() {
        var w = this.w;
        var yaxis = Utils$1.listToArray(w.globals.dom.baseEl.getElementsByClassName('apexcharts-yaxis'));
        yaxis.forEach(function (y, index) {
          var yaxe = w.config.yaxis[index];
          if (yaxe && !yaxe.floating && yaxe.labels.align !== undefined) {
            var yAxisInner = w.globals.dom.baseEl.querySelector(".apexcharts-yaxis[rel='".concat(index, "'] .apexcharts-yaxis-texts-g"));
            var yAxisTexts = Utils$1.listToArray(w.globals.dom.baseEl.querySelectorAll(".apexcharts-yaxis[rel='".concat(index, "'] .apexcharts-yaxis-label")));
            var rect = yAxisInner.getBoundingClientRect();
            yAxisTexts.forEach(function (label) {
              label.setAttribute('text-anchor', yaxe.labels.align);
            });
            if (yaxe.labels.align === 'left' && !yaxe.opposite) {
              yAxisInner.setAttribute('transform', "translate(-".concat(rect.width, ", 0)"));
            } else if (yaxe.labels.align === 'center') {
              yAxisInner.setAttribute('transform', "translate(".concat(rect.width / 2 * (!yaxe.opposite ? -1 : 1), ", 0)"));
            } else if (yaxe.labels.align === 'right' && yaxe.opposite) {
              yAxisInner.setAttribute('transform', "translate(".concat(rect.width, ", 0)"));
            }
          }
        });
      }
    }]);
    return YAxis;
  }();

  var Events = /*#__PURE__*/function () {
    function Events(ctx) {
      _classCallCheck(this, Events);
      this.ctx = ctx;
      this.w = ctx.w;
      this.documentEvent = Utils$1.bind(this.documentEvent, this);
    }
    _createClass(Events, [{
      key: "addEventListener",
      value: function addEventListener(name, handler) {
        var w = this.w;
        if (w.globals.events.hasOwnProperty(name)) {
          w.globals.events[name].push(handler);
        } else {
          w.globals.events[name] = [handler];
        }
      }
    }, {
      key: "removeEventListener",
      value: function removeEventListener(name, handler) {
        var w = this.w;
        if (!w.globals.events.hasOwnProperty(name)) {
          return;
        }
        var index = w.globals.events[name].indexOf(handler);
        if (index !== -1) {
          w.globals.events[name].splice(index, 1);
        }
      }
    }, {
      key: "fireEvent",
      value: function fireEvent(name, args) {
        var w = this.w;
        if (!w.globals.events.hasOwnProperty(name)) {
          return;
        }
        if (!args || !args.length) {
          args = [];
        }
        var evs = w.globals.events[name];
        var l = evs.length;
        for (var i = 0; i < l; i++) {
          evs[i].apply(null, args);
        }
      }
    }, {
      key: "setupEventHandlers",
      value: function setupEventHandlers() {
        var _this = this;
        var w = this.w;
        var me = this.ctx;
        var clickableArea = w.globals.dom.baseEl.querySelector(w.globals.chartClass);
        this.ctx.eventList.forEach(function (event) {
          clickableArea.addEventListener(event, function (e) {
            var opts = Object.assign({}, w, {
              seriesIndex: w.globals.axisCharts ? w.globals.capturedSeriesIndex : 0,
              dataPointIndex: w.globals.capturedDataPointIndex
            });
            if (e.type === 'mousemove' || e.type === 'touchmove') {
              if (typeof w.config.chart.events.mouseMove === 'function') {
                w.config.chart.events.mouseMove(e, me, opts);
              }
            } else if (e.type === 'mouseleave' || e.type === 'touchleave') {
              if (typeof w.config.chart.events.mouseLeave === 'function') {
                w.config.chart.events.mouseLeave(e, me, opts);
              }
            } else if (e.type === 'mouseup' && e.which === 1 || e.type === 'touchend') {
              if (typeof w.config.chart.events.click === 'function') {
                w.config.chart.events.click(e, me, opts);
              }
              me.ctx.events.fireEvent('click', [e, me, opts]);
            }
          }, {
            capture: false,
            passive: true
          });
        });
        this.ctx.eventList.forEach(function (event) {
          w.globals.dom.baseEl.addEventListener(event, _this.documentEvent, {
            passive: true
          });
        });
        this.ctx.core.setupBrushHandler();
      }
    }, {
      key: "documentEvent",
      value: function documentEvent(e) {
        var w = this.w;
        var target = e.target.className;
        if (e.type === 'click') {
          var elMenu = w.globals.dom.baseEl.querySelector('.apexcharts-menu');
          if (elMenu && elMenu.classList.contains('apexcharts-menu-open') && target !== 'apexcharts-menu-icon') {
            elMenu.classList.remove('apexcharts-menu-open');
          }
        }
        w.globals.clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
        w.globals.clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
      }
    }]);
    return Events;
  }();

  var Localization = /*#__PURE__*/function () {
    function Localization(ctx) {
      _classCallCheck(this, Localization);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(Localization, [{
      key: "setCurrentLocaleValues",
      value: function setCurrentLocaleValues(localeName) {
        var locales = this.w.config.chart.locales;

        // check if user has specified locales in global Apex variable
        // if yes - then extend those with local chart's locale
        if (window.Apex.chart && window.Apex.chart.locales && window.Apex.chart.locales.length > 0) {
          locales = this.w.config.chart.locales.concat(window.Apex.chart.locales);
        }

        // find the locale from the array of locales which user has set (either by chart.defaultLocale or by calling setLocale() method.)
        var selectedLocale = locales.filter(function (c) {
          return c.name === localeName;
        })[0];
        if (selectedLocale) {
          // create a complete locale object by extending defaults so you don't get undefined errors.
          var ret = Utils$1.extend(en, selectedLocale);

          // store these locale options in global var for ease access
          this.w.globals.locale = ret.options;
        } else {
          throw new Error('Wrong locale name provided. Please make sure you set the correct locale name in options');
        }
      }
    }]);
    return Localization;
  }();

  var Axes = /*#__PURE__*/function () {
    function Axes(ctx) {
      _classCallCheck(this, Axes);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(Axes, [{
      key: "drawAxis",
      value: function drawAxis(type, elgrid) {
        var _this = this;
        var gl = this.w.globals;
        var cnf = this.w.config;
        var xAxis = new XAxis(this.ctx, elgrid);
        var yAxis = new YAxis(this.ctx, elgrid);
        if (gl.axisCharts && type !== 'radar') {
          var elXaxis, elYaxis;
          if (gl.isBarHorizontal) {
            elYaxis = yAxis.drawYaxisInversed(0);
            elXaxis = xAxis.drawXaxisInversed(0);
            gl.dom.elGraphical.add(elXaxis);
            gl.dom.elGraphical.add(elYaxis);
          } else {
            elXaxis = xAxis.drawXaxis();
            gl.dom.elGraphical.add(elXaxis);
            cnf.yaxis.map(function (yaxe, index) {
              if (gl.ignoreYAxisIndexes.indexOf(index) === -1) {
                elYaxis = yAxis.drawYaxis(index);
                gl.dom.Paper.add(elYaxis);
                if (_this.w.config.grid.position === 'back') {
                  var inner = gl.dom.Paper.children()[1];
                  inner.remove();
                  gl.dom.Paper.add(inner);
                }
              }
            });
          }
        }
      }
    }]);
    return Axes;
  }();

  var Crosshairs = /*#__PURE__*/function () {
    function Crosshairs(ctx) {
      _classCallCheck(this, Crosshairs);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(Crosshairs, [{
      key: "drawXCrosshairs",
      value: function drawXCrosshairs() {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var filters = new Filters(this.ctx);
        var crosshairGradient = w.config.xaxis.crosshairs.fill.gradient;
        var crosshairShadow = w.config.xaxis.crosshairs.dropShadow;
        var fillType = w.config.xaxis.crosshairs.fill.type;
        var gradientFrom = crosshairGradient.colorFrom;
        var gradientTo = crosshairGradient.colorTo;
        var opacityFrom = crosshairGradient.opacityFrom;
        var opacityTo = crosshairGradient.opacityTo;
        var stops = crosshairGradient.stops;
        var shadow = 'none';
        var dropShadow = crosshairShadow.enabled;
        var shadowLeft = crosshairShadow.left;
        var shadowTop = crosshairShadow.top;
        var shadowBlur = crosshairShadow.blur;
        var shadowColor = crosshairShadow.color;
        var shadowOpacity = crosshairShadow.opacity;
        var xcrosshairsFill = w.config.xaxis.crosshairs.fill.color;
        if (w.config.xaxis.crosshairs.show) {
          if (fillType === 'gradient') {
            xcrosshairsFill = graphics.drawGradient('vertical', gradientFrom, gradientTo, opacityFrom, opacityTo, null, stops, null);
          }
          var xcrosshairs = graphics.drawRect();
          if (w.config.xaxis.crosshairs.width === 1) {
            // to prevent drawing 2 lines, convert rect to line
            xcrosshairs = graphics.drawLine();
          }
          var gridHeight = w.globals.gridHeight;
          if (!Utils$1.isNumber(gridHeight) || gridHeight < 0) {
            gridHeight = 0;
          }
          var crosshairsWidth = w.config.xaxis.crosshairs.width;
          if (!Utils$1.isNumber(crosshairsWidth) || crosshairsWidth < 0) {
            crosshairsWidth = 0;
          }
          xcrosshairs.attr({
            class: 'apexcharts-xcrosshairs',
            x: 0,
            y: 0,
            y2: gridHeight,
            width: crosshairsWidth,
            height: gridHeight,
            fill: xcrosshairsFill,
            filter: shadow,
            'fill-opacity': w.config.xaxis.crosshairs.opacity,
            stroke: w.config.xaxis.crosshairs.stroke.color,
            'stroke-width': w.config.xaxis.crosshairs.stroke.width,
            'stroke-dasharray': w.config.xaxis.crosshairs.stroke.dashArray
          });
          if (dropShadow) {
            xcrosshairs = filters.dropShadow(xcrosshairs, {
              left: shadowLeft,
              top: shadowTop,
              blur: shadowBlur,
              color: shadowColor,
              opacity: shadowOpacity
            });
          }
          w.globals.dom.elGraphical.add(xcrosshairs);
        }
      }
    }, {
      key: "drawYCrosshairs",
      value: function drawYCrosshairs() {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var crosshair = w.config.yaxis[0].crosshairs;
        var offX = w.globals.barPadForNumericAxis;
        if (w.config.yaxis[0].crosshairs.show) {
          var ycrosshairs = graphics.drawLine(-offX, 0, w.globals.gridWidth + offX, 0, crosshair.stroke.color, crosshair.stroke.dashArray, crosshair.stroke.width);
          ycrosshairs.attr({
            class: 'apexcharts-ycrosshairs'
          });
          w.globals.dom.elGraphical.add(ycrosshairs);
        }

        // draw an invisible crosshair to help in positioning the yaxis tooltip
        var ycrosshairsHidden = graphics.drawLine(-offX, 0, w.globals.gridWidth + offX, 0, crosshair.stroke.color, 0, 0);
        ycrosshairsHidden.attr({
          class: 'apexcharts-ycrosshairs-hidden'
        });
        w.globals.dom.elGraphical.add(ycrosshairsHidden);
      }
    }]);
    return Crosshairs;
  }();

  /**
   * ApexCharts Responsive Class to override options for different screen sizes.
   *
   * @module Responsive
   **/
  var Responsive = /*#__PURE__*/function () {
    function Responsive(ctx) {
      _classCallCheck(this, Responsive);
      this.ctx = ctx;
      this.w = ctx.w;
    }

    // the opts parameter if not null has to be set overriding everything
    // as the opts is set by user externally
    _createClass(Responsive, [{
      key: "checkResponsiveConfig",
      value: function checkResponsiveConfig(opts) {
        var _this = this;
        var w = this.w;
        var cnf = w.config;

        // check if responsive config exists
        if (cnf.responsive.length === 0) return;
        var res = cnf.responsive.slice();
        res.sort(function (a, b) {
          return a.breakpoint > b.breakpoint ? 1 : b.breakpoint > a.breakpoint ? -1 : 0;
        }).reverse();
        var config = new Config({});
        var iterateResponsiveOptions = function iterateResponsiveOptions() {
          var newOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
          var largestBreakpoint = res[0].breakpoint;
          var width = window.innerWidth > 0 ? window.innerWidth : screen.width;
          if (width > largestBreakpoint) {
            var initialConfig = Utils$1.clone(w.globals.initialConfig);
            // Retain state of series in case any have been collapsed
            // (indicated by series.data === [], these series' will be zeroed later
            // enabling stacking to work correctly)
            initialConfig.series = Utils$1.clone(w.config.series);
            var options = CoreUtils.extendArrayProps(config, initialConfig, w);
            newOptions = Utils$1.extend(options, newOptions);
            newOptions = Utils$1.extend(w.config, newOptions);
            _this.overrideResponsiveOptions(newOptions);
          } else {
            for (var i = 0; i < res.length; i++) {
              if (width < res[i].breakpoint) {
                newOptions = CoreUtils.extendArrayProps(config, res[i].options, w);
                newOptions = Utils$1.extend(w.config, newOptions);
                _this.overrideResponsiveOptions(newOptions);
              }
            }
          }
        };
        if (opts) {
          var options = CoreUtils.extendArrayProps(config, opts, w);
          options = Utils$1.extend(w.config, options);
          options = Utils$1.extend(options, opts);
          iterateResponsiveOptions(options);
        } else {
          iterateResponsiveOptions({});
        }
      }
    }, {
      key: "overrideResponsiveOptions",
      value: function overrideResponsiveOptions(newOptions) {
        var newConfig = new Config(newOptions).init({
          responsiveOverride: true
        });
        this.w.config = newConfig;
      }
    }]);
    return Responsive;
  }();

  /**
   * ApexCharts Theme Class for setting the colors and palettes.
   *
   * @module Theme
   **/
  var Theme = /*#__PURE__*/function () {
    function Theme(ctx) {
      _classCallCheck(this, Theme);
      this.ctx = ctx;
      this.w = ctx.w;
      this.colors = [];
      this.isColorFn = false;
      this.isHeatmapDistributed = this.checkHeatmapDistributed();
      this.isBarDistributed = this.checkBarDistributed();
    }
    _createClass(Theme, [{
      key: "checkHeatmapDistributed",
      value: function checkHeatmapDistributed() {
        var _this$w$config = this.w.config,
          chart = _this$w$config.chart,
          plotOptions = _this$w$config.plotOptions;
        return chart.type === 'treemap' && plotOptions.treemap && plotOptions.treemap.distributed || chart.type === 'heatmap' && plotOptions.heatmap && plotOptions.heatmap.distributed;
      }
    }, {
      key: "checkBarDistributed",
      value: function checkBarDistributed() {
        var _this$w$config2 = this.w.config,
          chart = _this$w$config2.chart,
          plotOptions = _this$w$config2.plotOptions;
        return plotOptions.bar && plotOptions.bar.distributed && (chart.type === 'bar' || chart.type === 'rangeBar');
      }
    }, {
      key: "init",
      value: function init() {
        this.setDefaultColors();
      }
    }, {
      key: "setDefaultColors",
      value: function setDefaultColors() {
        var w = this.w;
        var utils = new Utils$1();
        w.globals.dom.elWrap.classList.add("apexcharts-theme-".concat(w.config.theme.mode));

        // Create a copy of config.colors array to avoid mutating the original config.colors
        var configColors = _toConsumableArray(w.config.colors || w.config.fill.colors || []);
        w.globals.colors = this.getColors(configColors);
        this.applySeriesColors(w.globals.seriesColors, w.globals.colors);
        if (w.config.theme.monochrome.enabled) {
          w.globals.colors = this.getMonochromeColors(w.config.theme.monochrome, w.globals.series, utils);
        }
        var defaultColors = w.globals.colors.slice();
        this.pushExtraColors(w.globals.colors);
        this.applyColorTypes(['fill', 'stroke'], defaultColors);
        this.applyDataLabelsColors(defaultColors);
        this.applyRadarPolygonsColors();
        this.applyMarkersColors(defaultColors);
      }
    }, {
      key: "getColors",
      value: function getColors(configColors) {
        var _this = this;
        var w = this.w;
        if (!configColors || configColors.length === 0) {
          return this.predefined();
        }
        if (Array.isArray(configColors) && configColors.length > 0 && typeof configColors[0] === 'function') {
          this.isColorFn = true;
          return w.config.series.map(function (s, i) {
            var c = configColors[i] || configColors[0];
            return typeof c === 'function' ? c({
              value: w.globals.axisCharts ? w.globals.series[i][0] || 0 : w.globals.series[i],
              seriesIndex: i,
              dataPointIndex: i,
              w: _this.w
            }) : c;
          });
        }
        return configColors;
      }
    }, {
      key: "applySeriesColors",
      value: function applySeriesColors(seriesColors, globalsColors) {
        seriesColors.forEach(function (c, i) {
          if (c) {
            globalsColors[i] = c;
          }
        });
      }
    }, {
      key: "getMonochromeColors",
      value: function getMonochromeColors(monochrome, series, utils) {
        var color = monochrome.color,
          shadeIntensity = monochrome.shadeIntensity,
          shadeTo = monochrome.shadeTo;
        var glsCnt = this.isBarDistributed || this.isHeatmapDistributed ? series[0].length * series.length : series.length;
        var part = 1 / (glsCnt / shadeIntensity);
        var percent = 0;
        return Array.from({
          length: glsCnt
        }, function () {
          var newColor = shadeTo === 'dark' ? utils.shadeColor(percent * -1, color) : utils.shadeColor(percent, color);
          percent += part;
          return newColor;
        });
      }
    }, {
      key: "applyColorTypes",
      value: function applyColorTypes(colorTypes, defaultColors) {
        var _this2 = this;
        var w = this.w;
        colorTypes.forEach(function (c) {
          w.globals[c].colors = w.config[c].colors === undefined ? _this2.isColorFn ? w.config.colors : defaultColors : w.config[c].colors.slice();
          _this2.pushExtraColors(w.globals[c].colors);
        });
      }
    }, {
      key: "applyDataLabelsColors",
      value: function applyDataLabelsColors(defaultColors) {
        var w = this.w;
        w.globals.dataLabels.style.colors = w.config.dataLabels.style.colors === undefined ? defaultColors : w.config.dataLabels.style.colors.slice();
        this.pushExtraColors(w.globals.dataLabels.style.colors, 50);
      }
    }, {
      key: "applyRadarPolygonsColors",
      value: function applyRadarPolygonsColors() {
        var w = this.w;
        w.globals.radarPolygons.fill.colors = w.config.plotOptions.radar.polygons.fill.colors === undefined ? [w.config.theme.mode === 'dark' ? '#424242' : 'none'] : w.config.plotOptions.radar.polygons.fill.colors.slice();
        this.pushExtraColors(w.globals.radarPolygons.fill.colors, 20);
      }
    }, {
      key: "applyMarkersColors",
      value: function applyMarkersColors(defaultColors) {
        var w = this.w;
        w.globals.markers.colors = w.config.markers.colors === undefined ? defaultColors : w.config.markers.colors.slice();
        this.pushExtraColors(w.globals.markers.colors);
      }
    }, {
      key: "pushExtraColors",
      value: function pushExtraColors(colorSeries, length) {
        var distributed = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
        var w = this.w;
        var len = length || w.globals.series.length;
        if (distributed === null) {
          distributed = this.isBarDistributed || this.isHeatmapDistributed || w.config.chart.type === 'heatmap' && w.config.plotOptions.heatmap && w.config.plotOptions.heatmap.colorScale.inverse;
        }
        if (distributed && w.globals.series.length) {
          len = w.globals.series[w.globals.maxValsInArrayIndex].length * w.globals.series.length;
        }
        if (colorSeries.length < len) {
          var diff = len - colorSeries.length;
          for (var i = 0; i < diff; i++) {
            colorSeries.push(colorSeries[i]);
          }
        }
      }
    }, {
      key: "updateThemeOptions",
      value: function updateThemeOptions(options) {
        options.chart = options.chart || {};
        options.tooltip = options.tooltip || {};
        var mode = options.theme.mode;
        var palette = mode === 'dark' ? 'palette4' : mode === 'light' ? 'palette1' : options.theme.palette || 'palette1';
        var foreColor = mode === 'dark' ? '#f6f7f8' : mode === 'light' ? '#373d3f' : options.chart.foreColor || '#373d3f';
        options.tooltip.theme = mode || 'light';
        options.chart.foreColor = foreColor;
        options.theme.palette = palette;
        return options;
      }
    }, {
      key: "predefined",
      value: function predefined() {
        var palette = this.w.config.theme.palette;
        var palettes = {
          palette1: ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#775DD0'],
          palette2: ['#3f51b5', '#03a9f4', '#4caf50', '#f9ce1d', '#FF9800'],
          palette3: ['#33b2df', '#546E7A', '#d4526e', '#13d8aa', '#A5978B'],
          palette4: ['#4ecdc4', '#c7f464', '#81D4FA', '#fd6a6a', '#546E7A'],
          palette5: ['#2b908f', '#f9a3a4', '#90ee7e', '#fa4443', '#69d2e7'],
          palette6: ['#449DD1', '#F86624', '#EA3546', '#662E9B', '#C5D86D'],
          palette7: ['#D7263D', '#1B998B', '#2E294E', '#F46036', '#E2C044'],
          palette8: ['#662E9B', '#F86624', '#F9C80E', '#EA3546', '#43BCCD'],
          palette9: ['#5C4742', '#A5978B', '#8D5B4C', '#5A2A27', '#C4BBAF'],
          palette10: ['#A300D6', '#7D02EB', '#5653FE', '#2983FF', '#00B1F2'],
          default: ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#775DD0']
        };
        return palettes[palette] || palettes.default;
      }
    }]);
    return Theme;
  }();

  var TitleSubtitle = /*#__PURE__*/function () {
    function TitleSubtitle(ctx) {
      _classCallCheck(this, TitleSubtitle);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(TitleSubtitle, [{
      key: "draw",
      value: function draw() {
        this.drawTitleSubtitle('title');
        this.drawTitleSubtitle('subtitle');
      }
    }, {
      key: "drawTitleSubtitle",
      value: function drawTitleSubtitle(type) {
        var w = this.w;
        var tsConfig = type === 'title' ? w.config.title : w.config.subtitle;
        var x = w.globals.svgWidth / 2;
        var y = tsConfig.offsetY;
        var textAnchor = 'middle';
        if (tsConfig.align === 'left') {
          x = 10;
          textAnchor = 'start';
        } else if (tsConfig.align === 'right') {
          x = w.globals.svgWidth - 10;
          textAnchor = 'end';
        }
        x = x + tsConfig.offsetX;
        y = y + parseInt(tsConfig.style.fontSize, 10) + tsConfig.margin / 2;
        if (tsConfig.text !== undefined) {
          var graphics = new Graphics(this.ctx);
          var titleText = graphics.drawText({
            x: x,
            y: y,
            text: tsConfig.text,
            textAnchor: textAnchor,
            fontSize: tsConfig.style.fontSize,
            fontFamily: tsConfig.style.fontFamily,
            fontWeight: tsConfig.style.fontWeight,
            foreColor: tsConfig.style.color,
            opacity: 1
          });
          titleText.node.setAttribute('class', "apexcharts-".concat(type, "-text"));
          w.globals.dom.Paper.add(titleText);
        }
      }
    }]);
    return TitleSubtitle;
  }();

  var Helpers$3 = /*#__PURE__*/function () {
    function Helpers(dCtx) {
      _classCallCheck(this, Helpers);
      this.w = dCtx.w;
      this.dCtx = dCtx;
    }

    /**
     * Get Chart Title/Subtitle Dimensions
     * @memberof Dimensions
     * @return {{width, height}}
     **/
    _createClass(Helpers, [{
      key: "getTitleSubtitleCoords",
      value: function getTitleSubtitleCoords(type) {
        var w = this.w;
        var width = 0;
        var height = 0;
        var floating = type === 'title' ? w.config.title.floating : w.config.subtitle.floating;
        var el = w.globals.dom.baseEl.querySelector(".apexcharts-".concat(type, "-text"));
        if (el !== null && !floating) {
          var coord = el.getBoundingClientRect();
          width = coord.width;
          height = w.globals.axisCharts ? coord.height + 5 : coord.height;
        }
        return {
          width: width,
          height: height
        };
      }
    }, {
      key: "getLegendsRect",
      value: function getLegendsRect() {
        var w = this.w;
        var elLegendWrap = w.globals.dom.elLegendWrap;
        if (!w.config.legend.height && (w.config.legend.position === 'top' || w.config.legend.position === 'bottom')) {
          // avoid legend to take up all the space
          elLegendWrap.style.maxHeight = w.globals.svgHeight / 2 + 'px';
        }
        var lgRect = Object.assign({}, Utils$1.getBoundingClientRect(elLegendWrap));
        if (elLegendWrap !== null && !w.config.legend.floating && w.config.legend.show) {
          this.dCtx.lgRect = {
            x: lgRect.x,
            y: lgRect.y,
            height: lgRect.height,
            width: lgRect.height === 0 ? 0 : lgRect.width
          };
        } else {
          this.dCtx.lgRect = {
            x: 0,
            y: 0,
            height: 0,
            width: 0
          };
        }

        // if legend takes up all of the chart space, we need to restrict it.
        if (w.config.legend.position === 'left' || w.config.legend.position === 'right') {
          if (this.dCtx.lgRect.width * 1.5 > w.globals.svgWidth) {
            this.dCtx.lgRect.width = w.globals.svgWidth / 1.5;
          }
        }
        return this.dCtx.lgRect;
      }

      /**
       * Get Y Axis Dimensions
       * @memberof Dimensions
       * @return {{width, height}}
       **/
    }, {
      key: "getDatalabelsRect",
      value: function getDatalabelsRect() {
        var _this = this;
        var w = this.w;
        var allLabels = [];
        w.config.series.forEach(function (serie, seriesIndex) {
          serie.data.forEach(function (datum, dataPointIndex) {
            var getText = function getText(v) {
              return w.config.dataLabels.formatter(v, {
                ctx: _this.dCtx.ctx,
                seriesIndex: seriesIndex,
                dataPointIndex: dataPointIndex,
                w: w
              });
            };
            val = getText(w.globals.series[seriesIndex][dataPointIndex]);
            allLabels.push(val);
          });
        });
        var val = Utils$1.getLargestStringFromArr(allLabels);
        var graphics = new Graphics(this.dCtx.ctx);
        var dataLabelsStyle = w.config.dataLabels.style;
        var labelrect = graphics.getTextRects(val, parseInt(dataLabelsStyle.fontSize), dataLabelsStyle.fontFamily);
        return {
          width: labelrect.width * 1.05,
          height: labelrect.height
        };
      }
    }, {
      key: "getLargestStringFromMultiArr",
      value: function getLargestStringFromMultiArr(val, arr) {
        var w = this.w;
        var valArr = val;
        if (w.globals.isMultiLineX) {
          // if the xaxis labels has multiline texts (array)
          var maxArrs = arr.map(function (xl, idx) {
            return Array.isArray(xl) ? xl.length : 1;
          });
          var maxArrLen = Math.max.apply(Math, _toConsumableArray(maxArrs));
          var maxArrIndex = maxArrs.indexOf(maxArrLen);
          valArr = arr[maxArrIndex];
        }
        return valArr;
      }
    }]);
    return Helpers;
  }();

  var DimXAxis = /*#__PURE__*/function () {
    function DimXAxis(dCtx) {
      _classCallCheck(this, DimXAxis);
      this.w = dCtx.w;
      this.dCtx = dCtx;
    }

    /**
     * Get X Axis Dimensions
     * @memberof Dimensions
     * @return {{width, height}}
     **/
    _createClass(DimXAxis, [{
      key: "getxAxisLabelsCoords",
      value: function getxAxisLabelsCoords() {
        var w = this.w;
        var xaxisLabels = w.globals.labels.slice();
        if (w.config.xaxis.convertedCatToNumeric && xaxisLabels.length === 0) {
          xaxisLabels = w.globals.categoryLabels;
        }
        var rect;
        if (w.globals.timescaleLabels.length > 0) {
          var coords = this.getxAxisTimeScaleLabelsCoords();
          rect = {
            width: coords.width,
            height: coords.height
          };
          w.globals.rotateXLabels = false;
        } else {
          this.dCtx.lgWidthForSideLegends = (w.config.legend.position === 'left' || w.config.legend.position === 'right') && !w.config.legend.floating ? this.dCtx.lgRect.width : 0;

          // get the longest string from the labels array and also apply label formatter
          var xlbFormatter = w.globals.xLabelFormatter;
          // prevent changing xaxisLabels to avoid issues in multi-yaxes - fix #522
          var val = Utils$1.getLargestStringFromArr(xaxisLabels);
          var valArr = this.dCtx.dimHelpers.getLargestStringFromMultiArr(val, xaxisLabels);

          // the labels gets changed for bar charts
          if (w.globals.isBarHorizontal) {
            val = w.globals.yAxisScale[0].result.reduce(function (a, b) {
              return a.length > b.length ? a : b;
            }, 0);
            valArr = val;
          }
          var xFormat = new Formatters(this.dCtx.ctx);
          var timestamp = val;
          val = xFormat.xLabelFormat(xlbFormatter, val, timestamp, {
            i: undefined,
            dateFormatter: new DateTime(this.dCtx.ctx).formatDate,
            w: w
          });
          valArr = xFormat.xLabelFormat(xlbFormatter, valArr, timestamp, {
            i: undefined,
            dateFormatter: new DateTime(this.dCtx.ctx).formatDate,
            w: w
          });
          if (w.config.xaxis.convertedCatToNumeric && typeof val === 'undefined' || String(val).trim() === '') {
            val = '1';
            valArr = val;
          }
          var graphics = new Graphics(this.dCtx.ctx);
          var xLabelrect = graphics.getTextRects(val, w.config.xaxis.labels.style.fontSize);
          var xArrLabelrect = xLabelrect;
          if (val !== valArr) {
            xArrLabelrect = graphics.getTextRects(valArr, w.config.xaxis.labels.style.fontSize);
          }
          rect = {
            width: xLabelrect.width >= xArrLabelrect.width ? xLabelrect.width : xArrLabelrect.width,
            height: xLabelrect.height >= xArrLabelrect.height ? xLabelrect.height : xArrLabelrect.height
          };
          if (rect.width * xaxisLabels.length > w.globals.svgWidth - this.dCtx.lgWidthForSideLegends - this.dCtx.yAxisWidth - this.dCtx.gridPad.left - this.dCtx.gridPad.right && w.config.xaxis.labels.rotate !== 0 || w.config.xaxis.labels.rotateAlways) {
            if (!w.globals.isBarHorizontal) {
              w.globals.rotateXLabels = true;
              var getRotatedTextRects = function getRotatedTextRects(text) {
                return graphics.getTextRects(text, w.config.xaxis.labels.style.fontSize, w.config.xaxis.labels.style.fontFamily, "rotate(".concat(w.config.xaxis.labels.rotate, " 0 0)"), false);
              };
              xLabelrect = getRotatedTextRects(val);
              if (val !== valArr) {
                xArrLabelrect = getRotatedTextRects(valArr);
              }
              rect.height = (xLabelrect.height > xArrLabelrect.height ? xLabelrect.height : xArrLabelrect.height) / 1.5;
              rect.width = xLabelrect.width > xArrLabelrect.width ? xLabelrect.width : xArrLabelrect.width;
            }
          } else {
            w.globals.rotateXLabels = false;
          }
        }
        if (!w.config.xaxis.labels.show) {
          rect = {
            width: 0,
            height: 0
          };
        }
        return {
          width: rect.width,
          height: rect.height
        };
      }

      /**
       * Get X Axis Label Group height
       * @memberof Dimensions
       * @return {{width, height}}
       */
    }, {
      key: "getxAxisGroupLabelsCoords",
      value: function getxAxisGroupLabelsCoords() {
        var _w$config$xaxis$group;
        var w = this.w;
        if (!w.globals.hasXaxisGroups) {
          return {
            width: 0,
            height: 0
          };
        }
        var fontSize = ((_w$config$xaxis$group = w.config.xaxis.group.style) === null || _w$config$xaxis$group === void 0 ? void 0 : _w$config$xaxis$group.fontSize) || w.config.xaxis.labels.style.fontSize;
        var xaxisLabels = w.globals.groups.map(function (g) {
          return g.title;
        });
        var rect;

        // prevent changing xaxisLabels to avoid issues in multi-yaxes - fix #522
        var val = Utils$1.getLargestStringFromArr(xaxisLabels);
        var valArr = this.dCtx.dimHelpers.getLargestStringFromMultiArr(val, xaxisLabels);
        var graphics = new Graphics(this.dCtx.ctx);
        var xLabelrect = graphics.getTextRects(val, fontSize);
        var xArrLabelrect = xLabelrect;
        if (val !== valArr) {
          xArrLabelrect = graphics.getTextRects(valArr, fontSize);
        }
        rect = {
          width: xLabelrect.width >= xArrLabelrect.width ? xLabelrect.width : xArrLabelrect.width,
          height: xLabelrect.height >= xArrLabelrect.height ? xLabelrect.height : xArrLabelrect.height
        };
        if (!w.config.xaxis.labels.show) {
          rect = {
            width: 0,
            height: 0
          };
        }
        return {
          width: rect.width,
          height: rect.height
        };
      }

      /**
       * Get X Axis Title Dimensions
       * @memberof Dimensions
       * @return {{width, height}}
       **/
    }, {
      key: "getxAxisTitleCoords",
      value: function getxAxisTitleCoords() {
        var w = this.w;
        var width = 0;
        var height = 0;
        if (w.config.xaxis.title.text !== undefined) {
          var graphics = new Graphics(this.dCtx.ctx);
          var rect = graphics.getTextRects(w.config.xaxis.title.text, w.config.xaxis.title.style.fontSize);
          width = rect.width;
          height = rect.height;
        }
        return {
          width: width,
          height: height
        };
      }
    }, {
      key: "getxAxisTimeScaleLabelsCoords",
      value: function getxAxisTimeScaleLabelsCoords() {
        var w = this.w;
        var rect;
        this.dCtx.timescaleLabels = w.globals.timescaleLabels.slice();
        var labels = this.dCtx.timescaleLabels.map(function (label) {
          return label.value;
        });

        //  get the longest string from the labels array and also apply label formatter to it
        var val = labels.reduce(function (a, b) {
          // if undefined, maybe user didn't pass the datetime(x) values
          if (typeof a === 'undefined') {
            console.error('You have possibly supplied invalid Date format. Please supply a valid JavaScript Date');
            return 0;
          } else {
            return a.length > b.length ? a : b;
          }
        }, 0);
        var graphics = new Graphics(this.dCtx.ctx);
        rect = graphics.getTextRects(val, w.config.xaxis.labels.style.fontSize);
        var totalWidthRotated = rect.width * 1.05 * labels.length;
        if (totalWidthRotated > w.globals.gridWidth && w.config.xaxis.labels.rotate !== 0) {
          w.globals.overlappingXLabels = true;
        }
        return rect;
      }

      // In certain cases, the last labels gets cropped in xaxis.
      // Hence, we add some additional padding based on the label length to avoid the last label being cropped or we don't draw it at all
    }, {
      key: "additionalPaddingXLabels",
      value: function additionalPaddingXLabels(xaxisLabelCoords) {
        var _this = this;
        var w = this.w;
        var gl = w.globals;
        var cnf = w.config;
        var xtype = cnf.xaxis.type;
        var lbWidth = xaxisLabelCoords.width;
        gl.skipLastTimelinelabel = false;
        gl.skipFirstTimelinelabel = false;
        var isBarOpposite = w.config.yaxis[0].opposite && w.globals.isBarHorizontal;
        var isCollapsed = function isCollapsed(i) {
          return gl.collapsedSeriesIndices.indexOf(i) !== -1;
        };
        var rightPad = function rightPad(yaxe) {
          if (_this.dCtx.timescaleLabels && _this.dCtx.timescaleLabels.length) {
            // for timeline labels, we take the last label and check if it exceeds gridWidth
            var firstimescaleLabel = _this.dCtx.timescaleLabels[0];
            var lastTimescaleLabel = _this.dCtx.timescaleLabels[_this.dCtx.timescaleLabels.length - 1];
            var lastLabelPosition = lastTimescaleLabel.position + lbWidth / 1.75 - _this.dCtx.yAxisWidthRight;
            var firstLabelPosition = firstimescaleLabel.position - lbWidth / 1.75 + _this.dCtx.yAxisWidthLeft;
            var lgRightRectWidth = w.config.legend.position === 'right' && _this.dCtx.lgRect.width > 0 ? _this.dCtx.lgRect.width : 0;
            if (lastLabelPosition > gl.svgWidth - gl.translateX - lgRightRectWidth) {
              gl.skipLastTimelinelabel = true;
            }
            if (firstLabelPosition < -((!yaxe.show || yaxe.floating) && (cnf.chart.type === 'bar' || cnf.chart.type === 'candlestick' || cnf.chart.type === 'rangeBar' || cnf.chart.type === 'boxPlot') ? lbWidth / 1.75 : 10)) {
              gl.skipFirstTimelinelabel = true;
            }
          } else if (xtype === 'datetime') {
            // If user has enabled DateTime, but uses own's formatter
            if (_this.dCtx.gridPad.right < lbWidth && !gl.rotateXLabels) {
              gl.skipLastTimelinelabel = true;
            }
          } else if (xtype !== 'datetime') {
            if (_this.dCtx.gridPad.right < lbWidth / 2 - _this.dCtx.yAxisWidthRight && !gl.rotateXLabels && !w.config.xaxis.labels.trim) {
              _this.dCtx.xPadRight = lbWidth / 2 + 1;
            }
          }
        };
        var padYAxe = function padYAxe(yaxe, i) {
          if (cnf.yaxis.length > 1 && isCollapsed(i)) return;
          rightPad(yaxe);
        };
        cnf.yaxis.forEach(function (yaxe, i) {
          if (isBarOpposite) {
            if (_this.dCtx.gridPad.left < lbWidth) {
              _this.dCtx.xPadLeft = lbWidth / 2 + 1;
            }
            _this.dCtx.xPadRight = lbWidth / 2 + 1;
          } else {
            padYAxe(yaxe, i);
          }
        });
      }
    }]);
    return DimXAxis;
  }();

  var DimYAxis = /*#__PURE__*/function () {
    function DimYAxis(dCtx) {
      _classCallCheck(this, DimYAxis);
      this.w = dCtx.w;
      this.dCtx = dCtx;
    }

    /**
     * Get Y Axis Dimensions
     * @memberof Dimensions
     * @return {{width, height}}
     **/
    _createClass(DimYAxis, [{
      key: "getyAxisLabelsCoords",
      value: function getyAxisLabelsCoords() {
        var _this = this;
        var w = this.w;
        var width = 0;
        var height = 0;
        var ret = [];
        var labelPad = 10;
        var axesUtils = new AxesUtils(this.dCtx.ctx);
        w.config.yaxis.map(function (yaxe, index) {
          var formatterArgs = {
            seriesIndex: index,
            dataPointIndex: -1,
            w: w
          };
          var yS = w.globals.yAxisScale[index];
          var yAxisMinWidth = 0;
          if (!axesUtils.isYAxisHidden(index) && yaxe.labels.show && yaxe.labels.minWidth !== undefined) yAxisMinWidth = yaxe.labels.minWidth;
          if (!axesUtils.isYAxisHidden(index) && yaxe.labels.show && yS.result.length) {
            var lbFormatter = w.globals.yLabelFormatters[index];
            var minV = yS.niceMin === Number.MIN_VALUE ? 0 : yS.niceMin;
            var val = yS.result.reduce(function (acc, curr) {
              var _String, _String2;
              return ((_String = String(lbFormatter(acc, formatterArgs))) === null || _String === void 0 ? void 0 : _String.length) > ((_String2 = String(lbFormatter(curr, formatterArgs))) === null || _String2 === void 0 ? void 0 : _String2.length) ? acc : curr;
            }, minV);
            val = lbFormatter(val, formatterArgs);

            // the second parameter -1 is the index of tick which user can use in the formatter
            var valArr = val;

            // if user has specified a custom formatter, and the result is null or empty, we need to discard the formatter and take the value as it is.
            if (typeof val === 'undefined' || val.length === 0) {
              val = yS.niceMax;
            }
            if (w.globals.isBarHorizontal) {
              labelPad = 0;
              var barYaxisLabels = w.globals.labels.slice();

              //  get the longest string from the labels array and also apply label formatter to it
              val = Utils$1.getLargestStringFromArr(barYaxisLabels);
              val = lbFormatter(val, {
                seriesIndex: index,
                dataPointIndex: -1,
                w: w
              });
              valArr = _this.dCtx.dimHelpers.getLargestStringFromMultiArr(val, barYaxisLabels);
            }
            var graphics = new Graphics(_this.dCtx.ctx);
            var rotateStr = 'rotate('.concat(yaxe.labels.rotate, ' 0 0)');
            var rect = graphics.getTextRects(val, yaxe.labels.style.fontSize, yaxe.labels.style.fontFamily, rotateStr, false);
            var arrLabelrect = rect;
            if (val !== valArr) {
              arrLabelrect = graphics.getTextRects(valArr, yaxe.labels.style.fontSize, yaxe.labels.style.fontFamily, rotateStr, false);
            }
            ret.push({
              width: (yAxisMinWidth > arrLabelrect.width || yAxisMinWidth > rect.width ? yAxisMinWidth : arrLabelrect.width > rect.width ? arrLabelrect.width : rect.width) + labelPad,
              height: arrLabelrect.height > rect.height ? arrLabelrect.height : rect.height
            });
          } else {
            ret.push({
              width: width,
              height: height
            });
          }
        });
        return ret;
      }

      /**
       * Get Y Axis Dimensions
       * @memberof Dimensions
       * @return {{width, height}}
       **/
    }, {
      key: "getyAxisTitleCoords",
      value: function getyAxisTitleCoords() {
        var _this2 = this;
        var w = this.w;
        var ret = [];
        w.config.yaxis.map(function (yaxe, index) {
          if (yaxe.show && yaxe.title.text !== undefined) {
            var graphics = new Graphics(_this2.dCtx.ctx);
            var rotateStr = 'rotate('.concat(yaxe.title.rotate, ' 0 0)');
            var rect = graphics.getTextRects(yaxe.title.text, yaxe.title.style.fontSize, yaxe.title.style.fontFamily, rotateStr, false);
            ret.push({
              width: rect.width,
              height: rect.height
            });
          } else {
            ret.push({
              width: 0,
              height: 0
            });
          }
        });
        return ret;
      }
    }, {
      key: "getTotalYAxisWidth",
      value: function getTotalYAxisWidth() {
        var w = this.w;
        var yAxisWidth = 0;
        var yAxisWidthLeft = 0;
        var yAxisWidthRight = 0;
        var padding = w.globals.yAxisScale.length > 1 ? 10 : 0;
        var axesUtils = new AxesUtils(this.dCtx.ctx);
        var isHiddenYAxis = function isHiddenYAxis(index) {
          return w.globals.ignoreYAxisIndexes.indexOf(index) > -1;
        };
        var padForLabelTitle = function padForLabelTitle(coord, index) {
          var floating = w.config.yaxis[index].floating;
          var width = 0;
          if (coord.width > 0 && !floating) {
            width = coord.width + padding;
            if (isHiddenYAxis(index)) {
              width = width - coord.width - padding;
            }
          } else {
            width = floating || axesUtils.isYAxisHidden(index) ? 0 : 5;
          }
          w.config.yaxis[index].opposite ? yAxisWidthRight = yAxisWidthRight + width : yAxisWidthLeft = yAxisWidthLeft + width;
          yAxisWidth = yAxisWidth + width;
        };
        w.globals.yLabelsCoords.map(function (yLabelCoord, index) {
          padForLabelTitle(yLabelCoord, index);
        });
        w.globals.yTitleCoords.map(function (yTitleCoord, index) {
          padForLabelTitle(yTitleCoord, index);
        });
        if (w.globals.isBarHorizontal && !w.config.yaxis[0].floating) {
          yAxisWidth = w.globals.yLabelsCoords[0].width + w.globals.yTitleCoords[0].width + 15;
        }
        this.dCtx.yAxisWidthLeft = yAxisWidthLeft;
        this.dCtx.yAxisWidthRight = yAxisWidthRight;
        return yAxisWidth;
      }
    }]);
    return DimYAxis;
  }();

  var DimGrid = /*#__PURE__*/function () {
    function DimGrid(dCtx) {
      _classCallCheck(this, DimGrid);
      this.w = dCtx.w;
      this.dCtx = dCtx;
    }
    _createClass(DimGrid, [{
      key: "gridPadForColumnsInNumericAxis",
      value: function gridPadForColumnsInNumericAxis(gridWidth) {
        var w = this.w;
        var cnf = w.config,
          gl = w.globals;
        if (gl.noData || gl.collapsedSeries.length + gl.ancillaryCollapsedSeries.length === cnf.series.length) {
          return 0;
        }
        var hasBar = function hasBar(type) {
          return ['bar', 'rangeBar', 'candlestick', 'boxPlot'].includes(type);
        };
        var type = cnf.chart.type;
        var barWidth = 0;
        var seriesLen = hasBar(type) ? cnf.series.length : 1;
        if (gl.comboBarCount > 0) {
          seriesLen = gl.comboBarCount;
        }
        gl.collapsedSeries.forEach(function (c) {
          if (hasBar(c.type)) {
            seriesLen -= 1;
          }
        });
        if (cnf.chart.stacked) {
          seriesLen = 1;
        }
        var barsPresent = hasBar(type) || gl.comboBarCount > 0;
        var xRange = Math.abs(gl.initialMaxX - gl.initialMinX);
        if (barsPresent && gl.isXNumeric && !gl.isBarHorizontal && seriesLen > 0 && xRange !== 0) {
          if (xRange <= 3) {
            xRange = gl.dataPoints;
          }
          var xRatio = xRange / gridWidth;
          var xDivision = gl.minXDiff && gl.minXDiff / xRatio > 0 ? gl.minXDiff / xRatio : 0;
          if (xDivision > gridWidth / 2) {
            xDivision /= 2;
          }
          // Here, barWidth is assumed to be the width occupied by a group of bars.
          // There will be one bar in the group for each series plotted.
          // Note: This version of the following math is different to that over in
          // Helpers.js. Don't assume they should be the same. Over there,
          // xDivision is computed differently and it's used on different charts.
          // They were the same, but the solution to
          // https://github.com/apexcharts/apexcharts.js/issues/4178
          // was to remove the division by seriesLen.
          barWidth = xDivision * parseInt(cnf.plotOptions.bar.columnWidth, 10) / 100;
          if (barWidth < 1) {
            barWidth = 1;
          }
          gl.barPadForNumericAxis = barWidth;
        }
        return barWidth;
      }
    }, {
      key: "gridPadFortitleSubtitle",
      value: function gridPadFortitleSubtitle() {
        var _this = this;
        var w = this.w;
        var gl = w.globals;
        var gridShrinkOffset = this.dCtx.isSparkline || !gl.axisCharts ? 0 : 10;
        var titleSubtitle = ['title', 'subtitle'];
        titleSubtitle.forEach(function (t) {
          if (w.config[t].text !== undefined) {
            gridShrinkOffset += w.config[t].margin;
          } else {
            gridShrinkOffset += _this.dCtx.isSparkline || !gl.axisCharts ? 0 : 5;
          }
        });
        if (w.config.legend.show && w.config.legend.position === 'bottom' && !w.config.legend.floating && !gl.axisCharts) {
          gridShrinkOffset += 10;
        }
        var titleCoords = this.dCtx.dimHelpers.getTitleSubtitleCoords('title');
        var subtitleCoords = this.dCtx.dimHelpers.getTitleSubtitleCoords('subtitle');
        gl.gridHeight -= titleCoords.height + subtitleCoords.height + gridShrinkOffset;
        gl.translateY += titleCoords.height + subtitleCoords.height + gridShrinkOffset;
      }
    }, {
      key: "setGridXPosForDualYAxis",
      value: function setGridXPosForDualYAxis(yTitleCoords, yaxisLabelCoords) {
        var w = this.w;
        var axesUtils = new AxesUtils(this.dCtx.ctx);
        w.config.yaxis.forEach(function (yaxe, index) {
          if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1 && !yaxe.floating && !axesUtils.isYAxisHidden(index)) {
            if (yaxe.opposite) {
              w.globals.translateX -= yaxisLabelCoords[index].width + yTitleCoords[index].width + parseInt(yaxe.labels.style.fontSize, 10) / 1.2 + 12;
            }

            // fixes apexcharts.js#1599
            if (w.globals.translateX < 2) {
              w.globals.translateX = 2;
            }
          }
        });
      }
    }]);
    return DimGrid;
  }();

  /**
   * ApexCharts Dimensions Class for calculating rects of all elements that are drawn and will be drawn.
   *
   * @module Dimensions
   **/
  var Dimensions = /*#__PURE__*/function () {
    function Dimensions(ctx) {
      _classCallCheck(this, Dimensions);
      this.ctx = ctx;
      this.w = ctx.w;
      this.lgRect = {};
      this.yAxisWidth = 0;
      this.yAxisWidthLeft = 0;
      this.yAxisWidthRight = 0;
      this.xAxisHeight = 0;
      this.isSparkline = this.w.config.chart.sparkline.enabled;
      this.dimHelpers = new Helpers$3(this);
      this.dimYAxis = new DimYAxis(this);
      this.dimXAxis = new DimXAxis(this);
      this.dimGrid = new DimGrid(this);
      this.lgWidthForSideLegends = 0;
      this.gridPad = this.w.config.grid.padding;
      this.xPadRight = 0;
      this.xPadLeft = 0;
    }

    /**
     * @memberof Dimensions
     * @param {object} w - chart context
     **/
    _createClass(Dimensions, [{
      key: "plotCoords",
      value: function plotCoords() {
        var _this = this;
        var w = this.w;
        var gl = w.globals;
        this.lgRect = this.dimHelpers.getLegendsRect();
        this.datalabelsCoords = {
          width: 0,
          height: 0
        };
        var maxStrokeWidth = Array.isArray(w.config.stroke.width) ? Math.max.apply(Math, _toConsumableArray(w.config.stroke.width)) : w.config.stroke.width;
        if (this.isSparkline) {
          if (w.config.markers.discrete.length > 0 || w.config.markers.size > 0) {
            Object.entries(this.gridPad).forEach(function (_ref) {
              var _ref2 = _slicedToArray(_ref, 2),
                k = _ref2[0],
                v = _ref2[1];
              _this.gridPad[k] = Math.max(v, _this.w.globals.markers.largestSize / 1.5);
            });
          }
          this.gridPad.top = Math.max(maxStrokeWidth / 2, this.gridPad.top);
          this.gridPad.bottom = Math.max(maxStrokeWidth / 2, this.gridPad.bottom);
        }
        if (gl.axisCharts) {
          // for line / area / scatter / column
          this.setDimensionsForAxisCharts();
        } else {
          // for pie / donuts / circle
          this.setDimensionsForNonAxisCharts();
        }
        this.dimGrid.gridPadFortitleSubtitle();

        // after calculating everything, apply padding set by user
        gl.gridHeight = gl.gridHeight - this.gridPad.top - this.gridPad.bottom;
        gl.gridWidth = gl.gridWidth - this.gridPad.left - this.gridPad.right - this.xPadRight - this.xPadLeft;
        var barWidth = this.dimGrid.gridPadForColumnsInNumericAxis(gl.gridWidth);
        gl.gridWidth = gl.gridWidth - barWidth * 2;
        gl.translateX = gl.translateX + this.gridPad.left + this.xPadLeft + (barWidth > 0 ? barWidth : 0);
        gl.translateY = gl.translateY + this.gridPad.top;
      }
    }, {
      key: "setDimensionsForAxisCharts",
      value: function setDimensionsForAxisCharts() {
        var _this2 = this;
        var w = this.w;
        var gl = w.globals;
        var yaxisLabelCoords = this.dimYAxis.getyAxisLabelsCoords();
        var yTitleCoords = this.dimYAxis.getyAxisTitleCoords();
        if (gl.isSlopeChart) {
          this.datalabelsCoords = this.dimHelpers.getDatalabelsRect();
        }
        w.globals.yLabelsCoords = [];
        w.globals.yTitleCoords = [];
        w.config.yaxis.map(function (yaxe, index) {
          // store the labels and titles coords in global vars
          w.globals.yLabelsCoords.push({
            width: yaxisLabelCoords[index].width,
            index: index
          });
          w.globals.yTitleCoords.push({
            width: yTitleCoords[index].width,
            index: index
          });
        });
        this.yAxisWidth = this.dimYAxis.getTotalYAxisWidth();
        var xaxisLabelCoords = this.dimXAxis.getxAxisLabelsCoords();
        var xaxisGroupLabelCoords = this.dimXAxis.getxAxisGroupLabelsCoords();
        var xtitleCoords = this.dimXAxis.getxAxisTitleCoords();
        this.conditionalChecksForAxisCoords(xaxisLabelCoords, xtitleCoords, xaxisGroupLabelCoords);
        gl.translateXAxisY = w.globals.rotateXLabels ? this.xAxisHeight / 8 : -4;
        gl.translateXAxisX = w.globals.rotateXLabels && w.globals.isXNumeric && w.config.xaxis.labels.rotate <= -45 ? -this.xAxisWidth / 4 : 0;
        if (w.globals.isBarHorizontal) {
          gl.rotateXLabels = false;
          gl.translateXAxisY = -1 * (parseInt(w.config.xaxis.labels.style.fontSize, 10) / 1.5);
        }
        gl.translateXAxisY = gl.translateXAxisY + w.config.xaxis.labels.offsetY;
        gl.translateXAxisX = gl.translateXAxisX + w.config.xaxis.labels.offsetX;
        var yAxisWidth = this.yAxisWidth;
        var xAxisHeight = this.xAxisHeight;
        gl.xAxisLabelsHeight = this.xAxisHeight - xtitleCoords.height;
        gl.xAxisGroupLabelsHeight = gl.xAxisLabelsHeight - xaxisLabelCoords.height;
        gl.xAxisLabelsWidth = this.xAxisWidth;
        gl.xAxisHeight = this.xAxisHeight;
        var translateY = 10;
        if (w.config.chart.type === 'radar' || this.isSparkline) {
          yAxisWidth = 0;
          xAxisHeight = 0;
        }
        if (this.isSparkline) {
          this.lgRect = {
            height: 0,
            width: 0
          };
        }
        if (this.isSparkline || w.config.chart.type === 'treemap') {
          yAxisWidth = 0;
          xAxisHeight = 0;
          translateY = 0;
        }
        if (!this.isSparkline && w.config.chart.type !== 'treemap') {
          this.dimXAxis.additionalPaddingXLabels(xaxisLabelCoords);
        }
        var legendTopBottom = function legendTopBottom() {
          gl.translateX = yAxisWidth + _this2.datalabelsCoords.width;
          gl.gridHeight = gl.svgHeight - _this2.lgRect.height - xAxisHeight - (!_this2.isSparkline && w.config.chart.type !== 'treemap' ? w.globals.rotateXLabels ? 10 : 15 : 0);
          gl.gridWidth = gl.svgWidth - yAxisWidth - _this2.datalabelsCoords.width * 2;
        };
        if (w.config.xaxis.position === 'top') translateY = gl.xAxisHeight - w.config.xaxis.axisTicks.height - 5;
        switch (w.config.legend.position) {
          case 'bottom':
            gl.translateY = translateY;
            legendTopBottom();
            break;
          case 'top':
            gl.translateY = this.lgRect.height + translateY;
            legendTopBottom();
            break;
          case 'left':
            gl.translateY = translateY;
            gl.translateX = this.lgRect.width + yAxisWidth + this.datalabelsCoords.width;
            gl.gridHeight = gl.svgHeight - xAxisHeight - 12;
            gl.gridWidth = gl.svgWidth - this.lgRect.width - yAxisWidth - this.datalabelsCoords.width * 2;
            break;
          case 'right':
            gl.translateY = translateY;
            gl.translateX = yAxisWidth + this.datalabelsCoords.width;
            gl.gridHeight = gl.svgHeight - xAxisHeight - 12;
            gl.gridWidth = gl.svgWidth - this.lgRect.width - yAxisWidth - this.datalabelsCoords.width * 2 - 5;
            break;
          default:
            throw new Error('Legend position not supported');
        }
        this.dimGrid.setGridXPosForDualYAxis(yTitleCoords, yaxisLabelCoords);

        // after drawing everything, set the Y axis positions
        var objyAxis = new YAxis(this.ctx);
        objyAxis.setYAxisXPosition(yaxisLabelCoords, yTitleCoords);
      }
    }, {
      key: "setDimensionsForNonAxisCharts",
      value: function setDimensionsForNonAxisCharts() {
        var w = this.w;
        var gl = w.globals;
        var cnf = w.config;
        var xPad = 0;
        if (w.config.legend.show && !w.config.legend.floating) {
          xPad = 20;
        }
        var type = cnf.chart.type === 'pie' || cnf.chart.type === 'polarArea' || cnf.chart.type === 'donut' ? 'pie' : 'radialBar';
        var offY = cnf.plotOptions[type].offsetY;
        var offX = cnf.plotOptions[type].offsetX;
        if (!cnf.legend.show || cnf.legend.floating) {
          gl.gridHeight = gl.svgHeight;
          var maxWidth = gl.dom.elWrap.getBoundingClientRect().width;
          gl.gridWidth = Math.min(maxWidth, gl.gridHeight);
          gl.translateY = offY;
          gl.translateX = offX + (gl.svgWidth - gl.gridWidth) / 2;
          return;
        }
        switch (cnf.legend.position) {
          case 'bottom':
            gl.gridHeight = gl.svgHeight - this.lgRect.height;
            gl.gridWidth = gl.svgWidth;
            gl.translateY = offY - 10;
            gl.translateX = offX + (gl.svgWidth - gl.gridWidth) / 2;
            break;
          case 'top':
            gl.gridHeight = gl.svgHeight - this.lgRect.height;
            gl.gridWidth = gl.svgWidth;
            gl.translateY = this.lgRect.height + offY + 10;
            gl.translateX = offX + (gl.svgWidth - gl.gridWidth) / 2;
            break;
          case 'left':
            gl.gridWidth = gl.svgWidth - this.lgRect.width - xPad;
            gl.gridHeight = cnf.chart.height !== 'auto' ? gl.svgHeight : gl.gridWidth;
            gl.translateY = offY;
            gl.translateX = offX + this.lgRect.width + xPad;
            break;
          case 'right':
            gl.gridWidth = gl.svgWidth - this.lgRect.width - xPad - 5;
            gl.gridHeight = cnf.chart.height !== 'auto' ? gl.svgHeight : gl.gridWidth;
            gl.translateY = offY;
            gl.translateX = offX + 10;
            break;
          default:
            throw new Error('Legend position not supported');
        }
      }
    }, {
      key: "conditionalChecksForAxisCoords",
      value: function conditionalChecksForAxisCoords(xaxisLabelCoords, xtitleCoords, xaxisGroupLabelCoords) {
        var w = this.w;
        var xAxisNum = w.globals.hasXaxisGroups ? 2 : 1;
        var baseXAxisHeight = xaxisGroupLabelCoords.height + xaxisLabelCoords.height + xtitleCoords.height;
        var xAxisHeightMultiplicate = w.globals.isMultiLineX ? 1.2 : w.globals.LINE_HEIGHT_RATIO;
        var rotatedXAxisOffset = w.globals.rotateXLabels ? 22 : 10;
        var rotatedXAxisLegendOffset = w.globals.rotateXLabels && w.config.legend.position === 'bottom';
        var additionalOffset = rotatedXAxisLegendOffset ? 10 : 0;
        this.xAxisHeight = baseXAxisHeight * xAxisHeightMultiplicate + xAxisNum * rotatedXAxisOffset + additionalOffset;
        this.xAxisWidth = xaxisLabelCoords.width;
        if (this.xAxisHeight - xtitleCoords.height > w.config.xaxis.labels.maxHeight) {
          this.xAxisHeight = w.config.xaxis.labels.maxHeight;
        }
        if (w.config.xaxis.labels.minHeight && this.xAxisHeight < w.config.xaxis.labels.minHeight) {
          this.xAxisHeight = w.config.xaxis.labels.minHeight;
        }
        if (w.config.xaxis.floating) {
          this.xAxisHeight = 0;
        }
        var minYAxisWidth = 0;
        var maxYAxisWidth = 0;
        w.config.yaxis.forEach(function (y) {
          minYAxisWidth += y.labels.minWidth;
          maxYAxisWidth += y.labels.maxWidth;
        });
        if (this.yAxisWidth < minYAxisWidth) {
          this.yAxisWidth = minYAxisWidth;
        }
        if (this.yAxisWidth > maxYAxisWidth) {
          this.yAxisWidth = maxYAxisWidth;
        }
      }
    }]);
    return Dimensions;
  }();

  var Helpers$2 = /*#__PURE__*/function () {
    function Helpers(lgCtx) {
      _classCallCheck(this, Helpers);
      this.w = lgCtx.w;
      this.lgCtx = lgCtx;
    }
    _createClass(Helpers, [{
      key: "getLegendStyles",
      value: function getLegendStyles() {
        var _this$lgCtx$ctx, _this$lgCtx$ctx$opts, _this$lgCtx$ctx$opts$;
        var stylesheet = document.createElement('style');
        stylesheet.setAttribute('type', 'text/css');
        var nonce = ((_this$lgCtx$ctx = this.lgCtx.ctx) === null || _this$lgCtx$ctx === void 0 ? void 0 : (_this$lgCtx$ctx$opts = _this$lgCtx$ctx.opts) === null || _this$lgCtx$ctx$opts === void 0 ? void 0 : (_this$lgCtx$ctx$opts$ = _this$lgCtx$ctx$opts.chart) === null || _this$lgCtx$ctx$opts$ === void 0 ? void 0 : _this$lgCtx$ctx$opts$.nonce) || this.w.config.chart.nonce;
        if (nonce) {
          stylesheet.setAttribute('nonce', nonce);
        }
        var text = "\n      .apexcharts-flip-y {\n        transform: scaleY(-1) translateY(-100%);\n        transform-origin: top;\n        transform-box: fill-box;\n      }\n      .apexcharts-flip-x {\n        transform: scaleX(-1);\n        transform-origin: center;\n        transform-box: fill-box;\n      }\n      .apexcharts-legend {\n        display: flex;\n        overflow: auto;\n        padding: 0 10px;\n      }\n      .apexcharts-legend.apx-legend-position-bottom, .apexcharts-legend.apx-legend-position-top {\n        flex-wrap: wrap\n      }\n      .apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {\n        flex-direction: column;\n        bottom: 0;\n      }\n      .apexcharts-legend.apx-legend-position-bottom.apexcharts-align-left, .apexcharts-legend.apx-legend-position-top.apexcharts-align-left, .apexcharts-legend.apx-legend-position-right, .apexcharts-legend.apx-legend-position-left {\n        justify-content: flex-start;\n      }\n      .apexcharts-legend.apx-legend-position-bottom.apexcharts-align-center, .apexcharts-legend.apx-legend-position-top.apexcharts-align-center {\n        justify-content: center;\n      }\n      .apexcharts-legend.apx-legend-position-bottom.apexcharts-align-right, .apexcharts-legend.apx-legend-position-top.apexcharts-align-right {\n        justify-content: flex-end;\n      }\n      .apexcharts-legend-series {\n        cursor: pointer;\n        line-height: normal;\n        display: flex;\n        align-items: center;\n      }\n      .apexcharts-legend-text {\n        position: relative;\n        font-size: 14px;\n      }\n      .apexcharts-legend-text *, .apexcharts-legend-marker * {\n        pointer-events: none;\n      }\n      .apexcharts-legend-marker {\n        position: relative;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        cursor: pointer;\n        margin-right: 1px;\n      }\n\n      .apexcharts-legend-series.apexcharts-no-click {\n        cursor: auto;\n      }\n      .apexcharts-legend .apexcharts-hidden-zero-series, .apexcharts-legend .apexcharts-hidden-null-series {\n        display: none !important;\n      }\n      .apexcharts-inactive-legend {\n        opacity: 0.45;\n      }";
        var rules = document.createTextNode(text);
        stylesheet.appendChild(rules);
        return stylesheet;
      }
    }, {
      key: "getLegendDimensions",
      value: function getLegendDimensions() {
        var w = this.w;
        var currLegendsWrap = w.globals.dom.baseEl.querySelector('.apexcharts-legend');
        var _currLegendsWrap$getB = currLegendsWrap.getBoundingClientRect(),
          currLegendsWrapWidth = _currLegendsWrap$getB.width,
          currLegendsWrapHeight = _currLegendsWrap$getB.height;
        return {
          clwh: currLegendsWrapHeight,
          clww: currLegendsWrapWidth
        };
      }
    }, {
      key: "appendToForeignObject",
      value: function appendToForeignObject() {
        var gl = this.w.globals;
        gl.dom.elLegendForeign.appendChild(this.getLegendStyles());
      }
    }, {
      key: "toggleDataSeries",
      value: function toggleDataSeries(seriesCnt, isHidden) {
        var _this = this;
        var w = this.w;
        if (w.globals.axisCharts || w.config.chart.type === 'radialBar') {
          w.globals.resized = true; // we don't want initial animations again

          var seriesEl = null;
          var realIndex = null;

          // yes, make it null. 1 series will rise at a time
          w.globals.risingSeries = [];
          if (w.globals.axisCharts) {
            seriesEl = w.globals.dom.baseEl.querySelector(".apexcharts-series[data\\:realIndex='".concat(seriesCnt, "']"));
            realIndex = parseInt(seriesEl.getAttribute('data:realIndex'), 10);
          } else {
            seriesEl = w.globals.dom.baseEl.querySelector(".apexcharts-series[rel='".concat(seriesCnt + 1, "']"));
            realIndex = parseInt(seriesEl.getAttribute('rel'), 10) - 1;
          }
          if (isHidden) {
            var seriesToMakeVisible = [{
              cs: w.globals.collapsedSeries,
              csi: w.globals.collapsedSeriesIndices
            }, {
              cs: w.globals.ancillaryCollapsedSeries,
              csi: w.globals.ancillaryCollapsedSeriesIndices
            }];
            seriesToMakeVisible.forEach(function (r) {
              _this.riseCollapsedSeries(r.cs, r.csi, realIndex);
            });
          } else {
            this.hideSeries({
              seriesEl: seriesEl,
              realIndex: realIndex
            });
          }
        } else {
          // for non-axis charts i.e pie / donuts
          var _seriesEl = w.globals.dom.Paper.select(" .apexcharts-series[rel='".concat(seriesCnt + 1, "'] path"));
          var type = w.config.chart.type;
          if (type === 'pie' || type === 'polarArea' || type === 'donut') {
            var dataLabels = w.config.plotOptions.pie.donut.labels;
            var graphics = new Graphics(this.lgCtx.ctx);
            graphics.pathMouseDown(_seriesEl.members[0], null);
            this.lgCtx.ctx.pie.printDataLabelsInner(_seriesEl.members[0].node, dataLabels);
          }
          _seriesEl.fire('click');
        }
      }
    }, {
      key: "getSeriesAfterCollapsing",
      value: function getSeriesAfterCollapsing(_ref) {
        var realIndex = _ref.realIndex;
        var w = this.w;
        var gl = w.globals;
        var series = Utils$1.clone(w.config.series);
        if (gl.axisCharts) {
          var yaxis = w.config.yaxis[gl.seriesYAxisReverseMap[realIndex]];
          var collapseData = {
            index: realIndex,
            data: series[realIndex].data.slice(),
            type: series[realIndex].type || w.config.chart.type
          };
          if (yaxis && yaxis.show && yaxis.showAlways) {
            if (gl.ancillaryCollapsedSeriesIndices.indexOf(realIndex) < 0) {
              gl.ancillaryCollapsedSeries.push(collapseData);
              gl.ancillaryCollapsedSeriesIndices.push(realIndex);
            }
          } else {
            if (gl.collapsedSeriesIndices.indexOf(realIndex) < 0) {
              gl.collapsedSeries.push(collapseData);
              gl.collapsedSeriesIndices.push(realIndex);
              var removeIndexOfRising = gl.risingSeries.indexOf(realIndex);
              gl.risingSeries.splice(removeIndexOfRising, 1);
            }
          }
        } else {
          gl.collapsedSeries.push({
            index: realIndex,
            data: series[realIndex]
          });
          gl.collapsedSeriesIndices.push(realIndex);
        }
        gl.allSeriesCollapsed = gl.collapsedSeries.length + gl.ancillaryCollapsedSeries.length === w.config.series.length;
        return this._getSeriesBasedOnCollapsedState(series);
      }
    }, {
      key: "hideSeries",
      value: function hideSeries(_ref2) {
        var seriesEl = _ref2.seriesEl,
          realIndex = _ref2.realIndex;
        var w = this.w;
        var series = this.getSeriesAfterCollapsing({
          realIndex: realIndex
        });
        var seriesChildren = seriesEl.childNodes;
        for (var sc = 0; sc < seriesChildren.length; sc++) {
          if (seriesChildren[sc].classList.contains('apexcharts-series-markers-wrap')) {
            if (seriesChildren[sc].classList.contains('apexcharts-hide')) {
              seriesChildren[sc].classList.remove('apexcharts-hide');
            } else {
              seriesChildren[sc].classList.add('apexcharts-hide');
            }
          }
        }
        this.lgCtx.ctx.updateHelpers._updateSeries(series, w.config.chart.animations.dynamicAnimation.enabled);
      }
    }, {
      key: "riseCollapsedSeries",
      value: function riseCollapsedSeries(collapsedSeries, seriesIndices, realIndex) {
        var w = this.w;
        var series = Utils$1.clone(w.config.series);
        if (collapsedSeries.length > 0) {
          for (var c = 0; c < collapsedSeries.length; c++) {
            if (collapsedSeries[c].index === realIndex) {
              if (w.globals.axisCharts) {
                series[realIndex].data = collapsedSeries[c].data.slice();
              } else {
                series[realIndex] = collapsedSeries[c].data;
              }
              series[realIndex].hidden = false;
              collapsedSeries.splice(c, 1);
              seriesIndices.splice(c, 1);
              w.globals.risingSeries.push(realIndex);
            }
          }
          series = this._getSeriesBasedOnCollapsedState(series);
          this.lgCtx.ctx.updateHelpers._updateSeries(series, w.config.chart.animations.dynamicAnimation.enabled);
        }
      }
    }, {
      key: "_getSeriesBasedOnCollapsedState",
      value: function _getSeriesBasedOnCollapsedState(series) {
        var w = this.w;
        var collapsed = 0;
        if (w.globals.axisCharts) {
          series.forEach(function (s, sI) {
            if (!(w.globals.collapsedSeriesIndices.indexOf(sI) < 0 && w.globals.ancillaryCollapsedSeriesIndices.indexOf(sI) < 0)) {
              series[sI].data = [];
              collapsed++;
            }
          });
        } else {
          series.forEach(function (s, sI) {
            if (!w.globals.collapsedSeriesIndices.indexOf(sI) < 0) {
              series[sI] = 0;
              collapsed++;
            }
          });
        }
        w.globals.allSeriesCollapsed = collapsed === series.length;
        return series;
      }
    }]);
    return Helpers;
  }();

  /**
   * ApexCharts Legend Class to draw legend.
   *
   * @module Legend
   **/
  var Legend = /*#__PURE__*/function () {
    function Legend(ctx) {
      _classCallCheck(this, Legend);
      this.ctx = ctx;
      this.w = ctx.w;
      this.onLegendClick = this.onLegendClick.bind(this);
      this.onLegendHovered = this.onLegendHovered.bind(this);
      this.isBarsDistributed = this.w.config.chart.type === 'bar' && this.w.config.plotOptions.bar.distributed && this.w.config.series.length === 1;
      this.legendHelpers = new Helpers$2(this);
    }
    _createClass(Legend, [{
      key: "init",
      value: function init() {
        var w = this.w;
        var gl = w.globals;
        var cnf = w.config;
        var showLegendAlways = cnf.legend.showForSingleSeries && gl.series.length === 1 || this.isBarsDistributed || gl.series.length > 1;
        this.legendHelpers.appendToForeignObject();
        if ((showLegendAlways || !gl.axisCharts) && cnf.legend.show) {
          while (gl.dom.elLegendWrap.firstChild) {
            gl.dom.elLegendWrap.removeChild(gl.dom.elLegendWrap.firstChild);
          }
          this.drawLegends();
          if (cnf.legend.position === 'bottom' || cnf.legend.position === 'top') {
            this.legendAlignHorizontal();
          } else if (cnf.legend.position === 'right' || cnf.legend.position === 'left') {
            this.legendAlignVertical();
          }
        }
      }
    }, {
      key: "createLegendMarker",
      value: function createLegendMarker(_ref) {
        var i = _ref.i,
          fillcolor = _ref.fillcolor;
        var w = this.w;
        var elMarker = document.createElement('span');
        elMarker.classList.add('apexcharts-legend-marker');
        var mShape = w.config.legend.markers.shape || w.config.markers.shape;
        var shape = mShape;
        if (Array.isArray(mShape)) {
          shape = mShape[i];
        }
        var mSize = Array.isArray(w.config.legend.markers.size) ? parseFloat(w.config.legend.markers.size[i]) : parseFloat(w.config.legend.markers.size);
        var mOffsetX = Array.isArray(w.config.legend.markers.offsetX) ? parseFloat(w.config.legend.markers.offsetX[i]) : parseFloat(w.config.legend.markers.offsetX);
        var mOffsetY = Array.isArray(w.config.legend.markers.offsetY) ? parseFloat(w.config.legend.markers.offsetY[i]) : parseFloat(w.config.legend.markers.offsetY);
        var mBorderWidth = Array.isArray(w.config.legend.markers.strokeWidth) ? parseFloat(w.config.legend.markers.strokeWidth[i]) : parseFloat(w.config.legend.markers.strokeWidth);
        var mStyle = elMarker.style;
        mStyle.height = (mSize + mBorderWidth) * 2 + 'px';
        mStyle.width = (mSize + mBorderWidth) * 2 + 'px';
        mStyle.left = mOffsetX + 'px';
        mStyle.top = mOffsetY + 'px';
        if (w.config.legend.markers.customHTML) {
          mStyle.background = 'transparent';
          mStyle.color = fillcolor[i];
          if (Array.isArray(w.config.legend.markers.customHTML)) {
            if (w.config.legend.markers.customHTML[i]) {
              elMarker.innerHTML = w.config.legend.markers.customHTML[i]();
            }
          } else {
            elMarker.innerHTML = w.config.legend.markers.customHTML();
          }
        } else {
          var markers = new Markers(this.ctx);
          var markerConfig = markers.getMarkerConfig({
            cssClass: "apexcharts-legend-marker apexcharts-marker apexcharts-marker-".concat(shape),
            seriesIndex: i,
            strokeWidth: mBorderWidth,
            size: mSize
          });
          var SVGMarker = SVG(elMarker).size('100%', '100%');
          var marker = new Graphics(this.ctx).drawMarker(0, 0, _objectSpread2(_objectSpread2({}, markerConfig), {}, {
            pointFillColor: Array.isArray(fillcolor) ? fillcolor[i] : markerConfig.pointFillColor,
            shape: shape
          }));
          var shapesEls = SVG.select('.apexcharts-legend-marker.apexcharts-marker').members;
          shapesEls.forEach(function (shapeEl) {
            if (shapeEl.node.classList.contains('apexcharts-marker-triangle')) {
              shapeEl.node.style.transform = 'translate(50%, 45%)';
            } else {
              shapeEl.node.style.transform = 'translate(50%, 50%)';
            }
          });
          SVGMarker.add(marker);
        }
        return elMarker;
      }
    }, {
      key: "drawLegends",
      value: function drawLegends() {
        var me = this;
        var w = this.w;
        var fontFamily = w.config.legend.fontFamily;
        var legendNames = w.globals.seriesNames;
        var fillcolor = w.config.legend.markers.fillColors ? w.config.legend.markers.fillColors.slice() : w.globals.colors.slice();
        if (w.config.chart.type === 'heatmap') {
          var ranges = w.config.plotOptions.heatmap.colorScale.ranges;
          legendNames = ranges.map(function (colorScale) {
            return colorScale.name ? colorScale.name : colorScale.from + ' - ' + colorScale.to;
          });
          fillcolor = ranges.map(function (color) {
            return color.color;
          });
        } else if (this.isBarsDistributed) {
          legendNames = w.globals.labels.slice();
        }
        if (w.config.legend.customLegendItems.length) {
          legendNames = w.config.legend.customLegendItems;
        }
        var legendFormatter = w.globals.legendFormatter;
        var isLegendInversed = w.config.legend.inverseOrder;
        for (var i = isLegendInversed ? legendNames.length - 1 : 0; isLegendInversed ? i >= 0 : i <= legendNames.length - 1; isLegendInversed ? i-- : i++) {
          var _w$config$legend$labe;
          var text = legendFormatter(legendNames[i], {
            seriesIndex: i,
            w: w
          });
          var collapsedSeries = false;
          var ancillaryCollapsedSeries = false;
          if (w.globals.collapsedSeries.length > 0) {
            for (var c = 0; c < w.globals.collapsedSeries.length; c++) {
              if (w.globals.collapsedSeries[c].index === i) {
                collapsedSeries = true;
              }
            }
          }
          if (w.globals.ancillaryCollapsedSeriesIndices.length > 0) {
            for (var _c = 0; _c < w.globals.ancillaryCollapsedSeriesIndices.length; _c++) {
              if (w.globals.ancillaryCollapsedSeriesIndices[_c] === i) {
                ancillaryCollapsedSeries = true;
              }
            }
          }
          var elMarker = this.createLegendMarker({
            i: i,
            fillcolor: fillcolor
          });
          Graphics.setAttrs(elMarker, {
            rel: i + 1,
            'data:collapsed': collapsedSeries || ancillaryCollapsedSeries
          });
          if (collapsedSeries || ancillaryCollapsedSeries) {
            elMarker.classList.add('apexcharts-inactive-legend');
          }
          var elLegend = document.createElement('div');
          var elLegendText = document.createElement('span');
          elLegendText.classList.add('apexcharts-legend-text');
          elLegendText.innerHTML = Array.isArray(text) ? text.join(' ') : text;
          var textColor = w.config.legend.labels.useSeriesColors ? w.globals.colors[i] : Array.isArray(w.config.legend.labels.colors) ? (_w$config$legend$labe = w.config.legend.labels.colors) === null || _w$config$legend$labe === void 0 ? void 0 : _w$config$legend$labe[i] : w.config.legend.labels.colors;
          if (!textColor) {
            textColor = w.config.chart.foreColor;
          }
          elLegendText.style.color = textColor;
          elLegendText.style.fontSize = parseFloat(w.config.legend.fontSize) + 'px';
          elLegendText.style.fontWeight = w.config.legend.fontWeight;
          elLegendText.style.fontFamily = fontFamily || w.config.chart.fontFamily;
          Graphics.setAttrs(elLegendText, {
            rel: i + 1,
            i: i,
            'data:default-text': encodeURIComponent(text),
            'data:collapsed': collapsedSeries || ancillaryCollapsedSeries
          });
          elLegend.appendChild(elMarker);
          elLegend.appendChild(elLegendText);
          var coreUtils = new CoreUtils(this.ctx);
          if (!w.config.legend.showForZeroSeries) {
            var total = coreUtils.getSeriesTotalByIndex(i);
            if (total === 0 && coreUtils.seriesHaveSameValues(i) && !coreUtils.isSeriesNull(i) && w.globals.collapsedSeriesIndices.indexOf(i) === -1 && w.globals.ancillaryCollapsedSeriesIndices.indexOf(i) === -1) {
              elLegend.classList.add('apexcharts-hidden-zero-series');
            }
          }
          if (!w.config.legend.showForNullSeries) {
            if (coreUtils.isSeriesNull(i) && w.globals.collapsedSeriesIndices.indexOf(i) === -1 && w.globals.ancillaryCollapsedSeriesIndices.indexOf(i) === -1) {
              elLegend.classList.add('apexcharts-hidden-null-series');
            }
          }
          w.globals.dom.elLegendWrap.appendChild(elLegend);
          w.globals.dom.elLegendWrap.classList.add("apexcharts-align-".concat(w.config.legend.horizontalAlign));
          w.globals.dom.elLegendWrap.classList.add('apx-legend-position-' + w.config.legend.position);
          elLegend.classList.add('apexcharts-legend-series');
          elLegend.style.margin = "".concat(w.config.legend.itemMargin.vertical, "px ").concat(w.config.legend.itemMargin.horizontal, "px");
          w.globals.dom.elLegendWrap.style.width = w.config.legend.width ? w.config.legend.width + 'px' : '';
          w.globals.dom.elLegendWrap.style.height = w.config.legend.height ? w.config.legend.height + 'px' : '';
          Graphics.setAttrs(elLegend, {
            rel: i + 1,
            seriesName: Utils$1.escapeString(legendNames[i]),
            'data:collapsed': collapsedSeries || ancillaryCollapsedSeries
          });
          if (collapsedSeries || ancillaryCollapsedSeries) {
            elLegend.classList.add('apexcharts-inactive-legend');
          }
          if (!w.config.legend.onItemClick.toggleDataSeries) {
            elLegend.classList.add('apexcharts-no-click');
          }
        }
        w.globals.dom.elWrap.addEventListener('click', me.onLegendClick, true);
        if (w.config.legend.onItemHover.highlightDataSeries && w.config.legend.customLegendItems.length === 0) {
          w.globals.dom.elWrap.addEventListener('mousemove', me.onLegendHovered, true);
          w.globals.dom.elWrap.addEventListener('mouseout', me.onLegendHovered, true);
        }
      }
    }, {
      key: "setLegendWrapXY",
      value: function setLegendWrapXY(offsetX, offsetY) {
        var w = this.w;
        var elLegendWrap = w.globals.dom.elLegendWrap;
        var legendHeight = elLegendWrap.clientHeight;
        var x = 0;
        var y = 0;
        if (w.config.legend.position === 'bottom') {
          y = w.globals.svgHeight - Math.min(legendHeight, w.globals.svgHeight / 2) - 5;
        } else if (w.config.legend.position === 'top') {
          var dim = new Dimensions(this.ctx);
          var titleH = dim.dimHelpers.getTitleSubtitleCoords('title').height;
          var subtitleH = dim.dimHelpers.getTitleSubtitleCoords('subtitle').height;
          y = (titleH > 0 ? titleH - 10 : 0) + (subtitleH > 0 ? subtitleH - 10 : 0);
        }
        elLegendWrap.style.position = 'absolute';
        x = x + offsetX + w.config.legend.offsetX;
        y = y + offsetY + w.config.legend.offsetY;
        elLegendWrap.style.left = x + 'px';
        elLegendWrap.style.top = y + 'px';
        if (w.config.legend.position === 'right') {
          elLegendWrap.style.left = 'auto';
          elLegendWrap.style.right = 25 + w.config.legend.offsetX + 'px';
        }
        var fixedHeigthWidth = ['width', 'height'];
        fixedHeigthWidth.forEach(function (hw) {
          if (elLegendWrap.style[hw]) {
            elLegendWrap.style[hw] = parseInt(w.config.legend[hw], 10) + 'px';
          }
        });
      }
    }, {
      key: "legendAlignHorizontal",
      value: function legendAlignHorizontal() {
        var w = this.w;
        var elLegendWrap = w.globals.dom.elLegendWrap;
        elLegendWrap.style.right = 0;
        var dimensions = new Dimensions(this.ctx);
        var titleRect = dimensions.dimHelpers.getTitleSubtitleCoords('title');
        var subtitleRect = dimensions.dimHelpers.getTitleSubtitleCoords('subtitle');
        var offsetX = 20;
        var offsetY = 0;
        if (w.config.legend.position === 'top') {
          offsetY = titleRect.height + subtitleRect.height + w.config.title.margin + w.config.subtitle.margin - 10;
        }
        this.setLegendWrapXY(offsetX, offsetY);
      }
    }, {
      key: "legendAlignVertical",
      value: function legendAlignVertical() {
        var w = this.w;
        var lRect = this.legendHelpers.getLegendDimensions();
        var offsetY = 20;
        var offsetX = 0;
        if (w.config.legend.position === 'left') {
          offsetX = 20;
        }
        if (w.config.legend.position === 'right') {
          offsetX = w.globals.svgWidth - lRect.clww - 10;
        }
        this.setLegendWrapXY(offsetX, offsetY);
      }
    }, {
      key: "onLegendHovered",
      value: function onLegendHovered(e) {
        var w = this.w;
        var hoverOverLegend = e.target.classList.contains('apexcharts-legend-series') || e.target.classList.contains('apexcharts-legend-text') || e.target.classList.contains('apexcharts-legend-marker');
        if (w.config.chart.type !== 'heatmap' && !this.isBarsDistributed) {
          if (!e.target.classList.contains('apexcharts-inactive-legend') && hoverOverLegend) {
            var series = new Series(this.ctx);
            series.toggleSeriesOnHover(e, e.target);
          }
        } else {
          // for heatmap handling
          if (hoverOverLegend) {
            var seriesCnt = parseInt(e.target.getAttribute('rel'), 10) - 1;
            this.ctx.events.fireEvent('legendHover', [this.ctx, seriesCnt, this.w]);
            var _series = new Series(this.ctx);
            _series.highlightRangeInSeries(e, e.target);
          }
        }
      }
    }, {
      key: "onLegendClick",
      value: function onLegendClick(e) {
        var w = this.w;
        if (w.config.legend.customLegendItems.length) return;
        if (e.target.classList.contains('apexcharts-legend-series') || e.target.classList.contains('apexcharts-legend-text') || e.target.classList.contains('apexcharts-legend-marker')) {
          var seriesCnt = parseInt(e.target.getAttribute('rel'), 10) - 1;
          var isHidden = e.target.getAttribute('data:collapsed') === 'true';
          var legendClick = this.w.config.chart.events.legendClick;
          if (typeof legendClick === 'function') {
            legendClick(this.ctx, seriesCnt, this.w);
          }
          this.ctx.events.fireEvent('legendClick', [this.ctx, seriesCnt, this.w]);
          var markerClick = this.w.config.legend.markers.onClick;
          if (typeof markerClick === 'function' && e.target.classList.contains('apexcharts-legend-marker')) {
            markerClick(this.ctx, seriesCnt, this.w);
            this.ctx.events.fireEvent('legendMarkerClick', [this.ctx, seriesCnt, this.w]);
          }

          // for now - just prevent click on heatmap legend - and allow hover only
          var clickAllowed = w.config.chart.type !== 'treemap' && w.config.chart.type !== 'heatmap' && !this.isBarsDistributed;
          if (clickAllowed && w.config.legend.onItemClick.toggleDataSeries) {
            this.legendHelpers.toggleDataSeries(seriesCnt, isHidden);
          }
        }
      }
    }]);
    return Legend;
  }();

  var icoPan = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" fill=\"#000000\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\">\n    <defs>\n        <path d=\"M0 0h24v24H0z\" id=\"a\"/>\n    </defs>\n    <clipPath id=\"b\">\n        <use overflow=\"visible\" xlink:href=\"#a\"/>\n    </clipPath>\n    <path clip-path=\"url(#b)\" d=\"M23 5.5V20c0 2.2-1.8 4-4 4h-7.3c-1.08 0-2.1-.43-2.85-1.19L1 14.83s1.26-1.23 1.3-1.25c.22-.19.49-.29.79-.29.22 0 .42.06.6.16.04.01 4.31 2.46 4.31 2.46V4c0-.83.67-1.5 1.5-1.5S11 3.17 11 4v7h1V1.5c0-.83.67-1.5 1.5-1.5S15 .67 15 1.5V11h1V2.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V11h1V5.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5z\"/>\n</svg>";

  var icoZoom = "<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"#000000\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\">\n    <path d=\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\"/>\n    <path d=\"M0 0h24v24H0V0z\" fill=\"none\"/>\n    <path d=\"M12 10h-2v2H9v-2H7V9h2V7h1v2h2v1z\"/>\n</svg>";

  var icoReset = "<svg fill=\"#000000\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\">\n    <path d=\"M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z\"/>\n    <path d=\"M0 0h24v24H0z\" fill=\"none\"/>\n</svg>";

  var icoZoomIn = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n    <path d=\"M0 0h24v24H0z\" fill=\"none\"/>\n    <path d=\"M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z\"/>\n</svg>\n";

  var icoZoomOut = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n    <path d=\"M0 0h24v24H0z\" fill=\"none\"/>\n    <path d=\"M7 11v2h10v-2H7zm5-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z\"/>\n</svg>\n";

  var icoSelect = "<svg fill=\"#6E8192\" height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\">\n    <path d=\"M0 0h24v24H0z\" fill=\"none\"/>\n    <path d=\"M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2z\"/>\n</svg>";

  var icoMenu = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z\"/></svg>";

  /**
   * ApexCharts Toolbar Class for creating toolbar in axis based charts.
   *
   * @module Toolbar
   **/
  var Toolbar = /*#__PURE__*/function () {
    function Toolbar(ctx) {
      _classCallCheck(this, Toolbar);
      this.ctx = ctx;
      this.w = ctx.w;
      var w = this.w;
      this.ev = this.w.config.chart.events;
      this.selectedClass = 'apexcharts-selected';
      this.localeValues = this.w.globals.locale.toolbar;
      this.minX = w.globals.minX;
      this.maxX = w.globals.maxX;
    }
    _createClass(Toolbar, [{
      key: "createToolbar",
      value: function createToolbar() {
        var _this = this;
        var w = this.w;
        var createDiv = function createDiv() {
          return document.createElement('div');
        };
        var elToolbarWrap = createDiv();
        elToolbarWrap.setAttribute('class', 'apexcharts-toolbar');
        elToolbarWrap.style.top = w.config.chart.toolbar.offsetY + 'px';
        elToolbarWrap.style.right = -w.config.chart.toolbar.offsetX + 3 + 'px';
        w.globals.dom.elWrap.appendChild(elToolbarWrap);
        this.elZoom = createDiv();
        this.elZoomIn = createDiv();
        this.elZoomOut = createDiv();
        this.elPan = createDiv();
        this.elSelection = createDiv();
        this.elZoomReset = createDiv();
        this.elMenuIcon = createDiv();
        this.elMenu = createDiv();
        this.elCustomIcons = [];
        this.t = w.config.chart.toolbar.tools;
        if (Array.isArray(this.t.customIcons)) {
          for (var i = 0; i < this.t.customIcons.length; i++) {
            this.elCustomIcons.push(createDiv());
          }
        }
        var toolbarControls = [];
        var appendZoomControl = function appendZoomControl(type, el, ico) {
          var tool = type.toLowerCase();
          if (_this.t[tool] && w.config.chart.zoom.enabled) {
            toolbarControls.push({
              el: el,
              icon: typeof _this.t[tool] === 'string' ? _this.t[tool] : ico,
              title: _this.localeValues[type],
              class: "apexcharts-".concat(tool, "-icon")
            });
          }
        };
        appendZoomControl('zoomIn', this.elZoomIn, icoZoomIn);
        appendZoomControl('zoomOut', this.elZoomOut, icoZoomOut);
        var zoomSelectionCtrls = function zoomSelectionCtrls(z) {
          if (_this.t[z] && w.config.chart[z].enabled) {
            toolbarControls.push({
              el: z === 'zoom' ? _this.elZoom : _this.elSelection,
              icon: typeof _this.t[z] === 'string' ? _this.t[z] : z === 'zoom' ? icoZoom : icoSelect,
              title: _this.localeValues[z === 'zoom' ? 'selectionZoom' : 'selection'],
              class: w.globals.isTouchDevice ? 'apexcharts-element-hidden' : "apexcharts-".concat(z, "-icon")
            });
          }
        };
        zoomSelectionCtrls('zoom');
        zoomSelectionCtrls('selection');
        if (this.t.pan && w.config.chart.zoom.enabled) {
          toolbarControls.push({
            el: this.elPan,
            icon: typeof this.t.pan === 'string' ? this.t.pan : icoPan,
            title: this.localeValues.pan,
            class: w.globals.isTouchDevice ? 'apexcharts-element-hidden' : 'apexcharts-pan-icon'
          });
        }
        appendZoomControl('reset', this.elZoomReset, icoReset);
        if (this.t.download) {
          toolbarControls.push({
            el: this.elMenuIcon,
            icon: typeof this.t.download === 'string' ? this.t.download : icoMenu,
            title: this.localeValues.menu,
            class: 'apexcharts-menu-icon'
          });
        }
        for (var _i = 0; _i < this.elCustomIcons.length; _i++) {
          toolbarControls.push({
            el: this.elCustomIcons[_i],
            icon: this.t.customIcons[_i].icon,
            title: this.t.customIcons[_i].title,
            index: this.t.customIcons[_i].index,
            class: 'apexcharts-toolbar-custom-icon ' + this.t.customIcons[_i].class
          });
        }
        toolbarControls.forEach(function (t, index) {
          if (t.index) {
            Utils$1.moveIndexInArray(toolbarControls, index, t.index);
          }
        });
        for (var _i2 = 0; _i2 < toolbarControls.length; _i2++) {
          Graphics.setAttrs(toolbarControls[_i2].el, {
            class: toolbarControls[_i2].class,
            title: toolbarControls[_i2].title
          });
          toolbarControls[_i2].el.innerHTML = toolbarControls[_i2].icon;
          elToolbarWrap.appendChild(toolbarControls[_i2].el);
        }
        this._createHamburgerMenu(elToolbarWrap);
        if (w.globals.zoomEnabled) {
          this.elZoom.classList.add(this.selectedClass);
        } else if (w.globals.panEnabled) {
          this.elPan.classList.add(this.selectedClass);
        } else if (w.globals.selectionEnabled) {
          this.elSelection.classList.add(this.selectedClass);
        }
        this.addToolbarEventListeners();
      }
    }, {
      key: "_createHamburgerMenu",
      value: function _createHamburgerMenu(parent) {
        this.elMenuItems = [];
        parent.appendChild(this.elMenu);
        Graphics.setAttrs(this.elMenu, {
          class: 'apexcharts-menu'
        });
        var menuItems = [{
          name: 'exportSVG',
          title: this.localeValues.exportToSVG
        }, {
          name: 'exportPNG',
          title: this.localeValues.exportToPNG
        }, {
          name: 'exportCSV',
          title: this.localeValues.exportToCSV
        }];
        for (var i = 0; i < menuItems.length; i++) {
          this.elMenuItems.push(document.createElement('div'));
          this.elMenuItems[i].innerHTML = menuItems[i].title;
          Graphics.setAttrs(this.elMenuItems[i], {
            class: "apexcharts-menu-item ".concat(menuItems[i].name),
            title: menuItems[i].title
          });
          this.elMenu.appendChild(this.elMenuItems[i]);
        }
      }
    }, {
      key: "addToolbarEventListeners",
      value: function addToolbarEventListeners() {
        var _this2 = this;
        this.elZoomReset.addEventListener('click', this.handleZoomReset.bind(this));
        this.elSelection.addEventListener('click', this.toggleZoomSelection.bind(this, 'selection'));
        this.elZoom.addEventListener('click', this.toggleZoomSelection.bind(this, 'zoom'));
        this.elZoomIn.addEventListener('click', this.handleZoomIn.bind(this));
        this.elZoomOut.addEventListener('click', this.handleZoomOut.bind(this));
        this.elPan.addEventListener('click', this.togglePanning.bind(this));
        this.elMenuIcon.addEventListener('click', this.toggleMenu.bind(this));
        this.elMenuItems.forEach(function (m) {
          if (m.classList.contains('exportSVG')) {
            m.addEventListener('click', _this2.handleDownload.bind(_this2, 'svg'));
          } else if (m.classList.contains('exportPNG')) {
            m.addEventListener('click', _this2.handleDownload.bind(_this2, 'png'));
          } else if (m.classList.contains('exportCSV')) {
            m.addEventListener('click', _this2.handleDownload.bind(_this2, 'csv'));
          }
        });
        for (var i = 0; i < this.t.customIcons.length; i++) {
          this.elCustomIcons[i].addEventListener('click', this.t.customIcons[i].click.bind(this, this.ctx, this.ctx.w));
        }
      }
    }, {
      key: "toggleZoomSelection",
      value: function toggleZoomSelection(type) {
        var charts = this.ctx.getSyncedCharts();
        charts.forEach(function (ch) {
          ch.ctx.toolbar.toggleOtherControls();
          var el = type === 'selection' ? ch.ctx.toolbar.elSelection : ch.ctx.toolbar.elZoom;
          var enabledType = type === 'selection' ? 'selectionEnabled' : 'zoomEnabled';
          ch.w.globals[enabledType] = !ch.w.globals[enabledType];
          if (!el.classList.contains(ch.ctx.toolbar.selectedClass)) {
            el.classList.add(ch.ctx.toolbar.selectedClass);
          } else {
            el.classList.remove(ch.ctx.toolbar.selectedClass);
          }
        });
      }
    }, {
      key: "getToolbarIconsReference",
      value: function getToolbarIconsReference() {
        var w = this.w;
        if (!this.elZoom) {
          this.elZoom = w.globals.dom.baseEl.querySelector('.apexcharts-zoom-icon');
        }
        if (!this.elPan) {
          this.elPan = w.globals.dom.baseEl.querySelector('.apexcharts-pan-icon');
        }
        if (!this.elSelection) {
          this.elSelection = w.globals.dom.baseEl.querySelector('.apexcharts-selection-icon');
        }
      }
    }, {
      key: "enableZoomPanFromToolbar",
      value: function enableZoomPanFromToolbar(type) {
        this.toggleOtherControls();
        type === 'pan' ? this.w.globals.panEnabled = true : this.w.globals.zoomEnabled = true;
        var el = type === 'pan' ? this.elPan : this.elZoom;
        var el2 = type === 'pan' ? this.elZoom : this.elPan;
        if (el) {
          el.classList.add(this.selectedClass);
        }
        if (el2) {
          el2.classList.remove(this.selectedClass);
        }
      }
    }, {
      key: "togglePanning",
      value: function togglePanning() {
        var charts = this.ctx.getSyncedCharts();
        charts.forEach(function (ch) {
          ch.ctx.toolbar.toggleOtherControls();
          ch.w.globals.panEnabled = !ch.w.globals.panEnabled;
          if (!ch.ctx.toolbar.elPan.classList.contains(ch.ctx.toolbar.selectedClass)) {
            ch.ctx.toolbar.elPan.classList.add(ch.ctx.toolbar.selectedClass);
          } else {
            ch.ctx.toolbar.elPan.classList.remove(ch.ctx.toolbar.selectedClass);
          }
        });
      }
    }, {
      key: "toggleOtherControls",
      value: function toggleOtherControls() {
        var _this3 = this;
        var w = this.w;
        w.globals.panEnabled = false;
        w.globals.zoomEnabled = false;
        w.globals.selectionEnabled = false;
        this.getToolbarIconsReference();
        var toggleEls = [this.elPan, this.elSelection, this.elZoom];
        toggleEls.forEach(function (el) {
          if (el) {
            el.classList.remove(_this3.selectedClass);
          }
        });
      }
    }, {
      key: "handleZoomIn",
      value: function handleZoomIn() {
        var w = this.w;
        if (w.globals.isRangeBar) {
          this.minX = w.globals.minY;
          this.maxX = w.globals.maxY;
        }
        var centerX = (this.minX + this.maxX) / 2;
        var newMinX = (this.minX + centerX) / 2;
        var newMaxX = (this.maxX + centerX) / 2;
        var newMinXMaxX = this._getNewMinXMaxX(newMinX, newMaxX);
        if (!w.globals.disableZoomIn) {
          this.zoomUpdateOptions(newMinXMaxX.minX, newMinXMaxX.maxX);
        }
      }
    }, {
      key: "handleZoomOut",
      value: function handleZoomOut() {
        var w = this.w;
        if (w.globals.isRangeBar) {
          this.minX = w.globals.minY;
          this.maxX = w.globals.maxY;
        }

        // avoid zooming out beyond 1000 which may result in NaN values being printed on x-axis
        if (w.config.xaxis.type === 'datetime' && new Date(this.minX).getUTCFullYear() < 1000) {
          return;
        }
        var centerX = (this.minX + this.maxX) / 2;
        var newMinX = this.minX - (centerX - this.minX);
        var newMaxX = this.maxX - (centerX - this.maxX);
        var newMinXMaxX = this._getNewMinXMaxX(newMinX, newMaxX);
        if (!w.globals.disableZoomOut) {
          this.zoomUpdateOptions(newMinXMaxX.minX, newMinXMaxX.maxX);
        }
      }
    }, {
      key: "_getNewMinXMaxX",
      value: function _getNewMinXMaxX(newMinX, newMaxX) {
        var shouldFloor = this.w.config.xaxis.convertedCatToNumeric;
        return {
          minX: shouldFloor ? Math.floor(newMinX) : newMinX,
          maxX: shouldFloor ? Math.floor(newMaxX) : newMaxX
        };
      }
    }, {
      key: "zoomUpdateOptions",
      value: function zoomUpdateOptions(newMinX, newMaxX) {
        var w = this.w;
        if (newMinX === undefined && newMaxX === undefined) {
          this.handleZoomReset();
          return;
        }
        if (w.config.xaxis.convertedCatToNumeric) {
          // in category charts, avoid zooming out beyond min and max
          if (newMinX < 1) {
            newMinX = 1;
            newMaxX = w.globals.dataPoints;
          }
          if (newMaxX - newMinX < 2) {
            return;
          }
        }
        var xaxis = {
          min: newMinX,
          max: newMaxX
        };
        var beforeZoomRange = this.getBeforeZoomRange(xaxis);
        if (beforeZoomRange) {
          xaxis = beforeZoomRange.xaxis;
        }
        var options = {
          xaxis: xaxis
        };
        var yaxis = Utils$1.clone(w.globals.initialConfig.yaxis);
        if (!w.config.chart.group) {
          // if chart in a group, prevent yaxis update here
          // fix issue #650
          options.yaxis = yaxis;
        }
        this.w.globals.zoomed = true;
        this.ctx.updateHelpers._updateOptions(options, false, this.w.config.chart.animations.dynamicAnimation.enabled);
        this.zoomCallback(xaxis, yaxis);
      }
    }, {
      key: "zoomCallback",
      value: function zoomCallback(xaxis, yaxis) {
        if (typeof this.ev.zoomed === 'function') {
          this.ev.zoomed(this.ctx, {
            xaxis: xaxis,
            yaxis: yaxis
          });
        }
      }
    }, {
      key: "getBeforeZoomRange",
      value: function getBeforeZoomRange(xaxis, yaxis) {
        var newRange = null;
        if (typeof this.ev.beforeZoom === 'function') {
          newRange = this.ev.beforeZoom(this, {
            xaxis: xaxis,
            yaxis: yaxis
          });
        }
        return newRange;
      }
    }, {
      key: "toggleMenu",
      value: function toggleMenu() {
        var _this4 = this;
        window.setTimeout(function () {
          if (_this4.elMenu.classList.contains('apexcharts-menu-open')) {
            _this4.elMenu.classList.remove('apexcharts-menu-open');
          } else {
            _this4.elMenu.classList.add('apexcharts-menu-open');
          }
        }, 0);
      }
    }, {
      key: "handleDownload",
      value: function handleDownload(type) {
        var w = this.w;
        var exprt = new Exports(this.ctx);
        switch (type) {
          case 'svg':
            exprt.exportToSVG(this.ctx);
            break;
          case 'png':
            exprt.exportToPng(this.ctx);
            break;
          case 'csv':
            exprt.exportToCSV({
              series: w.config.series,
              columnDelimiter: w.config.chart.toolbar.export.csv.columnDelimiter
            });
            break;
        }
      }
    }, {
      key: "handleZoomReset",
      value: function handleZoomReset(e) {
        var charts = this.ctx.getSyncedCharts();
        charts.forEach(function (ch) {
          var w = ch.w;

          // forget lastXAxis min/max as reset button isn't resetting the x-axis completely if zoomX is called before
          w.globals.lastXAxis.min = w.globals.initialConfig.xaxis.min;
          w.globals.lastXAxis.max = w.globals.initialConfig.xaxis.max;
          ch.updateHelpers.revertDefaultAxisMinMax();
          if (typeof w.config.chart.events.beforeResetZoom === 'function') {
            // here, user get an option to control xaxis and yaxis when resetZoom is called
            // at this point, whatever is returned from w.config.chart.events.beforeResetZoom
            // is set as the new xaxis/yaxis min/max
            var resetZoomRange = w.config.chart.events.beforeResetZoom(ch, w);
            if (resetZoomRange) {
              ch.updateHelpers.revertDefaultAxisMinMax(resetZoomRange);
            }
          }
          if (typeof w.config.chart.events.zoomed === 'function') {
            ch.ctx.toolbar.zoomCallback({
              min: w.config.xaxis.min,
              max: w.config.xaxis.max
            });
          }
          w.globals.zoomed = false;

          // if user has some series collapsed before hitting zoom reset button,
          // those series should stay collapsed
          var series = ch.ctx.series.emptyCollapsedSeries(Utils$1.clone(w.globals.initialSeries));
          ch.updateHelpers._updateSeries(series, w.config.chart.animations.dynamicAnimation.enabled);
        });
      }
    }, {
      key: "destroy",
      value: function destroy() {
        this.elZoom = null;
        this.elZoomIn = null;
        this.elZoomOut = null;
        this.elPan = null;
        this.elSelection = null;
        this.elZoomReset = null;
        this.elMenuIcon = null;
      }
    }]);
    return Toolbar;
  }();

  /**
   * ApexCharts Zoom Class for handling zooming and panning on axes based charts.
   *
   * @module ZoomPanSelection
   **/
  var ZoomPanSelection = /*#__PURE__*/function (_Toolbar) {
    _inherits(ZoomPanSelection, _Toolbar);
    var _super = _createSuper(ZoomPanSelection);
    function ZoomPanSelection(ctx) {
      var _this;
      _classCallCheck(this, ZoomPanSelection);
      _this = _super.call(this, ctx);
      _this.ctx = ctx;
      _this.w = ctx.w;
      _this.dragged = false;
      _this.graphics = new Graphics(_this.ctx);
      _this.eventList = ['mousedown', 'mouseleave', 'mousemove', 'touchstart', 'touchmove', 'mouseup', 'touchend', 'wheel'];
      _this.clientX = 0;
      _this.clientY = 0;
      _this.startX = 0;
      _this.endX = 0;
      _this.dragX = 0;
      _this.startY = 0;
      _this.endY = 0;
      _this.dragY = 0;
      _this.moveDirection = 'none';
      _this.debounceTimer = null;
      _this.debounceDelay = 100;
      _this.wheelDelay = 400;
      return _this;
    }
    _createClass(ZoomPanSelection, [{
      key: "init",
      value: function init(_ref) {
        var _this2 = this;
        var xyRatios = _ref.xyRatios;
        var w = this.w;
        var me = this;
        this.xyRatios = xyRatios;
        this.zoomRect = this.graphics.drawRect(0, 0, 0, 0);
        this.selectionRect = this.graphics.drawRect(0, 0, 0, 0);
        this.gridRect = w.globals.dom.baseEl.querySelector('.apexcharts-grid');
        this.zoomRect.node.classList.add('apexcharts-zoom-rect');
        this.selectionRect.node.classList.add('apexcharts-selection-rect');
        w.globals.dom.elGraphical.add(this.zoomRect);
        w.globals.dom.elGraphical.add(this.selectionRect);
        if (w.config.chart.selection.type === 'x') {
          this.slDraggableRect = this.selectionRect.draggable({
            minX: 0,
            minY: 0,
            maxX: w.globals.gridWidth,
            maxY: w.globals.gridHeight
          }).on('dragmove', this.selectionDragging.bind(this, 'dragging'));
        } else if (w.config.chart.selection.type === 'y') {
          this.slDraggableRect = this.selectionRect.draggable({
            minX: 0,
            maxX: w.globals.gridWidth
          }).on('dragmove', this.selectionDragging.bind(this, 'dragging'));
        } else {
          this.slDraggableRect = this.selectionRect.draggable().on('dragmove', this.selectionDragging.bind(this, 'dragging'));
        }
        this.preselectedSelection();
        this.hoverArea = w.globals.dom.baseEl.querySelector("".concat(w.globals.chartClass, " .apexcharts-svg"));
        this.hoverArea.classList.add('apexcharts-zoomable');
        this.eventList.forEach(function (event) {
          _this2.hoverArea.addEventListener(event, me.svgMouseEvents.bind(me, xyRatios), {
            capture: false,
            passive: true
          });
        });
        if (w.config.chart.zoom.allowMouseWheelZoom) {
          this.hoverArea.addEventListener('wheel', me.mouseWheelEvent.bind(me), {
            capture: false,
            passive: false
          });
        }
      }

      // remove the event listeners which were previously added on hover area
    }, {
      key: "destroy",
      value: function destroy() {
        if (this.slDraggableRect) {
          this.slDraggableRect.draggable(false);
          this.slDraggableRect.off();
          this.selectionRect.off();
        }
        this.selectionRect = null;
        this.zoomRect = null;
        this.gridRect = null;
      }
    }, {
      key: "svgMouseEvents",
      value: function svgMouseEvents(xyRatios, e) {
        var w = this.w;
        var me = this;
        var toolbar = this.ctx.toolbar;
        var zoomtype = w.globals.zoomEnabled ? w.config.chart.zoom.type : w.config.chart.selection.type;
        var autoSelected = w.config.chart.toolbar.autoSelected;
        if (e.shiftKey) {
          this.shiftWasPressed = true;
          toolbar.enableZoomPanFromToolbar(autoSelected === 'pan' ? 'zoom' : 'pan');
        } else {
          if (this.shiftWasPressed) {
            toolbar.enableZoomPanFromToolbar(autoSelected);
            this.shiftWasPressed = false;
          }
        }
        if (!e.target) return;
        var tc = e.target.classList;
        var pc;
        if (e.target.parentNode && e.target.parentNode !== null) {
          pc = e.target.parentNode.classList;
        }
        var falsePositives = tc.contains('apexcharts-selection-rect') || tc.contains('apexcharts-legend-marker') || tc.contains('apexcharts-legend-text') || pc && pc.contains('apexcharts-toolbar');
        if (falsePositives) return;
        me.clientX = e.type === 'touchmove' || e.type === 'touchstart' ? e.touches[0].clientX : e.type === 'touchend' ? e.changedTouches[0].clientX : e.clientX;
        me.clientY = e.type === 'touchmove' || e.type === 'touchstart' ? e.touches[0].clientY : e.type === 'touchend' ? e.changedTouches[0].clientY : e.clientY;
        if (e.type === 'mousedown' && e.which === 1) {
          var gridRectDim = me.gridRect.getBoundingClientRect();
          me.startX = me.clientX - gridRectDim.left;
          me.startY = me.clientY - gridRectDim.top;
          me.dragged = false;
          me.w.globals.mousedown = true;
        }
        if (e.type === 'mousemove' && e.which === 1 || e.type === 'touchmove') {
          me.dragged = true;
          if (w.globals.panEnabled) {
            w.globals.selection = null;
            if (me.w.globals.mousedown) {
              me.panDragging({
                context: me,
                zoomtype: zoomtype,
                xyRatios: xyRatios
              });
            }
          } else {
            if (me.w.globals.mousedown && w.globals.zoomEnabled || me.w.globals.mousedown && w.globals.selectionEnabled) {
              me.selection = me.selectionDrawing({
                context: me,
                zoomtype: zoomtype
              });
            }
          }
        }
        if (e.type === 'mouseup' || e.type === 'touchend' || e.type === 'mouseleave') {
          var _me$gridRect;
          // we will be calling getBoundingClientRect on each mousedown/mousemove/mouseup
          var _gridRectDim = (_me$gridRect = me.gridRect) === null || _me$gridRect === void 0 ? void 0 : _me$gridRect.getBoundingClientRect();
          if (_gridRectDim && me.w.globals.mousedown) {
            // user released the drag, now do all the calculations
            me.endX = me.clientX - _gridRectDim.left;
            me.endY = me.clientY - _gridRectDim.top;
            me.dragX = Math.abs(me.endX - me.startX);
            me.dragY = Math.abs(me.endY - me.startY);
            if (w.globals.zoomEnabled || w.globals.selectionEnabled) {
              me.selectionDrawn({
                context: me,
                zoomtype: zoomtype
              });
            }
            if (w.globals.panEnabled && w.config.xaxis.convertedCatToNumeric) {
              me.delayedPanScrolled();
            }
          }
          if (w.globals.zoomEnabled) {
            me.hideSelectionRect(this.selectionRect);
          }
          me.dragged = false;
          me.w.globals.mousedown = false;
        }
        this.makeSelectionRectDraggable();
      }
    }, {
      key: "mouseWheelEvent",
      value: function mouseWheelEvent(e) {
        var _this3 = this;
        var w = this.w;
        e.preventDefault();
        var now = Date.now();

        // Execute immediately if it's the first action or enough time has passed
        if (now - w.globals.lastWheelExecution > this.wheelDelay) {
          this.executeMouseWheelZoom(e);
          w.globals.lastWheelExecution = now;
        }
        if (this.debounceTimer) clearTimeout(this.debounceTimer);
        this.debounceTimer = setTimeout(function () {
          if (now - w.globals.lastWheelExecution > _this3.wheelDelay) {
            _this3.executeMouseWheelZoom(e);
            w.globals.lastWheelExecution = now;
          }
        }, this.debounceDelay);
      }
    }, {
      key: "executeMouseWheelZoom",
      value: function executeMouseWheelZoom(e) {
        var _this$gridRect;
        var w = this.w;
        this.minX = w.globals.isRangeBar ? w.globals.minY : w.globals.minX;
        this.maxX = w.globals.isRangeBar ? w.globals.maxY : w.globals.maxX;

        // Calculate the relative position of the mouse on the chart
        var gridRectDim = (_this$gridRect = this.gridRect) === null || _this$gridRect === void 0 ? void 0 : _this$gridRect.getBoundingClientRect();
        if (!gridRectDim) return;
        var mouseX = (e.clientX - gridRectDim.left) / gridRectDim.width;
        var currentMinX = this.minX;
        var currentMaxX = this.maxX;
        var totalX = currentMaxX - currentMinX;

        // Determine zoom factor
        var zoomFactorIn = 0.5;
        var zoomFactorOut = 1.5;
        var zoomRange;
        var newMinX, newMaxX;
        if (e.deltaY < 0) {
          // Zoom In
          zoomRange = zoomFactorIn * totalX;
          var midPoint = currentMinX + mouseX * totalX;
          newMinX = midPoint - zoomRange / 2;
          newMaxX = midPoint + zoomRange / 2;
        } else {
          // Zoom Out
          zoomRange = zoomFactorOut * totalX;
          newMinX = currentMinX - zoomRange / 2;
          newMaxX = currentMaxX + zoomRange / 2;
        }

        // Constrain within original chart bounds
        if (!w.globals.isRangeBar) {
          newMinX = Math.max(newMinX, w.globals.initialMinX);
          newMaxX = Math.min(newMaxX, w.globals.initialMaxX);

          // Ensure minimum range
          var minRange = (w.globals.initialMaxX - w.globals.initialMinX) * 0.01;
          if (newMaxX - newMinX < minRange) {
            var _midPoint = (newMinX + newMaxX) / 2;
            newMinX = _midPoint - minRange / 2;
            newMaxX = _midPoint + minRange / 2;
          }
        }
        var newMinXMaxX = this._getNewMinXMaxX(newMinX, newMaxX);

        // Apply zoom if valid
        if (!isNaN(newMinXMaxX.minX) && !isNaN(newMinXMaxX.maxX)) {
          this.zoomUpdateOptions(newMinXMaxX.minX, newMinXMaxX.maxX);
        }
      }
    }, {
      key: "makeSelectionRectDraggable",
      value: function makeSelectionRectDraggable() {
        var w = this.w;
        if (!this.selectionRect) return;
        var rectDim = this.selectionRect.node.getBoundingClientRect();
        if (rectDim.width > 0 && rectDim.height > 0) {
          this.slDraggableRect.selectize({
            points: 'l, r',
            pointSize: 8,
            pointType: 'rect'
          }).resize({
            constraint: {
              minX: 0,
              minY: 0,
              maxX: w.globals.gridWidth,
              maxY: w.globals.gridHeight
            }
          }).on('resizing', this.selectionDragging.bind(this, 'resizing'));
        }
      }
    }, {
      key: "preselectedSelection",
      value: function preselectedSelection() {
        var w = this.w;
        var xyRatios = this.xyRatios;
        if (!w.globals.zoomEnabled) {
          if (typeof w.globals.selection !== 'undefined' && w.globals.selection !== null) {
            this.drawSelectionRect(w.globals.selection);
          } else {
            if (w.config.chart.selection.xaxis.min !== undefined && w.config.chart.selection.xaxis.max !== undefined) {
              var x = (w.config.chart.selection.xaxis.min - w.globals.minX) / xyRatios.xRatio;
              var width = w.globals.gridWidth - (w.globals.maxX - w.config.chart.selection.xaxis.max) / xyRatios.xRatio - x;
              if (w.globals.isRangeBar) {
                // rangebars put datetime data in y axis
                x =
                // calculation: (selection left time - chart left time) / milliseconds per pixel = selection X value in pixels
                (w.config.chart.selection.xaxis.min - w.globals.yAxisScale[0].niceMin) / xyRatios.invertedYRatio;
                width = (w.config.chart.selection.xaxis.max - w.config.chart.selection.xaxis.min) / xyRatios.invertedYRatio;
              }
              var selectionRect = {
                x: x,
                y: 0,
                width: width,
                height: w.globals.gridHeight,
                translateX: 0,
                translateY: 0,
                selectionEnabled: true
              };
              this.drawSelectionRect(selectionRect);
              this.makeSelectionRectDraggable();
              if (typeof w.config.chart.events.selection === 'function') {
                w.config.chart.events.selection(this.ctx, {
                  xaxis: {
                    min: w.config.chart.selection.xaxis.min,
                    max: w.config.chart.selection.xaxis.max
                  },
                  yaxis: {}
                });
              }
            }
          }
        }
      }
    }, {
      key: "drawSelectionRect",
      value: function drawSelectionRect(_ref2) {
        var x = _ref2.x,
          y = _ref2.y,
          width = _ref2.width,
          height = _ref2.height,
          _ref2$translateX = _ref2.translateX,
          translateX = _ref2$translateX === void 0 ? 0 : _ref2$translateX,
          _ref2$translateY = _ref2.translateY,
          translateY = _ref2$translateY === void 0 ? 0 : _ref2$translateY;
        var w = this.w;
        var zoomRect = this.zoomRect;
        var selectionRect = this.selectionRect;
        if (this.dragged || w.globals.selection !== null) {
          var scalingAttrs = {
            transform: 'translate(' + translateX + ', ' + translateY + ')'
          };

          // change styles based on zoom or selection
          // zoom is Enabled and user has dragged, so draw blue rect
          if (w.globals.zoomEnabled && this.dragged) {
            if (width < 0) width = 1; // fixes apexcharts.js#1168
            zoomRect.attr({
              x: x,
              y: y,
              width: width,
              height: height,
              fill: w.config.chart.zoom.zoomedArea.fill.color,
              'fill-opacity': w.config.chart.zoom.zoomedArea.fill.opacity,
              stroke: w.config.chart.zoom.zoomedArea.stroke.color,
              'stroke-width': w.config.chart.zoom.zoomedArea.stroke.width,
              'stroke-opacity': w.config.chart.zoom.zoomedArea.stroke.opacity
            });
            Graphics.setAttrs(zoomRect.node, scalingAttrs);
          }

          // selection is enabled
          if (w.globals.selectionEnabled) {
            selectionRect.attr({
              x: x,
              y: y,
              width: width > 0 ? width : 0,
              height: height > 0 ? height : 0,
              fill: w.config.chart.selection.fill.color,
              'fill-opacity': w.config.chart.selection.fill.opacity,
              stroke: w.config.chart.selection.stroke.color,
              'stroke-width': w.config.chart.selection.stroke.width,
              'stroke-dasharray': w.config.chart.selection.stroke.dashArray,
              'stroke-opacity': w.config.chart.selection.stroke.opacity
            });
            Graphics.setAttrs(selectionRect.node, scalingAttrs);
          }
        }
      }
    }, {
      key: "hideSelectionRect",
      value: function hideSelectionRect(rect) {
        if (rect) {
          rect.attr({
            x: 0,
            y: 0,
            width: 0,
            height: 0
          });
        }
      }
    }, {
      key: "selectionDrawing",
      value: function selectionDrawing(_ref3) {
        var context = _ref3.context,
          zoomtype = _ref3.zoomtype;
        var w = this.w;
        var me = context;
        var gridRectDim = this.gridRect.getBoundingClientRect();
        var startX = me.startX - 1;
        var startY = me.startY;
        var inversedX = false;
        var inversedY = false;
        var selectionWidth = me.clientX - gridRectDim.left - startX;
        var selectionHeight = me.clientY - gridRectDim.top - startY;
        var selectionRect = {};
        if (Math.abs(selectionWidth + startX) > w.globals.gridWidth) {
          // user dragged the mouse outside drawing area to the right
          selectionWidth = w.globals.gridWidth - startX;
        } else if (me.clientX - gridRectDim.left < 0) {
          // user dragged the mouse outside drawing area to the left
          selectionWidth = startX;
        }

        // inverse selection X
        if (startX > me.clientX - gridRectDim.left) {
          inversedX = true;
          selectionWidth = Math.abs(selectionWidth);
        }

        // inverse selection Y
        if (startY > me.clientY - gridRectDim.top) {
          inversedY = true;
          selectionHeight = Math.abs(selectionHeight);
        }
        if (zoomtype === 'x') {
          selectionRect = {
            x: inversedX ? startX - selectionWidth : startX,
            y: 0,
            width: selectionWidth,
            height: w.globals.gridHeight
          };
        } else if (zoomtype === 'y') {
          selectionRect = {
            x: 0,
            y: inversedY ? startY - selectionHeight : startY,
            width: w.globals.gridWidth,
            height: selectionHeight
          };
        } else {
          selectionRect = {
            x: inversedX ? startX - selectionWidth : startX,
            y: inversedY ? startY - selectionHeight : startY,
            width: selectionWidth,
            height: selectionHeight
          };
        }
        me.drawSelectionRect(selectionRect);
        me.selectionDragging('resizing');
        return selectionRect;
      }
    }, {
      key: "selectionDragging",
      value: function selectionDragging(type, e) {
        var _this4 = this;
        var w = this.w;
        var xyRatios = this.xyRatios;
        var selRect = this.selectionRect;
        var timerInterval = 0;
        if (type === 'resizing') {
          timerInterval = 30;
        }

        // update selection when selection rect is dragged
        var getSelAttr = function getSelAttr(attr) {
          return parseFloat(selRect.node.getAttribute(attr));
        };
        var draggedProps = {
          x: getSelAttr('x'),
          y: getSelAttr('y'),
          width: getSelAttr('width'),
          height: getSelAttr('height')
        };
        w.globals.selection = draggedProps;
        // update selection ends

        if (typeof w.config.chart.events.selection === 'function' && w.globals.selectionEnabled) {
          // a small debouncer is required when resizing to avoid freezing the chart
          clearTimeout(this.w.globals.selectionResizeTimer);
          this.w.globals.selectionResizeTimer = window.setTimeout(function () {
            var gridRectDim = _this4.gridRect.getBoundingClientRect();
            var selectionRect = selRect.node.getBoundingClientRect();
            var minX, maxX, minY, maxY;
            if (!w.globals.isRangeBar) {
              // original code is in the IF. rangeBar exception is in the ELSE.
              minX = w.globals.xAxisScale.niceMin + (selectionRect.left - gridRectDim.left) * xyRatios.xRatio;
              maxX = w.globals.xAxisScale.niceMin + (selectionRect.right - gridRectDim.left) * xyRatios.xRatio;
              minY = w.globals.yAxisScale[0].niceMin + (gridRectDim.bottom - selectionRect.bottom) * xyRatios.yRatio[0];
              maxY = w.globals.yAxisScale[0].niceMax - (selectionRect.top - gridRectDim.top) * xyRatios.yRatio[0];
            } else {
              // rangeBars use x as the category, and y as the datetime data. // find data in y axis and use Y ratio
              minX = w.globals.yAxisScale[0].niceMin + (selectionRect.left - gridRectDim.left) * xyRatios.invertedYRatio;
              maxX = w.globals.yAxisScale[0].niceMin + (selectionRect.right - gridRectDim.left) * xyRatios.invertedYRatio;
              minY = 0; // there is no y min/max with rangebars (it uses categories, not numeric data), so use dummy values
              maxY = 1;
            }
            var xyAxis = {
              xaxis: {
                min: minX,
                max: maxX
              },
              yaxis: {
                min: minY,
                max: maxY
              }
            };
            w.config.chart.events.selection(_this4.ctx, xyAxis);
            if (w.config.chart.brush.enabled && w.config.chart.events.brushScrolled !== undefined) {
              w.config.chart.events.brushScrolled(_this4.ctx, xyAxis);
            }
          }, timerInterval);
        }
      }
    }, {
      key: "selectionDrawn",
      value: function selectionDrawn(_ref4) {
        var context = _ref4.context,
          zoomtype = _ref4.zoomtype;
        var w = this.w;
        var me = context;
        var xyRatios = this.xyRatios;
        var toolbar = this.ctx.toolbar;
        if (me.startX > me.endX) {
          var tempX = me.startX;
          me.startX = me.endX;
          me.endX = tempX;
        }
        if (me.startY > me.endY) {
          var tempY = me.startY;
          me.startY = me.endY;
          me.endY = tempY;
        }
        var xLowestValue = undefined;
        var xHighestValue = undefined;
        if (!w.globals.isRangeBar) {
          xLowestValue = w.globals.xAxisScale.niceMin + me.startX * xyRatios.xRatio;
          xHighestValue = w.globals.xAxisScale.niceMin + me.endX * xyRatios.xRatio;
        } else {
          xLowestValue = w.globals.yAxisScale[0].niceMin + me.startX * xyRatios.invertedYRatio;
          xHighestValue = w.globals.yAxisScale[0].niceMin + me.endX * xyRatios.invertedYRatio;
        }

        // TODO: we will consider the 1st y axis values here for getting highest and lowest y
        var yHighestValue = [];
        var yLowestValue = [];
        w.config.yaxis.forEach(function (yaxe, index) {
          // We can use the index of any series referenced by the Yaxis
          // because they will all return the same value, so we choose the first.
          var seriesIndex = w.globals.seriesYAxisMap[index][0];
          yHighestValue.push(w.globals.yAxisScale[index].niceMax - xyRatios.yRatio[seriesIndex] * me.startY);
          yLowestValue.push(w.globals.yAxisScale[index].niceMax - xyRatios.yRatio[seriesIndex] * me.endY);
        });
        if (me.dragged && (me.dragX > 10 || me.dragY > 10) && xLowestValue !== xHighestValue) {
          if (w.globals.zoomEnabled) {
            var yaxis = Utils$1.clone(w.globals.initialConfig.yaxis);
            var xaxis = Utils$1.clone(w.globals.initialConfig.xaxis);
            w.globals.zoomed = true;
            if (w.config.xaxis.convertedCatToNumeric) {
              xLowestValue = Math.floor(xLowestValue);
              xHighestValue = Math.floor(xHighestValue);
              if (xLowestValue < 1) {
                xLowestValue = 1;
                xHighestValue = w.globals.dataPoints;
              }
              if (xHighestValue - xLowestValue < 2) {
                xHighestValue = xLowestValue + 1;
              }
            }
            if (zoomtype === 'xy' || zoomtype === 'x') {
              xaxis = {
                min: xLowestValue,
                max: xHighestValue
              };
            }
            if (zoomtype === 'xy' || zoomtype === 'y') {
              yaxis.forEach(function (yaxe, index) {
                yaxis[index].min = yLowestValue[index];
                yaxis[index].max = yHighestValue[index];
              });
            }
            if (toolbar) {
              var beforeZoomRange = toolbar.getBeforeZoomRange(xaxis, yaxis);
              if (beforeZoomRange) {
                xaxis = beforeZoomRange.xaxis ? beforeZoomRange.xaxis : xaxis;
                yaxis = beforeZoomRange.yaxis ? beforeZoomRange.yaxis : yaxis;
              }
            }
            var options = {
              xaxis: xaxis
            };
            if (!w.config.chart.group) {
              // if chart in a group, prevent yaxis update here
              // fix issue #650
              options.yaxis = yaxis;
            }
            me.ctx.updateHelpers._updateOptions(options, false, me.w.config.chart.animations.dynamicAnimation.enabled);
            if (typeof w.config.chart.events.zoomed === 'function') {
              toolbar.zoomCallback(xaxis, yaxis);
            }
          } else if (w.globals.selectionEnabled) {
            var _yaxis = null;
            var _xaxis = null;
            _xaxis = {
              min: xLowestValue,
              max: xHighestValue
            };
            if (zoomtype === 'xy' || zoomtype === 'y') {
              _yaxis = Utils$1.clone(w.config.yaxis);
              _yaxis.forEach(function (yaxe, index) {
                _yaxis[index].min = yLowestValue[index];
                _yaxis[index].max = yHighestValue[index];
              });
            }
            w.globals.selection = me.selection;
            if (typeof w.config.chart.events.selection === 'function') {
              w.config.chart.events.selection(me.ctx, {
                xaxis: _xaxis,
                yaxis: _yaxis
              });
            }
          }
        }
      }
    }, {
      key: "panDragging",
      value: function panDragging(_ref5) {
        var context = _ref5.context;
        var w = this.w;
        var me = context;

        // check to make sure there is data to compare against
        if (typeof w.globals.lastClientPosition.x !== 'undefined') {
          // get the change from last position to this position
          var deltaX = w.globals.lastClientPosition.x - me.clientX;
          var deltaY = w.globals.lastClientPosition.y - me.clientY;

          // check which direction had the highest amplitude and then figure out direction by checking if the value is greater or less than zero
          if (Math.abs(deltaX) > Math.abs(deltaY) && deltaX > 0) {
            this.moveDirection = 'left';
          } else if (Math.abs(deltaX) > Math.abs(deltaY) && deltaX < 0) {
            this.moveDirection = 'right';
          } else if (Math.abs(deltaY) > Math.abs(deltaX) && deltaY > 0) {
            this.moveDirection = 'up';
          } else if (Math.abs(deltaY) > Math.abs(deltaX) && deltaY < 0) {
            this.moveDirection = 'down';
          }
        }

        // set the new last position to the current for next time (to get the position of drag)
        w.globals.lastClientPosition = {
          x: me.clientX,
          y: me.clientY
        };
        var xLowestValue = w.globals.isRangeBar ? w.globals.minY : w.globals.minX;
        var xHighestValue = w.globals.isRangeBar ? w.globals.maxY : w.globals.maxX;

        // on a category, we don't pan continuosly as it causes bugs
        if (!w.config.xaxis.convertedCatToNumeric) {
          me.panScrolled(xLowestValue, xHighestValue);
        }
      }
    }, {
      key: "delayedPanScrolled",
      value: function delayedPanScrolled() {
        var w = this.w;
        var newMinX = w.globals.minX;
        var newMaxX = w.globals.maxX;
        var centerX = (w.globals.maxX - w.globals.minX) / 2;
        if (this.moveDirection === 'left') {
          newMinX = w.globals.minX + centerX;
          newMaxX = w.globals.maxX + centerX;
        } else if (this.moveDirection === 'right') {
          newMinX = w.globals.minX - centerX;
          newMaxX = w.globals.maxX - centerX;
        }
        newMinX = Math.floor(newMinX);
        newMaxX = Math.floor(newMaxX);
        this.updateScrolledChart({
          xaxis: {
            min: newMinX,
            max: newMaxX
          }
        }, newMinX, newMaxX);
      }
    }, {
      key: "panScrolled",
      value: function panScrolled(xLowestValue, xHighestValue) {
        var w = this.w;
        var xyRatios = this.xyRatios;
        var yaxis = Utils$1.clone(w.globals.initialConfig.yaxis);
        var xRatio = xyRatios.xRatio;
        var minX = w.globals.minX;
        var maxX = w.globals.maxX;
        if (w.globals.isRangeBar) {
          xRatio = xyRatios.invertedYRatio;
          minX = w.globals.minY;
          maxX = w.globals.maxY;
        }
        if (this.moveDirection === 'left') {
          xLowestValue = minX + w.globals.gridWidth / 15 * xRatio;
          xHighestValue = maxX + w.globals.gridWidth / 15 * xRatio;
        } else if (this.moveDirection === 'right') {
          xLowestValue = minX - w.globals.gridWidth / 15 * xRatio;
          xHighestValue = maxX - w.globals.gridWidth / 15 * xRatio;
        }
        if (!w.globals.isRangeBar) {
          if (xLowestValue < w.globals.initialMinX || xHighestValue > w.globals.initialMaxX) {
            xLowestValue = minX;
            xHighestValue = maxX;
          }
        }
        var options = {
          xaxis: {
            min: xLowestValue,
            max: xHighestValue
          }
        };
        if (!w.config.chart.group) {
          // if chart in a group, prevent yaxis update here
          // fix issue #650
          options.yaxis = yaxis;
        }
        this.updateScrolledChart(options, xLowestValue, xHighestValue);
      }
    }, {
      key: "updateScrolledChart",
      value: function updateScrolledChart(options, xLowestValue, xHighestValue) {
        var w = this.w;
        this.ctx.updateHelpers._updateOptions(options, false, false);
        if (typeof w.config.chart.events.scrolled === 'function') {
          w.config.chart.events.scrolled(this.ctx, {
            xaxis: {
              min: xLowestValue,
              max: xHighestValue
            }
          });
        }
      }
    }]);
    return ZoomPanSelection;
  }(Toolbar);

  /**
   * ApexCharts Tooltip.Utils Class to support Tooltip functionality.
   *
   * @module Tooltip.Utils
   **/
  var Utils = /*#__PURE__*/function () {
    function Utils(tooltipContext) {
      _classCallCheck(this, Utils);
      this.w = tooltipContext.w;
      this.ttCtx = tooltipContext;
      this.ctx = tooltipContext.ctx;
    }

    /**
     ** When hovering over series, you need to capture which series is being hovered on.
     ** This function will return both capturedseries index as well as inner index of that series
     * @memberof Utils
     * @param {object}
     * - hoverArea = the rect on which user hovers
     * - elGrid = dimensions of the hover rect (it can be different than hoverarea)
     */
    _createClass(Utils, [{
      key: "getNearestValues",
      value: function getNearestValues(_ref) {
        var hoverArea = _ref.hoverArea,
          elGrid = _ref.elGrid,
          clientX = _ref.clientX,
          clientY = _ref.clientY;
        var w = this.w;
        var seriesBound = elGrid.getBoundingClientRect();
        var hoverWidth = seriesBound.width;
        var hoverHeight = seriesBound.height;
        var xDivisor = hoverWidth / (w.globals.dataPoints - 1);
        var yDivisor = hoverHeight / w.globals.dataPoints;
        var hasBars = this.hasBars();
        if ((w.globals.comboCharts || hasBars) && !w.config.xaxis.convertedCatToNumeric) {
          xDivisor = hoverWidth / w.globals.dataPoints;
        }
        var hoverX = clientX - seriesBound.left - w.globals.barPadForNumericAxis;
        var hoverY = clientY - seriesBound.top;
        var notInRect = hoverX < 0 || hoverY < 0 || hoverX > hoverWidth || hoverY > hoverHeight;
        if (notInRect) {
          hoverArea.classList.remove('hovering-zoom');
          hoverArea.classList.remove('hovering-pan');
        } else {
          if (w.globals.zoomEnabled) {
            hoverArea.classList.remove('hovering-pan');
            hoverArea.classList.add('hovering-zoom');
          } else if (w.globals.panEnabled) {
            hoverArea.classList.remove('hovering-zoom');
            hoverArea.classList.add('hovering-pan');
          }
        }
        var j = Math.round(hoverX / xDivisor);
        var jHorz = Math.floor(hoverY / yDivisor);
        if (hasBars && !w.config.xaxis.convertedCatToNumeric) {
          j = Math.ceil(hoverX / xDivisor);
          j = j - 1;
        }
        var capturedSeries = null;
        var closest = null;
        var seriesXValArr = w.globals.seriesXvalues.map(function (seriesXVal) {
          return seriesXVal.filter(function (s) {
            return Utils$1.isNumber(s);
          });
        });
        var seriesYValArr = w.globals.seriesYvalues.map(function (seriesYVal) {
          return seriesYVal.filter(function (s) {
            return Utils$1.isNumber(s);
          });
        });

        // if X axis type is not category and tooltip is not shared, then we need to find the cursor position and get the nearest value
        if (w.globals.isXNumeric) {
          // Change origin of cursor position so that we can compute the relative nearest point to the cursor on our chart
          // we only need to scale because all points are relative to the bounds.left and bounds.top => origin is virtually (0, 0)
          var chartGridEl = this.ttCtx.getElGrid();
          var chartGridElBoundingRect = chartGridEl.getBoundingClientRect();
          var transformedHoverX = hoverX * (chartGridElBoundingRect.width / hoverWidth);
          var transformedHoverY = hoverY * (chartGridElBoundingRect.height / hoverHeight);
          closest = this.closestInMultiArray(transformedHoverX, transformedHoverY, seriesXValArr, seriesYValArr);
          capturedSeries = closest.index;
          j = closest.j;
          if (capturedSeries !== null) {
            // initial push, it should be a little smaller than the 1st val
            seriesXValArr = w.globals.seriesXvalues[capturedSeries];
            closest = this.closestInArray(transformedHoverX, seriesXValArr);
            j = closest.index;
          }
        }
        w.globals.capturedSeriesIndex = capturedSeries === null ? -1 : capturedSeries;
        if (!j || j < 1) j = 0;
        if (w.globals.isBarHorizontal) {
          w.globals.capturedDataPointIndex = jHorz;
        } else {
          w.globals.capturedDataPointIndex = j;
        }
        return {
          capturedSeries: capturedSeries,
          j: w.globals.isBarHorizontal ? jHorz : j,
          hoverX: hoverX,
          hoverY: hoverY
        };
      }
    }, {
      key: "closestInMultiArray",
      value: function closestInMultiArray(hoverX, hoverY, Xarrays, Yarrays) {
        var w = this.w;
        var activeIndex = 0;
        var currIndex = null;
        var j = -1;
        if (w.globals.series.length > 1) {
          activeIndex = this.getFirstActiveXArray(Xarrays);
        } else {
          currIndex = 0;
        }
        var currX = Xarrays[activeIndex][0];
        var diffX = Math.abs(hoverX - currX);

        // find nearest point on x-axis
        Xarrays.forEach(function (arrX) {
          arrX.forEach(function (x, iX) {
            var newDiff = Math.abs(hoverX - x);
            if (newDiff <= diffX) {
              diffX = newDiff;
              j = iX;
            }
          });
        });
        if (j !== -1) {
          // find nearest graph on y-axis relevanted to nearest point on x-axis
          var currY = Yarrays[activeIndex][j];
          var diffY = Math.abs(hoverY - currY);
          currIndex = activeIndex;
          Yarrays.forEach(function (arrY, iAY) {
            var newDiff = Math.abs(hoverY - arrY[j]);
            if (newDiff <= diffY) {
              diffY = newDiff;
              currIndex = iAY;
            }
          });
        }
        return {
          index: currIndex,
          j: j
        };
      }
    }, {
      key: "getFirstActiveXArray",
      value: function getFirstActiveXArray(Xarrays) {
        var w = this.w;
        var activeIndex = 0;
        var firstActiveSeriesIndex = Xarrays.map(function (xarr, index) {
          return xarr.length > 0 ? index : -1;
        });
        for (var a = 0; a < firstActiveSeriesIndex.length; a++) {
          if (firstActiveSeriesIndex[a] !== -1 && w.globals.collapsedSeriesIndices.indexOf(a) === -1 && w.globals.ancillaryCollapsedSeriesIndices.indexOf(a) === -1) {
            activeIndex = firstActiveSeriesIndex[a];
            break;
          }
        }
        return activeIndex;
      }
    }, {
      key: "closestInArray",
      value: function closestInArray(val, arr) {
        var curr = arr[0];
        var currIndex = null;
        var diff = Math.abs(val - curr);
        for (var i = 0; i < arr.length; i++) {
          var newdiff = Math.abs(val - arr[i]);
          if (newdiff < diff) {
            diff = newdiff;
            currIndex = i;
          }
        }
        return {
          index: currIndex
        };
      }

      /**
       * When there are multiple series, it is possible to have different x values for each series.
       * But it may be possible in those multiple series, that there is same x value for 2 or more
       * series.
       * @memberof Utils
       * @param {int}
       * - j = is the inner index of series -> (series[i][j])
       * @return {bool}
       */
    }, {
      key: "isXoverlap",
      value: function isXoverlap(j) {
        var w = this.w;
        var xSameForAllSeriesJArr = [];
        var seriesX = w.globals.seriesX.filter(function (s) {
          return typeof s[0] !== 'undefined';
        });
        if (seriesX.length > 0) {
          for (var i = 0; i < seriesX.length - 1; i++) {
            if (typeof seriesX[i][j] !== 'undefined' && typeof seriesX[i + 1][j] !== 'undefined') {
              if (seriesX[i][j] !== seriesX[i + 1][j]) {
                xSameForAllSeriesJArr.push('unEqual');
              }
            }
          }
        }
        if (xSameForAllSeriesJArr.length === 0) {
          return true;
        }
        return false;
      }
    }, {
      key: "isInitialSeriesSameLen",
      value: function isInitialSeriesSameLen() {
        var sameLen = true;
        var initialSeries = this.w.globals.initialSeries;
        for (var i = 0; i < initialSeries.length - 1; i++) {
          if (initialSeries[i].data.length !== initialSeries[i + 1].data.length) {
            sameLen = false;
            break;
          }
        }
        return sameLen;
      }
    }, {
      key: "getBarsHeight",
      value: function getBarsHeight(allbars) {
        var bars = _toConsumableArray(allbars);
        var totalHeight = bars.reduce(function (acc, bar) {
          return acc + bar.getBBox().height;
        }, 0);
        return totalHeight;
      }
    }, {
      key: "getElMarkers",
      value: function getElMarkers(capturedSeries) {
        // The selector .apexcharts-series-markers-wrap > * includes marker groups for which the
        // .apexcharts-series-markers class is not added due to null values or discrete markers
        if (typeof capturedSeries == 'number') {
          return this.w.globals.dom.baseEl.querySelectorAll(".apexcharts-series[data\\:realIndex='".concat(capturedSeries, "'] .apexcharts-series-markers-wrap > *"));
        }
        return this.w.globals.dom.baseEl.querySelectorAll('.apexcharts-series-markers-wrap > *');
      }
    }, {
      key: "getAllMarkers",
      value: function getAllMarkers() {
        // first get all marker parents. This parent class contains series-index
        // which helps to sort the markers as they are dynamic
        var markersWraps = this.w.globals.dom.baseEl.querySelectorAll('.apexcharts-series-markers-wrap');
        markersWraps = _toConsumableArray(markersWraps);
        markersWraps.sort(function (a, b) {
          var indexA = Number(a.getAttribute('data:realIndex'));
          var indexB = Number(b.getAttribute('data:realIndex'));
          return indexB < indexA ? 1 : indexB > indexA ? -1 : 0;
        });
        var markers = [];
        markersWraps.forEach(function (m) {
          markers.push(m.querySelector('.apexcharts-marker'));
        });
        return markers;
      }
    }, {
      key: "hasMarkers",
      value: function hasMarkers(capturedSeries) {
        var markers = this.getElMarkers(capturedSeries);
        return markers.length > 0;
      }
    }, {
      key: "getPathFromPoint",
      value: function getPathFromPoint(point, size) {
        var cx = Number(point.getAttribute('cx'));
        var cy = Number(point.getAttribute('cy'));
        var shape = point.getAttribute('shape');
        return new Graphics(this.ctx).getMarkerPath(cx, cy, shape, size);
      }
    }, {
      key: "getElBars",
      value: function getElBars() {
        return this.w.globals.dom.baseEl.querySelectorAll('.apexcharts-bar-series,  .apexcharts-candlestick-series, .apexcharts-boxPlot-series, .apexcharts-rangebar-series');
      }
    }, {
      key: "hasBars",
      value: function hasBars() {
        var bars = this.getElBars();
        return bars.length > 0;
      }
    }, {
      key: "getHoverMarkerSize",
      value: function getHoverMarkerSize(index) {
        var w = this.w;
        var hoverSize = w.config.markers.hover.size;
        if (hoverSize === undefined) {
          hoverSize = w.globals.markers.size[index] + w.config.markers.hover.sizeOffset;
        }
        return hoverSize;
      }
    }, {
      key: "toggleAllTooltipSeriesGroups",
      value: function toggleAllTooltipSeriesGroups(state) {
        var w = this.w;
        var ttCtx = this.ttCtx;
        if (ttCtx.allTooltipSeriesGroups.length === 0) {
          ttCtx.allTooltipSeriesGroups = w.globals.dom.baseEl.querySelectorAll('.apexcharts-tooltip-series-group');
        }
        var allTooltipSeriesGroups = ttCtx.allTooltipSeriesGroups;
        for (var i = 0; i < allTooltipSeriesGroups.length; i++) {
          if (state === 'enable') {
            allTooltipSeriesGroups[i].classList.add('apexcharts-active');
            allTooltipSeriesGroups[i].style.display = w.config.tooltip.items.display;
          } else {
            allTooltipSeriesGroups[i].classList.remove('apexcharts-active');
            allTooltipSeriesGroups[i].style.display = 'none';
          }
        }
      }
    }]);
    return Utils;
  }();

  /**
   * ApexCharts Tooltip.Labels Class to draw texts on the tooltip.
   * This file deals with printing actual text on the tooltip.
   *
   * @module Tooltip.Labels
   **/
  var Labels = /*#__PURE__*/function () {
    function Labels(tooltipContext) {
      _classCallCheck(this, Labels);
      this.w = tooltipContext.w;
      this.ctx = tooltipContext.ctx;
      this.ttCtx = tooltipContext;
      this.tooltipUtil = new Utils(tooltipContext);
    }
    _createClass(Labels, [{
      key: "drawSeriesTexts",
      value: function drawSeriesTexts(_ref) {
        var _ref$shared = _ref.shared,
          shared = _ref$shared === void 0 ? true : _ref$shared,
          ttItems = _ref.ttItems,
          _ref$i = _ref.i,
          i = _ref$i === void 0 ? 0 : _ref$i,
          _ref$j = _ref.j,
          j = _ref$j === void 0 ? null : _ref$j,
          y1 = _ref.y1,
          y2 = _ref.y2,
          e = _ref.e;
        var w = this.w;
        if (w.config.tooltip.custom !== undefined) {
          this.handleCustomTooltip({
            i: i,
            j: j,
            y1: y1,
            y2: y2,
            w: w
          });
        } else {
          this.toggleActiveInactiveSeries(shared, i);
        }
        var values = this.getValuesToPrint({
          i: i,
          j: j
        });
        this.printLabels({
          i: i,
          j: j,
          values: values,
          ttItems: ttItems,
          shared: shared,
          e: e
        });

        // Re-calculate tooltip dimensions now that we have drawn the text
        var tooltipEl = this.ttCtx.getElTooltip();
        this.ttCtx.tooltipRect.ttWidth = tooltipEl.getBoundingClientRect().width;
        this.ttCtx.tooltipRect.ttHeight = tooltipEl.getBoundingClientRect().height;
      }
    }, {
      key: "printLabels",
      value: function printLabels(_ref2) {
        var _this = this;
        var i = _ref2.i,
          j = _ref2.j,
          values = _ref2.values,
          ttItems = _ref2.ttItems,
          shared = _ref2.shared,
          e = _ref2.e;
        var w = this.w;
        var val;
        var goalVals = [];
        var hasGoalValues = function hasGoalValues(gi) {
          return w.globals.seriesGoals[gi] && w.globals.seriesGoals[gi][j] && Array.isArray(w.globals.seriesGoals[gi][j]);
        };
        var xVal = values.xVal,
          zVal = values.zVal,
          xAxisTTVal = values.xAxisTTVal;
        var seriesName = '';
        var pColor = w.globals.colors[i]; // The pColor here is for the markers inside tooltip
        if (j !== null && w.config.plotOptions.bar.distributed) {
          pColor = w.globals.colors[j];
        }
        var _loop = function _loop(t, inverset) {
          var f = _this.getFormatters(i);
          seriesName = _this.getSeriesName({
            fn: f.yLbTitleFormatter,
            index: i,
            seriesIndex: i,
            j: j
          });
          if (w.config.chart.type === 'treemap') {
            seriesName = f.yLbTitleFormatter(String(w.config.series[i].data[j].x), {
              series: w.globals.series,
              seriesIndex: i,
              dataPointIndex: j,
              w: w
            });
          }
          var tIndex = w.config.tooltip.inverseOrder ? inverset : t;
          if (w.globals.axisCharts) {
            var getValBySeriesIndex = function getValBySeriesIndex(index) {
              if (w.globals.isRangeData) {
                var _w$globals$seriesRang, _w$globals$seriesRang2, _w$globals$seriesRang3, _w$globals$seriesRang4;
                return f.yLbFormatter((_w$globals$seriesRang = w.globals.seriesRangeStart) === null || _w$globals$seriesRang === void 0 ? void 0 : (_w$globals$seriesRang2 = _w$globals$seriesRang[index]) === null || _w$globals$seriesRang2 === void 0 ? void 0 : _w$globals$seriesRang2[j], {
                  series: w.globals.seriesRangeStart,
                  seriesIndex: index,
                  dataPointIndex: j,
                  w: w
                }) + ' - ' + f.yLbFormatter((_w$globals$seriesRang3 = w.globals.seriesRangeEnd) === null || _w$globals$seriesRang3 === void 0 ? void 0 : (_w$globals$seriesRang4 = _w$globals$seriesRang3[index]) === null || _w$globals$seriesRang4 === void 0 ? void 0 : _w$globals$seriesRang4[j], {
                  series: w.globals.seriesRangeEnd,
                  seriesIndex: index,
                  dataPointIndex: j,
                  w: w
                });
              }
              return f.yLbFormatter(w.globals.series[index][j], {
                series: w.globals.series,
                seriesIndex: index,
                dataPointIndex: j,
                w: w
              });
            };
            if (shared) {
              f = _this.getFormatters(tIndex);
              seriesName = _this.getSeriesName({
                fn: f.yLbTitleFormatter,
                index: tIndex,
                seriesIndex: i,
                j: j
              });
              pColor = w.globals.colors[tIndex];
              val = getValBySeriesIndex(tIndex);
              if (hasGoalValues(tIndex)) {
                goalVals = w.globals.seriesGoals[tIndex][j].map(function (goal) {
                  return {
                    attrs: goal,
                    val: f.yLbFormatter(goal.value, {
                      seriesIndex: tIndex,
                      dataPointIndex: j,
                      w: w
                    })
                  };
                });
              }
            } else {
              var _e$target;
              // get a color from a hover area (if it's a line pattern then get from a first line)
              var targetFill = e === null || e === void 0 ? void 0 : (_e$target = e.target) === null || _e$target === void 0 ? void 0 : _e$target.getAttribute('fill');
              if (targetFill) {
                if (targetFill.indexOf('url') !== -1) {
                  // pattern fill
                  if (targetFill.indexOf('Pattern') !== -1) {
                    pColor = w.globals.dom.baseEl.querySelector(targetFill.substr(4).slice(0, -1)).childNodes[0].getAttribute('stroke');
                  }
                } else {
                  pColor = targetFill;
                }
              }
              val = getValBySeriesIndex(i);
              if (hasGoalValues(i) && Array.isArray(w.globals.seriesGoals[i][j])) {
                goalVals = w.globals.seriesGoals[i][j].map(function (goal) {
                  return {
                    attrs: goal,
                    val: f.yLbFormatter(goal.value, {
                      seriesIndex: i,
                      dataPointIndex: j,
                      w: w
                    })
                  };
                });
              }
            }
          }

          // for pie / donuts
          if (j === null) {
            val = f.yLbFormatter(w.globals.series[i], _objectSpread2(_objectSpread2({}, w), {}, {
              seriesIndex: i,
              dataPointIndex: i
            }));
          }
          _this.DOMHandling({
            i: i,
            t: tIndex,
            j: j,
            ttItems: ttItems,
            values: {
              val: val,
              goalVals: goalVals,
              xVal: xVal,
              xAxisTTVal: xAxisTTVal,
              zVal: zVal
            },
            seriesName: seriesName,
            shared: shared,
            pColor: pColor
          });
        };
        for (var t = 0, inverset = w.globals.series.length - 1; t < w.globals.series.length; t++, inverset--) {
          _loop(t, inverset);
        }
      }
    }, {
      key: "getFormatters",
      value: function getFormatters(i) {
        var w = this.w;
        var yLbFormatter = w.globals.yLabelFormatters[i];
        var yLbTitleFormatter;
        if (w.globals.ttVal !== undefined) {
          if (Array.isArray(w.globals.ttVal)) {
            yLbFormatter = w.globals.ttVal[i] && w.globals.ttVal[i].formatter;
            yLbTitleFormatter = w.globals.ttVal[i] && w.globals.ttVal[i].title && w.globals.ttVal[i].title.formatter;
          } else {
            yLbFormatter = w.globals.ttVal.formatter;
            if (typeof w.globals.ttVal.title.formatter === 'function') {
              yLbTitleFormatter = w.globals.ttVal.title.formatter;
            }
          }
        } else {
          yLbTitleFormatter = w.config.tooltip.y.title.formatter;
        }
        if (typeof yLbFormatter !== 'function') {
          if (w.globals.yLabelFormatters[0]) {
            yLbFormatter = w.globals.yLabelFormatters[0];
          } else {
            yLbFormatter = function yLbFormatter(label) {
              return label;
            };
          }
        }
        if (typeof yLbTitleFormatter !== 'function') {
          yLbTitleFormatter = function yLbTitleFormatter(label) {
            return label;
          };
        }
        return {
          yLbFormatter: yLbFormatter,
          yLbTitleFormatter: yLbTitleFormatter
        };
      }
    }, {
      key: "getSeriesName",
      value: function getSeriesName(_ref3) {
        var fn = _ref3.fn,
          index = _ref3.index,
          seriesIndex = _ref3.seriesIndex,
          j = _ref3.j;
        var w = this.w;
        return fn(String(w.globals.seriesNames[index]), {
          series: w.globals.series,
          seriesIndex: seriesIndex,
          dataPointIndex: j,
          w: w
        });
      }
    }, {
      key: "DOMHandling",
      value: function DOMHandling(_ref4) {
        _ref4.i;
          var t = _ref4.t,
          j = _ref4.j,
          ttItems = _ref4.ttItems,
          values = _ref4.values,
          seriesName = _ref4.seriesName,
          shared = _ref4.shared,
          pColor = _ref4.pColor;
        var w = this.w;
        var ttCtx = this.ttCtx;
        var val = values.val,
          goalVals = values.goalVals,
          xVal = values.xVal,
          xAxisTTVal = values.xAxisTTVal,
          zVal = values.zVal;
        var ttItemsChildren = null;
        ttItemsChildren = ttItems[t].children;
        if (w.config.tooltip.fillSeriesColor) {
          ttItems[t].style.backgroundColor = pColor;
          ttItemsChildren[0].style.display = 'none';
        }
        if (ttCtx.showTooltipTitle) {
          if (ttCtx.tooltipTitle === null) {
            // get it once if null, and store it in class property
            ttCtx.tooltipTitle = w.globals.dom.baseEl.querySelector('.apexcharts-tooltip-title');
          }
          ttCtx.tooltipTitle.innerHTML = xVal;
        }

        // if xaxis tooltip is constructed, we need to replace the innerHTML
        if (ttCtx.isXAxisTooltipEnabled) {
          ttCtx.xaxisTooltipText.innerHTML = xAxisTTVal !== '' ? xAxisTTVal : xVal;
        }
        var ttYLabel = ttItems[t].querySelector('.apexcharts-tooltip-text-y-label');
        if (ttYLabel) {
          ttYLabel.innerHTML = seriesName ? seriesName : '';
        }
        var ttYVal = ttItems[t].querySelector('.apexcharts-tooltip-text-y-value');
        if (ttYVal) {
          ttYVal.innerHTML = typeof val !== 'undefined' ? val : '';
        }
        if (ttItemsChildren[0] && ttItemsChildren[0].classList.contains('apexcharts-tooltip-marker')) {
          if (w.config.tooltip.marker.fillColors && Array.isArray(w.config.tooltip.marker.fillColors)) {
            pColor = w.config.tooltip.marker.fillColors[t];
          }
          ttItemsChildren[0].style.backgroundColor = pColor;
        }
        if (!w.config.tooltip.marker.show) {
          ttItemsChildren[0].style.display = 'none';
        }
        var ttGLabel = ttItems[t].querySelector('.apexcharts-tooltip-text-goals-label');
        var ttGVal = ttItems[t].querySelector('.apexcharts-tooltip-text-goals-value');
        if (goalVals.length && w.globals.seriesGoals[t]) {
          var createGoalsHtml = function createGoalsHtml() {
            var gLabels = '<div >';
            var gVals = '<div>';
            goalVals.forEach(function (goal, gi) {
              gLabels += " <div style=\"display: flex\"><span class=\"apexcharts-tooltip-marker\" style=\"background-color: ".concat(goal.attrs.strokeColor, "; height: 3px; border-radius: 0; top: 5px;\"></span> ").concat(goal.attrs.name, "</div>");
              gVals += "<div>".concat(goal.val, "</div>");
            });
            ttGLabel.innerHTML = gLabels + "</div>";
            ttGVal.innerHTML = gVals + "</div>";
          };
          if (shared) {
            if (w.globals.seriesGoals[t][j] && Array.isArray(w.globals.seriesGoals[t][j])) {
              createGoalsHtml();
            } else {
              ttGLabel.innerHTML = '';
              ttGVal.innerHTML = '';
            }
          } else {
            createGoalsHtml();
          }
        } else {
          ttGLabel.innerHTML = '';
          ttGVal.innerHTML = '';
        }
        if (zVal !== null) {
          var ttZLabel = ttItems[t].querySelector('.apexcharts-tooltip-text-z-label');
          ttZLabel.innerHTML = w.config.tooltip.z.title;
          var ttZVal = ttItems[t].querySelector('.apexcharts-tooltip-text-z-value');
          ttZVal.innerHTML = typeof zVal !== 'undefined' ? zVal : '';
        }
        if (shared && ttItemsChildren[0]) {
          // hide when no Val or series collapsed
          if (w.config.tooltip.hideEmptySeries) {
            var ttItemMarker = ttItems[t].querySelector('.apexcharts-tooltip-marker');
            var ttItemText = ttItems[t].querySelector('.apexcharts-tooltip-text');
            if (parseFloat(val) == 0) {
              ttItemMarker.style.display = 'none';
              ttItemText.style.display = 'none';
            } else {
              ttItemMarker.style.display = 'block';
              ttItemText.style.display = 'block';
            }
          }
          if (typeof val === 'undefined' || val === null || w.globals.ancillaryCollapsedSeriesIndices.indexOf(t) > -1 || w.globals.collapsedSeriesIndices.indexOf(t) > -1 || Array.isArray(ttCtx.tConfig.enabledOnSeries) && ttCtx.tConfig.enabledOnSeries.indexOf(t) === -1) {
            ttItemsChildren[0].parentNode.style.display = 'none';
          } else {
            ttItemsChildren[0].parentNode.style.display = w.config.tooltip.items.display;
          }
        } else {
          if (Array.isArray(ttCtx.tConfig.enabledOnSeries) && ttCtx.tConfig.enabledOnSeries.indexOf(t) === -1) {
            ttItemsChildren[0].parentNode.style.display = 'none';
          }
        }
      }
    }, {
      key: "toggleActiveInactiveSeries",
      value: function toggleActiveInactiveSeries(shared, i) {
        var w = this.w;
        if (shared) {
          // make all tooltips active
          this.tooltipUtil.toggleAllTooltipSeriesGroups('enable');
        } else {
          // disable all tooltip text groups
          this.tooltipUtil.toggleAllTooltipSeriesGroups('disable');

          // enable the first tooltip text group
          var firstTooltipSeriesGroup = w.globals.dom.baseEl.querySelector(".apexcharts-tooltip-series-group-".concat(i));
          if (firstTooltipSeriesGroup) {
            firstTooltipSeriesGroup.classList.add('apexcharts-active');
            firstTooltipSeriesGroup.style.display = w.config.tooltip.items.display;
          }
        }
      }
    }, {
      key: "getValuesToPrint",
      value: function getValuesToPrint(_ref5) {
        var i = _ref5.i,
          j = _ref5.j;
        var w = this.w;
        var filteredSeriesX = this.ctx.series.filteredSeriesX();
        var xVal = '';
        var xAxisTTVal = '';
        var zVal = null;
        var val = null;
        var customFormatterOpts = {
          series: w.globals.series,
          seriesIndex: i,
          dataPointIndex: j,
          w: w
        };
        var zFormatter = w.globals.ttZFormatter;
        if (j === null) {
          val = w.globals.series[i];
        } else {
          if (w.globals.isXNumeric && w.config.chart.type !== 'treemap') {
            xVal = filteredSeriesX[i][j];
            if (filteredSeriesX[i].length === 0) {
              // a series (possibly the first one) might be collapsed, so get the next active index
              var firstActiveSeriesIndex = this.tooltipUtil.getFirstActiveXArray(filteredSeriesX);
              xVal = filteredSeriesX[firstActiveSeriesIndex][j];
            }
          } else {
            var dataFormat = new Data(this.ctx);
            if (dataFormat.isFormatXY()) {
              xVal = typeof w.config.series[i].data[j] !== 'undefined' ? w.config.series[i].data[j].x : '';
            } else {
              xVal = typeof w.globals.labels[j] !== 'undefined' ? w.globals.labels[j] : '';
            }
          }
        }
        var bufferXVal = xVal;
        if (w.globals.isXNumeric && w.config.xaxis.type === 'datetime') {
          var xFormat = new Formatters(this.ctx);
          xVal = xFormat.xLabelFormat(w.globals.ttKeyFormatter, bufferXVal, bufferXVal, {
            i: undefined,
            dateFormatter: new DateTime(this.ctx).formatDate,
            w: this.w
          });
        } else {
          if (w.globals.isBarHorizontal) {
            xVal = w.globals.yLabelFormatters[0](bufferXVal, customFormatterOpts);
          } else {
            xVal = w.globals.xLabelFormatter(bufferXVal, customFormatterOpts);
          }
        }

        // override default x-axis formatter with tooltip formatter
        if (w.config.tooltip.x.formatter !== undefined) {
          xVal = w.globals.ttKeyFormatter(bufferXVal, customFormatterOpts);
        }
        if (w.globals.seriesZ.length > 0 && w.globals.seriesZ[i].length > 0) {
          zVal = zFormatter(w.globals.seriesZ[i][j], w);
        }
        if (typeof w.config.xaxis.tooltip.formatter === 'function') {
          xAxisTTVal = w.globals.xaxisTooltipFormatter(bufferXVal, customFormatterOpts);
        } else {
          xAxisTTVal = xVal;
        }
        return {
          val: Array.isArray(val) ? val.join(' ') : val,
          xVal: Array.isArray(xVal) ? xVal.join(' ') : xVal,
          xAxisTTVal: Array.isArray(xAxisTTVal) ? xAxisTTVal.join(' ') : xAxisTTVal,
          zVal: zVal
        };
      }
    }, {
      key: "handleCustomTooltip",
      value: function handleCustomTooltip(_ref6) {
        var i = _ref6.i,
          j = _ref6.j,
          y1 = _ref6.y1,
          y2 = _ref6.y2,
          w = _ref6.w;
        var tooltipEl = this.ttCtx.getElTooltip();
        var fn = w.config.tooltip.custom;
        if (Array.isArray(fn) && fn[i]) {
          fn = fn[i];
        }

        // override everything with a custom html tooltip and replace it
        tooltipEl.innerHTML = fn({
          ctx: this.ctx,
          series: w.globals.series,
          seriesIndex: i,
          dataPointIndex: j,
          y1: y1,
          y2: y2,
          w: w
        });
      }
    }]);
    return Labels;
  }();

  /**
   * ApexCharts Tooltip.Position Class to move the tooltip based on x and y position.
   *
   * @module Tooltip.Position
   **/
  var Position = /*#__PURE__*/function () {
    function Position(tooltipContext) {
      _classCallCheck(this, Position);
      this.ttCtx = tooltipContext;
      this.ctx = tooltipContext.ctx;
      this.w = tooltipContext.w;
    }

    /**
     * This will move the crosshair (the vertical/horz line that moves along with mouse)
     * Along with this, this function also calls the xaxisMove function
     * @memberof Position
     * @param {int} - cx = point's x position, wherever point's x is, you need to move crosshair
     */
    _createClass(Position, [{
      key: "moveXCrosshairs",
      value: function moveXCrosshairs(cx) {
        var j = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
        var ttCtx = this.ttCtx;
        var w = this.w;
        var xcrosshairs = ttCtx.getElXCrosshairs();
        var x = cx - ttCtx.xcrosshairsWidth / 2;
        var tickAmount = w.globals.labels.slice().length;
        if (j !== null) {
          x = w.globals.gridWidth / tickAmount * j;
        }
        if (xcrosshairs !== null && !w.globals.isBarHorizontal) {
          xcrosshairs.setAttribute('x', x);
          xcrosshairs.setAttribute('x1', x);
          xcrosshairs.setAttribute('x2', x);
          xcrosshairs.setAttribute('y2', w.globals.gridHeight);
          xcrosshairs.classList.add('apexcharts-active');
        }
        if (x < 0) {
          x = 0;
        }
        if (x > w.globals.gridWidth) {
          x = w.globals.gridWidth;
        }
        if (ttCtx.isXAxisTooltipEnabled) {
          var tx = x;
          if (w.config.xaxis.crosshairs.width === 'tickWidth' || w.config.xaxis.crosshairs.width === 'barWidth') {
            tx = x + ttCtx.xcrosshairsWidth / 2;
          }
          this.moveXAxisTooltip(tx);
        }
      }

      /**
       * This will move the crosshair (the vertical/horz line that moves along with mouse)
       * Along with this, this function also calls the xaxisMove function
       * @memberof Position
       * @param {int} - cx = point's x position, wherever point's x is, you need to move crosshair
       */
    }, {
      key: "moveYCrosshairs",
      value: function moveYCrosshairs(cy) {
        var ttCtx = this.ttCtx;
        if (ttCtx.ycrosshairs !== null) {
          Graphics.setAttrs(ttCtx.ycrosshairs, {
            y1: cy,
            y2: cy
          });
        }
        if (ttCtx.ycrosshairsHidden !== null) {
          Graphics.setAttrs(ttCtx.ycrosshairsHidden, {
            y1: cy,
            y2: cy
          });
        }
      }

      /**
       ** AxisTooltip is the small rectangle which appears on x axis with x value, when user moves
       * @memberof Position
       * @param {int} - cx = point's x position, wherever point's x is, you need to move
       */
    }, {
      key: "moveXAxisTooltip",
      value: function moveXAxisTooltip(cx) {
        var w = this.w;
        var ttCtx = this.ttCtx;
        if (ttCtx.xaxisTooltip !== null && ttCtx.xcrosshairsWidth !== 0) {
          ttCtx.xaxisTooltip.classList.add('apexcharts-active');
          var cy = ttCtx.xaxisOffY + w.config.xaxis.tooltip.offsetY + w.globals.translateY + 1 + w.config.xaxis.offsetY;
          var xaxisTTText = ttCtx.xaxisTooltip.getBoundingClientRect();
          var xaxisTTTextWidth = xaxisTTText.width;
          cx = cx - xaxisTTTextWidth / 2;
          if (!isNaN(cx)) {
            cx = cx + w.globals.translateX;
            var textRect = 0;
            var graphics = new Graphics(this.ctx);
            textRect = graphics.getTextRects(ttCtx.xaxisTooltipText.innerHTML);
            ttCtx.xaxisTooltipText.style.minWidth = textRect.width + 'px';
            ttCtx.xaxisTooltip.style.left = cx + 'px';
            ttCtx.xaxisTooltip.style.top = cy + 'px';
          }
        }
      }
    }, {
      key: "moveYAxisTooltip",
      value: function moveYAxisTooltip(index) {
        var w = this.w;
        var ttCtx = this.ttCtx;
        if (ttCtx.yaxisTTEls === null) {
          ttCtx.yaxisTTEls = w.globals.dom.baseEl.querySelectorAll('.apexcharts-yaxistooltip');
        }
        var ycrosshairsHiddenRectY1 = parseInt(ttCtx.ycrosshairsHidden.getAttribute('y1'), 10);
        var cy = w.globals.translateY + ycrosshairsHiddenRectY1;
        var yAxisTTRect = ttCtx.yaxisTTEls[index].getBoundingClientRect();
        var yAxisTTHeight = yAxisTTRect.height;
        var cx = w.globals.translateYAxisX[index] - 2;
        if (w.config.yaxis[index].opposite) {
          cx = cx - 26;
        }
        cy = cy - yAxisTTHeight / 2;
        if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1) {
          ttCtx.yaxisTTEls[index].classList.add('apexcharts-active');
          ttCtx.yaxisTTEls[index].style.top = cy + 'px';
          ttCtx.yaxisTTEls[index].style.left = cx + w.config.yaxis[index].tooltip.offsetX + 'px';
        } else {
          ttCtx.yaxisTTEls[index].classList.remove('apexcharts-active');
        }
      }

      /**
       ** moves the whole tooltip by changing x, y attrs
       * @memberof Position
       * @param {int} - cx = point's x position, wherever point's x is, you need to move tooltip
       * @param {int} - cy = point's y position, wherever point's y is, you need to move tooltip
       * @param {int} - markerSize = point's size
       */
    }, {
      key: "moveTooltip",
      value: function moveTooltip(cx, cy) {
        var markerSize = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
        var w = this.w;
        var ttCtx = this.ttCtx;
        var tooltipEl = ttCtx.getElTooltip();
        var tooltipRect = ttCtx.tooltipRect;
        var pointSize = markerSize !== null ? parseFloat(markerSize) : 1;
        var x = parseFloat(cx) + pointSize + 5;
        var y = parseFloat(cy) + pointSize / 2; // - tooltipRect.ttHeight / 2

        if (x > w.globals.gridWidth / 2) {
          x = x - tooltipRect.ttWidth - pointSize - 10;
        }
        if (x > w.globals.gridWidth - tooltipRect.ttWidth - 10) {
          x = w.globals.gridWidth - tooltipRect.ttWidth;
        }
        if (x < -20) {
          x = -20;
        }
        if (w.config.tooltip.followCursor) {
          var elGrid = ttCtx.getElGrid();
          var seriesBound = elGrid.getBoundingClientRect();
          x = ttCtx.e.clientX - seriesBound.left;
          if (x > w.globals.gridWidth / 2) {
            x = x - ttCtx.tooltipRect.ttWidth;
          }
          y = ttCtx.e.clientY + w.globals.translateY - seriesBound.top;
          if (y > w.globals.gridHeight / 2) {
            y = y - ttCtx.tooltipRect.ttHeight;
          }
        } else {
          if (!w.globals.isBarHorizontal) {
            if (tooltipRect.ttHeight / 2 + y > w.globals.gridHeight) {
              y = w.globals.gridHeight - tooltipRect.ttHeight + w.globals.translateY;
            }
          }
        }
        if (!isNaN(x)) {
          x = x + w.globals.translateX;
          tooltipEl.style.left = x + 'px';
          tooltipEl.style.top = y + 'px';
        }
      }
    }, {
      key: "moveMarkers",
      value: function moveMarkers(i, j) {
        var w = this.w;
        var ttCtx = this.ttCtx;
        if (w.globals.markers.size[i] > 0) {
          var allPoints = w.globals.dom.baseEl.querySelectorAll(" .apexcharts-series[data\\:realIndex='".concat(i, "'] .apexcharts-marker"));
          for (var p = 0; p < allPoints.length; p++) {
            if (parseInt(allPoints[p].getAttribute('rel'), 10) === j) {
              ttCtx.marker.resetPointsSize();
              ttCtx.marker.enlargeCurrentPoint(j, allPoints[p]);
            }
          }
        } else {
          ttCtx.marker.resetPointsSize();
          this.moveDynamicPointOnHover(j, i);
        }
      }

      // This function is used when you need to show markers/points only on hover -
      // DIFFERENT X VALUES in multiple series
    }, {
      key: "moveDynamicPointOnHover",
      value: function moveDynamicPointOnHover(j, capturedSeries) {
        var _pointsArr$capturedSe, _pointsArr$capturedSe2;
        var w = this.w;
        var ttCtx = this.ttCtx;
        var cx = 0;
        var cy = 0;
        var graphics = new Graphics(this.ctx);
        var pointsArr = w.globals.pointsArray;
        var hoverSize = ttCtx.tooltipUtil.getHoverMarkerSize(capturedSeries);
        var serType = w.config.series[capturedSeries].type;
        if (serType && (serType === 'column' || serType === 'candlestick' || serType === 'boxPlot')) {
          // fix error mentioned in #811
          return;
        }
        cx = (_pointsArr$capturedSe = pointsArr[capturedSeries][j]) === null || _pointsArr$capturedSe === void 0 ? void 0 : _pointsArr$capturedSe[0];
        cy = ((_pointsArr$capturedSe2 = pointsArr[capturedSeries][j]) === null || _pointsArr$capturedSe2 === void 0 ? void 0 : _pointsArr$capturedSe2[1]) || 0;
        var point = w.globals.dom.baseEl.querySelector(".apexcharts-series[data\\:realIndex='".concat(capturedSeries, "'] .apexcharts-series-markers path"));
        if (point && cy < w.globals.gridHeight && cy > 0) {
          var shape = point.getAttribute('shape');
          var path = graphics.getMarkerPath(cx, cy, shape, hoverSize * 1.5);
          point.setAttribute('d', path);
        }
        this.moveXCrosshairs(cx);
        if (!ttCtx.fixedTooltip) {
          this.moveTooltip(cx, cy, hoverSize);
        }
      }

      // This function is used when you need to show markers/points only on hover -
      // SAME X VALUES in multiple series
    }, {
      key: "moveDynamicPointsOnHover",
      value: function moveDynamicPointsOnHover(j) {
        var ttCtx = this.ttCtx;
        var w = ttCtx.w;
        var cx = 0;
        var cy = 0;
        var activeSeries = 0;
        var pointsArr = w.globals.pointsArray;
        var series = new Series(this.ctx);
        var graphics = new Graphics(this.ctx);
        activeSeries = series.getActiveConfigSeriesIndex('asc', ['line', 'area', 'scatter', 'bubble']);
        var hoverSize = ttCtx.tooltipUtil.getHoverMarkerSize(activeSeries);
        if (pointsArr[activeSeries]) {
          cx = pointsArr[activeSeries][j][0];
          cy = pointsArr[activeSeries][j][1];
        }
        var points = ttCtx.tooltipUtil.getAllMarkers();
        if (points !== null) {
          for (var p = 0; p < w.globals.series.length; p++) {
            var pointArr = pointsArr[p];
            if (w.globals.comboCharts) {
              // in a combo chart, if column charts are present, markers will not match with the number of series, hence this patch to push a null value in points array
              if (typeof pointArr === 'undefined') {
                // nodelist to array
                points.splice(p, 0, null);
              }
            }
            if (pointArr && pointArr.length) {
              var pcy = pointsArr[p][j][1];
              var pcy2 = void 0;
              points[p].setAttribute('cx', cx);
              var shape = points[p].getAttribute('shape');
              if (w.config.chart.type === 'rangeArea' && !w.globals.comboCharts) {
                var rangeStartIndex = j + w.globals.series[p].length;
                pcy2 = pointsArr[p][rangeStartIndex][1];
                var pcyDiff = Math.abs(pcy - pcy2) / 2;
                pcy = pcy - pcyDiff;
              }
              if (pcy !== null && !isNaN(pcy) && pcy < w.globals.gridHeight + hoverSize && pcy + hoverSize > 0) {
                var path = graphics.getMarkerPath(cx, pcy, shape, hoverSize);
                points[p].setAttribute('d', path);
              } else {
                points[p].setAttribute('d', '');
              }
            }
          }
        }
        this.moveXCrosshairs(cx);
        if (!ttCtx.fixedTooltip) {
          this.moveTooltip(cx, cy || w.globals.gridHeight, hoverSize);
        }
      }
    }, {
      key: "moveStickyTooltipOverBars",
      value: function moveStickyTooltipOverBars(j, capturedSeries) {
        var w = this.w;
        var ttCtx = this.ttCtx;
        var barLen = w.globals.columnSeries ? w.globals.columnSeries.length : w.globals.series.length;
        var i = barLen >= 2 && barLen % 2 === 0 ? Math.floor(barLen / 2) : Math.floor(barLen / 2) + 1;
        if (w.globals.isBarHorizontal) {
          var series = new Series(this.ctx);
          i = series.getActiveConfigSeriesIndex('desc') + 1;
        }
        var jBar = w.globals.dom.baseEl.querySelector(".apexcharts-bar-series .apexcharts-series[rel='".concat(i, "'] path[j='").concat(j, "'], .apexcharts-candlestick-series .apexcharts-series[rel='").concat(i, "'] path[j='").concat(j, "'], .apexcharts-boxPlot-series .apexcharts-series[rel='").concat(i, "'] path[j='").concat(j, "'], .apexcharts-rangebar-series .apexcharts-series[rel='").concat(i, "'] path[j='").concat(j, "']"));
        if (!jBar && typeof capturedSeries === 'number') {
          // Try with captured series index
          jBar = w.globals.dom.baseEl.querySelector(".apexcharts-bar-series .apexcharts-series[data\\:realIndex='".concat(capturedSeries, "'] path[j='").concat(j, "'],\n        .apexcharts-candlestick-series .apexcharts-series[data\\:realIndex='").concat(capturedSeries, "'] path[j='").concat(j, "'],\n        .apexcharts-boxPlot-series .apexcharts-series[data\\:realIndex='").concat(capturedSeries, "'] path[j='").concat(j, "'],\n        .apexcharts-rangebar-series .apexcharts-series[data\\:realIndex='").concat(capturedSeries, "'] path[j='").concat(j, "']"));
        }
        var bcx = jBar ? parseFloat(jBar.getAttribute('cx')) : 0;
        var bcy = jBar ? parseFloat(jBar.getAttribute('cy')) : 0;
        var bw = jBar ? parseFloat(jBar.getAttribute('barWidth')) : 0;
        var elGrid = ttCtx.getElGrid();
        var seriesBound = elGrid.getBoundingClientRect();
        var isBoxOrCandle = jBar && (jBar.classList.contains('apexcharts-candlestick-area') || jBar.classList.contains('apexcharts-boxPlot-area'));
        if (w.globals.isXNumeric) {
          if (jBar && !isBoxOrCandle) {
            bcx = bcx - (barLen % 2 !== 0 ? bw / 2 : 0);
          }
          if (jBar &&
          // fixes apexcharts.js#2354
          isBoxOrCandle && w.globals.comboCharts) {
            bcx = bcx - bw / 2;
          }
        } else {
          if (!w.globals.isBarHorizontal) {
            bcx = ttCtx.xAxisTicksPositions[j - 1] + ttCtx.dataPointsDividedWidth / 2;
            if (isNaN(bcx)) {
              bcx = ttCtx.xAxisTicksPositions[j] - ttCtx.dataPointsDividedWidth / 2;
            }
          }
        }
        if (!w.globals.isBarHorizontal) {
          if (w.config.tooltip.followCursor) {
            bcy = ttCtx.e.clientY - seriesBound.top - ttCtx.tooltipRect.ttHeight / 2;
          } else {
            if (bcy + ttCtx.tooltipRect.ttHeight + 15 > w.globals.gridHeight) {
              bcy = w.globals.gridHeight;
            }
          }
        } else {
          bcy = bcy - ttCtx.tooltipRect.ttHeight;
        }
        if (!w.globals.isBarHorizontal) {
          this.moveXCrosshairs(bcx);
        }
        if (!ttCtx.fixedTooltip) {
          this.moveTooltip(bcx, bcy || w.globals.gridHeight);
        }
      }
    }]);
    return Position;
  }();

  /**
   * ApexCharts Tooltip.Marker Class to draw texts on the tooltip.
   * This file deals with the markers that appear near tooltip in line/area charts.
   * These markers helps the user to associate the data-points and the values
   * that are shown in the tooltip
   *
   * @module Tooltip.Marker
   **/
  var Marker = /*#__PURE__*/function () {
    function Marker(tooltipContext) {
      _classCallCheck(this, Marker);
      this.w = tooltipContext.w;
      this.ttCtx = tooltipContext;
      this.ctx = tooltipContext.ctx;
      this.tooltipPosition = new Position(tooltipContext);
    }
    _createClass(Marker, [{
      key: "drawDynamicPoints",
      value: function drawDynamicPoints() {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var marker = new Markers(this.ctx);
        var elsSeries = w.globals.dom.baseEl.querySelectorAll('.apexcharts-series');
        elsSeries = _toConsumableArray(elsSeries);
        if (w.config.chart.stacked) {
          elsSeries.sort(function (a, b) {
            return parseFloat(a.getAttribute('data:realIndex')) - parseFloat(b.getAttribute('data:realIndex'));
          });
        }
        for (var i = 0; i < elsSeries.length; i++) {
          var pointsMain = elsSeries[i].querySelector(".apexcharts-series-markers-wrap");
          if (pointsMain !== null) {
            // it can be null as we have tooltips in donut/bar charts
            var point = void 0;
            var PointClasses = "apexcharts-marker w".concat((Math.random() + 1).toString(36).substring(4));
            if ((w.config.chart.type === 'line' || w.config.chart.type === 'area') && !w.globals.comboCharts && !w.config.tooltip.intersect) {
              PointClasses += ' no-pointer-events';
            }
            var elPointOptions = marker.getMarkerConfig({
              cssClass: PointClasses,
              seriesIndex: Number(pointsMain.getAttribute('data:realIndex')) // fixes apexcharts/apexcharts.js #1427
            });
            point = graphics.drawMarker(0, 0, elPointOptions);
            point.node.setAttribute('default-marker-size', 0);
            var elPointsG = document.createElementNS(w.globals.SVGNS, 'g');
            elPointsG.classList.add('apexcharts-series-markers');
            elPointsG.appendChild(point.node);
            pointsMain.appendChild(elPointsG);
          }
        }
      }
    }, {
      key: "enlargeCurrentPoint",
      value: function enlargeCurrentPoint(rel, point) {
        var x = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
        var y = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
        var w = this.w;
        if (w.config.chart.type !== 'bubble') {
          this.newPointSize(rel, point);
        }
        var cx = point.getAttribute('cx');
        var cy = point.getAttribute('cy');
        if (x !== null && y !== null) {
          cx = x;
          cy = y;
        }
        this.tooltipPosition.moveXCrosshairs(cx);
        if (!this.fixedTooltip) {
          if (w.config.chart.type === 'radar') {
            var elGrid = this.ttCtx.getElGrid();
            var seriesBound = elGrid.getBoundingClientRect();
            cx = this.ttCtx.e.clientX - seriesBound.left;
          }
          this.tooltipPosition.moveTooltip(cx, cy, w.config.markers.hover.size);
        }
      }
    }, {
      key: "enlargePoints",
      value: function enlargePoints(j) {
        var w = this.w;
        var me = this;
        var ttCtx = this.ttCtx;
        var col = j;
        var points = w.globals.dom.baseEl.querySelectorAll('.apexcharts-series:not(.apexcharts-series-collapsed) .apexcharts-marker');
        var newSize = w.config.markers.hover.size;
        for (var p = 0; p < points.length; p++) {
          var rel = points[p].getAttribute('rel');
          var index = points[p].getAttribute('index');
          if (newSize === undefined) {
            newSize = w.globals.markers.size[index] + w.config.markers.hover.sizeOffset;
          }
          if (col === parseInt(rel, 10)) {
            me.newPointSize(col, points[p]);
            var cx = points[p].getAttribute('cx');
            var cy = points[p].getAttribute('cy');
            me.tooltipPosition.moveXCrosshairs(cx);
            if (!ttCtx.fixedTooltip) {
              me.tooltipPosition.moveTooltip(cx, cy, newSize);
            }
          } else {
            me.oldPointSize(points[p]);
          }
        }
      }
    }, {
      key: "newPointSize",
      value: function newPointSize(rel, point) {
        var w = this.w;
        var newSize = w.config.markers.hover.size;
        var elPoint = rel === 0 ? point.parentNode.firstChild : point.parentNode.lastChild;
        if (elPoint.getAttribute('default-marker-size') !== '0') {
          var index = parseInt(elPoint.getAttribute('index'), 10);
          if (newSize === undefined) {
            newSize = w.globals.markers.size[index] + w.config.markers.hover.sizeOffset;
          }
          if (newSize < 0) {
            newSize = 0;
          }
          var path = this.ttCtx.tooltipUtil.getPathFromPoint(point, newSize);
          point.setAttribute('d', path);
        }
      }
    }, {
      key: "oldPointSize",
      value: function oldPointSize(point) {
        var size = parseFloat(point.getAttribute('default-marker-size'));
        var path = this.ttCtx.tooltipUtil.getPathFromPoint(point, size);
        point.setAttribute('d', path);
      }
    }, {
      key: "resetPointsSize",
      value: function resetPointsSize() {
        var w = this.w;
        var points = w.globals.dom.baseEl.querySelectorAll('.apexcharts-series:not(.apexcharts-series-collapsed) .apexcharts-marker');
        for (var p = 0; p < points.length; p++) {
          var size = parseFloat(points[p].getAttribute('default-marker-size'));
          if (Utils$1.isNumber(size) && size >= 0) {
            var path = this.ttCtx.tooltipUtil.getPathFromPoint(points[p], size);
            points[p].setAttribute('d', path);
          } else {
            points[p].setAttribute('d', 'M0,0');
          }
        }
      }
    }]);
    return Marker;
  }();

  /**
   * ApexCharts Tooltip.Intersect Class.
   * This file deals with functions related to intersecting tooltips
   * (tooltips that appear when user hovers directly over a data-point whether)
   *
   * @module Tooltip.Intersect
   **/
  var Intersect = /*#__PURE__*/function () {
    function Intersect(tooltipContext) {
      _classCallCheck(this, Intersect);
      this.w = tooltipContext.w;
      var w = this.w;
      this.ttCtx = tooltipContext;
      this.isVerticalGroupedRangeBar = !w.globals.isBarHorizontal && w.config.chart.type === 'rangeBar' && w.config.plotOptions.bar.rangeBarGroupRows;
    }

    // a helper function to get an element's attribute value
    _createClass(Intersect, [{
      key: "getAttr",
      value: function getAttr(e, attr) {
        return parseFloat(e.target.getAttribute(attr));
      }

      // handle tooltip for heatmaps and treemaps
    }, {
      key: "handleHeatTreeTooltip",
      value: function handleHeatTreeTooltip(_ref) {
        var e = _ref.e,
          opt = _ref.opt,
          x = _ref.x,
          y = _ref.y,
          type = _ref.type;
        var ttCtx = this.ttCtx;
        var w = this.w;
        if (e.target.classList.contains("apexcharts-".concat(type, "-rect"))) {
          var i = this.getAttr(e, 'i');
          var j = this.getAttr(e, 'j');
          var cx = this.getAttr(e, 'cx');
          var cy = this.getAttr(e, 'cy');
          var width = this.getAttr(e, 'width');
          var height = this.getAttr(e, 'height');
          ttCtx.tooltipLabels.drawSeriesTexts({
            ttItems: opt.ttItems,
            i: i,
            j: j,
            shared: false,
            e: e
          });
          w.globals.capturedSeriesIndex = i;
          w.globals.capturedDataPointIndex = j;
          x = cx + ttCtx.tooltipRect.ttWidth / 2 + width;
          y = cy + ttCtx.tooltipRect.ttHeight / 2 - height / 2;
          ttCtx.tooltipPosition.moveXCrosshairs(cx + width / 2);
          if (x > w.globals.gridWidth / 2) {
            x = cx - ttCtx.tooltipRect.ttWidth / 2 + width;
          }
          if (ttCtx.w.config.tooltip.followCursor) {
            var seriesBound = w.globals.dom.elWrap.getBoundingClientRect();
            x = w.globals.clientX - seriesBound.left - (x > w.globals.gridWidth / 2 ? ttCtx.tooltipRect.ttWidth : 0);
            y = w.globals.clientY - seriesBound.top - (y > w.globals.gridHeight / 2 ? ttCtx.tooltipRect.ttHeight : 0);
          }
        }
        return {
          x: x,
          y: y
        };
      }

      /**
       * handle tooltips for line/area/scatter charts where tooltip.intersect is true
       * when user hovers over the marker directly, this function is executed
       */
    }, {
      key: "handleMarkerTooltip",
      value: function handleMarkerTooltip(_ref2) {
        var e = _ref2.e,
          opt = _ref2.opt,
          x = _ref2.x,
          y = _ref2.y;
        var w = this.w;
        var ttCtx = this.ttCtx;
        var i;
        var j;
        if (e.target.classList.contains('apexcharts-marker')) {
          var cx = parseInt(opt.paths.getAttribute('cx'), 10);
          var cy = parseInt(opt.paths.getAttribute('cy'), 10);
          var val = parseFloat(opt.paths.getAttribute('val'));
          j = parseInt(opt.paths.getAttribute('rel'), 10);
          i = parseInt(opt.paths.parentNode.parentNode.parentNode.getAttribute('rel'), 10) - 1;
          if (ttCtx.intersect) {
            var el = Utils$1.findAncestor(opt.paths, 'apexcharts-series');
            if (el) {
              i = parseInt(el.getAttribute('data:realIndex'), 10);
            }
          }
          ttCtx.tooltipLabels.drawSeriesTexts({
            ttItems: opt.ttItems,
            i: i,
            j: j,
            shared: ttCtx.showOnIntersect ? false : w.config.tooltip.shared,
            e: e
          });
          if (e.type === 'mouseup') {
            ttCtx.markerClick(e, i, j);
          }
          w.globals.capturedSeriesIndex = i;
          w.globals.capturedDataPointIndex = j;
          x = cx;
          y = cy + w.globals.translateY - ttCtx.tooltipRect.ttHeight * 1.4;
          if (ttCtx.w.config.tooltip.followCursor) {
            var elGrid = ttCtx.getElGrid();
            var seriesBound = elGrid.getBoundingClientRect();
            y = ttCtx.e.clientY + w.globals.translateY - seriesBound.top;
          }
          if (val < 0) {
            y = cy;
          }
          ttCtx.marker.enlargeCurrentPoint(j, opt.paths, x, y);
        }
        return {
          x: x,
          y: y
        };
      }

      /**
       * handle tooltips for bar/column charts
       */
    }, {
      key: "handleBarTooltip",
      value: function handleBarTooltip(_ref3) {
        var e = _ref3.e,
          opt = _ref3.opt;
        var w = this.w;
        var ttCtx = this.ttCtx;
        var tooltipEl = ttCtx.getElTooltip();
        var bx = 0;
        var x = 0;
        var y = 0;
        var i = 0;
        var strokeWidth;
        var barXY = this.getBarTooltipXY({
          e: e,
          opt: opt
        });
        i = barXY.i;
        var j = barXY.j;
        w.globals.capturedSeriesIndex = i;
        w.globals.capturedDataPointIndex = j;
        if (w.globals.isBarHorizontal && ttCtx.tooltipUtil.hasBars() || !w.config.tooltip.shared) {
          x = barXY.x;
          y = barXY.y;
          strokeWidth = Array.isArray(w.config.stroke.width) ? w.config.stroke.width[i] : w.config.stroke.width;
          bx = x;
        } else {
          if (!w.globals.comboCharts && !w.config.tooltip.shared) {
            // todo: re-check this condition as it's always 0
            bx = bx / 2;
          }
        }

        // y is NaN, make it touch the bottom of grid area
        if (isNaN(y)) {
          y = w.globals.svgHeight - ttCtx.tooltipRect.ttHeight;
        }
        var seriesIndex = parseInt(opt.paths.parentNode.getAttribute('data:realIndex'), 10);
        w.globals.isMultipleYAxis ? w.config.yaxis[seriesIndex] && w.config.yaxis[seriesIndex].reversed : w.config.yaxis[0].reversed;
        if (x + ttCtx.tooltipRect.ttWidth > w.globals.gridWidth) {
          x = x - ttCtx.tooltipRect.ttWidth;
        } else if (x < 0) {
          x = 0;
        }
        if (ttCtx.w.config.tooltip.followCursor) {
          var elGrid = ttCtx.getElGrid();
          var seriesBound = elGrid.getBoundingClientRect();
          y = ttCtx.e.clientY - seriesBound.top;
        }

        // if tooltip is still null, querySelector
        if (ttCtx.tooltip === null) {
          ttCtx.tooltip = w.globals.dom.baseEl.querySelector('.apexcharts-tooltip');
        }
        if (!w.config.tooltip.shared) {
          if (w.globals.comboBarCount > 0) {
            ttCtx.tooltipPosition.moveXCrosshairs(bx + strokeWidth / 2);
          } else {
            ttCtx.tooltipPosition.moveXCrosshairs(bx);
          }
        }

        // move tooltip here
        if (!ttCtx.fixedTooltip && (!w.config.tooltip.shared || w.globals.isBarHorizontal && ttCtx.tooltipUtil.hasBars())) {
          y = y + w.globals.translateY - ttCtx.tooltipRect.ttHeight / 2;
          tooltipEl.style.left = x + w.globals.translateX + 'px';
          tooltipEl.style.top = y + 'px';
        }
      }
    }, {
      key: "getBarTooltipXY",
      value: function getBarTooltipXY(_ref4) {
        var _this = this;
        var e = _ref4.e,
          opt = _ref4.opt;
        var w = this.w;
        var j = null;
        var ttCtx = this.ttCtx;
        var i = 0;
        var x = 0;
        var y = 0;
        var barWidth = 0;
        var barHeight = 0;
        var cl = e.target.classList;
        if (cl.contains('apexcharts-bar-area') || cl.contains('apexcharts-candlestick-area') || cl.contains('apexcharts-boxPlot-area') || cl.contains('apexcharts-rangebar-area')) {
          var bar = e.target;
          var barRect = bar.getBoundingClientRect();
          var seriesBound = opt.elGrid.getBoundingClientRect();
          var bh = barRect.height;
          barHeight = barRect.height;
          var bw = barRect.width;
          var cx = parseInt(bar.getAttribute('cx'), 10);
          var cy = parseInt(bar.getAttribute('cy'), 10);
          barWidth = parseFloat(bar.getAttribute('barWidth'));
          var clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
          j = parseInt(bar.getAttribute('j'), 10);
          i = parseInt(bar.parentNode.getAttribute('rel'), 10) - 1;
          var y1 = bar.getAttribute('data-range-y1');
          var y2 = bar.getAttribute('data-range-y2');
          if (w.globals.comboCharts) {
            i = parseInt(bar.parentNode.getAttribute('data:realIndex'), 10);
          }
          var handleXForColumns = function handleXForColumns(x) {
            if (w.globals.isXNumeric) {
              x = cx - bw / 2;
            } else {
              if (_this.isVerticalGroupedRangeBar) {
                x = cx + bw / 2;
              } else {
                x = cx - ttCtx.dataPointsDividedWidth + bw / 2;
              }
            }
            return x;
          };
          var handleYForBars = function handleYForBars() {
            return cy - ttCtx.dataPointsDividedHeight + bh / 2 - ttCtx.tooltipRect.ttHeight / 2;
          };
          ttCtx.tooltipLabels.drawSeriesTexts({
            ttItems: opt.ttItems,
            i: i,
            j: j,
            y1: y1 ? parseInt(y1, 10) : null,
            y2: y2 ? parseInt(y2, 10) : null,
            shared: ttCtx.showOnIntersect ? false : w.config.tooltip.shared,
            e: e
          });
          if (w.config.tooltip.followCursor) {
            if (w.globals.isBarHorizontal) {
              x = clientX - seriesBound.left + 15;
              y = handleYForBars();
            } else {
              x = handleXForColumns(x);
              y = e.clientY - seriesBound.top - ttCtx.tooltipRect.ttHeight / 2 - 15;
            }
          } else {
            if (w.globals.isBarHorizontal) {
              x = cx;
              if (x < ttCtx.xyRatios.baseLineInvertedY) {
                x = cx - ttCtx.tooltipRect.ttWidth;
              }
              y = handleYForBars();
            } else {
              x = handleXForColumns(x);
              y = cy; // - ttCtx.tooltipRect.ttHeight / 2 + 10
            }
          }
        }
        return {
          x: x,
          y: y,
          barHeight: barHeight,
          barWidth: barWidth,
          i: i,
          j: j
        };
      }
    }]);
    return Intersect;
  }();

  /**
   * ApexCharts Tooltip.AxesTooltip Class.
   * This file deals with the x-axis and y-axis tooltips.
   *
   * @module Tooltip.AxesTooltip
   **/
  var AxesTooltip = /*#__PURE__*/function () {
    function AxesTooltip(tooltipContext) {
      _classCallCheck(this, AxesTooltip);
      this.w = tooltipContext.w;
      this.ttCtx = tooltipContext;
    }

    /**
     * This method adds the secondary tooltip which appears below x axis
     * @memberof Tooltip
     **/
    _createClass(AxesTooltip, [{
      key: "drawXaxisTooltip",
      value: function drawXaxisTooltip() {
        var w = this.w;
        var ttCtx = this.ttCtx;
        var isBottom = w.config.xaxis.position === 'bottom';
        ttCtx.xaxisOffY = isBottom ? w.globals.gridHeight + 1 : -w.globals.xAxisHeight - w.config.xaxis.axisTicks.height + 3;
        var tooltipCssClass = isBottom ? 'apexcharts-xaxistooltip apexcharts-xaxistooltip-bottom' : 'apexcharts-xaxistooltip apexcharts-xaxistooltip-top';
        var renderTo = w.globals.dom.elWrap;
        if (ttCtx.isXAxisTooltipEnabled) {
          var xaxisTooltip = w.globals.dom.baseEl.querySelector('.apexcharts-xaxistooltip');
          if (xaxisTooltip === null) {
            ttCtx.xaxisTooltip = document.createElement('div');
            ttCtx.xaxisTooltip.setAttribute('class', tooltipCssClass + ' apexcharts-theme-' + w.config.tooltip.theme);
            renderTo.appendChild(ttCtx.xaxisTooltip);
            ttCtx.xaxisTooltipText = document.createElement('div');
            ttCtx.xaxisTooltipText.classList.add('apexcharts-xaxistooltip-text');
            ttCtx.xaxisTooltipText.style.fontFamily = w.config.xaxis.tooltip.style.fontFamily || w.config.chart.fontFamily;
            ttCtx.xaxisTooltipText.style.fontSize = w.config.xaxis.tooltip.style.fontSize;
            ttCtx.xaxisTooltip.appendChild(ttCtx.xaxisTooltipText);
          }
        }
      }

      /**
       * This method adds the secondary tooltip which appears below x axis
       * @memberof Tooltip
       **/
    }, {
      key: "drawYaxisTooltip",
      value: function drawYaxisTooltip() {
        var w = this.w;
        var ttCtx = this.ttCtx;
        for (var i = 0; i < w.config.yaxis.length; i++) {
          var isRight = w.config.yaxis[i].opposite || w.config.yaxis[i].crosshairs.opposite;
          ttCtx.yaxisOffX = isRight ? w.globals.gridWidth + 1 : 1;
          var tooltipCssClass = isRight ? "apexcharts-yaxistooltip apexcharts-yaxistooltip-".concat(i, " apexcharts-yaxistooltip-right") : "apexcharts-yaxistooltip apexcharts-yaxistooltip-".concat(i, " apexcharts-yaxistooltip-left");
          var renderTo = w.globals.dom.elWrap;
          var yaxisTooltip = w.globals.dom.baseEl.querySelector(".apexcharts-yaxistooltip apexcharts-yaxistooltip-".concat(i));
          if (yaxisTooltip === null) {
            ttCtx.yaxisTooltip = document.createElement('div');
            ttCtx.yaxisTooltip.setAttribute('class', tooltipCssClass + ' apexcharts-theme-' + w.config.tooltip.theme);
            renderTo.appendChild(ttCtx.yaxisTooltip);
            if (i === 0) ttCtx.yaxisTooltipText = [];
            ttCtx.yaxisTooltipText[i] = document.createElement('div');
            ttCtx.yaxisTooltipText[i].classList.add('apexcharts-yaxistooltip-text');
            ttCtx.yaxisTooltip.appendChild(ttCtx.yaxisTooltipText[i]);
          }
        }
      }

      /**
       * @memberof Tooltip
       **/
    }, {
      key: "setXCrosshairWidth",
      value: function setXCrosshairWidth() {
        var w = this.w;
        var ttCtx = this.ttCtx;

        // set xcrosshairs width
        var xcrosshairs = ttCtx.getElXCrosshairs();
        ttCtx.xcrosshairsWidth = parseInt(w.config.xaxis.crosshairs.width, 10);
        if (!w.globals.comboCharts) {
          if (w.config.xaxis.crosshairs.width === 'tickWidth') {
            var count = w.globals.labels.length;
            ttCtx.xcrosshairsWidth = w.globals.gridWidth / count;
          } else if (w.config.xaxis.crosshairs.width === 'barWidth') {
            var bar = w.globals.dom.baseEl.querySelector('.apexcharts-bar-area');
            if (bar !== null) {
              var barWidth = parseFloat(bar.getAttribute('barWidth'));
              ttCtx.xcrosshairsWidth = barWidth;
            } else {
              ttCtx.xcrosshairsWidth = 1;
            }
          }
        } else {
          var _bar = w.globals.dom.baseEl.querySelector('.apexcharts-bar-area');
          if (_bar !== null && w.config.xaxis.crosshairs.width === 'barWidth') {
            var _barWidth = parseFloat(_bar.getAttribute('barWidth'));
            ttCtx.xcrosshairsWidth = _barWidth;
          } else {
            if (w.config.xaxis.crosshairs.width === 'tickWidth') {
              var _count = w.globals.labels.length;
              ttCtx.xcrosshairsWidth = w.globals.gridWidth / _count;
            }
          }
        }
        if (w.globals.isBarHorizontal) {
          ttCtx.xcrosshairsWidth = 0;
        }
        if (xcrosshairs !== null && ttCtx.xcrosshairsWidth > 0) {
          xcrosshairs.setAttribute('width', ttCtx.xcrosshairsWidth);
        }
      }
    }, {
      key: "handleYCrosshair",
      value: function handleYCrosshair() {
        var w = this.w;
        var ttCtx = this.ttCtx;

        // set ycrosshairs height
        ttCtx.ycrosshairs = w.globals.dom.baseEl.querySelector('.apexcharts-ycrosshairs');
        ttCtx.ycrosshairsHidden = w.globals.dom.baseEl.querySelector('.apexcharts-ycrosshairs-hidden');
      }
    }, {
      key: "drawYaxisTooltipText",
      value: function drawYaxisTooltipText(index, clientY, xyRatios) {
        var ttCtx = this.ttCtx;
        var w = this.w;
        var gl = w.globals;
        var yAxisSeriesArr = gl.seriesYAxisMap[index];
        if (ttCtx.yaxisTooltips[index] && yAxisSeriesArr.length > 0) {
          var lbFormatter = gl.yLabelFormatters[index];
          var elGrid = ttCtx.getElGrid();
          var seriesBound = elGrid.getBoundingClientRect();

          // We can use the index of any series referenced by the Yaxis
          // because they will all return the same value.
          var seriesIndex = yAxisSeriesArr[0];
          var translationsIndex = 0;
          if (xyRatios.yRatio.length > 1) {
            translationsIndex = seriesIndex;
          }
          var hoverY = (clientY - seriesBound.top) * xyRatios.yRatio[translationsIndex];
          var height = gl.maxYArr[seriesIndex] - gl.minYArr[seriesIndex];
          var val = gl.minYArr[seriesIndex] + (height - hoverY);
          if (w.config.yaxis[index].reversed) {
            val = gl.maxYArr[seriesIndex] - (height - hoverY);
          }
          ttCtx.tooltipPosition.moveYCrosshairs(clientY - seriesBound.top);
          ttCtx.yaxisTooltipText[index].innerHTML = lbFormatter(val);
          ttCtx.tooltipPosition.moveYAxisTooltip(index);
        }
      }
    }]);
    return AxesTooltip;
  }();

  /**
   * ApexCharts Core Tooltip Class to handle the tooltip generation.
   *
   * @module Tooltip
   **/
  var Tooltip = /*#__PURE__*/function () {
    function Tooltip(ctx) {
      _classCallCheck(this, Tooltip);
      this.ctx = ctx;
      this.w = ctx.w;
      var w = this.w;
      this.tConfig = w.config.tooltip;
      this.tooltipUtil = new Utils(this);
      this.tooltipLabels = new Labels(this);
      this.tooltipPosition = new Position(this);
      this.marker = new Marker(this);
      this.intersect = new Intersect(this);
      this.axesTooltip = new AxesTooltip(this);
      this.showOnIntersect = this.tConfig.intersect;
      this.showTooltipTitle = this.tConfig.x.show;
      this.fixedTooltip = this.tConfig.fixed.enabled;
      this.xaxisTooltip = null;
      this.yaxisTTEls = null;
      this.isBarShared = !w.globals.isBarHorizontal && this.tConfig.shared;
      this.lastHoverTime = Date.now();
    }
    _createClass(Tooltip, [{
      key: "getElTooltip",
      value: function getElTooltip(ctx) {
        if (!ctx) ctx = this;
        if (!ctx.w.globals.dom.baseEl) return null;
        return ctx.w.globals.dom.baseEl.querySelector('.apexcharts-tooltip');
      }
    }, {
      key: "getElXCrosshairs",
      value: function getElXCrosshairs() {
        return this.w.globals.dom.baseEl.querySelector('.apexcharts-xcrosshairs');
      }
    }, {
      key: "getElGrid",
      value: function getElGrid() {
        return this.w.globals.dom.baseEl.querySelector('.apexcharts-grid');
      }
    }, {
      key: "drawTooltip",
      value: function drawTooltip(xyRatios) {
        var w = this.w;
        this.xyRatios = xyRatios;
        this.isXAxisTooltipEnabled = w.config.xaxis.tooltip.enabled && w.globals.axisCharts;
        this.yaxisTooltips = w.config.yaxis.map(function (y, i) {
          return y.show && y.tooltip.enabled && w.globals.axisCharts ? true : false;
        });
        this.allTooltipSeriesGroups = [];
        if (!w.globals.axisCharts) {
          this.showTooltipTitle = false;
        }
        var tooltipEl = document.createElement('div');
        tooltipEl.classList.add('apexcharts-tooltip');
        if (w.config.tooltip.cssClass) {
          tooltipEl.classList.add(w.config.tooltip.cssClass);
        }
        tooltipEl.classList.add("apexcharts-theme-".concat(this.tConfig.theme));
        w.globals.dom.elWrap.appendChild(tooltipEl);
        if (w.globals.axisCharts) {
          this.axesTooltip.drawXaxisTooltip();
          this.axesTooltip.drawYaxisTooltip();
          this.axesTooltip.setXCrosshairWidth();
          this.axesTooltip.handleYCrosshair();
          var xAxis = new XAxis(this.ctx);
          this.xAxisTicksPositions = xAxis.getXAxisTicksPositions();
        }

        // we forcefully set intersect true for these conditions
        if ((w.globals.comboCharts || this.tConfig.intersect || w.config.chart.type === 'rangeBar') && !this.tConfig.shared) {
          this.showOnIntersect = true;
        }
        if (w.config.markers.size === 0 || w.globals.markers.largestSize === 0) {
          // when user don't want to show points all the time, but only on when hovering on series
          this.marker.drawDynamicPoints(this);
        }

        // no visible series, exit
        if (w.globals.collapsedSeries.length === w.globals.series.length) return;
        this.dataPointsDividedHeight = w.globals.gridHeight / w.globals.dataPoints;
        this.dataPointsDividedWidth = w.globals.gridWidth / w.globals.dataPoints;
        if (this.showTooltipTitle) {
          this.tooltipTitle = document.createElement('div');
          this.tooltipTitle.classList.add('apexcharts-tooltip-title');
          this.tooltipTitle.style.fontFamily = this.tConfig.style.fontFamily || w.config.chart.fontFamily;
          this.tooltipTitle.style.fontSize = this.tConfig.style.fontSize;
          tooltipEl.appendChild(this.tooltipTitle);
        }
        var ttItemsCnt = w.globals.series.length; // whether shared or not, default is shared
        if ((w.globals.xyCharts || w.globals.comboCharts) && this.tConfig.shared) {
          if (!this.showOnIntersect) {
            ttItemsCnt = w.globals.series.length;
          } else {
            ttItemsCnt = 1;
          }
        }
        this.legendLabels = w.globals.dom.baseEl.querySelectorAll('.apexcharts-legend-text');
        this.ttItems = this.createTTElements(ttItemsCnt);
        this.addSVGEvents();
      }
    }, {
      key: "createTTElements",
      value: function createTTElements(ttItemsCnt) {
        var _this = this;
        var w = this.w;
        var ttItems = [];
        var tooltipEl = this.getElTooltip();
        var _loop = function _loop(i) {
          var gTxt = document.createElement('div');
          gTxt.classList.add('apexcharts-tooltip-series-group', "apexcharts-tooltip-series-group-".concat(i));
          gTxt.style.order = w.config.tooltip.inverseOrder ? ttItemsCnt - i : i + 1;
          var point = document.createElement('span');
          point.classList.add('apexcharts-tooltip-marker');
          point.style.backgroundColor = w.globals.colors[i];
          gTxt.appendChild(point);
          var gYZ = document.createElement('div');
          gYZ.classList.add('apexcharts-tooltip-text');
          gYZ.style.fontFamily = _this.tConfig.style.fontFamily || w.config.chart.fontFamily;
          gYZ.style.fontSize = _this.tConfig.style.fontSize;
          ['y', 'goals', 'z'].forEach(function (g) {
            var gValText = document.createElement('div');
            gValText.classList.add("apexcharts-tooltip-".concat(g, "-group"));
            var txtLabel = document.createElement('span');
            txtLabel.classList.add("apexcharts-tooltip-text-".concat(g, "-label"));
            gValText.appendChild(txtLabel);
            var txtValue = document.createElement('span');
            txtValue.classList.add("apexcharts-tooltip-text-".concat(g, "-value"));
            gValText.appendChild(txtValue);
            gYZ.appendChild(gValText);
          });
          gTxt.appendChild(gYZ);
          tooltipEl.appendChild(gTxt);
          ttItems.push(gTxt);
        };
        for (var i = 0; i < ttItemsCnt; i++) {
          _loop(i);
        }
        return ttItems;
      }
    }, {
      key: "addSVGEvents",
      value: function addSVGEvents() {
        var w = this.w;
        var type = w.config.chart.type;
        var tooltipEl = this.getElTooltip();
        var commonBar = !!(type === 'bar' || type === 'candlestick' || type === 'boxPlot' || type === 'rangeBar');
        var chartWithmarkers = type === 'area' || type === 'line' || type === 'scatter' || type === 'bubble' || type === 'radar';
        var hoverArea = w.globals.dom.Paper.node;
        var elGrid = this.getElGrid();
        if (elGrid) {
          this.seriesBound = elGrid.getBoundingClientRect();
        }
        var tooltipY = [];
        var tooltipX = [];
        var seriesHoverParams = {
          hoverArea: hoverArea,
          elGrid: elGrid,
          tooltipEl: tooltipEl,
          tooltipY: tooltipY,
          tooltipX: tooltipX,
          ttItems: this.ttItems
        };
        var points;
        if (w.globals.axisCharts) {
          if (chartWithmarkers) {
            points = w.globals.dom.baseEl.querySelectorAll(".apexcharts-series[data\\:longestSeries='true'] .apexcharts-marker");
          } else if (commonBar) {
            points = w.globals.dom.baseEl.querySelectorAll('.apexcharts-series .apexcharts-bar-area, .apexcharts-series .apexcharts-candlestick-area, .apexcharts-series .apexcharts-boxPlot-area, .apexcharts-series .apexcharts-rangebar-area');
          } else if (type === 'heatmap' || type === 'treemap') {
            points = w.globals.dom.baseEl.querySelectorAll('.apexcharts-series .apexcharts-heatmap, .apexcharts-series .apexcharts-treemap');
          }
          if (points && points.length) {
            for (var p = 0; p < points.length; p++) {
              tooltipY.push(points[p].getAttribute('cy'));
              tooltipX.push(points[p].getAttribute('cx'));
            }
          }
        }
        var validSharedChartTypes = w.globals.xyCharts && !this.showOnIntersect || w.globals.comboCharts && !this.showOnIntersect || commonBar && this.tooltipUtil.hasBars() && this.tConfig.shared;
        if (validSharedChartTypes) {
          this.addPathsEventListeners([hoverArea], seriesHoverParams);
        } else if (commonBar && !w.globals.comboCharts || chartWithmarkers && this.showOnIntersect) {
          this.addDatapointEventsListeners(seriesHoverParams);
        } else if (!w.globals.axisCharts || type === 'heatmap' || type === 'treemap') {
          var seriesAll = w.globals.dom.baseEl.querySelectorAll('.apexcharts-series');
          this.addPathsEventListeners(seriesAll, seriesHoverParams);
        }
        if (this.showOnIntersect) {
          var lineAreaPoints = w.globals.dom.baseEl.querySelectorAll('.apexcharts-line-series .apexcharts-marker, .apexcharts-area-series .apexcharts-marker');
          if (lineAreaPoints.length > 0) {
            // if we find any lineSeries, addEventListeners for them
            this.addPathsEventListeners(lineAreaPoints, seriesHoverParams);
          }

          // combo charts may have bars, so add event listeners here too
          if (this.tooltipUtil.hasBars() && !this.tConfig.shared) {
            this.addDatapointEventsListeners(seriesHoverParams);
          }
        }
      }
    }, {
      key: "drawFixedTooltipRect",
      value: function drawFixedTooltipRect() {
        var w = this.w;
        var tooltipEl = this.getElTooltip();
        var tooltipRect = tooltipEl.getBoundingClientRect();
        var ttWidth = tooltipRect.width + 10;
        var ttHeight = tooltipRect.height + 10;
        var x = this.tConfig.fixed.offsetX;
        var y = this.tConfig.fixed.offsetY;
        var fixed = this.tConfig.fixed.position.toLowerCase();
        if (fixed.indexOf('right') > -1) {
          x = x + w.globals.svgWidth - ttWidth + 10;
        }
        if (fixed.indexOf('bottom') > -1) {
          y = y + w.globals.svgHeight - ttHeight - 10;
        }
        tooltipEl.style.left = x + 'px';
        tooltipEl.style.top = y + 'px';
        return {
          x: x,
          y: y,
          ttWidth: ttWidth,
          ttHeight: ttHeight
        };
      }
    }, {
      key: "addDatapointEventsListeners",
      value: function addDatapointEventsListeners(seriesHoverParams) {
        var w = this.w;
        var points = w.globals.dom.baseEl.querySelectorAll('.apexcharts-series-markers .apexcharts-marker, .apexcharts-bar-area, .apexcharts-candlestick-area, .apexcharts-boxPlot-area, .apexcharts-rangebar-area');
        this.addPathsEventListeners(points, seriesHoverParams);
      }
    }, {
      key: "addPathsEventListeners",
      value: function addPathsEventListeners(paths, opts) {
        var self = this;
        var _loop2 = function _loop2(p) {
          var extendedOpts = {
            paths: paths[p],
            tooltipEl: opts.tooltipEl,
            tooltipY: opts.tooltipY,
            tooltipX: opts.tooltipX,
            elGrid: opts.elGrid,
            hoverArea: opts.hoverArea,
            ttItems: opts.ttItems
          };
          var events = ['mousemove', 'mouseup', 'touchmove', 'mouseout', 'touchend'];
          events.map(function (ev) {
            return paths[p].addEventListener(ev, self.onSeriesHover.bind(self, extendedOpts), {
              capture: false,
              passive: true
            });
          });
        };
        for (var p = 0; p < paths.length; p++) {
          _loop2(p);
        }
      }

      /*
       ** Check to see if the tooltips should be updated based on a mouse / touch event
       */
    }, {
      key: "onSeriesHover",
      value: function onSeriesHover(opt, e) {
        var _this2 = this;
        // If a user is moving their mouse quickly, don't bother updating the tooltip every single frame

        var targetDelay = 100;
        var timeSinceLastUpdate = Date.now() - this.lastHoverTime;
        if (timeSinceLastUpdate >= targetDelay) {
          // The tooltip was last updated over 100ms ago - redraw it even if the user is still moving their
          // mouse so they get some feedback that their moves are being registered
          this.seriesHover(opt, e);
        } else {
          // The tooltip was last updated less than 100ms ago
          // Cancel any other delayed draw, so we don't show stale data
          clearTimeout(this.seriesHoverTimeout);

          // Schedule the next draw so that it happens about 100ms after the last update
          this.seriesHoverTimeout = setTimeout(function () {
            _this2.seriesHover(opt, e);
          }, targetDelay - timeSinceLastUpdate);
        }
      }

      /*
       ** The actual series hover function
       */
    }, {
      key: "seriesHover",
      value: function seriesHover(opt, e) {
        var _this3 = this;
        this.lastHoverTime = Date.now();
        var chartGroups = [];
        var w = this.w;

        // if user has more than one charts in group, we need to sync
        if (w.config.chart.group) {
          chartGroups = this.ctx.getGroupedCharts();
        }
        if (w.globals.axisCharts && (w.globals.minX === -Infinity && w.globals.maxX === Infinity || w.globals.dataPoints === 0)) {
          return;
        }
        if (chartGroups.length) {
          chartGroups.forEach(function (ch) {
            var tooltipEl = _this3.getElTooltip(ch);
            var newOpts = {
              paths: opt.paths,
              tooltipEl: tooltipEl,
              tooltipY: opt.tooltipY,
              tooltipX: opt.tooltipX,
              elGrid: opt.elGrid,
              hoverArea: opt.hoverArea,
              ttItems: ch.w.globals.tooltip.ttItems
            };

            // all the charts should have the same minX and maxX (same xaxis) for multiple tooltips to work correctly
            if (ch.w.globals.minX === _this3.w.globals.minX && ch.w.globals.maxX === _this3.w.globals.maxX) {
              ch.w.globals.tooltip.seriesHoverByContext({
                chartCtx: ch,
                ttCtx: ch.w.globals.tooltip,
                opt: newOpts,
                e: e
              });
            }
          });
        } else {
          this.seriesHoverByContext({
            chartCtx: this.ctx,
            ttCtx: this.w.globals.tooltip,
            opt: opt,
            e: e
          });
        }
      }
    }, {
      key: "seriesHoverByContext",
      value: function seriesHoverByContext(_ref) {
        var chartCtx = _ref.chartCtx,
          ttCtx = _ref.ttCtx,
          opt = _ref.opt,
          e = _ref.e;
        var w = chartCtx.w;
        var tooltipEl = this.getElTooltip(chartCtx);
        if (!tooltipEl) return;

        // tooltipRect is calculated on every mousemove, because the text is dynamic
        ttCtx.tooltipRect = {
          x: 0,
          y: 0,
          ttWidth: tooltipEl.getBoundingClientRect().width,
          ttHeight: tooltipEl.getBoundingClientRect().height
        };
        ttCtx.e = e;

        // highlight the current hovered bars
        if (ttCtx.tooltipUtil.hasBars() && !w.globals.comboCharts && !ttCtx.isBarShared) {
          if (this.tConfig.onDatasetHover.highlightDataSeries) {
            var series = new Series(chartCtx);
            series.toggleSeriesOnHover(e, e.target.parentNode);
          }
        }
        if (ttCtx.fixedTooltip) {
          ttCtx.drawFixedTooltipRect();
        }
        if (w.globals.axisCharts) {
          ttCtx.axisChartsTooltips({
            e: e,
            opt: opt,
            tooltipRect: ttCtx.tooltipRect
          });
        } else {
          // non-plot charts i.e pie/donut/circle
          ttCtx.nonAxisChartsTooltips({
            e: e,
            opt: opt,
            tooltipRect: ttCtx.tooltipRect
          });
        }
      }

      // tooltip handling for line/area/bar/columns/scatter
    }, {
      key: "axisChartsTooltips",
      value: function axisChartsTooltips(_ref2) {
        var e = _ref2.e,
          opt = _ref2.opt;
        var w = this.w;
        var x, y;
        var seriesBound = opt.elGrid.getBoundingClientRect();
        var clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
        var clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
        this.clientY = clientY;
        this.clientX = clientX;
        w.globals.capturedSeriesIndex = -1;
        w.globals.capturedDataPointIndex = -1;
        if (clientY < seriesBound.top || clientY > seriesBound.top + seriesBound.height) {
          this.handleMouseOut(opt);
          return;
        }
        if (Array.isArray(this.tConfig.enabledOnSeries) && !w.config.tooltip.shared) {
          var index = parseInt(opt.paths.getAttribute('index'), 10);
          if (this.tConfig.enabledOnSeries.indexOf(index) < 0) {
            this.handleMouseOut(opt);
            return;
          }
        }
        var tooltipEl = this.getElTooltip();
        var xcrosshairs = this.getElXCrosshairs();
        var syncedCharts = [];
        if (w.config.chart.group) {
          // we need to fallback to sticky tooltip in case charts are synced
          syncedCharts = this.ctx.getSyncedCharts();
        }
        var isStickyTooltip = w.globals.xyCharts || w.config.chart.type === 'bar' && !w.globals.isBarHorizontal && this.tooltipUtil.hasBars() && this.tConfig.shared || w.globals.comboCharts && this.tooltipUtil.hasBars();
        if (e.type === 'mousemove' || e.type === 'touchmove' || e.type === 'mouseup') {
          // there is no series to hover over
          if (w.globals.collapsedSeries.length + w.globals.ancillaryCollapsedSeries.length === w.globals.series.length) {
            return;
          }
          if (xcrosshairs !== null) {
            xcrosshairs.classList.add('apexcharts-active');
          }
          var hasYAxisTooltip = this.yaxisTooltips.filter(function (b) {
            return b === true;
          });
          if (this.ycrosshairs !== null && hasYAxisTooltip.length) {
            this.ycrosshairs.classList.add('apexcharts-active');
          }
          if (isStickyTooltip && !this.showOnIntersect || syncedCharts.length > 1) {
            this.handleStickyTooltip(e, clientX, clientY, opt);
          } else {
            if (w.config.chart.type === 'heatmap' || w.config.chart.type === 'treemap') {
              var markerXY = this.intersect.handleHeatTreeTooltip({
                e: e,
                opt: opt,
                x: x,
                y: y,
                type: w.config.chart.type
              });
              x = markerXY.x;
              y = markerXY.y;
              tooltipEl.style.left = x + 'px';
              tooltipEl.style.top = y + 'px';
            } else {
              if (this.tooltipUtil.hasBars()) {
                this.intersect.handleBarTooltip({
                  e: e,
                  opt: opt
                });
              }
              if (this.tooltipUtil.hasMarkers()) {
                // intersect - line/area/scatter/bubble
                this.intersect.handleMarkerTooltip({
                  e: e,
                  opt: opt,
                  x: x,
                  y: y
                });
              }
            }
          }
          if (this.yaxisTooltips.length) {
            for (var yt = 0; yt < w.config.yaxis.length; yt++) {
              this.axesTooltip.drawYaxisTooltipText(yt, clientY, this.xyRatios);
            }
          }
          w.globals.dom.baseEl.classList.add('apexcharts-tooltip-active');
          opt.tooltipEl.classList.add('apexcharts-active');
        } else if (e.type === 'mouseout' || e.type === 'touchend') {
          this.handleMouseOut(opt);
        }
      }

      // tooltip handling for pie/donuts
    }, {
      key: "nonAxisChartsTooltips",
      value: function nonAxisChartsTooltips(_ref3) {
        var e = _ref3.e,
          opt = _ref3.opt,
          tooltipRect = _ref3.tooltipRect;
        var w = this.w;
        var rel = opt.paths.getAttribute('rel');
        var tooltipEl = this.getElTooltip();
        var seriesBound = w.globals.dom.elWrap.getBoundingClientRect();
        if (e.type === 'mousemove' || e.type === 'touchmove') {
          w.globals.dom.baseEl.classList.add('apexcharts-tooltip-active');
          tooltipEl.classList.add('apexcharts-active');
          this.tooltipLabels.drawSeriesTexts({
            ttItems: opt.ttItems,
            i: parseInt(rel, 10) - 1,
            shared: false
          });
          var x = w.globals.clientX - seriesBound.left - tooltipRect.ttWidth / 2;
          var y = w.globals.clientY - seriesBound.top - tooltipRect.ttHeight - 10;
          tooltipEl.style.left = x + 'px';
          tooltipEl.style.top = y + 'px';
          if (w.config.legend.tooltipHoverFormatter) {
            var legendFormatter = w.config.legend.tooltipHoverFormatter;
            var i = rel - 1;
            var legendName = this.legendLabels[i].getAttribute('data:default-text');
            var text = legendFormatter(legendName, {
              seriesIndex: i,
              dataPointIndex: i,
              w: w
            });
            this.legendLabels[i].innerHTML = text;
          }
        } else if (e.type === 'mouseout' || e.type === 'touchend') {
          tooltipEl.classList.remove('apexcharts-active');
          w.globals.dom.baseEl.classList.remove('apexcharts-tooltip-active');
          if (w.config.legend.tooltipHoverFormatter) {
            this.legendLabels.forEach(function (l) {
              var defaultText = l.getAttribute('data:default-text');
              l.innerHTML = decodeURIComponent(defaultText);
            });
          }
        }
      }
    }, {
      key: "handleStickyTooltip",
      value: function handleStickyTooltip(e, clientX, clientY, opt) {
        var w = this.w;
        var capj = this.tooltipUtil.getNearestValues({
          context: this,
          hoverArea: opt.hoverArea,
          elGrid: opt.elGrid,
          clientX: clientX,
          clientY: clientY
        });
        var j = capj.j;
        var capturedSeries = capj.capturedSeries;
        if (w.globals.collapsedSeriesIndices.includes(capturedSeries)) capturedSeries = null;
        var bounds = opt.elGrid.getBoundingClientRect();
        if (capj.hoverX < 0 || capj.hoverX > bounds.width) {
          this.handleMouseOut(opt);
          return;
        }
        if (capturedSeries !== null) {
          this.handleStickyCapturedSeries(e, capturedSeries, opt, j);
        } else {
          // couldn't capture any series. check if shared X is same,
          // if yes, draw a grouped tooltip
          if (this.tooltipUtil.isXoverlap(j) || w.globals.isBarHorizontal) {
            var firstVisibleSeries = w.globals.series.findIndex(function (s, i) {
              return !w.globals.collapsedSeriesIndices.includes(i);
            });
            this.create(e, this, firstVisibleSeries, j, opt.ttItems);
          }
        }
      }
    }, {
      key: "handleStickyCapturedSeries",
      value: function handleStickyCapturedSeries(e, capturedSeries, opt, j) {
        var w = this.w;
        if (!this.tConfig.shared) {
          var ignoreNull = w.globals.series[capturedSeries][j] === null;
          if (ignoreNull) {
            this.handleMouseOut(opt);
            return;
          }
        }
        if (typeof w.globals.series[capturedSeries][j] !== 'undefined') {
          if (this.tConfig.shared && this.tooltipUtil.isXoverlap(j) && this.tooltipUtil.isInitialSeriesSameLen()) {
            this.create(e, this, capturedSeries, j, opt.ttItems);
          } else {
            this.create(e, this, capturedSeries, j, opt.ttItems, false);
          }
        } else {
          if (this.tooltipUtil.isXoverlap(j)) {
            var firstVisibleSeries = w.globals.series.findIndex(function (s, i) {
              return !w.globals.collapsedSeriesIndices.includes(i);
            });
            this.create(e, this, firstVisibleSeries, j, opt.ttItems);
          }
        }
      }
    }, {
      key: "deactivateHoverFilter",
      value: function deactivateHoverFilter() {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var allPaths = w.globals.dom.Paper.select(".apexcharts-bar-area");
        for (var b = 0; b < allPaths.length; b++) {
          graphics.pathMouseLeave(allPaths[b]);
        }
      }
    }, {
      key: "handleMouseOut",
      value: function handleMouseOut(opt) {
        var w = this.w;
        var xcrosshairs = this.getElXCrosshairs();
        w.globals.dom.baseEl.classList.remove('apexcharts-tooltip-active');
        opt.tooltipEl.classList.remove('apexcharts-active');
        this.deactivateHoverFilter();
        if (w.config.chart.type !== 'bubble') {
          this.marker.resetPointsSize();
        }
        if (xcrosshairs !== null) {
          xcrosshairs.classList.remove('apexcharts-active');
        }
        if (this.ycrosshairs !== null) {
          this.ycrosshairs.classList.remove('apexcharts-active');
        }
        if (this.isXAxisTooltipEnabled) {
          this.xaxisTooltip.classList.remove('apexcharts-active');
        }
        if (this.yaxisTooltips.length) {
          if (this.yaxisTTEls === null) {
            this.yaxisTTEls = w.globals.dom.baseEl.querySelectorAll('.apexcharts-yaxistooltip');
          }
          for (var i = 0; i < this.yaxisTTEls.length; i++) {
            this.yaxisTTEls[i].classList.remove('apexcharts-active');
          }
        }
        if (w.config.legend.tooltipHoverFormatter) {
          this.legendLabels.forEach(function (l) {
            var defaultText = l.getAttribute('data:default-text');
            l.innerHTML = decodeURIComponent(defaultText);
          });
        }
      }
    }, {
      key: "markerClick",
      value: function markerClick(e, seriesIndex, dataPointIndex) {
        var w = this.w;
        if (typeof w.config.chart.events.markerClick === 'function') {
          w.config.chart.events.markerClick(e, this.ctx, {
            seriesIndex: seriesIndex,
            dataPointIndex: dataPointIndex,
            w: w
          });
        }
        this.ctx.events.fireEvent('markerClick', [e, this.ctx, {
          seriesIndex: seriesIndex,
          dataPointIndex: dataPointIndex,
          w: w
        }]);
      }
    }, {
      key: "create",
      value: function create(e, context, capturedSeries, j, ttItems) {
        var _w$globals$seriesRang, _w$globals$seriesRang2, _w$globals$seriesRang3, _w$globals$seriesRang4, _w$globals$seriesRang5, _w$globals$seriesRang6, _w$globals$seriesRang7, _w$globals$seriesRang8, _w$globals$seriesRang9, _w$globals$seriesRang10, _w$globals$seriesRang11, _w$globals$seriesRang12, _w$globals$seriesRang13, _w$globals$seriesRang14, _w$globals$seriesRang15, _w$globals$seriesRang16;
        var shared = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
        var w = this.w;
        var ttCtx = context;
        if (e.type === 'mouseup') {
          this.markerClick(e, capturedSeries, j);
        }
        if (shared === null) shared = this.tConfig.shared;
        var hasMarkers = this.tooltipUtil.hasMarkers(capturedSeries);
        var bars = this.tooltipUtil.getElBars();
        if (w.config.legend.tooltipHoverFormatter) {
          var legendFormatter = w.config.legend.tooltipHoverFormatter;
          var els = Array.from(this.legendLabels);

          // reset all legend values first
          els.forEach(function (l) {
            var legendName = l.getAttribute('data:default-text');
            l.innerHTML = decodeURIComponent(legendName);
          });

          // for irregular time series
          for (var i = 0; i < els.length; i++) {
            var l = els[i];
            var lsIndex = parseInt(l.getAttribute('i'), 10);
            var legendName = decodeURIComponent(l.getAttribute('data:default-text'));
            var text = legendFormatter(legendName, {
              seriesIndex: shared ? lsIndex : capturedSeries,
              dataPointIndex: j,
              w: w
            });
            if (!shared) {
              l.innerHTML = lsIndex === capturedSeries ? text : legendName;
              if (capturedSeries === lsIndex) {
                break;
              }
            } else {
              l.innerHTML = w.globals.collapsedSeriesIndices.indexOf(lsIndex) < 0 ? text : legendName;
            }
          }
        }
        var commonSeriesTextsParams = _objectSpread2(_objectSpread2({
          ttItems: ttItems,
          i: capturedSeries,
          j: j
        }, typeof ((_w$globals$seriesRang = w.globals.seriesRange) === null || _w$globals$seriesRang === void 0 ? void 0 : (_w$globals$seriesRang2 = _w$globals$seriesRang[capturedSeries]) === null || _w$globals$seriesRang2 === void 0 ? void 0 : (_w$globals$seriesRang3 = _w$globals$seriesRang2[j]) === null || _w$globals$seriesRang3 === void 0 ? void 0 : (_w$globals$seriesRang4 = _w$globals$seriesRang3.y[0]) === null || _w$globals$seriesRang4 === void 0 ? void 0 : _w$globals$seriesRang4.y1) !== 'undefined' && {
          y1: (_w$globals$seriesRang5 = w.globals.seriesRange) === null || _w$globals$seriesRang5 === void 0 ? void 0 : (_w$globals$seriesRang6 = _w$globals$seriesRang5[capturedSeries]) === null || _w$globals$seriesRang6 === void 0 ? void 0 : (_w$globals$seriesRang7 = _w$globals$seriesRang6[j]) === null || _w$globals$seriesRang7 === void 0 ? void 0 : (_w$globals$seriesRang8 = _w$globals$seriesRang7.y[0]) === null || _w$globals$seriesRang8 === void 0 ? void 0 : _w$globals$seriesRang8.y1
        }), typeof ((_w$globals$seriesRang9 = w.globals.seriesRange) === null || _w$globals$seriesRang9 === void 0 ? void 0 : (_w$globals$seriesRang10 = _w$globals$seriesRang9[capturedSeries]) === null || _w$globals$seriesRang10 === void 0 ? void 0 : (_w$globals$seriesRang11 = _w$globals$seriesRang10[j]) === null || _w$globals$seriesRang11 === void 0 ? void 0 : (_w$globals$seriesRang12 = _w$globals$seriesRang11.y[0]) === null || _w$globals$seriesRang12 === void 0 ? void 0 : _w$globals$seriesRang12.y2) !== 'undefined' && {
          y2: (_w$globals$seriesRang13 = w.globals.seriesRange) === null || _w$globals$seriesRang13 === void 0 ? void 0 : (_w$globals$seriesRang14 = _w$globals$seriesRang13[capturedSeries]) === null || _w$globals$seriesRang14 === void 0 ? void 0 : (_w$globals$seriesRang15 = _w$globals$seriesRang14[j]) === null || _w$globals$seriesRang15 === void 0 ? void 0 : (_w$globals$seriesRang16 = _w$globals$seriesRang15.y[0]) === null || _w$globals$seriesRang16 === void 0 ? void 0 : _w$globals$seriesRang16.y2
        });
        if (shared) {
          ttCtx.tooltipLabels.drawSeriesTexts(_objectSpread2(_objectSpread2({}, commonSeriesTextsParams), {}, {
            shared: this.showOnIntersect ? false : this.tConfig.shared
          }));
          if (hasMarkers) {
            if (w.globals.markers.largestSize > 0) {
              ttCtx.marker.enlargePoints(j);
            } else {
              ttCtx.tooltipPosition.moveDynamicPointsOnHover(j);
            }
          } else if (this.tooltipUtil.hasBars()) {
            this.barSeriesHeight = this.tooltipUtil.getBarsHeight(bars);
            if (this.barSeriesHeight > 0) {
              // hover state, activate snap filter
              var graphics = new Graphics(this.ctx);
              var paths = w.globals.dom.Paper.select(".apexcharts-bar-area[j='".concat(j, "']"));

              // de-activate first
              this.deactivateHoverFilter();
              this.tooltipPosition.moveStickyTooltipOverBars(j, capturedSeries);
              for (var b = 0; b < paths.length; b++) {
                graphics.pathMouseEnter(paths[b]);
              }
            }
          }
        } else {
          ttCtx.tooltipLabels.drawSeriesTexts(_objectSpread2({
            shared: false
          }, commonSeriesTextsParams));
          if (this.tooltipUtil.hasBars()) {
            ttCtx.tooltipPosition.moveStickyTooltipOverBars(j, capturedSeries);
          }
          if (hasMarkers) {
            ttCtx.tooltipPosition.moveMarkers(capturedSeries, j);
          }
        }
      }
    }]);
    return Tooltip;
  }();

  var BarDataLabels = /*#__PURE__*/function () {
    function BarDataLabels(barCtx) {
      _classCallCheck(this, BarDataLabels);
      this.w = barCtx.w;
      this.barCtx = barCtx;
      this.totalFormatter = this.w.config.plotOptions.bar.dataLabels.total.formatter;
      if (!this.totalFormatter) {
        this.totalFormatter = this.w.config.dataLabels.formatter;
      }
    }
    /** handleBarDataLabels is used to calculate the positions for the data-labels
     * It also sets the element's data attr for bars and calls drawCalculatedBarDataLabels()
     * After calculating, it also calls the function to draw data labels
     * @memberof Bar
     * @param {object} {barProps} most of the bar properties used throughout the bar
     * drawing function
     * @return {object} dataLabels node-element which you can append later
     **/
    _createClass(BarDataLabels, [{
      key: "handleBarDataLabels",
      value: function handleBarDataLabels(opts) {
        var x = opts.x,
          y = opts.y,
          y1 = opts.y1,
          y2 = opts.y2,
          i = opts.i,
          j = opts.j,
          realIndex = opts.realIndex,
          columnGroupIndex = opts.columnGroupIndex,
          series = opts.series,
          barHeight = opts.barHeight,
          barWidth = opts.barWidth,
          barXPosition = opts.barXPosition,
          barYPosition = opts.barYPosition,
          visibleSeries = opts.visibleSeries,
          renderedPath = opts.renderedPath;
        var w = this.w;
        var graphics = new Graphics(this.barCtx.ctx);
        var strokeWidth = Array.isArray(this.barCtx.strokeWidth) ? this.barCtx.strokeWidth[realIndex] : this.barCtx.strokeWidth;
        var bcx;
        var bcy;
        if (w.globals.isXNumeric && !w.globals.isBarHorizontal) {
          bcx = x + parseFloat(barWidth * (visibleSeries + 1));
          bcy = y + parseFloat(barHeight * (visibleSeries + 1)) - strokeWidth;
        } else {
          bcx = x + parseFloat(barWidth * visibleSeries);
          bcy = y + parseFloat(barHeight * visibleSeries);
        }
        var dataLabels = null;
        var totalDataLabels = null;
        var dataLabelsX = x;
        var dataLabelsY = y;
        var dataLabelsPos = {};
        var dataLabelsConfig = w.config.dataLabels;
        var barDataLabelsConfig = this.barCtx.barOptions.dataLabels;
        var barTotalDataLabelsConfig = this.barCtx.barOptions.dataLabels.total;
        if (typeof barYPosition !== 'undefined' && this.barCtx.isRangeBar) {
          bcy = barYPosition;
          dataLabelsY = barYPosition;
        }
        if (typeof barXPosition !== 'undefined' && this.barCtx.isVerticalGroupedRangeBar) {
          bcx = barXPosition;
          dataLabelsX = barXPosition;
        }
        var offX = dataLabelsConfig.offsetX;
        var offY = dataLabelsConfig.offsetY;
        var textRects = {
          width: 0,
          height: 0
        };
        if (w.config.dataLabels.enabled) {
          var yLabel = w.globals.series[i][j];
          textRects = graphics.getTextRects(w.config.dataLabels.formatter ? w.config.dataLabels.formatter(yLabel, _objectSpread2(_objectSpread2({}, w), {}, {
            seriesIndex: i,
            dataPointIndex: j,
            w: w
          })) : w.globals.yLabelFormatters[0](yLabel), parseFloat(dataLabelsConfig.style.fontSize));
        }
        var params = {
          x: x,
          y: y,
          i: i,
          j: j,
          realIndex: realIndex,
          columnGroupIndex: columnGroupIndex,
          renderedPath: renderedPath,
          bcx: bcx,
          bcy: bcy,
          barHeight: barHeight,
          barWidth: barWidth,
          textRects: textRects,
          strokeWidth: strokeWidth,
          dataLabelsX: dataLabelsX,
          dataLabelsY: dataLabelsY,
          dataLabelsConfig: dataLabelsConfig,
          barDataLabelsConfig: barDataLabelsConfig,
          barTotalDataLabelsConfig: barTotalDataLabelsConfig,
          offX: offX,
          offY: offY
        };
        if (this.barCtx.isHorizontal) {
          dataLabelsPos = this.calculateBarsDataLabelsPosition(params);
        } else {
          dataLabelsPos = this.calculateColumnsDataLabelsPosition(params);
        }
        renderedPath.attr({
          cy: dataLabelsPos.bcy,
          cx: dataLabelsPos.bcx,
          j: j,
          val: w.globals.series[i][j],
          barHeight: barHeight,
          barWidth: barWidth
        });
        dataLabels = this.drawCalculatedDataLabels({
          x: dataLabelsPos.dataLabelsX,
          y: dataLabelsPos.dataLabelsY,
          val: this.barCtx.isRangeBar ? [y1, y2] : w.config.chart.stackType === '100%' ? series[realIndex][j] : w.globals.series[realIndex][j],
          i: realIndex,
          j: j,
          barWidth: barWidth,
          barHeight: barHeight,
          textRects: textRects,
          dataLabelsConfig: dataLabelsConfig
        });
        if (w.config.chart.stacked && barTotalDataLabelsConfig.enabled) {
          totalDataLabels = this.drawTotalDataLabels({
            x: dataLabelsPos.totalDataLabelsX,
            y: dataLabelsPos.totalDataLabelsY,
            barWidth: barWidth,
            barHeight: barHeight,
            realIndex: realIndex,
            textAnchor: dataLabelsPos.totalDataLabelsAnchor,
            val: this.getStackedTotalDataLabel({
              realIndex: realIndex,
              j: j
            }),
            dataLabelsConfig: dataLabelsConfig,
            barTotalDataLabelsConfig: barTotalDataLabelsConfig
          });
        }
        return {
          dataLabels: dataLabels,
          totalDataLabels: totalDataLabels
        };
      }
    }, {
      key: "getStackedTotalDataLabel",
      value: function getStackedTotalDataLabel(_ref) {
        var realIndex = _ref.realIndex,
          j = _ref.j;
        var w = this.w;
        var val = this.barCtx.stackedSeriesTotals[j];
        if (this.totalFormatter) {
          val = this.totalFormatter(val, _objectSpread2(_objectSpread2({}, w), {}, {
            seriesIndex: realIndex,
            dataPointIndex: j,
            w: w
          }));
        }
        return val;
      }
    }, {
      key: "calculateColumnsDataLabelsPosition",
      value: function calculateColumnsDataLabelsPosition(opts) {
        var w = this.w;
        var i = opts.i,
          j = opts.j,
          realIndex = opts.realIndex;
          opts.columnGroupIndex;
          var y = opts.y,
          bcx = opts.bcx,
          barWidth = opts.barWidth,
          barHeight = opts.barHeight,
          textRects = opts.textRects,
          dataLabelsX = opts.dataLabelsX,
          dataLabelsY = opts.dataLabelsY,
          dataLabelsConfig = opts.dataLabelsConfig,
          barDataLabelsConfig = opts.barDataLabelsConfig,
          barTotalDataLabelsConfig = opts.barTotalDataLabelsConfig,
          strokeWidth = opts.strokeWidth,
          offX = opts.offX,
          offY = opts.offY;
        var totalDataLabelsY;
        var totalDataLabelsX;
        var totalDataLabelsAnchor = 'middle';
        var totalDataLabelsBcx = bcx;
        barHeight = Math.abs(barHeight);
        var vertical = w.config.plotOptions.bar.dataLabels.orientation === 'vertical';
        var _this$barCtx$barHelpe = this.barCtx.barHelpers.getZeroValueEncounters({
            i: i,
            j: j
          }),
          zeroEncounters = _this$barCtx$barHelpe.zeroEncounters;
        bcx = bcx - strokeWidth / 2;
        var dataPointsDividedWidth = w.globals.gridWidth / w.globals.dataPoints;
        if (this.barCtx.isVerticalGroupedRangeBar) {
          dataLabelsX += barWidth / 2;
        } else {
          if (w.globals.isXNumeric) {
            dataLabelsX = bcx - barWidth / 2 + offX;
          } else {
            dataLabelsX = bcx - dataPointsDividedWidth + barWidth / 2 + offX;
          }
          if (zeroEncounters > 0 && w.config.plotOptions.bar.hideZeroBarsWhenGrouped) {
            dataLabelsX -= barWidth * zeroEncounters;
          }
        }
        if (vertical) {
          var offsetDLX = 2;
          dataLabelsX = dataLabelsX + textRects.height / 2 - strokeWidth / 2 - offsetDLX;
        }
        var valIsNegative = w.globals.series[i][j] < 0;
        var newY = y;
        if (this.barCtx.isReversed) {
          newY = y + (valIsNegative ? barHeight : -barHeight);
        }
        switch (barDataLabelsConfig.position) {
          case 'center':
            if (vertical) {
              if (valIsNegative) {
                dataLabelsY = newY - barHeight / 2 + offY;
              } else {
                dataLabelsY = newY + barHeight / 2 - offY;
              }
            } else {
              if (valIsNegative) {
                dataLabelsY = newY - barHeight / 2 + textRects.height / 2 + offY;
              } else {
                dataLabelsY = newY + barHeight / 2 + textRects.height / 2 - offY;
              }
            }
            break;
          case 'bottom':
            if (vertical) {
              if (valIsNegative) {
                dataLabelsY = newY - barHeight + offY;
              } else {
                dataLabelsY = newY + barHeight - offY;
              }
            } else {
              if (valIsNegative) {
                dataLabelsY = newY - barHeight + textRects.height + strokeWidth + offY;
              } else {
                dataLabelsY = newY + barHeight - textRects.height / 2 + strokeWidth - offY;
              }
            }
            break;
          case 'top':
            if (vertical) {
              if (valIsNegative) {
                dataLabelsY = newY + offY;
              } else {
                dataLabelsY = newY - offY;
              }
            } else {
              if (valIsNegative) {
                dataLabelsY = newY - textRects.height / 2 - offY;
              } else {
                dataLabelsY = newY + textRects.height + offY;
              }
            }
            break;
        }
        if (this.barCtx.lastActiveBarSerieIndex === realIndex && barTotalDataLabelsConfig.enabled) {
          var ADDITIONAL_OFFY = 18;
          var graphics = new Graphics(this.barCtx.ctx);
          var totalLabeltextRects = graphics.getTextRects(this.getStackedTotalDataLabel({
            realIndex: realIndex,
            j: j
          }), dataLabelsConfig.fontSize);
          if (valIsNegative) {
            totalDataLabelsY = newY - totalLabeltextRects.height / 2 - offY - barTotalDataLabelsConfig.offsetY + ADDITIONAL_OFFY;
          } else {
            totalDataLabelsY = newY + totalLabeltextRects.height + offY + barTotalDataLabelsConfig.offsetY - ADDITIONAL_OFFY;
          }

          // width divided into equal parts
          var xDivision = dataPointsDividedWidth;
          totalDataLabelsX = totalDataLabelsBcx + (w.globals.isXNumeric ? -barWidth * w.globals.barGroups.length / 2 : w.globals.barGroups.length * barWidth / 2 - (w.globals.barGroups.length - 1) * barWidth - xDivision) + barTotalDataLabelsConfig.offsetX;
        }
        if (!w.config.chart.stacked) {
          if (dataLabelsY < 0) {
            dataLabelsY = 0 + strokeWidth;
          } else if (dataLabelsY + textRects.height / 3 > w.globals.gridHeight) {
            dataLabelsY = w.globals.gridHeight - strokeWidth;
          }
        }
        return {
          bcx: bcx,
          bcy: y,
          dataLabelsX: dataLabelsX,
          dataLabelsY: dataLabelsY,
          totalDataLabelsX: totalDataLabelsX,
          totalDataLabelsY: totalDataLabelsY,
          totalDataLabelsAnchor: totalDataLabelsAnchor
        };
      }
    }, {
      key: "calculateBarsDataLabelsPosition",
      value: function calculateBarsDataLabelsPosition(opts) {
        var w = this.w;
        var x = opts.x,
          i = opts.i,
          j = opts.j,
          realIndex = opts.realIndex,
          bcy = opts.bcy,
          barHeight = opts.barHeight,
          barWidth = opts.barWidth,
          textRects = opts.textRects,
          dataLabelsX = opts.dataLabelsX,
          strokeWidth = opts.strokeWidth,
          dataLabelsConfig = opts.dataLabelsConfig,
          barDataLabelsConfig = opts.barDataLabelsConfig,
          barTotalDataLabelsConfig = opts.barTotalDataLabelsConfig,
          offX = opts.offX,
          offY = opts.offY;
        var dataPointsDividedHeight = w.globals.gridHeight / w.globals.dataPoints;
        barWidth = Math.abs(barWidth);
        var dataLabelsY = bcy - (this.barCtx.isRangeBar ? 0 : dataPointsDividedHeight) + barHeight / 2 + textRects.height / 2 + offY - 3;
        var totalDataLabelsX;
        var totalDataLabelsY;
        var totalDataLabelsAnchor = 'start';
        var valIsNegative = w.globals.series[i][j] < 0;
        var newX = x;
        if (this.barCtx.isReversed) {
          newX = x + (valIsNegative ? -barWidth : barWidth);
          totalDataLabelsAnchor = valIsNegative ? 'start' : 'end';
        }
        switch (barDataLabelsConfig.position) {
          case 'center':
            if (valIsNegative) {
              dataLabelsX = newX + barWidth / 2 - offX;
            } else {
              dataLabelsX = Math.max(textRects.width / 2, newX - barWidth / 2) + offX;
            }
            break;
          case 'bottom':
            if (valIsNegative) {
              dataLabelsX = newX + barWidth - strokeWidth - offX;
            } else {
              dataLabelsX = newX - barWidth + strokeWidth + offX;
            }
            break;
          case 'top':
            if (valIsNegative) {
              dataLabelsX = newX - strokeWidth - offX;
            } else {
              dataLabelsX = newX - strokeWidth + offX;
            }
            break;
        }
        if (this.barCtx.lastActiveBarSerieIndex === realIndex && barTotalDataLabelsConfig.enabled) {
          var graphics = new Graphics(this.barCtx.ctx);
          var totalLabeltextRects = graphics.getTextRects(this.getStackedTotalDataLabel({
            realIndex: realIndex,
            j: j
          }), dataLabelsConfig.fontSize);
          if (valIsNegative) {
            totalDataLabelsX = newX - strokeWidth - offX - barTotalDataLabelsConfig.offsetX;
            totalDataLabelsAnchor = 'end';
          } else {
            totalDataLabelsX = newX + offX + barTotalDataLabelsConfig.offsetX + (this.barCtx.isReversed ? -(barWidth + strokeWidth) : strokeWidth);
          }
          totalDataLabelsY = dataLabelsY - textRects.height / 2 + totalLabeltextRects.height / 2 + barTotalDataLabelsConfig.offsetY + strokeWidth;
        }
        if (!w.config.chart.stacked) {
          if (dataLabelsConfig.textAnchor === 'start') {
            if (dataLabelsX - textRects.width < 0) {
              dataLabelsX = valIsNegative ? textRects.width + strokeWidth : strokeWidth;
            } else if (dataLabelsX + textRects.width > w.globals.gridWidth) {
              dataLabelsX = valIsNegative ? w.globals.gridWidth - strokeWidth : w.globals.gridWidth - textRects.width - strokeWidth;
            }
          } else if (dataLabelsConfig.textAnchor === 'middle') {
            if (dataLabelsX - textRects.width / 2 < 0) {
              dataLabelsX = textRects.width / 2 + strokeWidth;
            } else if (dataLabelsX + textRects.width / 2 > w.globals.gridWidth) {
              dataLabelsX = w.globals.gridWidth - textRects.width / 2 - strokeWidth;
            }
          } else if (dataLabelsConfig.textAnchor === 'end') {
            if (dataLabelsX < 1) {
              dataLabelsX = textRects.width + strokeWidth;
            } else if (dataLabelsX + 1 > w.globals.gridWidth) {
              dataLabelsX = w.globals.gridWidth - textRects.width - strokeWidth;
            }
          }
        }
        return {
          bcx: x,
          bcy: bcy,
          dataLabelsX: dataLabelsX,
          dataLabelsY: dataLabelsY,
          totalDataLabelsX: totalDataLabelsX,
          totalDataLabelsY: totalDataLabelsY,
          totalDataLabelsAnchor: totalDataLabelsAnchor
        };
      }
    }, {
      key: "drawCalculatedDataLabels",
      value: function drawCalculatedDataLabels(_ref2) {
        var x = _ref2.x,
          y = _ref2.y,
          val = _ref2.val,
          i = _ref2.i,
          j = _ref2.j,
          textRects = _ref2.textRects,
          barHeight = _ref2.barHeight,
          barWidth = _ref2.barWidth,
          dataLabelsConfig = _ref2.dataLabelsConfig;
        var w = this.w;
        var rotate = 'rotate(0)';
        if (w.config.plotOptions.bar.dataLabels.orientation === 'vertical') rotate = "rotate(-90, ".concat(x, ", ").concat(y, ")");
        var dataLabels = new DataLabels(this.barCtx.ctx);
        var graphics = new Graphics(this.barCtx.ctx);
        var formatter = dataLabelsConfig.formatter;
        var elDataLabelsWrap = null;
        var isSeriesNotCollapsed = w.globals.collapsedSeriesIndices.indexOf(i) > -1;
        if (dataLabelsConfig.enabled && !isSeriesNotCollapsed) {
          elDataLabelsWrap = graphics.group({
            class: 'apexcharts-data-labels',
            transform: rotate
          });
          var text = '';
          if (typeof val !== 'undefined') {
            text = formatter(val, _objectSpread2(_objectSpread2({}, w), {}, {
              seriesIndex: i,
              dataPointIndex: j,
              w: w
            }));
          }
          if (!val && w.config.plotOptions.bar.hideZeroBarsWhenGrouped) {
            text = '';
          }
          var valIsNegative = w.globals.series[i][j] < 0;
          var position = w.config.plotOptions.bar.dataLabels.position;
          if (w.config.plotOptions.bar.dataLabels.orientation === 'vertical') {
            if (position === 'top') {
              if (valIsNegative) dataLabelsConfig.textAnchor = 'end';else dataLabelsConfig.textAnchor = 'start';
            }
            if (position === 'center') {
              dataLabelsConfig.textAnchor = 'middle';
            }
            if (position === 'bottom') {
              if (valIsNegative) dataLabelsConfig.textAnchor = 'end';else dataLabelsConfig.textAnchor = 'start';
            }
          }
          if (this.barCtx.isRangeBar && this.barCtx.barOptions.dataLabels.hideOverflowingLabels) {
            // hide the datalabel if it cannot fit into the rect
            var txRect = graphics.getTextRects(text, parseFloat(dataLabelsConfig.style.fontSize));
            if (barWidth < txRect.width) {
              text = '';
            }
          }
          if (w.config.chart.stacked && this.barCtx.barOptions.dataLabels.hideOverflowingLabels) {
            // if there is not enough space to draw the label in the bar/column rect, check hideOverflowingLabels property to prevent overflowing on wrong rect
            // Note: This issue is only seen in stacked charts
            if (this.barCtx.isHorizontal) {
              if (textRects.width / 1.6 > Math.abs(barWidth)) {
                text = '';
              }
            } else {
              if (textRects.height / 1.6 > Math.abs(barHeight)) {
                text = '';
              }
            }
          }
          var modifiedDataLabelsConfig = _objectSpread2({}, dataLabelsConfig);
          if (this.barCtx.isHorizontal) {
            if (val < 0) {
              if (dataLabelsConfig.textAnchor === 'start') {
                modifiedDataLabelsConfig.textAnchor = 'end';
              } else if (dataLabelsConfig.textAnchor === 'end') {
                modifiedDataLabelsConfig.textAnchor = 'start';
              }
            }
          }
          dataLabels.plotDataLabelsText({
            x: x,
            y: y,
            text: text,
            i: i,
            j: j,
            parent: elDataLabelsWrap,
            dataLabelsConfig: modifiedDataLabelsConfig,
            alwaysDrawDataLabel: true,
            offsetCorrection: true
          });
        }
        return elDataLabelsWrap;
      }
    }, {
      key: "drawTotalDataLabels",
      value: function drawTotalDataLabels(_ref3) {
        var x = _ref3.x,
          y = _ref3.y,
          val = _ref3.val,
          realIndex = _ref3.realIndex,
          textAnchor = _ref3.textAnchor,
          barTotalDataLabelsConfig = _ref3.barTotalDataLabelsConfig;
        this.w;
        var graphics = new Graphics(this.barCtx.ctx);
        var totalDataLabelText;
        if (barTotalDataLabelsConfig.enabled && typeof x !== 'undefined' && typeof y !== 'undefined' && this.barCtx.lastActiveBarSerieIndex === realIndex) {
          totalDataLabelText = graphics.drawText({
            x: x,
            y: y,
            foreColor: barTotalDataLabelsConfig.style.color,
            text: val,
            textAnchor: textAnchor,
            fontFamily: barTotalDataLabelsConfig.style.fontFamily,
            fontSize: barTotalDataLabelsConfig.style.fontSize,
            fontWeight: barTotalDataLabelsConfig.style.fontWeight
          });
        }
        return totalDataLabelText;
      }
    }]);
    return BarDataLabels;
  }();

  var Helpers$1 = /*#__PURE__*/function () {
    function Helpers(barCtx) {
      _classCallCheck(this, Helpers);
      this.w = barCtx.w;
      this.barCtx = barCtx;
    }
    _createClass(Helpers, [{
      key: "initVariables",
      value: function initVariables(series) {
        var w = this.w;
        this.barCtx.series = series;
        this.barCtx.totalItems = 0;
        this.barCtx.seriesLen = 0;
        this.barCtx.visibleI = -1; // visible Series
        this.barCtx.visibleItems = 1; // number of visible bars after user zoomed in/out

        for (var sl = 0; sl < series.length; sl++) {
          if (series[sl].length > 0) {
            this.barCtx.seriesLen = this.barCtx.seriesLen + 1;
            this.barCtx.totalItems += series[sl].length;
          }
          if (w.globals.isXNumeric) {
            // get max visible items
            for (var _j = 0; _j < series[sl].length; _j++) {
              if (w.globals.seriesX[sl][_j] > w.globals.minX && w.globals.seriesX[sl][_j] < w.globals.maxX) {
                this.barCtx.visibleItems++;
              }
            }
          } else {
            this.barCtx.visibleItems = w.globals.dataPoints;
          }
        }
        this.arrBorderRadius = this.createBorderRadiusArr(w.globals.series);
        if (this.barCtx.seriesLen === 0) {
          // A small adjustment when combo charts are used
          this.barCtx.seriesLen = 1;
        }
        this.barCtx.zeroSerieses = [];
        if (!w.globals.comboCharts) {
          this.checkZeroSeries({
            series: series
          });
        }
      }
    }, {
      key: "initialPositions",
      value: function initialPositions() {
        var w = this.w;
        var x, y, yDivision, xDivision, barHeight, barWidth, zeroH, zeroW;
        var dataPoints = w.globals.dataPoints;
        if (this.barCtx.isRangeBar) {
          // timeline rangebar chart
          dataPoints = w.globals.labels.length;
        }
        var seriesLen = this.barCtx.seriesLen;
        if (w.config.plotOptions.bar.rangeBarGroupRows) {
          seriesLen = 1;
        }
        if (this.barCtx.isHorizontal) {
          // height divided into equal parts
          yDivision = w.globals.gridHeight / dataPoints;
          barHeight = yDivision / seriesLen;
          if (w.globals.isXNumeric) {
            yDivision = w.globals.gridHeight / this.barCtx.totalItems;
            barHeight = yDivision / this.barCtx.seriesLen;
          }
          barHeight = barHeight * parseInt(this.barCtx.barOptions.barHeight, 10) / 100;
          if (String(this.barCtx.barOptions.barHeight).indexOf('%') === -1) {
            barHeight = parseInt(this.barCtx.barOptions.barHeight, 10);
          }
          zeroW = this.barCtx.baseLineInvertedY + w.globals.padHorizontal + (this.barCtx.isReversed ? w.globals.gridWidth : 0) - (this.barCtx.isReversed ? this.barCtx.baseLineInvertedY * 2 : 0);
          if (this.barCtx.isFunnel) {
            zeroW = w.globals.gridWidth / 2;
          }
          y = (yDivision - barHeight * this.barCtx.seriesLen) / 2;
        } else {
          // width divided into equal parts
          xDivision = w.globals.gridWidth / this.barCtx.visibleItems;
          if (w.config.xaxis.convertedCatToNumeric) {
            xDivision = w.globals.gridWidth / w.globals.dataPoints;
          }
          barWidth = xDivision / seriesLen * parseInt(this.barCtx.barOptions.columnWidth, 10) / 100;
          if (w.globals.isXNumeric) {
            // max barwidth should be equal to minXDiff to avoid overlap
            var xRatio = this.barCtx.xRatio;
            if (w.globals.minXDiff && w.globals.minXDiff !== 0.5 && w.globals.minXDiff / xRatio > 0) {
              xDivision = w.globals.minXDiff / xRatio;
            }
            barWidth = xDivision / seriesLen * parseInt(this.barCtx.barOptions.columnWidth, 10) / 100;
            if (barWidth < 1) {
              barWidth = 1;
            }
          }
          if (String(this.barCtx.barOptions.columnWidth).indexOf('%') === -1) {
            barWidth = parseInt(this.barCtx.barOptions.columnWidth, 10);
          }
          zeroH = w.globals.gridHeight - this.barCtx.baseLineY[this.barCtx.translationsIndex] - (this.barCtx.isReversed ? w.globals.gridHeight : 0) + (this.barCtx.isReversed ? this.barCtx.baseLineY[this.barCtx.translationsIndex] * 2 : 0);
          x = w.globals.padHorizontal + (xDivision - barWidth * this.barCtx.seriesLen) / 2;
        }
        w.globals.barHeight = barHeight;
        w.globals.barWidth = barWidth;
        return {
          x: x,
          y: y,
          yDivision: yDivision,
          xDivision: xDivision,
          barHeight: barHeight,
          barWidth: barWidth,
          zeroH: zeroH,
          zeroW: zeroW
        };
      }
    }, {
      key: "initializeStackedPrevVars",
      value: function initializeStackedPrevVars(ctx) {
        var w = ctx.w;
        w.globals.seriesGroups.forEach(function (group) {
          if (!ctx[group]) ctx[group] = {};
          ctx[group].prevY = [];
          ctx[group].prevX = [];
          ctx[group].prevYF = [];
          ctx[group].prevXF = [];
          ctx[group].prevYVal = [];
          ctx[group].prevXVal = [];
        });
      }
    }, {
      key: "initializeStackedXYVars",
      value: function initializeStackedXYVars(ctx) {
        var w = ctx.w;
        w.globals.seriesGroups.forEach(function (group) {
          if (!ctx[group]) ctx[group] = {};
          ctx[group].xArrj = [];
          ctx[group].xArrjF = [];
          ctx[group].xArrjVal = [];
          ctx[group].yArrj = [];
          ctx[group].yArrjF = [];
          ctx[group].yArrjVal = [];
        });
      }
    }, {
      key: "getPathFillColor",
      value: function getPathFillColor(series, i, j, realIndex) {
        var _w$config$series$i$da, _w$config$series$i$da2, _w$config$series$i$da3, _w$config$series$i$da4, _w$config$series$i$da5;
        var w = this.w;
        var fill = this.barCtx.ctx.fill;
        var fillColor = null;
        var seriesNumber = this.barCtx.barOptions.distributed ? j : i;
        if (this.barCtx.barOptions.colors.ranges.length > 0) {
          var colorRange = this.barCtx.barOptions.colors.ranges;
          colorRange.map(function (range) {
            if (series[i][j] >= range.from && series[i][j] <= range.to) {
              fillColor = range.color;
            }
          });
        }
        if ((_w$config$series$i$da = w.config.series[i].data[j]) !== null && _w$config$series$i$da !== void 0 && _w$config$series$i$da.fillColor) {
          fillColor = w.config.series[i].data[j].fillColor;
        }
        var pathFill = fill.fillPath({
          seriesNumber: this.barCtx.barOptions.distributed ? seriesNumber : realIndex,
          dataPointIndex: j,
          color: fillColor,
          value: series[i][j],
          fillConfig: (_w$config$series$i$da2 = w.config.series[i].data[j]) === null || _w$config$series$i$da2 === void 0 ? void 0 : _w$config$series$i$da2.fill,
          fillType: (_w$config$series$i$da3 = w.config.series[i].data[j]) !== null && _w$config$series$i$da3 !== void 0 && (_w$config$series$i$da4 = _w$config$series$i$da3.fill) !== null && _w$config$series$i$da4 !== void 0 && _w$config$series$i$da4.type ? (_w$config$series$i$da5 = w.config.series[i].data[j]) === null || _w$config$series$i$da5 === void 0 ? void 0 : _w$config$series$i$da5.fill.type : Array.isArray(w.config.fill.type) ? w.config.fill.type[realIndex] : w.config.fill.type
        });
        return pathFill;
      }
    }, {
      key: "getStrokeWidth",
      value: function getStrokeWidth(i, j, realIndex) {
        var strokeWidth = 0;
        var w = this.w;
        if (!this.barCtx.series[i][j]) {
          this.barCtx.isNullValue = true;
        } else {
          this.barCtx.isNullValue = false;
        }
        if (w.config.stroke.show) {
          if (!this.barCtx.isNullValue) {
            strokeWidth = Array.isArray(this.barCtx.strokeWidth) ? this.barCtx.strokeWidth[realIndex] : this.barCtx.strokeWidth;
          }
        }
        return strokeWidth;
      }
    }, {
      key: "createBorderRadiusArr",
      value: function createBorderRadiusArr(series) {
        var w = this.w;
        var alwaysApplyRadius = !this.w.config.chart.stacked || w.config.plotOptions.bar.borderRadiusWhenStacked !== 'last' || w.config.plotOptions.bar.borderRadius <= 0;
        var numSeries = series.length;
        var numColumns = series[0].length;
        var output = Array.from({
          length: numSeries
        }, function () {
          return Array(numColumns).fill(alwaysApplyRadius ? 'top' : 'none');
        });
        if (alwaysApplyRadius) return output;
        for (var _j2 = 0; _j2 < numColumns; _j2++) {
          var positiveIndices = [];
          var negativeIndices = [];
          var nonZeroCount = 0;

          // Collect positive and negative indices
          for (var i = 0; i < numSeries; i++) {
            var value = series[i][_j2];
            if (value > 0) {
              positiveIndices.push(i);
              nonZeroCount++;
            } else if (value < 0) {
              negativeIndices.push(i);
              nonZeroCount++;
            }
          }
          if (positiveIndices.length > 0 && negativeIndices.length === 0) {
            // Only positive values in this column
            if (positiveIndices.length === 1) {
              // Single positive value
              output[positiveIndices[0]][_j2] = 'both';
            } else {
              // Multiple positive values
              var firstPositiveIndex = positiveIndices[0];
              var lastPositiveIndex = positiveIndices[positiveIndices.length - 1];
              var _iterator = _createForOfIteratorHelper(positiveIndices),
                _step;
              try {
                for (_iterator.s(); !(_step = _iterator.n()).done;) {
                  var _i2 = _step.value;
                  if (_i2 === firstPositiveIndex) {
                    output[_i2][_j2] = 'bottom';
                  } else if (_i2 === lastPositiveIndex) {
                    output[_i2][_j2] = 'top';
                  } else {
                    output[_i2][_j2] = 'none';
                  }
                }
              } catch (err) {
                _iterator.e(err);
              } finally {
                _iterator.f();
              }
            }
          } else if (negativeIndices.length > 0 && positiveIndices.length === 0) {
            // Only negative values in this column
            if (negativeIndices.length === 1) {
              // Single negative value
              output[negativeIndices[0]][_j2] = 'both';
            } else {
              // Multiple negative values
              var firstNegativeIndex = negativeIndices[0];
              var lastNegativeIndex = negativeIndices[negativeIndices.length - 1];
              var _iterator2 = _createForOfIteratorHelper(negativeIndices),
                _step2;
              try {
                for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
                  var _i3 = _step2.value;
                  if (_i3 === firstNegativeIndex) {
                    output[_i3][_j2] = 'bottom';
                  } else if (_i3 === lastNegativeIndex) {
                    output[_i3][_j2] = 'top';
                  } else {
                    output[_i3][_j2] = 'none';
                  }
                }
              } catch (err) {
                _iterator2.e(err);
              } finally {
                _iterator2.f();
              }
            }
          } else if (positiveIndices.length > 0 && negativeIndices.length > 0) {
            // Mixed positive and negative values
            // Assign 'top' to the last positive bar
            var _lastPositiveIndex = positiveIndices[positiveIndices.length - 1];
            var _iterator3 = _createForOfIteratorHelper(positiveIndices),
              _step3;
            try {
              for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
                var _i4 = _step3.value;
                if (_i4 === _lastPositiveIndex) {
                  output[_i4][_j2] = 'top';
                } else {
                  output[_i4][_j2] = 'none';
                }
              }
              // Assign 'bottom' to the last negative bar (closest to axis)
            } catch (err) {
              _iterator3.e(err);
            } finally {
              _iterator3.f();
            }
            var _lastNegativeIndex = negativeIndices[negativeIndices.length - 1];
            var _iterator4 = _createForOfIteratorHelper(negativeIndices),
              _step4;
            try {
              for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
                var _i5 = _step4.value;
                if (_i5 === _lastNegativeIndex) {
                  output[_i5][_j2] = 'bottom';
                } else {
                  output[_i5][_j2] = 'none';
                }
              }
            } catch (err) {
              _iterator4.e(err);
            } finally {
              _iterator4.f();
            }
          } else if (nonZeroCount === 1) {
            // Only one non-zero value (either positive or negative)
            var index = positiveIndices[0] || negativeIndices[0];
            output[index][_j2] = 'both';
          }
        }
        return output;
      }
    }, {
      key: "barBackground",
      value: function barBackground(_ref) {
        var j = _ref.j,
          i = _ref.i,
          x1 = _ref.x1,
          x2 = _ref.x2,
          y1 = _ref.y1,
          y2 = _ref.y2,
          elSeries = _ref.elSeries;
        var w = this.w;
        var graphics = new Graphics(this.barCtx.ctx);
        var sr = new Series(this.barCtx.ctx);
        var activeSeriesIndex = sr.getActiveConfigSeriesIndex();
        if (this.barCtx.barOptions.colors.backgroundBarColors.length > 0 && activeSeriesIndex === i) {
          if (j >= this.barCtx.barOptions.colors.backgroundBarColors.length) {
            j %= this.barCtx.barOptions.colors.backgroundBarColors.length;
          }
          var bcolor = this.barCtx.barOptions.colors.backgroundBarColors[j];
          var rect = graphics.drawRect(typeof x1 !== 'undefined' ? x1 : 0, typeof y1 !== 'undefined' ? y1 : 0, typeof x2 !== 'undefined' ? x2 : w.globals.gridWidth, typeof y2 !== 'undefined' ? y2 : w.globals.gridHeight, this.barCtx.barOptions.colors.backgroundBarRadius, bcolor, this.barCtx.barOptions.colors.backgroundBarOpacity);
          elSeries.add(rect);
          rect.node.classList.add('apexcharts-backgroundBar');
        }
      }
    }, {
      key: "getColumnPaths",
      value: function getColumnPaths(_ref2) {
        var _w$config$series$real;
        var barWidth = _ref2.barWidth,
          barXPosition = _ref2.barXPosition,
          y1 = _ref2.y1,
          y2 = _ref2.y2,
          strokeWidth = _ref2.strokeWidth,
          isReversed = _ref2.isReversed,
          series = _ref2.series,
          seriesGroup = _ref2.seriesGroup,
          realIndex = _ref2.realIndex,
          i = _ref2.i,
          j = _ref2.j,
          w = _ref2.w;
        var graphics = new Graphics(this.barCtx.ctx);
        strokeWidth = Array.isArray(strokeWidth) ? strokeWidth[realIndex] : strokeWidth;
        if (!strokeWidth) strokeWidth = 0;
        var bW = barWidth;
        var bXP = barXPosition;
        if ((_w$config$series$real = w.config.series[realIndex].data[j]) !== null && _w$config$series$real !== void 0 && _w$config$series$real.columnWidthOffset) {
          bXP = barXPosition - w.config.series[realIndex].data[j].columnWidthOffset / 2;
          bW = barWidth + w.config.series[realIndex].data[j].columnWidthOffset;
        }

        // Center the stroke on the coordinates
        var strokeCenter = strokeWidth / 2;
        var x1 = bXP + strokeCenter;
        var x2 = bXP + bW - strokeCenter;
        var direction = (series[i][j] >= 0 ? 1 : -1) * (isReversed ? -1 : 1);

        // append tiny pixels to avoid exponentials (which cause issues in border-radius)
        y1 += 0.001 - strokeCenter * direction;
        y2 += 0.001 + strokeCenter * direction;
        var pathTo = graphics.move(x1, y1);
        var pathFrom = graphics.move(x1, y1);
        var sl = graphics.line(x2, y1);
        if (w.globals.previousPaths.length > 0) {
          pathFrom = this.barCtx.getPreviousPath(realIndex, j, false);
        }
        pathTo = pathTo + graphics.line(x1, y2) + graphics.line(x2, y2) + sl + (w.config.plotOptions.bar.borderRadiusApplication === 'around' || this.arrBorderRadius[realIndex][j] === 'both' ? ' Z' : ' z');

        // the lines in pathFrom are repeated to equal it to the points of pathTo
        // this is to avoid weird animation (bug in svg.js)
        pathFrom = pathFrom + graphics.line(x1, y1) + sl + sl + sl + sl + sl + graphics.line(x1, y1) + (w.config.plotOptions.bar.borderRadiusApplication === 'around' || this.arrBorderRadius[realIndex][j] === 'both' ? ' Z' : ' z');
        if (this.arrBorderRadius[realIndex][j] !== 'none') {
          pathTo = graphics.roundPathCorners(pathTo, w.config.plotOptions.bar.borderRadius);
        }
        if (w.config.chart.stacked) {
          var _ctx = this.barCtx;
          _ctx = this.barCtx[seriesGroup];
          _ctx.yArrj.push(y2 - strokeCenter * direction);
          _ctx.yArrjF.push(Math.abs(y1 - y2 + strokeWidth * direction));
          _ctx.yArrjVal.push(this.barCtx.series[i][j]);
        }
        return {
          pathTo: pathTo,
          pathFrom: pathFrom
        };
      }
    }, {
      key: "getBarpaths",
      value: function getBarpaths(_ref3) {
        var _w$config$series$real2;
        var barYPosition = _ref3.barYPosition,
          barHeight = _ref3.barHeight,
          x1 = _ref3.x1,
          x2 = _ref3.x2,
          strokeWidth = _ref3.strokeWidth,
          isReversed = _ref3.isReversed,
          series = _ref3.series,
          seriesGroup = _ref3.seriesGroup,
          realIndex = _ref3.realIndex,
          i = _ref3.i,
          j = _ref3.j,
          w = _ref3.w;
        var graphics = new Graphics(this.barCtx.ctx);
        strokeWidth = Array.isArray(strokeWidth) ? strokeWidth[realIndex] : strokeWidth;
        if (!strokeWidth) strokeWidth = 0;
        var bYP = barYPosition;
        var bH = barHeight;
        if ((_w$config$series$real2 = w.config.series[realIndex].data[j]) !== null && _w$config$series$real2 !== void 0 && _w$config$series$real2.barHeightOffset) {
          bYP = barYPosition - w.config.series[realIndex].data[j].barHeightOffset / 2;
          bH = barHeight + w.config.series[realIndex].data[j].barHeightOffset;
        }

        // Center the stroke on the coordinates
        var strokeCenter = strokeWidth / 2;
        var y1 = bYP + strokeCenter;
        var y2 = bYP + bH - strokeCenter;
        var direction = (series[i][j] >= 0 ? 1 : -1) * (isReversed ? -1 : 1);

        // append tiny pixels to avoid exponentials (which cause issues in border-radius)
        x1 += 0.001 + strokeCenter * direction;
        x2 += 0.001 - strokeCenter * direction;
        var pathTo = graphics.move(x1, y1);
        var pathFrom = graphics.move(x1, y1);
        if (w.globals.previousPaths.length > 0) {
          pathFrom = this.barCtx.getPreviousPath(realIndex, j, false);
        }
        var sl = graphics.line(x1, y2);
        pathTo = pathTo + graphics.line(x2, y1) + graphics.line(x2, y2) + sl + (w.config.plotOptions.bar.borderRadiusApplication === 'around' || this.arrBorderRadius[realIndex][j] === 'both' ? ' Z' : ' z');
        pathFrom = pathFrom + graphics.line(x1, y1) + sl + sl + sl + sl + sl + graphics.line(x1, y1) + (w.config.plotOptions.bar.borderRadiusApplication === 'around' || this.arrBorderRadius[realIndex][j] === 'both' ? ' Z' : ' z');
        if (this.arrBorderRadius[realIndex][j] !== 'none') {
          pathTo = graphics.roundPathCorners(pathTo, w.config.plotOptions.bar.borderRadius);
        }
        if (w.config.chart.stacked) {
          var _ctx = this.barCtx;
          _ctx = this.barCtx[seriesGroup];
          _ctx.xArrj.push(x2 + strokeCenter * direction);
          _ctx.xArrjF.push(Math.abs(x1 - x2 - strokeWidth * direction));
          _ctx.xArrjVal.push(this.barCtx.series[i][j]);
        }
        return {
          pathTo: pathTo,
          pathFrom: pathFrom
        };
      }
    }, {
      key: "checkZeroSeries",
      value: function checkZeroSeries(_ref4) {
        var series = _ref4.series;
        var w = this.w;
        for (var zs = 0; zs < series.length; zs++) {
          var total = 0;
          for (var zsj = 0; zsj < series[w.globals.maxValsInArrayIndex].length; zsj++) {
            total += series[zs][zsj];
          }
          if (total === 0) {
            this.barCtx.zeroSerieses.push(zs);
          }
        }
      }
    }, {
      key: "getXForValue",
      value: function getXForValue(value, zeroW) {
        var zeroPositionForNull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
        var xForVal = zeroPositionForNull ? zeroW : null;
        if (typeof value !== 'undefined' && value !== null) {
          xForVal = zeroW + value / this.barCtx.invertedYRatio - (this.barCtx.isReversed ? value / this.barCtx.invertedYRatio : 0) * 2;
        }
        return xForVal;
      }
    }, {
      key: "getYForValue",
      value: function getYForValue(value, zeroH, translationsIndex) {
        var zeroPositionForNull = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
        var yForVal = zeroPositionForNull ? zeroH : null;
        if (typeof value !== 'undefined' && value !== null) {
          yForVal = zeroH - value / this.barCtx.yRatio[translationsIndex] + (this.barCtx.isReversed ? value / this.barCtx.yRatio[translationsIndex] : 0) * 2;
        }
        return yForVal;
      }
    }, {
      key: "getGoalValues",
      value: function getGoalValues(type, zeroW, zeroH, i, j, translationsIndex) {
        var _this = this;
        var w = this.w;
        var goals = [];
        var pushGoal = function pushGoal(value, attrs) {
          var _goals$push;
          goals.push((_goals$push = {}, _defineProperty(_goals$push, type, type === 'x' ? _this.getXForValue(value, zeroW, false) : _this.getYForValue(value, zeroH, translationsIndex, false)), _defineProperty(_goals$push, "attrs", attrs), _goals$push));
        };
        if (w.globals.seriesGoals[i] && w.globals.seriesGoals[i][j] && Array.isArray(w.globals.seriesGoals[i][j])) {
          w.globals.seriesGoals[i][j].forEach(function (goal) {
            pushGoal(goal.value, goal);
          });
        }
        if (this.barCtx.barOptions.isDumbbell && w.globals.seriesRange.length) {
          var colors = this.barCtx.barOptions.dumbbellColors ? this.barCtx.barOptions.dumbbellColors : w.globals.colors;
          var commonAttrs = {
            strokeHeight: type === 'x' ? 0 : w.globals.markers.size[i],
            strokeWidth: type === 'x' ? w.globals.markers.size[i] : 0,
            strokeDashArray: 0,
            strokeLineCap: 'round',
            strokeColor: Array.isArray(colors[i]) ? colors[i][0] : colors[i]
          };
          pushGoal(w.globals.seriesRangeStart[i][j], commonAttrs);
          pushGoal(w.globals.seriesRangeEnd[i][j], _objectSpread2(_objectSpread2({}, commonAttrs), {}, {
            strokeColor: Array.isArray(colors[i]) ? colors[i][1] : colors[i]
          }));
        }
        return goals;
      }
    }, {
      key: "drawGoalLine",
      value: function drawGoalLine(_ref5) {
        var barXPosition = _ref5.barXPosition,
          barYPosition = _ref5.barYPosition,
          goalX = _ref5.goalX,
          goalY = _ref5.goalY,
          barWidth = _ref5.barWidth,
          barHeight = _ref5.barHeight;
        var graphics = new Graphics(this.barCtx.ctx);
        var lineGroup = graphics.group({
          className: 'apexcharts-bar-goals-groups'
        });
        lineGroup.node.classList.add('apexcharts-element-hidden');
        this.barCtx.w.globals.delayedElements.push({
          el: lineGroup.node
        });
        lineGroup.attr('clip-path', "url(#gridRectMarkerMask".concat(this.barCtx.w.globals.cuid, ")"));
        var line = null;
        if (this.barCtx.isHorizontal) {
          if (Array.isArray(goalX)) {
            goalX.forEach(function (goal) {
              // Need a tiny margin of 1 each side so goals don't disappear at extremeties
              if (goal.x >= -1 && goal.x <= graphics.w.globals.gridWidth + 1) {
                var sHeight = typeof goal.attrs.strokeHeight !== 'undefined' ? goal.attrs.strokeHeight : barHeight / 2;
                var y = barYPosition + sHeight + barHeight / 2;
                line = graphics.drawLine(goal.x, y - sHeight * 2, goal.x, y, goal.attrs.strokeColor ? goal.attrs.strokeColor : undefined, goal.attrs.strokeDashArray, goal.attrs.strokeWidth ? goal.attrs.strokeWidth : 2, goal.attrs.strokeLineCap);
                lineGroup.add(line);
              }
            });
          }
        } else {
          if (Array.isArray(goalY)) {
            goalY.forEach(function (goal) {
              // Need a tiny margin of 1 each side so goals don't disappear at extremeties
              if (goal.y >= -1 && goal.y <= graphics.w.globals.gridHeight + 1) {
                var sWidth = typeof goal.attrs.strokeWidth !== 'undefined' ? goal.attrs.strokeWidth : barWidth / 2;
                var x = barXPosition + sWidth + barWidth / 2;
                line = graphics.drawLine(x - sWidth * 2, goal.y, x, goal.y, goal.attrs.strokeColor ? goal.attrs.strokeColor : undefined, goal.attrs.strokeDashArray, goal.attrs.strokeHeight ? goal.attrs.strokeHeight : 2, goal.attrs.strokeLineCap);
                lineGroup.add(line);
              }
            });
          }
        }
        return lineGroup;
      }
    }, {
      key: "drawBarShadow",
      value: function drawBarShadow(_ref6) {
        var prevPaths = _ref6.prevPaths,
          currPaths = _ref6.currPaths,
          color = _ref6.color;
        var w = this.w;
        var prevX2 = prevPaths.x,
          prevX1 = prevPaths.x1,
          prevY1 = prevPaths.barYPosition;
        var currX2 = currPaths.x,
          currX1 = currPaths.x1,
          currY1 = currPaths.barYPosition;
        var prevY2 = prevY1 + currPaths.barHeight;
        var graphics = new Graphics(this.barCtx.ctx);
        var utils = new Utils$1();
        var shadowPath = graphics.move(prevX1, prevY2) + graphics.line(prevX2, prevY2) + graphics.line(currX2, currY1) + graphics.line(currX1, currY1) + graphics.line(prevX1, prevY2) + (w.config.plotOptions.bar.borderRadiusApplication === 'around' || this.arrBorderRadius[realIndex][j] === 'both' ? ' Z' : ' z');
        return graphics.drawPath({
          d: shadowPath,
          fill: utils.shadeColor(0.5, Utils$1.rgb2hex(color)),
          stroke: 'none',
          strokeWidth: 0,
          fillOpacity: 1,
          classes: 'apexcharts-bar-shadows'
        });
      }
    }, {
      key: "getZeroValueEncounters",
      value: function getZeroValueEncounters(_ref7) {
        var _w$globals$columnSeri;
        var i = _ref7.i,
          j = _ref7.j;
        var w = this.w;
        var nonZeroColumns = 0;
        var zeroEncounters = 0;
        var seriesIndices = w.config.plotOptions.bar.horizontal ? w.globals.series.map(function (_, _i) {
          return _i;
        }) : ((_w$globals$columnSeri = w.globals.columnSeries) === null || _w$globals$columnSeri === void 0 ? void 0 : _w$globals$columnSeri.i.map(function (_i) {
          return _i;
        })) || [];
        seriesIndices.forEach(function (_si) {
          var val = w.globals.seriesPercent[_si][j];
          if (val) {
            nonZeroColumns++;
          }
          if (_si < i && val === 0) {
            zeroEncounters++;
          }
        });
        return {
          nonZeroColumns: nonZeroColumns,
          zeroEncounters: zeroEncounters
        };
      }
    }, {
      key: "getGroupIndex",
      value: function getGroupIndex(seriesIndex) {
        var w = this.w;
        // groupIndex is the index of group buckets (group1, group2, ...)
        var groupIndex = w.globals.seriesGroups.findIndex(function (group) {
          return (
            // w.config.series[i].name may be undefined, so use
            // w.globals.seriesNames[i], which has default names for those
            // series. w.globals.seriesGroups[] uses the same default naming.
            group.indexOf(w.globals.seriesNames[seriesIndex]) > -1
          );
        });
        // We need the column groups to be indexable as 0,1,2,... for their
        // positioning relative to each other.
        var cGI = this.barCtx.columnGroupIndices;
        var columnGroupIndex = cGI.indexOf(groupIndex);
        if (columnGroupIndex < 0) {
          cGI.push(groupIndex);
          columnGroupIndex = cGI.length - 1;
        }
        return {
          groupIndex: groupIndex,
          columnGroupIndex: columnGroupIndex
        };
      }
    }]);
    return Helpers;
  }();

  /**
   * ApexCharts Bar Class responsible for drawing both Columns and Bars.
   *
   * @module Bar
   **/
  var Bar = /*#__PURE__*/function () {
    function Bar(ctx, xyRatios) {
      _classCallCheck(this, Bar);
      this.ctx = ctx;
      this.w = ctx.w;
      var w = this.w;
      this.barOptions = w.config.plotOptions.bar;
      this.isHorizontal = this.barOptions.horizontal;
      this.strokeWidth = w.config.stroke.width;
      this.isNullValue = false;
      this.isRangeBar = w.globals.seriesRange.length && this.isHorizontal;
      this.isVerticalGroupedRangeBar = !w.globals.isBarHorizontal && w.globals.seriesRange.length && w.config.plotOptions.bar.rangeBarGroupRows;
      this.isFunnel = this.barOptions.isFunnel;
      this.xyRatios = xyRatios;
      if (this.xyRatios !== null) {
        this.xRatio = xyRatios.xRatio;
        this.yRatio = xyRatios.yRatio;
        this.invertedXRatio = xyRatios.invertedXRatio;
        this.invertedYRatio = xyRatios.invertedYRatio;
        this.baseLineY = xyRatios.baseLineY;
        this.baseLineInvertedY = xyRatios.baseLineInvertedY;
      }
      this.yaxisIndex = 0;
      this.translationsIndex = 0;
      this.seriesLen = 0;
      this.pathArr = [];
      var ser = new Series(this.ctx);
      this.lastActiveBarSerieIndex = ser.getActiveConfigSeriesIndex('desc', ['bar', 'column']);
      this.columnGroupIndices = [];
      var barSeriesIndices = ser.getBarSeriesIndices();
      var coreUtils = new CoreUtils(this.ctx);
      this.stackedSeriesTotals = coreUtils.getStackedSeriesTotals(this.w.config.series.map(function (s, i) {
        return barSeriesIndices.indexOf(i) === -1 ? i : -1;
      }).filter(function (s) {
        return s !== -1;
      }));
      this.barHelpers = new Helpers$1(this);
    }

    /** primary draw method which is called on bar object
     * @memberof Bar
     * @param {array} series - user supplied series values
     * @param {int} seriesIndex - the index by which series will be drawn on the svg
     * @return {node} element which is supplied to parent chart draw method for appending
     **/
    _createClass(Bar, [{
      key: "draw",
      value: function draw(series, seriesIndex) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var coreUtils = new CoreUtils(this.ctx, w);
        series = coreUtils.getLogSeries(series);
        this.series = series;
        this.yRatio = coreUtils.getLogYRatios(this.yRatio);
        this.barHelpers.initVariables(series);
        var ret = graphics.group({
          class: 'apexcharts-bar-series apexcharts-plot-series'
        });
        if (w.config.dataLabels.enabled) {
          if (this.totalItems > this.barOptions.dataLabels.maxItems) {
            console.warn('WARNING: DataLabels are enabled but there are too many to display. This may cause performance issue when rendering - ApexCharts');
          }
        }
        for (var i = 0, bc = 0; i < series.length; i++, bc++) {
          var x = void 0,
            y = void 0,
            xDivision = void 0,
            // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
            yDivision = void 0,
            // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
            zeroH = void 0,
            // zeroH is the baseline where 0 meets y axis
            zeroW = void 0; // zeroW is the baseline where 0 meets x axis

          var yArrj = []; // hold y values of current iterating series
          var xArrj = []; // hold x values of current iterating series

          var realIndex = w.globals.comboCharts ? seriesIndex[i] : i;
          var _this$barHelpers$getG = this.barHelpers.getGroupIndex(realIndex),
            columnGroupIndex = _this$barHelpers$getG.columnGroupIndex;

          // el to which series will be drawn
          var elSeries = graphics.group({
            class: "apexcharts-series",
            rel: i + 1,
            seriesName: Utils$1.escapeString(w.globals.seriesNames[realIndex]),
            'data:realIndex': realIndex
          });
          this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex);
          if (series[i].length > 0) {
            this.visibleI = this.visibleI + 1;
          }
          var barHeight = 0;
          var barWidth = 0;
          if (this.yRatio.length > 1) {
            this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex];
            this.translationsIndex = realIndex;
          }
          var translationsIndex = this.translationsIndex;
          this.isReversed = w.config.yaxis[this.yaxisIndex] && w.config.yaxis[this.yaxisIndex].reversed;
          var initPositions = this.barHelpers.initialPositions();
          y = initPositions.y;
          barHeight = initPositions.barHeight;
          yDivision = initPositions.yDivision;
          zeroW = initPositions.zeroW;
          x = initPositions.x;
          barWidth = initPositions.barWidth;
          xDivision = initPositions.xDivision;
          zeroH = initPositions.zeroH;
          if (!this.horizontal) {
            xArrj.push(x + barWidth / 2);
          }

          // eldatalabels
          var elDataLabelsWrap = graphics.group({
            class: 'apexcharts-datalabels',
            'data:realIndex': realIndex
          });
          w.globals.delayedElements.push({
            el: elDataLabelsWrap.node
          });
          elDataLabelsWrap.node.classList.add('apexcharts-element-hidden');
          var elGoalsMarkers = graphics.group({
            class: 'apexcharts-bar-goals-markers'
          });
          var elBarShadows = graphics.group({
            class: 'apexcharts-bar-shadows'
          });
          w.globals.delayedElements.push({
            el: elBarShadows.node
          });
          elBarShadows.node.classList.add('apexcharts-element-hidden');
          for (var j = 0; j < series[i].length; j++) {
            var strokeWidth = this.barHelpers.getStrokeWidth(i, j, realIndex);
            var paths = null;
            var pathsParams = {
              indexes: {
                i: i,
                j: j,
                realIndex: realIndex,
                translationsIndex: translationsIndex,
                bc: bc
              },
              x: x,
              y: y,
              strokeWidth: strokeWidth,
              elSeries: elSeries
            };
            if (this.isHorizontal) {
              paths = this.drawBarPaths(_objectSpread2(_objectSpread2({}, pathsParams), {}, {
                barHeight: barHeight,
                zeroW: zeroW,
                yDivision: yDivision
              }));
              barWidth = this.series[i][j] / this.invertedYRatio;
            } else {
              paths = this.drawColumnPaths(_objectSpread2(_objectSpread2({}, pathsParams), {}, {
                xDivision: xDivision,
                barWidth: barWidth,
                zeroH: zeroH
              }));
              barHeight = this.series[i][j] / this.yRatio[translationsIndex];
            }
            var pathFill = this.barHelpers.getPathFillColor(series, i, j, realIndex);
            if (this.isFunnel && this.barOptions.isFunnel3d && this.pathArr.length && j > 0) {
              var barShadow = this.barHelpers.drawBarShadow({
                color: typeof pathFill === 'string' && (pathFill === null || pathFill === void 0 ? void 0 : pathFill.indexOf('url')) === -1 ? pathFill : Utils$1.hexToRgba(w.globals.colors[i]),
                prevPaths: this.pathArr[this.pathArr.length - 1],
                currPaths: paths
              });
              if (barShadow) {
                elBarShadows.add(barShadow);
              }
            }
            this.pathArr.push(paths);
            var barGoalLine = this.barHelpers.drawGoalLine({
              barXPosition: paths.barXPosition,
              barYPosition: paths.barYPosition,
              goalX: paths.goalX,
              goalY: paths.goalY,
              barHeight: barHeight,
              barWidth: barWidth
            });
            if (barGoalLine) {
              elGoalsMarkers.add(barGoalLine);
            }
            y = paths.y;
            x = paths.x;

            // push current X
            if (j > 0) {
              xArrj.push(x + barWidth / 2);
            }
            yArrj.push(y);
            this.renderSeries({
              realIndex: realIndex,
              pathFill: pathFill,
              j: j,
              i: i,
              columnGroupIndex: columnGroupIndex,
              pathFrom: paths.pathFrom,
              pathTo: paths.pathTo,
              strokeWidth: strokeWidth,
              elSeries: elSeries,
              x: x,
              y: y,
              series: series,
              barHeight: Math.abs(paths.barHeight ? paths.barHeight : barHeight),
              barWidth: Math.abs(paths.barWidth ? paths.barWidth : barWidth),
              elDataLabelsWrap: elDataLabelsWrap,
              elGoalsMarkers: elGoalsMarkers,
              elBarShadows: elBarShadows,
              visibleSeries: this.visibleI,
              type: 'bar'
            });
          }

          // push all x val arrays into main xArr
          w.globals.seriesXvalues[realIndex] = xArrj;
          w.globals.seriesYvalues[realIndex] = yArrj;
          ret.add(elSeries);
        }
        return ret;
      }
    }, {
      key: "renderSeries",
      value: function renderSeries(_ref) {
        var realIndex = _ref.realIndex,
          pathFill = _ref.pathFill,
          lineFill = _ref.lineFill,
          j = _ref.j,
          i = _ref.i,
          columnGroupIndex = _ref.columnGroupIndex,
          pathFrom = _ref.pathFrom,
          pathTo = _ref.pathTo,
          strokeWidth = _ref.strokeWidth,
          elSeries = _ref.elSeries,
          x = _ref.x,
          y = _ref.y,
          y1 = _ref.y1,
          y2 = _ref.y2,
          series = _ref.series,
          barHeight = _ref.barHeight,
          barWidth = _ref.barWidth,
          barXPosition = _ref.barXPosition,
          barYPosition = _ref.barYPosition,
          elDataLabelsWrap = _ref.elDataLabelsWrap,
          elGoalsMarkers = _ref.elGoalsMarkers,
          elBarShadows = _ref.elBarShadows,
          visibleSeries = _ref.visibleSeries,
          type = _ref.type,
          classes = _ref.classes;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        if (!lineFill) {
          // if user provided a function in colors, we need to eval here
          // Note: the position of this function logic (ex. stroke: { colors: ["",function(){}] }) i.e array index 1 depicts the realIndex/seriesIndex.
          var fetchColor = function fetchColor(i) {
            var exp = w.config.stroke.colors;
            var c;
            if (Array.isArray(exp) && exp.length > 0) {
              c = exp[i];
              if (!c) c = '';
              if (typeof c === 'function') {
                return c({
                  value: w.globals.series[i][j],
                  dataPointIndex: j,
                  w: w
                });
              }
            }
            return c;
          };
          var checkAvailableColor = typeof w.globals.stroke.colors[realIndex] === 'function' ? fetchColor(realIndex) : w.globals.stroke.colors[realIndex];

          /* fix apexcharts#341 */
          lineFill = this.barOptions.distributed ? w.globals.stroke.colors[j] : checkAvailableColor;
        }
        if (w.config.series[i].data[j] && w.config.series[i].data[j].strokeColor) {
          lineFill = w.config.series[i].data[j].strokeColor;
        }
        if (this.isNullValue) {
          pathFill = 'none';
        }
        var delay = j / w.config.chart.animations.animateGradually.delay * (w.config.chart.animations.speed / w.globals.dataPoints) / 2.4;
        var renderedPath = graphics.renderPaths({
          i: i,
          j: j,
          realIndex: realIndex,
          pathFrom: pathFrom,
          pathTo: pathTo,
          stroke: lineFill,
          strokeWidth: strokeWidth,
          strokeLineCap: w.config.stroke.lineCap,
          fill: pathFill,
          animationDelay: delay,
          initialSpeed: w.config.chart.animations.speed,
          dataChangeSpeed: w.config.chart.animations.dynamicAnimation.speed,
          className: "apexcharts-".concat(type, "-area ").concat(classes),
          chartType: type
        });
        renderedPath.attr('clip-path', "url(#gridRectBarMask".concat(w.globals.cuid, ")"));
        var forecast = w.config.forecastDataPoints;
        if (forecast.count > 0) {
          if (j >= w.globals.dataPoints - forecast.count) {
            renderedPath.node.setAttribute('stroke-dasharray', forecast.dashArray);
            renderedPath.node.setAttribute('stroke-width', forecast.strokeWidth);
            renderedPath.node.setAttribute('fill-opacity', forecast.fillOpacity);
          }
        }
        if (typeof y1 !== 'undefined' && typeof y2 !== 'undefined') {
          renderedPath.attr('data-range-y1', y1);
          renderedPath.attr('data-range-y2', y2);
        }
        var filters = new Filters(this.ctx);
        filters.setSelectionFilter(renderedPath, realIndex, j);
        elSeries.add(renderedPath);
        var barDataLabels = new BarDataLabels(this);
        var dataLabelsObj = barDataLabels.handleBarDataLabels({
          x: x,
          y: y,
          y1: y1,
          y2: y2,
          i: i,
          j: j,
          series: series,
          realIndex: realIndex,
          columnGroupIndex: columnGroupIndex,
          barHeight: barHeight,
          barWidth: barWidth,
          barXPosition: barXPosition,
          barYPosition: barYPosition,
          renderedPath: renderedPath,
          visibleSeries: visibleSeries
        });
        if (dataLabelsObj.dataLabels !== null) {
          elDataLabelsWrap.add(dataLabelsObj.dataLabels);
        }
        if (dataLabelsObj.totalDataLabels) {
          elDataLabelsWrap.add(dataLabelsObj.totalDataLabels);
        }
        elSeries.add(elDataLabelsWrap);
        if (elGoalsMarkers) {
          elSeries.add(elGoalsMarkers);
        }
        if (elBarShadows) {
          elSeries.add(elBarShadows);
        }
        return elSeries;
      }
    }, {
      key: "drawBarPaths",
      value: function drawBarPaths(_ref2) {
        var indexes = _ref2.indexes,
          barHeight = _ref2.barHeight,
          strokeWidth = _ref2.strokeWidth,
          zeroW = _ref2.zeroW,
          x = _ref2.x,
          y = _ref2.y,
          yDivision = _ref2.yDivision,
          elSeries = _ref2.elSeries;
        var w = this.w;
        var i = indexes.i;
        var j = indexes.j;
        var barYPosition;
        if (w.globals.isXNumeric) {
          y = (w.globals.seriesX[i][j] - w.globals.minX) / this.invertedXRatio - barHeight;
          barYPosition = y + barHeight * this.visibleI;
        } else {
          if (w.config.plotOptions.bar.hideZeroBarsWhenGrouped) {
            var nonZeroColumns = 0;
            var zeroEncounters = 0;
            w.globals.seriesPercent.forEach(function (_s, _si) {
              if (_s[j]) {
                nonZeroColumns++;
              }
              if (_si < i && _s[j] === 0) {
                zeroEncounters++;
              }
            });
            if (nonZeroColumns > 0) {
              barHeight = this.seriesLen * barHeight / nonZeroColumns;
            }
            barYPosition = y + barHeight * this.visibleI;
            barYPosition -= barHeight * zeroEncounters;
          } else {
            barYPosition = y + barHeight * this.visibleI;
          }
        }
        if (this.isFunnel) {
          zeroW = zeroW - (this.barHelpers.getXForValue(this.series[i][j], zeroW) - zeroW) / 2;
        }
        x = this.barHelpers.getXForValue(this.series[i][j], zeroW);
        var paths = this.barHelpers.getBarpaths({
          barYPosition: barYPosition,
          barHeight: barHeight,
          x1: zeroW,
          x2: x,
          strokeWidth: strokeWidth,
          isReversed: this.isReversed,
          series: this.series,
          realIndex: indexes.realIndex,
          i: i,
          j: j,
          w: w
        });
        if (!w.globals.isXNumeric) {
          y = y + yDivision;
        }
        this.barHelpers.barBackground({
          j: j,
          i: i,
          y1: barYPosition - barHeight * this.visibleI,
          y2: barHeight * this.seriesLen,
          elSeries: elSeries
        });
        return {
          pathTo: paths.pathTo,
          pathFrom: paths.pathFrom,
          x1: zeroW,
          x: x,
          y: y,
          goalX: this.barHelpers.getGoalValues('x', zeroW, null, i, j),
          barYPosition: barYPosition,
          barHeight: barHeight
        };
      }
    }, {
      key: "drawColumnPaths",
      value: function drawColumnPaths(_ref3) {
        var indexes = _ref3.indexes,
          x = _ref3.x,
          y = _ref3.y,
          xDivision = _ref3.xDivision,
          barWidth = _ref3.barWidth,
          zeroH = _ref3.zeroH,
          strokeWidth = _ref3.strokeWidth,
          elSeries = _ref3.elSeries;
        var w = this.w;
        var realIndex = indexes.realIndex;
        var translationsIndex = indexes.translationsIndex;
        var i = indexes.i;
        var j = indexes.j;
        var bc = indexes.bc;
        var barXPosition;
        if (w.globals.isXNumeric) {
          var xForNumericX = this.getBarXForNumericXAxis({
            x: x,
            j: j,
            realIndex: realIndex,
            barWidth: barWidth
          });
          x = xForNumericX.x;
          barXPosition = xForNumericX.barXPosition;
        } else {
          if (w.config.plotOptions.bar.hideZeroBarsWhenGrouped) {
            var _this$barHelpers$getZ = this.barHelpers.getZeroValueEncounters({
                i: i,
                j: j
              }),
              nonZeroColumns = _this$barHelpers$getZ.nonZeroColumns,
              zeroEncounters = _this$barHelpers$getZ.zeroEncounters;
            if (nonZeroColumns > 0) {
              barWidth = this.seriesLen * barWidth / nonZeroColumns;
            }
            barXPosition = x + barWidth * this.visibleI;
            barXPosition -= barWidth * zeroEncounters;
          } else {
            barXPosition = x + barWidth * this.visibleI;
          }
        }
        y = this.barHelpers.getYForValue(this.series[i][j], zeroH, translationsIndex);
        var paths = this.barHelpers.getColumnPaths({
          barXPosition: barXPosition,
          barWidth: barWidth,
          y1: zeroH,
          y2: y,
          strokeWidth: strokeWidth,
          isReversed: this.isReversed,
          series: this.series,
          realIndex: realIndex,
          i: i,
          j: j,
          w: w
        });
        if (!w.globals.isXNumeric) {
          x = x + xDivision;
        }
        this.barHelpers.barBackground({
          bc: bc,
          j: j,
          i: i,
          x1: barXPosition - strokeWidth / 2 - barWidth * this.visibleI,
          x2: barWidth * this.seriesLen + strokeWidth / 2,
          elSeries: elSeries
        });
        return {
          pathTo: paths.pathTo,
          pathFrom: paths.pathFrom,
          x: x,
          y: y,
          goalY: this.barHelpers.getGoalValues('y', null, zeroH, i, j, translationsIndex),
          barXPosition: barXPosition,
          barWidth: barWidth
        };
      }
    }, {
      key: "getBarXForNumericXAxis",
      value: function getBarXForNumericXAxis(_ref4) {
        var x = _ref4.x,
          barWidth = _ref4.barWidth,
          realIndex = _ref4.realIndex,
          j = _ref4.j;
        var w = this.w;
        var sxI = realIndex;
        if (!w.globals.seriesX[realIndex].length) {
          sxI = w.globals.maxValsInArrayIndex;
        }
        if (w.globals.seriesX[sxI][j]) {
          x = (w.globals.seriesX[sxI][j] - w.globals.minX) / this.xRatio - barWidth * this.seriesLen / 2;
        }
        return {
          barXPosition: x + barWidth * this.visibleI,
          x: x
        };
      }

      /** getPreviousPath is a common function for bars/columns which is used to get previous paths when data changes.
       * @memberof Bar
       * @param {int} realIndex - current iterating i
       * @param {int} j - current iterating series's j index
       * @return {string} pathFrom is the string which will be appended in animations
       **/
    }, {
      key: "getPreviousPath",
      value: function getPreviousPath(realIndex, j) {
        var w = this.w;
        var pathFrom;
        for (var pp = 0; pp < w.globals.previousPaths.length; pp++) {
          var gpp = w.globals.previousPaths[pp];
          if (gpp.paths && gpp.paths.length > 0 && parseInt(gpp.realIndex, 10) === parseInt(realIndex, 10)) {
            if (typeof w.globals.previousPaths[pp].paths[j] !== 'undefined') {
              pathFrom = w.globals.previousPaths[pp].paths[j].d;
            }
          }
        }
        return pathFrom;
      }
    }]);
    return Bar;
  }();

  /**
   * ApexCharts BarStacked Class responsible for drawing both Stacked Columns and Bars.
   *
   * @module BarStacked
   * The whole calculation for stacked bar/column is different from normal bar/column,
   * hence it makes sense to derive a new class for it extending most of the props of Parent Bar
   **/
  var BarStacked = /*#__PURE__*/function (_Bar) {
    _inherits(BarStacked, _Bar);
    var _super = _createSuper(BarStacked);
    function BarStacked() {
      _classCallCheck(this, BarStacked);
      return _super.apply(this, arguments);
    }
    _createClass(BarStacked, [{
      key: "draw",
      value: function draw(series, seriesIndex) {
        var _this = this;
        var w = this.w;
        this.graphics = new Graphics(this.ctx);
        this.bar = new Bar(this.ctx, this.xyRatios);
        var coreUtils = new CoreUtils(this.ctx, w);
        series = coreUtils.getLogSeries(series);
        this.yRatio = coreUtils.getLogYRatios(this.yRatio);
        this.barHelpers.initVariables(series);
        if (w.config.chart.stackType === '100%') {
          series = w.globals.comboCharts ? seriesIndex.map(function (_) {
            return w.globals.seriesPercent[_];
          }) : w.globals.seriesPercent.slice();
        }
        this.series = series;
        this.barHelpers.initializeStackedPrevVars(this);
        var ret = this.graphics.group({
          class: 'apexcharts-bar-series apexcharts-plot-series'
        });
        var x = 0;
        var y = 0;
        var _loop = function _loop(i, bc) {
          var xDivision = void 0; // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
          var yDivision = void 0; // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
          var zeroH = void 0; // zeroH is the baseline where 0 meets y axis
          var zeroW = void 0; // zeroW is the baseline where 0 meets x axis

          var realIndex = w.globals.comboCharts ? seriesIndex[i] : i;
          var _this$barHelpers$getG = _this.barHelpers.getGroupIndex(realIndex),
            groupIndex = _this$barHelpers$getG.groupIndex,
            columnGroupIndex = _this$barHelpers$getG.columnGroupIndex;
          _this.groupCtx = _this[w.globals.seriesGroups[groupIndex]];
          var xArrValues = [];
          var yArrValues = [];
          var translationsIndex = 0;
          if (_this.yRatio.length > 1) {
            _this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex][0];
            translationsIndex = realIndex;
          }
          _this.isReversed = w.config.yaxis[_this.yaxisIndex] && w.config.yaxis[_this.yaxisIndex].reversed;

          // el to which series will be drawn
          var elSeries = _this.graphics.group({
            class: "apexcharts-series",
            seriesName: Utils$1.escapeString(w.globals.seriesNames[realIndex]),
            rel: i + 1,
            'data:realIndex': realIndex
          });
          _this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex);

          // eldatalabels
          var elDataLabelsWrap = _this.graphics.group({
            class: 'apexcharts-datalabels',
            'data:realIndex': realIndex
          });
          var elGoalsMarkers = _this.graphics.group({
            class: 'apexcharts-bar-goals-markers'
          });
          var barHeight = 0;
          var barWidth = 0;
          var initPositions = _this.initialPositions(x, y, xDivision, yDivision, zeroH, zeroW, translationsIndex);
          y = initPositions.y;
          barHeight = initPositions.barHeight;
          yDivision = initPositions.yDivision;
          zeroW = initPositions.zeroW;
          x = initPositions.x;
          barWidth = initPositions.barWidth;
          xDivision = initPositions.xDivision;
          zeroH = initPositions.zeroH;
          w.globals.barHeight = barHeight;
          w.globals.barWidth = barWidth;
          _this.barHelpers.initializeStackedXYVars(_this);

          // where all stack bar disappear after collapsing the first series
          if (_this.groupCtx.prevY.length === 1 && _this.groupCtx.prevY[0].every(function (val) {
            return isNaN(val);
          })) {
            _this.groupCtx.prevY[0] = _this.groupCtx.prevY[0].map(function () {
              return zeroH;
            });
            _this.groupCtx.prevYF[0] = _this.groupCtx.prevYF[0].map(function () {
              return 0;
            });
          }
          for (var j = 0; j < w.globals.dataPoints; j++) {
            var strokeWidth = _this.barHelpers.getStrokeWidth(i, j, realIndex);
            var commonPathOpts = {
              indexes: {
                i: i,
                j: j,
                realIndex: realIndex,
                translationsIndex: translationsIndex,
                bc: bc
              },
              strokeWidth: strokeWidth,
              x: x,
              y: y,
              elSeries: elSeries,
              columnGroupIndex: columnGroupIndex,
              seriesGroup: w.globals.seriesGroups[groupIndex]
            };
            var paths = null;
            if (_this.isHorizontal) {
              paths = _this.drawStackedBarPaths(_objectSpread2(_objectSpread2({}, commonPathOpts), {}, {
                zeroW: zeroW,
                barHeight: barHeight,
                yDivision: yDivision
              }));
              barWidth = _this.series[i][j] / _this.invertedYRatio;
            } else {
              paths = _this.drawStackedColumnPaths(_objectSpread2(_objectSpread2({}, commonPathOpts), {}, {
                xDivision: xDivision,
                barWidth: barWidth,
                zeroH: zeroH
              }));
              barHeight = _this.series[i][j] / _this.yRatio[translationsIndex];
            }
            var barGoalLine = _this.barHelpers.drawGoalLine({
              barXPosition: paths.barXPosition,
              barYPosition: paths.barYPosition,
              goalX: paths.goalX,
              goalY: paths.goalY,
              barHeight: barHeight,
              barWidth: barWidth
            });
            if (barGoalLine) {
              elGoalsMarkers.add(barGoalLine);
            }
            y = paths.y;
            x = paths.x;
            xArrValues.push(x);
            yArrValues.push(y);
            var pathFill = _this.barHelpers.getPathFillColor(series, i, j, realIndex);
            var classes = '';
            if (w.globals.isBarHorizontal) {
              if (_this.barHelpers.arrBorderRadius[realIndex][j] === 'bottom' && w.globals.series[realIndex][j] > 0) {
                classes = 'apexcharts-flip-x';
              }
            } else {
              if (_this.barHelpers.arrBorderRadius[realIndex][j] === 'bottom' && w.globals.series[realIndex][j] > 0) {
                classes = 'apexcharts-flip-y';
              }
            }
            elSeries = _this.renderSeries({
              realIndex: realIndex,
              pathFill: pathFill,
              j: j,
              i: i,
              columnGroupIndex: columnGroupIndex,
              pathFrom: paths.pathFrom,
              pathTo: paths.pathTo,
              strokeWidth: strokeWidth,
              elSeries: elSeries,
              x: x,
              y: y,
              series: series,
              barHeight: barHeight,
              barWidth: barWidth,
              elDataLabelsWrap: elDataLabelsWrap,
              elGoalsMarkers: elGoalsMarkers,
              type: 'bar',
              visibleSeries: columnGroupIndex,
              classes: classes
            });
          }

          // push all x val arrays into main xArr
          w.globals.seriesXvalues[realIndex] = xArrValues;
          w.globals.seriesYvalues[realIndex] = yArrValues;

          // push all current y values array to main PrevY Array
          _this.groupCtx.prevY.push(_this.groupCtx.yArrj);
          _this.groupCtx.prevYF.push(_this.groupCtx.yArrjF);
          _this.groupCtx.prevYVal.push(_this.groupCtx.yArrjVal);
          _this.groupCtx.prevX.push(_this.groupCtx.xArrj);
          _this.groupCtx.prevXF.push(_this.groupCtx.xArrjF);
          _this.groupCtx.prevXVal.push(_this.groupCtx.xArrjVal);
          ret.add(elSeries);
        };
        for (var i = 0, bc = 0; i < series.length; i++, bc++) {
          _loop(i, bc);
        }
        return ret;
      }
    }, {
      key: "initialPositions",
      value: function initialPositions(x, y, xDivision, yDivision, zeroH, zeroW, translationsIndex) {
        var w = this.w;
        var barHeight, barWidth;
        if (this.isHorizontal) {
          // height divided into equal parts
          yDivision = w.globals.gridHeight / w.globals.dataPoints;
          var userBarHeight = w.config.plotOptions.bar.barHeight;
          if (String(userBarHeight).indexOf('%') === -1) {
            barHeight = parseInt(userBarHeight, 10);
          } else {
            barHeight = yDivision * parseInt(userBarHeight, 10) / 100;
          }
          zeroW = w.globals.padHorizontal + (this.isReversed ? w.globals.gridWidth - this.baseLineInvertedY : this.baseLineInvertedY);

          // initial y position is half of barHeight * half of number of Bars
          y = (yDivision - barHeight) / 2;
        } else {
          // width divided into equal parts
          xDivision = w.globals.gridWidth / w.globals.dataPoints;
          barWidth = xDivision;
          var userColumnWidth = w.config.plotOptions.bar.columnWidth;
          if (w.globals.isXNumeric && w.globals.dataPoints > 1) {
            xDivision = w.globals.minXDiff / this.xRatio;
            barWidth = xDivision * parseInt(this.barOptions.columnWidth, 10) / 100;
          } else if (String(userColumnWidth).indexOf('%') === -1) {
            barWidth = parseInt(userColumnWidth, 10);
          } else {
            barWidth *= parseInt(userColumnWidth, 10) / 100;
          }
          if (this.isReversed) {
            zeroH = this.baseLineY[translationsIndex];
          } else {
            zeroH = w.globals.gridHeight - this.baseLineY[translationsIndex];
          }

          // initial x position is the left-most edge of the first bar relative to
          // the left-most side of the grid area.
          x = w.globals.padHorizontal + (xDivision - barWidth) / 2;
        }

        // Up to this point, barWidth is the width that will accommodate all bars
        // at each datapoint or category.

        // The crude subdivision here assumes the series within each group are
        // stacked. If there is no stacking then the barWidth/barHeight is
        // further divided later by the number of series in the group. So, eg, two
        // groups of three series would become six bars side-by-side unstacked,
        // or two bars stacked.
        var subDivisions = w.globals.barGroups.length || 1;
        return {
          x: x,
          y: y,
          yDivision: yDivision,
          xDivision: xDivision,
          barHeight: barHeight / subDivisions,
          barWidth: barWidth / subDivisions,
          zeroH: zeroH,
          zeroW: zeroW
        };
      }
    }, {
      key: "drawStackedBarPaths",
      value: function drawStackedBarPaths(_ref) {
        var indexes = _ref.indexes,
          barHeight = _ref.barHeight,
          strokeWidth = _ref.strokeWidth,
          zeroW = _ref.zeroW,
          x = _ref.x,
          y = _ref.y,
          columnGroupIndex = _ref.columnGroupIndex,
          seriesGroup = _ref.seriesGroup,
          yDivision = _ref.yDivision,
          elSeries = _ref.elSeries;
        var w = this.w;
        var barYPosition = y + columnGroupIndex * barHeight;
        var barXPosition;
        var i = indexes.i;
        var j = indexes.j;
        var realIndex = indexes.realIndex;
        var translationsIndex = indexes.translationsIndex;
        var prevBarW = 0;
        for (var k = 0; k < this.groupCtx.prevXF.length; k++) {
          prevBarW = prevBarW + this.groupCtx.prevXF[k][j];
        }
        var gsi = i; // an index to keep track of the series inside a group
        gsi = seriesGroup.indexOf(w.config.series[realIndex].name);
        if (gsi > 0) {
          var bXP = zeroW;
          if (this.groupCtx.prevXVal[gsi - 1][j] < 0) {
            bXP = this.series[i][j] >= 0 ? this.groupCtx.prevX[gsi - 1][j] + prevBarW - (this.isReversed ? prevBarW : 0) * 2 : this.groupCtx.prevX[gsi - 1][j];
          } else if (this.groupCtx.prevXVal[gsi - 1][j] >= 0) {
            bXP = this.series[i][j] >= 0 ? this.groupCtx.prevX[gsi - 1][j] : this.groupCtx.prevX[gsi - 1][j] - prevBarW + (this.isReversed ? prevBarW : 0) * 2;
          }
          barXPosition = bXP;
        } else {
          // the first series will not have prevX values
          barXPosition = zeroW;
        }
        if (this.series[i][j] === null) {
          x = barXPosition;
        } else {
          x = barXPosition + this.series[i][j] / this.invertedYRatio - (this.isReversed ? this.series[i][j] / this.invertedYRatio : 0) * 2;
        }
        var paths = this.barHelpers.getBarpaths({
          barYPosition: barYPosition,
          barHeight: barHeight,
          x1: barXPosition,
          x2: x,
          strokeWidth: strokeWidth,
          isReversed: this.isReversed,
          series: this.series,
          realIndex: indexes.realIndex,
          seriesGroup: seriesGroup,
          i: i,
          j: j,
          w: w
        });
        this.barHelpers.barBackground({
          j: j,
          i: i,
          y1: barYPosition,
          y2: barHeight,
          elSeries: elSeries
        });
        y = y + yDivision;
        return {
          pathTo: paths.pathTo,
          pathFrom: paths.pathFrom,
          goalX: this.barHelpers.getGoalValues('x', zeroW, null, i, j, translationsIndex),
          barXPosition: barXPosition,
          barYPosition: barYPosition,
          x: x,
          y: y
        };
      }
    }, {
      key: "drawStackedColumnPaths",
      value: function drawStackedColumnPaths(_ref2) {
        var indexes = _ref2.indexes,
          x = _ref2.x,
          y = _ref2.y,
          xDivision = _ref2.xDivision,
          barWidth = _ref2.barWidth,
          zeroH = _ref2.zeroH,
          columnGroupIndex = _ref2.columnGroupIndex,
          seriesGroup = _ref2.seriesGroup,
          elSeries = _ref2.elSeries;
        var w = this.w;
        var i = indexes.i;
        var j = indexes.j;
        var bc = indexes.bc;
        var realIndex = indexes.realIndex;
        var translationsIndex = indexes.translationsIndex;
        if (w.globals.isXNumeric) {
          var seriesVal = w.globals.seriesX[realIndex][j];
          if (!seriesVal) seriesVal = 0;
          // TODO: move the barWidth factor to barXPosition
          x = (seriesVal - w.globals.minX) / this.xRatio - barWidth / 2 * w.globals.barGroups.length;
        }
        var barXPosition = x + columnGroupIndex * barWidth;
        var barYPosition;
        var prevBarH = 0;
        for (var k = 0; k < this.groupCtx.prevYF.length; k++) {
          // fix issue #1215
          // in case where this.groupCtx.prevYF[k][j] is NaN, use 0 instead
          prevBarH = prevBarH + (!isNaN(this.groupCtx.prevYF[k][j]) ? this.groupCtx.prevYF[k][j] : 0);
        }
        var gsi = i; // an index to keep track of the series inside a group
        if (seriesGroup) {
          gsi = seriesGroup.indexOf(w.globals.seriesNames[realIndex]);
        }
        if (gsi > 0 && !w.globals.isXNumeric || gsi > 0 && w.globals.isXNumeric && w.globals.seriesX[realIndex - 1][j] === w.globals.seriesX[realIndex][j]) {
          var _this$groupCtx$prevYF;
          var bYP;
          var prevYValue;
          var p = Math.min(this.yRatio.length + 1, realIndex + 1);
          if (this.groupCtx.prevY[gsi - 1] !== undefined && this.groupCtx.prevY[gsi - 1].length) {
            for (var ii = 1; ii < p; ii++) {
              var _this$groupCtx$prevY;
              if (!isNaN((_this$groupCtx$prevY = this.groupCtx.prevY[gsi - ii]) === null || _this$groupCtx$prevY === void 0 ? void 0 : _this$groupCtx$prevY[j])) {
                // find the previous available value to give prevYValue
                prevYValue = this.groupCtx.prevY[gsi - ii][j];
                // if found it, break the loop
                break;
              }
            }
          }
          for (var _ii = 1; _ii < p; _ii++) {
            var _this$groupCtx$prevYV, _this$groupCtx$prevYV2;
            // find the previous available value(non-NaN) to give bYP
            if (((_this$groupCtx$prevYV = this.groupCtx.prevYVal[gsi - _ii]) === null || _this$groupCtx$prevYV === void 0 ? void 0 : _this$groupCtx$prevYV[j]) < 0) {
              bYP = this.series[i][j] >= 0 ? prevYValue - prevBarH + (this.isReversed ? prevBarH : 0) * 2 : prevYValue;
              // found it? break the loop
              break;
            } else if (((_this$groupCtx$prevYV2 = this.groupCtx.prevYVal[gsi - _ii]) === null || _this$groupCtx$prevYV2 === void 0 ? void 0 : _this$groupCtx$prevYV2[j]) >= 0) {
              bYP = this.series[i][j] >= 0 ? prevYValue : prevYValue + prevBarH - (this.isReversed ? prevBarH : 0) * 2;
              // found it? break the loop
              break;
            }
          }
          if (typeof bYP === 'undefined') bYP = w.globals.gridHeight;

          // if this.prevYF[0] is all 0 resulted from line #486
          // AND every arr starting from the second only contains NaN
          if ((_this$groupCtx$prevYF = this.groupCtx.prevYF[0]) !== null && _this$groupCtx$prevYF !== void 0 && _this$groupCtx$prevYF.every(function (val) {
            return val === 0;
          }) && this.groupCtx.prevYF.slice(1, gsi).every(function (arr) {
            return arr.every(function (val) {
              return isNaN(val);
            });
          })) {
            barYPosition = zeroH;
          } else {
            // Nothing special
            barYPosition = bYP;
          }
        } else {
          // the first series will not have prevY values, also if the prev index's
          // series X doesn't matches the current index's series X, then start from
          // zero
          barYPosition = zeroH;
        }
        if (this.series[i][j]) {
          y = barYPosition - this.series[i][j] / this.yRatio[translationsIndex] + (this.isReversed ? this.series[i][j] / this.yRatio[translationsIndex] : 0) * 2;
        } else {
          // fixes #3610
          y = barYPosition;
        }
        var paths = this.barHelpers.getColumnPaths({
          barXPosition: barXPosition,
          barWidth: barWidth,
          y1: barYPosition,
          y2: y,
          yRatio: this.yRatio[translationsIndex],
          strokeWidth: this.strokeWidth,
          isReversed: this.isReversed,
          series: this.series,
          seriesGroup: seriesGroup,
          realIndex: indexes.realIndex,
          i: i,
          j: j,
          w: w
        });
        this.barHelpers.barBackground({
          bc: bc,
          j: j,
          i: i,
          x1: barXPosition,
          x2: barWidth,
          elSeries: elSeries
        });
        return {
          pathTo: paths.pathTo,
          pathFrom: paths.pathFrom,
          goalY: this.barHelpers.getGoalValues('y', null, zeroH, i, j),
          barXPosition: barXPosition,
          x: w.globals.isXNumeric ? x : x + xDivision,
          y: y
        };
      }
    }]);
    return BarStacked;
  }(Bar);

  /**
   * ApexCharts BoxCandleStick Class responsible for drawing both Stacked Columns and Bars.
   *
   * @module BoxCandleStick
   **/
  var BoxCandleStick = /*#__PURE__*/function (_Bar) {
    _inherits(BoxCandleStick, _Bar);
    var _super = _createSuper(BoxCandleStick);
    function BoxCandleStick() {
      _classCallCheck(this, BoxCandleStick);
      return _super.apply(this, arguments);
    }
    _createClass(BoxCandleStick, [{
      key: "draw",
      value: function draw(series, ctype, seriesIndex) {
        var _this = this;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var type = w.globals.comboCharts ? ctype : w.config.chart.type;
        var fill = new Fill(this.ctx);
        this.candlestickOptions = this.w.config.plotOptions.candlestick;
        this.boxOptions = this.w.config.plotOptions.boxPlot;
        this.isHorizontal = w.config.plotOptions.bar.horizontal;
        var coreUtils = new CoreUtils(this.ctx, w);
        series = coreUtils.getLogSeries(series);
        this.series = series;
        this.yRatio = coreUtils.getLogYRatios(this.yRatio);
        this.barHelpers.initVariables(series);
        var ret = graphics.group({
          class: "apexcharts-".concat(type, "-series apexcharts-plot-series")
        });
        var _loop = function _loop(i) {
          _this.isBoxPlot = w.config.chart.type === 'boxPlot' || w.config.series[i].type === 'boxPlot';
          var x = void 0,
            y = void 0,
            xDivision = void 0,
            // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
            yDivision = void 0,
            // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
            zeroH = void 0,
            // zeroH is the baseline where 0 meets y axis
            zeroW = void 0; // zeroW is the baseline where 0 meets x axis

          var yArrj = []; // hold y values of current iterating series
          var xArrj = []; // hold x values of current iterating series

          var realIndex = w.globals.comboCharts ? seriesIndex[i] : i;
          // As BoxCandleStick derives from Bar, we need this to render.
          var _this$barHelpers$getG = _this.barHelpers.getGroupIndex(realIndex),
            columnGroupIndex = _this$barHelpers$getG.columnGroupIndex;

          // el to which series will be drawn
          var elSeries = graphics.group({
            class: "apexcharts-series",
            seriesName: Utils$1.escapeString(w.globals.seriesNames[realIndex]),
            rel: i + 1,
            'data:realIndex': realIndex
          });
          _this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex);
          if (series[i].length > 0) {
            _this.visibleI = _this.visibleI + 1;
          }
          var barHeight = 0;
          var barWidth = 0;
          var translationsIndex = 0;
          if (_this.yRatio.length > 1) {
            _this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex][0];
            translationsIndex = realIndex;
          }
          var initPositions = _this.barHelpers.initialPositions();
          y = initPositions.y;
          barHeight = initPositions.barHeight;
          yDivision = initPositions.yDivision;
          zeroW = initPositions.zeroW;
          x = initPositions.x;
          barWidth = initPositions.barWidth;
          xDivision = initPositions.xDivision;
          zeroH = initPositions.zeroH;
          xArrj.push(x + barWidth / 2);

          // eldatalabels
          var elDataLabelsWrap = graphics.group({
            class: 'apexcharts-datalabels',
            'data:realIndex': realIndex
          });
          var _loop2 = function _loop2(j) {
            var strokeWidth = _this.barHelpers.getStrokeWidth(i, j, realIndex);
            var paths = null;
            var pathsParams = {
              indexes: {
                i: i,
                j: j,
                realIndex: realIndex,
                translationsIndex: translationsIndex
              },
              x: x,
              y: y,
              strokeWidth: strokeWidth,
              elSeries: elSeries
            };
            if (_this.isHorizontal) {
              paths = _this.drawHorizontalBoxPaths(_objectSpread2(_objectSpread2({}, pathsParams), {}, {
                yDivision: yDivision,
                barHeight: barHeight,
                zeroW: zeroW
              }));
            } else {
              paths = _this.drawVerticalBoxPaths(_objectSpread2(_objectSpread2({}, pathsParams), {}, {
                xDivision: xDivision,
                barWidth: barWidth,
                zeroH: zeroH
              }));
            }
            y = paths.y;
            x = paths.x;

            // push current X
            if (j > 0) {
              xArrj.push(x + barWidth / 2);
            }
            yArrj.push(y);
            paths.pathTo.forEach(function (pathTo, pi) {
              var lineFill = !_this.isBoxPlot && _this.candlestickOptions.wick.useFillColor ? paths.color[pi] : w.globals.stroke.colors[i];
              var pathFill = fill.fillPath({
                seriesNumber: realIndex,
                dataPointIndex: j,
                color: paths.color[pi],
                value: series[i][j]
              });
              _this.renderSeries({
                realIndex: realIndex,
                pathFill: pathFill,
                lineFill: lineFill,
                j: j,
                i: i,
                pathFrom: paths.pathFrom,
                pathTo: pathTo,
                strokeWidth: strokeWidth,
                elSeries: elSeries,
                x: x,
                y: y,
                series: series,
                columnGroupIndex: columnGroupIndex,
                barHeight: barHeight,
                barWidth: barWidth,
                elDataLabelsWrap: elDataLabelsWrap,
                visibleSeries: _this.visibleI,
                type: w.config.chart.type
              });
            });
          };
          for (var j = 0; j < w.globals.dataPoints; j++) {
            _loop2(j);
          }

          // push all x val arrays into main xArr
          w.globals.seriesXvalues[realIndex] = xArrj;
          w.globals.seriesYvalues[realIndex] = yArrj;
          ret.add(elSeries);
        };
        for (var i = 0; i < series.length; i++) {
          _loop(i);
        }
        return ret;
      }
    }, {
      key: "drawVerticalBoxPaths",
      value: function drawVerticalBoxPaths(_ref) {
        var indexes = _ref.indexes,
          x = _ref.x;
          _ref.y;
          var xDivision = _ref.xDivision,
          barWidth = _ref.barWidth,
          zeroH = _ref.zeroH,
          strokeWidth = _ref.strokeWidth;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var i = indexes.i;
        var j = indexes.j;
        var isPositive = true;
        var colorPos = w.config.plotOptions.candlestick.colors.upward;
        var colorNeg = w.config.plotOptions.candlestick.colors.downward;
        var color = '';
        if (this.isBoxPlot) {
          color = [this.boxOptions.colors.lower, this.boxOptions.colors.upper];
        }
        var yRatio = this.yRatio[indexes.translationsIndex];
        var realIndex = indexes.realIndex;
        var ohlc = this.getOHLCValue(realIndex, j);
        var l1 = zeroH;
        var l2 = zeroH;
        if (ohlc.o > ohlc.c) {
          isPositive = false;
        }
        var y1 = Math.min(ohlc.o, ohlc.c);
        var y2 = Math.max(ohlc.o, ohlc.c);
        var m = ohlc.m;
        if (w.globals.isXNumeric) {
          x = (w.globals.seriesX[realIndex][j] - w.globals.minX) / this.xRatio - barWidth / 2;
        }
        var barXPosition = x + barWidth * this.visibleI;
        if (typeof this.series[i][j] === 'undefined' || this.series[i][j] === null) {
          y1 = zeroH;
          y2 = zeroH;
        } else {
          y1 = zeroH - y1 / yRatio;
          y2 = zeroH - y2 / yRatio;
          l1 = zeroH - ohlc.h / yRatio;
          l2 = zeroH - ohlc.l / yRatio;
          m = zeroH - ohlc.m / yRatio;
        }
        var pathTo = graphics.move(barXPosition, zeroH);
        var pathFrom = graphics.move(barXPosition + barWidth / 2, y1);
        if (w.globals.previousPaths.length > 0) {
          pathFrom = this.getPreviousPath(realIndex, j, true);
        }
        if (this.isBoxPlot) {
          pathTo = [graphics.move(barXPosition, y1) + graphics.line(barXPosition + barWidth / 2, y1) + graphics.line(barXPosition + barWidth / 2, l1) + graphics.line(barXPosition + barWidth / 4, l1) + graphics.line(barXPosition + barWidth - barWidth / 4, l1) + graphics.line(barXPosition + barWidth / 2, l1) + graphics.line(barXPosition + barWidth / 2, y1) + graphics.line(barXPosition + barWidth, y1) + graphics.line(barXPosition + barWidth, m) + graphics.line(barXPosition, m) + graphics.line(barXPosition, y1 + strokeWidth / 2), graphics.move(barXPosition, m) + graphics.line(barXPosition + barWidth, m) + graphics.line(barXPosition + barWidth, y2) + graphics.line(barXPosition + barWidth / 2, y2) + graphics.line(barXPosition + barWidth / 2, l2) + graphics.line(barXPosition + barWidth - barWidth / 4, l2) + graphics.line(barXPosition + barWidth / 4, l2) + graphics.line(barXPosition + barWidth / 2, l2) + graphics.line(barXPosition + barWidth / 2, y2) + graphics.line(barXPosition, y2) + graphics.line(barXPosition, m) + 'z'];
        } else {
          // candlestick
          pathTo = [graphics.move(barXPosition, y2) + graphics.line(barXPosition + barWidth / 2, y2) + graphics.line(barXPosition + barWidth / 2, l1) + graphics.line(barXPosition + barWidth / 2, y2) + graphics.line(barXPosition + barWidth, y2) + graphics.line(barXPosition + barWidth, y1) + graphics.line(barXPosition + barWidth / 2, y1) + graphics.line(barXPosition + barWidth / 2, l2) + graphics.line(barXPosition + barWidth / 2, y1) + graphics.line(barXPosition, y1) + graphics.line(barXPosition, y2 - strokeWidth / 2)];
        }
        pathFrom = pathFrom + graphics.move(barXPosition, y1);
        if (!w.globals.isXNumeric) {
          x = x + xDivision;
        }
        return {
          pathTo: pathTo,
          pathFrom: pathFrom,
          x: x,
          y: y2,
          barXPosition: barXPosition,
          color: this.isBoxPlot ? color : isPositive ? [colorPos] : [colorNeg]
        };
      }
    }, {
      key: "drawHorizontalBoxPaths",
      value: function drawHorizontalBoxPaths(_ref2) {
        var indexes = _ref2.indexes;
          _ref2.x;
          var y = _ref2.y,
          yDivision = _ref2.yDivision,
          barHeight = _ref2.barHeight,
          zeroW = _ref2.zeroW,
          strokeWidth = _ref2.strokeWidth;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var i = indexes.i;
        var j = indexes.j;
        var color = this.boxOptions.colors.lower;
        if (this.isBoxPlot) {
          color = [this.boxOptions.colors.lower, this.boxOptions.colors.upper];
        }
        var yRatio = this.invertedYRatio;
        var realIndex = indexes.realIndex;
        var ohlc = this.getOHLCValue(realIndex, j);
        var l1 = zeroW;
        var l2 = zeroW;
        var x1 = Math.min(ohlc.o, ohlc.c);
        var x2 = Math.max(ohlc.o, ohlc.c);
        var m = ohlc.m;
        if (w.globals.isXNumeric) {
          y = (w.globals.seriesX[realIndex][j] - w.globals.minX) / this.invertedXRatio - barHeight / 2;
        }
        var barYPosition = y + barHeight * this.visibleI;
        if (typeof this.series[i][j] === 'undefined' || this.series[i][j] === null) {
          x1 = zeroW;
          x2 = zeroW;
        } else {
          x1 = zeroW + x1 / yRatio;
          x2 = zeroW + x2 / yRatio;
          l1 = zeroW + ohlc.h / yRatio;
          l2 = zeroW + ohlc.l / yRatio;
          m = zeroW + ohlc.m / yRatio;
        }
        var pathTo = graphics.move(zeroW, barYPosition);
        var pathFrom = graphics.move(x1, barYPosition + barHeight / 2);
        if (w.globals.previousPaths.length > 0) {
          pathFrom = this.getPreviousPath(realIndex, j, true);
        }
        pathTo = [graphics.move(x1, barYPosition) + graphics.line(x1, barYPosition + barHeight / 2) + graphics.line(l1, barYPosition + barHeight / 2) + graphics.line(l1, barYPosition + barHeight / 2 - barHeight / 4) + graphics.line(l1, barYPosition + barHeight / 2 + barHeight / 4) + graphics.line(l1, barYPosition + barHeight / 2) + graphics.line(x1, barYPosition + barHeight / 2) + graphics.line(x1, barYPosition + barHeight) + graphics.line(m, barYPosition + barHeight) + graphics.line(m, barYPosition) + graphics.line(x1 + strokeWidth / 2, barYPosition), graphics.move(m, barYPosition) + graphics.line(m, barYPosition + barHeight) + graphics.line(x2, barYPosition + barHeight) + graphics.line(x2, barYPosition + barHeight / 2) + graphics.line(l2, barYPosition + barHeight / 2) + graphics.line(l2, barYPosition + barHeight - barHeight / 4) + graphics.line(l2, barYPosition + barHeight / 4) + graphics.line(l2, barYPosition + barHeight / 2) + graphics.line(x2, barYPosition + barHeight / 2) + graphics.line(x2, barYPosition) + graphics.line(m, barYPosition) + 'z'];
        pathFrom = pathFrom + graphics.move(x1, barYPosition);
        if (!w.globals.isXNumeric) {
          y = y + yDivision;
        }
        return {
          pathTo: pathTo,
          pathFrom: pathFrom,
          x: x2,
          y: y,
          barYPosition: barYPosition,
          color: color
        };
      }
    }, {
      key: "getOHLCValue",
      value: function getOHLCValue(i, j) {
        var w = this.w;
        return {
          o: this.isBoxPlot ? w.globals.seriesCandleH[i][j] : w.globals.seriesCandleO[i][j],
          h: this.isBoxPlot ? w.globals.seriesCandleO[i][j] : w.globals.seriesCandleH[i][j],
          m: w.globals.seriesCandleM[i][j],
          l: this.isBoxPlot ? w.globals.seriesCandleC[i][j] : w.globals.seriesCandleL[i][j],
          c: this.isBoxPlot ? w.globals.seriesCandleL[i][j] : w.globals.seriesCandleC[i][j]
        };
      }
    }]);
    return BoxCandleStick;
  }(Bar);

  var TreemapHelpers = /*#__PURE__*/function () {
    function TreemapHelpers(ctx) {
      _classCallCheck(this, TreemapHelpers);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(TreemapHelpers, [{
      key: "checkColorRange",
      value: function checkColorRange() {
        var w = this.w;
        var negRange = false;
        var chartOpts = w.config.plotOptions[w.config.chart.type];
        if (chartOpts.colorScale.ranges.length > 0) {
          chartOpts.colorScale.ranges.map(function (range, index) {
            if (range.from <= 0) {
              negRange = true;
            }
          });
        }
        return negRange;
      }
    }, {
      key: "getShadeColor",
      value: function getShadeColor(chartType, i, j, negRange) {
        var w = this.w;
        var colorShadePercent = 1;
        var shadeIntensity = w.config.plotOptions[chartType].shadeIntensity;
        var colorProps = this.determineColor(chartType, i, j);
        if (w.globals.hasNegs || negRange) {
          if (w.config.plotOptions[chartType].reverseNegativeShade) {
            if (colorProps.percent < 0) {
              colorShadePercent = colorProps.percent / 100 * (shadeIntensity * 1.25);
            } else {
              colorShadePercent = (1 - colorProps.percent / 100) * (shadeIntensity * 1.25);
            }
          } else {
            if (colorProps.percent <= 0) {
              colorShadePercent = 1 - (1 + colorProps.percent / 100) * shadeIntensity;
            } else {
              colorShadePercent = (1 - colorProps.percent / 100) * shadeIntensity;
            }
          }
        } else {
          colorShadePercent = 1 - colorProps.percent / 100;
          if (chartType === 'treemap') {
            colorShadePercent = (1 - colorProps.percent / 100) * (shadeIntensity * 1.25);
          }
        }
        var color = colorProps.color;
        var utils = new Utils$1();
        if (w.config.plotOptions[chartType].enableShades) {
          // The shadeColor function may return either an RGB or a hex color value
          // However, hexToRgba requires the input to be in hex format
          // The ternary operator checks if the color is in RGB format, and if so, converts it to hex
          if (this.w.config.theme.mode === 'dark') {
            var shadeColor = utils.shadeColor(colorShadePercent * -1, colorProps.color);
            color = Utils$1.hexToRgba(Utils$1.isColorHex(shadeColor) ? shadeColor : Utils$1.rgb2hex(shadeColor), w.config.fill.opacity);
          } else {
            var _shadeColor = utils.shadeColor(colorShadePercent, colorProps.color);
            color = Utils$1.hexToRgba(Utils$1.isColorHex(_shadeColor) ? _shadeColor : Utils$1.rgb2hex(_shadeColor), w.config.fill.opacity);
          }
        }
        return {
          color: color,
          colorProps: colorProps
        };
      }
    }, {
      key: "determineColor",
      value: function determineColor(chartType, i, j) {
        var w = this.w;
        var val = w.globals.series[i][j];
        var chartOpts = w.config.plotOptions[chartType];
        var seriesNumber = chartOpts.colorScale.inverse ? j : i;
        if (chartOpts.distributed && w.config.chart.type === 'treemap') {
          seriesNumber = j;
        }
        var color = w.globals.colors[seriesNumber];
        var foreColor = null;
        var min = Math.min.apply(Math, _toConsumableArray(w.globals.series[i]));
        var max = Math.max.apply(Math, _toConsumableArray(w.globals.series[i]));
        if (!chartOpts.distributed && chartType === 'heatmap') {
          min = w.globals.minY;
          max = w.globals.maxY;
        }
        if (typeof chartOpts.colorScale.min !== 'undefined') {
          min = chartOpts.colorScale.min < w.globals.minY ? chartOpts.colorScale.min : w.globals.minY;
          max = chartOpts.colorScale.max > w.globals.maxY ? chartOpts.colorScale.max : w.globals.maxY;
        }
        var total = Math.abs(max) + Math.abs(min);
        var percent = 100 * val / (total === 0 ? total - 0.000001 : total);
        if (chartOpts.colorScale.ranges.length > 0) {
          var colorRange = chartOpts.colorScale.ranges;
          colorRange.map(function (range, index) {
            if (val >= range.from && val <= range.to) {
              color = range.color;
              foreColor = range.foreColor ? range.foreColor : null;
              min = range.from;
              max = range.to;
              var rTotal = Math.abs(max) + Math.abs(min);
              percent = 100 * val / (rTotal === 0 ? rTotal - 0.000001 : rTotal);
            }
          });
        }
        return {
          color: color,
          foreColor: foreColor,
          percent: percent
        };
      }
    }, {
      key: "calculateDataLabels",
      value: function calculateDataLabels(_ref) {
        var text = _ref.text,
          x = _ref.x,
          y = _ref.y,
          i = _ref.i,
          j = _ref.j,
          colorProps = _ref.colorProps,
          fontSize = _ref.fontSize;
        var w = this.w;
        var dataLabelsConfig = w.config.dataLabels;
        var graphics = new Graphics(this.ctx);
        var dataLabels = new DataLabels(this.ctx);
        var elDataLabelsWrap = null;
        if (dataLabelsConfig.enabled) {
          elDataLabelsWrap = graphics.group({
            class: 'apexcharts-data-labels'
          });
          var offX = dataLabelsConfig.offsetX;
          var offY = dataLabelsConfig.offsetY;
          var dataLabelsX = x + offX;
          var dataLabelsY = y + parseFloat(dataLabelsConfig.style.fontSize) / 3 + offY;
          dataLabels.plotDataLabelsText({
            x: dataLabelsX,
            y: dataLabelsY,
            text: text,
            i: i,
            j: j,
            color: colorProps.foreColor,
            parent: elDataLabelsWrap,
            fontSize: fontSize,
            dataLabelsConfig: dataLabelsConfig
          });
        }
        return elDataLabelsWrap;
      }
    }, {
      key: "addListeners",
      value: function addListeners(elRect) {
        var graphics = new Graphics(this.ctx);
        elRect.node.addEventListener('mouseenter', graphics.pathMouseEnter.bind(this, elRect));
        elRect.node.addEventListener('mouseleave', graphics.pathMouseLeave.bind(this, elRect));
        elRect.node.addEventListener('mousedown', graphics.pathMouseDown.bind(this, elRect));
      }
    }]);
    return TreemapHelpers;
  }();

  /**
   * ApexCharts HeatMap Class.
   * @module HeatMap
   **/
  var HeatMap = /*#__PURE__*/function () {
    function HeatMap(ctx, xyRatios) {
      _classCallCheck(this, HeatMap);
      this.ctx = ctx;
      this.w = ctx.w;
      this.xRatio = xyRatios.xRatio;
      this.yRatio = xyRatios.yRatio;
      this.dynamicAnim = this.w.config.chart.animations.dynamicAnimation;
      this.helpers = new TreemapHelpers(ctx);
      this.rectRadius = this.w.config.plotOptions.heatmap.radius;
      this.strokeWidth = this.w.config.stroke.show ? this.w.config.stroke.width : 0;
    }
    _createClass(HeatMap, [{
      key: "draw",
      value: function draw(series) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var ret = graphics.group({
          class: 'apexcharts-heatmap'
        });
        ret.attr('clip-path', "url(#gridRectMask".concat(w.globals.cuid, ")"));

        // width divided into equal parts
        var xDivision = w.globals.gridWidth / w.globals.dataPoints;
        var yDivision = w.globals.gridHeight / w.globals.series.length;
        var y1 = 0;
        var rev = false;
        this.negRange = this.helpers.checkColorRange();
        var heatSeries = series.slice();
        if (w.config.yaxis[0].reversed) {
          rev = true;
          heatSeries.reverse();
        }
        for (var i = rev ? 0 : heatSeries.length - 1; rev ? i < heatSeries.length : i >= 0; rev ? i++ : i--) {
          // el to which series will be drawn
          var elSeries = graphics.group({
            class: "apexcharts-series apexcharts-heatmap-series",
            seriesName: Utils$1.escapeString(w.globals.seriesNames[i]),
            rel: i + 1,
            'data:realIndex': i
          });
          this.ctx.series.addCollapsedClassToSeries(elSeries, i);
          if (w.config.chart.dropShadow.enabled) {
            var shadow = w.config.chart.dropShadow;
            var filters = new Filters(this.ctx);
            filters.dropShadow(elSeries, shadow, i);
          }
          var x1 = 0;
          var shadeIntensity = w.config.plotOptions.heatmap.shadeIntensity;
          for (var j = 0; j < heatSeries[i].length; j++) {
            var heatColor = this.helpers.getShadeColor(w.config.chart.type, i, j, this.negRange);
            var color = heatColor.color;
            var heatColorProps = heatColor.colorProps;
            if (w.config.fill.type === 'image') {
              var fill = new Fill(this.ctx);
              color = fill.fillPath({
                seriesNumber: i,
                dataPointIndex: j,
                opacity: w.globals.hasNegs ? heatColorProps.percent < 0 ? 1 - (1 + heatColorProps.percent / 100) : shadeIntensity + heatColorProps.percent / 100 : heatColorProps.percent / 100,
                patternID: Utils$1.randomId(),
                width: w.config.fill.image.width ? w.config.fill.image.width : xDivision,
                height: w.config.fill.image.height ? w.config.fill.image.height : yDivision
              });
            }
            var radius = this.rectRadius;
            var rect = graphics.drawRect(x1, y1, xDivision, yDivision, radius);
            rect.attr({
              cx: x1,
              cy: y1
            });
            rect.node.classList.add('apexcharts-heatmap-rect');
            elSeries.add(rect);
            rect.attr({
              fill: color,
              i: i,
              index: i,
              j: j,
              val: series[i][j],
              'stroke-width': this.strokeWidth,
              stroke: w.config.plotOptions.heatmap.useFillColorAsStroke ? color : w.globals.stroke.colors[0],
              color: color
            });
            this.helpers.addListeners(rect);
            if (w.config.chart.animations.enabled && !w.globals.dataChanged) {
              var speed = 1;
              if (!w.globals.resized) {
                speed = w.config.chart.animations.speed;
              }
              this.animateHeatMap(rect, x1, y1, xDivision, yDivision, speed);
            }
            if (w.globals.dataChanged) {
              var _speed = 1;
              if (this.dynamicAnim.enabled && w.globals.shouldAnimate) {
                _speed = this.dynamicAnim.speed;
                var colorFrom = w.globals.previousPaths[i] && w.globals.previousPaths[i][j] && w.globals.previousPaths[i][j].color;
                if (!colorFrom) colorFrom = 'rgba(255, 255, 255, 0)';
                this.animateHeatColor(rect, Utils$1.isColorHex(colorFrom) ? colorFrom : Utils$1.rgb2hex(colorFrom), Utils$1.isColorHex(color) ? color : Utils$1.rgb2hex(color), _speed);
              }
            }
            var formatter = w.config.dataLabels.formatter;
            var formattedText = formatter(w.globals.series[i][j], {
              value: w.globals.series[i][j],
              seriesIndex: i,
              dataPointIndex: j,
              w: w
            });
            var dataLabels = this.helpers.calculateDataLabels({
              text: formattedText,
              x: x1 + xDivision / 2,
              y: y1 + yDivision / 2,
              i: i,
              j: j,
              colorProps: heatColorProps,
              series: heatSeries
            });
            if (dataLabels !== null) {
              elSeries.add(dataLabels);
            }
            x1 = x1 + xDivision;
          }
          y1 = y1 + yDivision;
          ret.add(elSeries);
        }

        // adjust yaxis labels for heatmap
        var yAxisScale = w.globals.yAxisScale[0].result.slice();
        if (w.config.yaxis[0].reversed) {
          yAxisScale.unshift('');
        } else {
          yAxisScale.push('');
        }
        w.globals.yAxisScale[0].result = yAxisScale;
        return ret;
      }
    }, {
      key: "animateHeatMap",
      value: function animateHeatMap(el, x, y, width, height, speed) {
        var animations = new Animations(this.ctx);
        animations.animateRect(el, {
          x: x + width / 2,
          y: y + height / 2,
          width: 0,
          height: 0
        }, {
          x: x,
          y: y,
          width: width,
          height: height
        }, speed, function () {
          animations.animationCompleted(el);
        });
      }
    }, {
      key: "animateHeatColor",
      value: function animateHeatColor(el, colorFrom, colorTo, speed) {
        el.attr({
          fill: colorFrom
        }).animate(speed).attr({
          fill: colorTo
        });
      }
    }]);
    return HeatMap;
  }();

  var CircularChartsHelpers = /*#__PURE__*/function () {
    function CircularChartsHelpers(ctx) {
      _classCallCheck(this, CircularChartsHelpers);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(CircularChartsHelpers, [{
      key: "drawYAxisTexts",
      value: function drawYAxisTexts(x, y, i, text) {
        var w = this.w;
        var yaxisConfig = w.config.yaxis[0];
        var formatter = w.globals.yLabelFormatters[0];
        var graphics = new Graphics(this.ctx);
        var yaxisLabel = graphics.drawText({
          x: x + yaxisConfig.labels.offsetX,
          y: y + yaxisConfig.labels.offsetY,
          text: formatter(text, i),
          textAnchor: 'middle',
          fontSize: yaxisConfig.labels.style.fontSize,
          fontFamily: yaxisConfig.labels.style.fontFamily,
          foreColor: Array.isArray(yaxisConfig.labels.style.colors) ? yaxisConfig.labels.style.colors[i] : yaxisConfig.labels.style.colors
        });
        return yaxisLabel;
      }
    }]);
    return CircularChartsHelpers;
  }();

  /**
   * ApexCharts Pie Class for drawing Pie / Donut Charts.
   * @module Pie
   **/
  var Pie = /*#__PURE__*/function () {
    function Pie(ctx) {
      _classCallCheck(this, Pie);
      this.ctx = ctx;
      this.w = ctx.w;
      var w = this.w;
      this.chartType = this.w.config.chart.type;
      this.initialAnim = this.w.config.chart.animations.enabled;
      this.dynamicAnim = this.initialAnim && this.w.config.chart.animations.dynamicAnimation.enabled;
      this.animBeginArr = [0];
      this.animDur = 0;
      this.donutDataLabels = this.w.config.plotOptions.pie.donut.labels;
      this.lineColorArr = w.globals.stroke.colors !== undefined ? w.globals.stroke.colors : w.globals.colors;
      this.defaultSize = Math.min(w.globals.gridWidth, w.globals.gridHeight);
      this.centerY = this.defaultSize / 2;
      this.centerX = w.globals.gridWidth / 2;
      if (w.config.chart.type === 'radialBar') {
        this.fullAngle = 360;
      } else {
        this.fullAngle = Math.abs(w.config.plotOptions.pie.endAngle - w.config.plotOptions.pie.startAngle);
      }
      this.initialAngle = w.config.plotOptions.pie.startAngle % this.fullAngle;
      w.globals.radialSize = this.defaultSize / 2.05 - w.config.stroke.width - (!w.config.chart.sparkline.enabled ? w.config.chart.dropShadow.blur : 0);
      this.donutSize = w.globals.radialSize * parseInt(w.config.plotOptions.pie.donut.size, 10) / 100;
      var scaleSize = w.config.plotOptions.pie.customScale;
      var halfW = w.globals.gridWidth / 2;
      var halfH = w.globals.gridHeight / 2;
      this.translateX = halfW - halfW * scaleSize;
      this.translateY = halfH - halfH * scaleSize;
      this.dataLabelsGroup = new Graphics(this.ctx).group({
        class: 'apexcharts-datalabels-group',
        transform: "translate(".concat(this.translateX, ", ").concat(this.translateY, ") scale(").concat(scaleSize, ")")
      });
      this.maxY = 0;
      this.sliceLabels = [];
      this.sliceSizes = [];
      this.prevSectorAngleArr = []; // for dynamic animations
    }
    _createClass(Pie, [{
      key: "draw",
      value: function draw(series) {
        var _this = this;
        var self = this;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var elPie = graphics.group({
          class: 'apexcharts-pie'
        });
        if (w.globals.noData) return elPie;
        var total = 0;
        for (var k = 0; k < series.length; k++) {
          // CALCULATE THE TOTAL
          total += Utils$1.negToZero(series[k]);
        }
        var sectorAngleArr = [];

        // el to which series will be drawn
        var elSeries = graphics.group();

        // prevent division by zero error if there is no data
        if (total === 0) {
          total = 0.00001;
        }
        series.forEach(function (m) {
          _this.maxY = Math.max(_this.maxY, m);
        });

        // override maxY if user provided in config
        if (w.config.yaxis[0].max) {
          this.maxY = w.config.yaxis[0].max;
        }
        if (w.config.grid.position === 'back' && this.chartType === 'polarArea') {
          this.drawPolarElements(elPie);
        }
        for (var i = 0; i < series.length; i++) {
          // CALCULATE THE ANGLES
          var angle = this.fullAngle * Utils$1.negToZero(series[i]) / total;
          sectorAngleArr.push(angle);
          if (this.chartType === 'polarArea') {
            sectorAngleArr[i] = this.fullAngle / series.length;
            this.sliceSizes.push(w.globals.radialSize * series[i] / this.maxY);
          } else {
            this.sliceSizes.push(w.globals.radialSize);
          }
        }
        if (w.globals.dataChanged) {
          var prevTotal = 0;
          for (var _k = 0; _k < w.globals.previousPaths.length; _k++) {
            // CALCULATE THE PREV TOTAL
            prevTotal += Utils$1.negToZero(w.globals.previousPaths[_k]);
          }
          var previousAngle;
          for (var _i = 0; _i < w.globals.previousPaths.length; _i++) {
            // CALCULATE THE PREVIOUS ANGLES
            previousAngle = this.fullAngle * Utils$1.negToZero(w.globals.previousPaths[_i]) / prevTotal;
            this.prevSectorAngleArr.push(previousAngle);
          }
        }

        // on small chart size after few count of resizes browser window donutSize can be negative
        if (this.donutSize < 0) {
          this.donutSize = 0;
        }
        if (this.chartType === 'donut') {
          // draw the inner circle and add some text to it
          var circle = graphics.drawCircle(this.donutSize);
          circle.attr({
            cx: this.centerX,
            cy: this.centerY,
            fill: w.config.plotOptions.pie.donut.background ? w.config.plotOptions.pie.donut.background : 'transparent'
          });
          elSeries.add(circle);
        }
        var elG = self.drawArcs(sectorAngleArr, series);

        // add slice dataLabels at the end
        this.sliceLabels.forEach(function (s) {
          elG.add(s);
        });
        elSeries.attr({
          transform: "translate(".concat(this.translateX, ", ").concat(this.translateY, ") scale(").concat(w.config.plotOptions.pie.customScale, ")")
        });
        elSeries.add(elG);
        elPie.add(elSeries);
        if (this.donutDataLabels.show) {
          var dataLabels = this.renderInnerDataLabels(this.dataLabelsGroup, this.donutDataLabels, {
            hollowSize: this.donutSize,
            centerX: this.centerX,
            centerY: this.centerY,
            opacity: this.donutDataLabels.show
          });
          elPie.add(dataLabels);
        }
        if (w.config.grid.position === 'front' && this.chartType === 'polarArea') {
          this.drawPolarElements(elPie);
        }
        return elPie;
      }

      // core function for drawing pie arcs
    }, {
      key: "drawArcs",
      value: function drawArcs(sectorAngleArr, series) {
        var w = this.w;
        var filters = new Filters(this.ctx);
        var graphics = new Graphics(this.ctx);
        var fill = new Fill(this.ctx);
        var g = graphics.group({
          class: 'apexcharts-slices'
        });
        var startAngle = this.initialAngle;
        var prevStartAngle = this.initialAngle;
        var endAngle = this.initialAngle;
        var prevEndAngle = this.initialAngle;
        this.strokeWidth = w.config.stroke.show ? w.config.stroke.width : 0;
        for (var i = 0; i < sectorAngleArr.length; i++) {
          var elPieArc = graphics.group({
            class: "apexcharts-series apexcharts-pie-series",
            seriesName: Utils$1.escapeString(w.globals.seriesNames[i]),
            rel: i + 1,
            'data:realIndex': i
          });
          g.add(elPieArc);
          startAngle = endAngle;
          prevStartAngle = prevEndAngle;
          endAngle = startAngle + sectorAngleArr[i];
          prevEndAngle = prevStartAngle + this.prevSectorAngleArr[i];
          var angle = endAngle < startAngle ? this.fullAngle + endAngle - startAngle : endAngle - startAngle;
          var pathFill = fill.fillPath({
            seriesNumber: i,
            size: this.sliceSizes[i],
            value: series[i]
          }); // additionally, pass size for gradient drawing in the fillPath function

          var path = this.getChangedPath(prevStartAngle, prevEndAngle);
          var elPath = graphics.drawPath({
            d: path,
            stroke: Array.isArray(this.lineColorArr) ? this.lineColorArr[i] : this.lineColorArr,
            strokeWidth: 0,
            fill: pathFill,
            fillOpacity: w.config.fill.opacity,
            classes: "apexcharts-pie-area apexcharts-".concat(this.chartType.toLowerCase(), "-slice-").concat(i)
          });
          elPath.attr({
            index: 0,
            j: i
          });
          filters.setSelectionFilter(elPath, 0, i);
          if (w.config.chart.dropShadow.enabled) {
            var shadow = w.config.chart.dropShadow;
            filters.dropShadow(elPath, shadow, i);
          }
          this.addListeners(elPath, this.donutDataLabels);
          Graphics.setAttrs(elPath.node, {
            'data:angle': angle,
            'data:startAngle': startAngle,
            'data:strokeWidth': this.strokeWidth,
            'data:value': series[i]
          });
          var labelPosition = {
            x: 0,
            y: 0
          };
          if (this.chartType === 'pie' || this.chartType === 'polarArea') {
            labelPosition = Utils$1.polarToCartesian(this.centerX, this.centerY, w.globals.radialSize / 1.25 + w.config.plotOptions.pie.dataLabels.offset, (startAngle + angle / 2) % this.fullAngle);
          } else if (this.chartType === 'donut') {
            labelPosition = Utils$1.polarToCartesian(this.centerX, this.centerY, (w.globals.radialSize + this.donutSize) / 2 + w.config.plotOptions.pie.dataLabels.offset, (startAngle + angle / 2) % this.fullAngle);
          }
          elPieArc.add(elPath);

          // Animation code starts
          var dur = 0;
          if (this.initialAnim && !w.globals.resized && !w.globals.dataChanged) {
            dur = angle / this.fullAngle * w.config.chart.animations.speed;
            if (dur === 0) dur = 1;
            this.animDur = dur + this.animDur;
            this.animBeginArr.push(this.animDur);
          } else {
            this.animBeginArr.push(0);
          }
          if (this.dynamicAnim && w.globals.dataChanged) {
            this.animatePaths(elPath, {
              size: this.sliceSizes[i],
              endAngle: endAngle,
              startAngle: startAngle,
              prevStartAngle: prevStartAngle,
              prevEndAngle: prevEndAngle,
              animateStartingPos: true,
              i: i,
              animBeginArr: this.animBeginArr,
              shouldSetPrevPaths: true,
              dur: w.config.chart.animations.dynamicAnimation.speed
            });
          } else {
            this.animatePaths(elPath, {
              size: this.sliceSizes[i],
              endAngle: endAngle,
              startAngle: startAngle,
              i: i,
              totalItems: sectorAngleArr.length - 1,
              animBeginArr: this.animBeginArr,
              dur: dur
            });
          }
          // animation code ends

          if (w.config.plotOptions.pie.expandOnClick && this.chartType !== 'polarArea') {
            elPath.node.addEventListener('mouseup', this.pieClicked.bind(this, i));
          }
          if (typeof w.globals.selectedDataPoints[0] !== 'undefined' && w.globals.selectedDataPoints[0].indexOf(i) > -1) {
            this.pieClicked(i);
          }
          if (w.config.dataLabels.enabled) {
            var xPos = labelPosition.x;
            var yPos = labelPosition.y;
            var text = 100 * angle / this.fullAngle + '%';
            if (angle !== 0 && w.config.plotOptions.pie.dataLabels.minAngleToShowLabel < sectorAngleArr[i]) {
              var formatter = w.config.dataLabels.formatter;
              if (formatter !== undefined) {
                text = formatter(w.globals.seriesPercent[i][0], {
                  seriesIndex: i,
                  w: w
                });
              }
              var foreColor = w.globals.dataLabels.style.colors[i];
              var elPieLabelWrap = graphics.group({
                class: "apexcharts-datalabels"
              });
              var elPieLabel = graphics.drawText({
                x: xPos,
                y: yPos,
                text: text,
                textAnchor: 'middle',
                fontSize: w.config.dataLabels.style.fontSize,
                fontFamily: w.config.dataLabels.style.fontFamily,
                fontWeight: w.config.dataLabels.style.fontWeight,
                foreColor: foreColor
              });
              elPieLabelWrap.add(elPieLabel);
              if (w.config.dataLabels.dropShadow.enabled) {
                var textShadow = w.config.dataLabels.dropShadow;
                filters.dropShadow(elPieLabel, textShadow);
              }
              elPieLabel.node.classList.add('apexcharts-pie-label');
              if (w.config.chart.animations.animate && w.globals.resized === false) {
                elPieLabel.node.classList.add('apexcharts-pie-label-delay');
                elPieLabel.node.style.animationDelay = w.config.chart.animations.speed / 940 + 's';
              }
              this.sliceLabels.push(elPieLabelWrap);
            }
          }
        }
        return g;
      }
    }, {
      key: "addListeners",
      value: function addListeners(elPath, dataLabels) {
        var graphics = new Graphics(this.ctx);
        // append filters on mouseenter and mouseleave
        elPath.node.addEventListener('mouseenter', graphics.pathMouseEnter.bind(this, elPath));
        elPath.node.addEventListener('mouseleave', graphics.pathMouseLeave.bind(this, elPath));
        elPath.node.addEventListener('mouseleave', this.revertDataLabelsInner.bind(this, elPath.node, dataLabels));
        elPath.node.addEventListener('mousedown', graphics.pathMouseDown.bind(this, elPath));
        if (!this.donutDataLabels.total.showAlways) {
          elPath.node.addEventListener('mouseenter', this.printDataLabelsInner.bind(this, elPath.node, dataLabels));
          elPath.node.addEventListener('mousedown', this.printDataLabelsInner.bind(this, elPath.node, dataLabels));
        }
      }

      // This function can be used for other circle charts too
    }, {
      key: "animatePaths",
      value: function animatePaths(el, opts) {
        var w = this.w;
        var me = this;
        var angle = opts.endAngle < opts.startAngle ? this.fullAngle + opts.endAngle - opts.startAngle : opts.endAngle - opts.startAngle;
        var prevAngle = angle;
        var fromStartAngle = opts.startAngle;
        var toStartAngle = opts.startAngle;
        if (opts.prevStartAngle !== undefined && opts.prevEndAngle !== undefined) {
          fromStartAngle = opts.prevEndAngle;
          prevAngle = opts.prevEndAngle < opts.prevStartAngle ? this.fullAngle + opts.prevEndAngle - opts.prevStartAngle : opts.prevEndAngle - opts.prevStartAngle;
        }
        if (opts.i === w.config.series.length - 1) {
          // some adjustments for the last overlapping paths
          if (angle + toStartAngle > this.fullAngle) {
            opts.endAngle = opts.endAngle - (angle + toStartAngle);
          } else if (angle + toStartAngle < this.fullAngle) {
            opts.endAngle = opts.endAngle + (this.fullAngle - (angle + toStartAngle));
          }
        }
        if (angle === this.fullAngle) angle = this.fullAngle - 0.01;
        me.animateArc(el, fromStartAngle, toStartAngle, angle, prevAngle, opts);
      }
    }, {
      key: "animateArc",
      value: function animateArc(el, fromStartAngle, toStartAngle, angle, prevAngle, opts) {
        var me = this;
        var w = this.w;
        var animations = new Animations(this.ctx);
        var size = opts.size;
        var path;
        if (isNaN(fromStartAngle) || isNaN(prevAngle)) {
          fromStartAngle = toStartAngle;
          prevAngle = angle;
          opts.dur = 0;
        }
        var currAngle = angle;
        var startAngle = toStartAngle;
        var fromAngle = fromStartAngle < toStartAngle ? this.fullAngle + fromStartAngle - toStartAngle : fromStartAngle - toStartAngle;
        if (w.globals.dataChanged && opts.shouldSetPrevPaths) {
          // to avoid flicker when updating, set prev path first and then animate from there
          if (opts.prevEndAngle) {
            path = me.getPiePath({
              me: me,
              startAngle: opts.prevStartAngle,
              angle: opts.prevEndAngle < opts.prevStartAngle ? this.fullAngle + opts.prevEndAngle - opts.prevStartAngle : opts.prevEndAngle - opts.prevStartAngle,
              size: size
            });
            el.attr({
              d: path
            });
          }
        }
        if (opts.dur !== 0) {
          el.animate(opts.dur, w.globals.easing, opts.animBeginArr[opts.i]).afterAll(function () {
            if (me.chartType === 'pie' || me.chartType === 'donut' || me.chartType === 'polarArea') {
              this.animate(w.config.chart.animations.dynamicAnimation.speed).attr({
                'stroke-width': me.strokeWidth
              });
            }
            if (opts.i === w.config.series.length - 1) {
              animations.animationCompleted(el);
            }
          }).during(function (pos) {
            currAngle = fromAngle + (angle - fromAngle) * pos;
            if (opts.animateStartingPos) {
              currAngle = prevAngle + (angle - prevAngle) * pos;
              startAngle = fromStartAngle - prevAngle + (toStartAngle - (fromStartAngle - prevAngle)) * pos;
            }
            path = me.getPiePath({
              me: me,
              startAngle: startAngle,
              angle: currAngle,
              size: size
            });
            el.node.setAttribute('data:pathOrig', path);
            el.attr({
              d: path
            });
          });
        } else {
          path = me.getPiePath({
            me: me,
            startAngle: startAngle,
            angle: angle,
            size: size
          });
          if (!opts.isTrack) {
            w.globals.animationEnded = true;
          }
          el.node.setAttribute('data:pathOrig', path);
          el.attr({
            d: path,
            'stroke-width': me.strokeWidth
          });
        }
      }
    }, {
      key: "pieClicked",
      value: function pieClicked(i) {
        var w = this.w;
        var me = this;
        var path;
        var size = me.sliceSizes[i] + (w.config.plotOptions.pie.expandOnClick ? 4 : 0);
        var elPath = w.globals.dom.Paper.select(".apexcharts-".concat(me.chartType.toLowerCase(), "-slice-").concat(i)).members[0];
        if (elPath.attr('data:pieClicked') === 'true') {
          elPath.attr({
            'data:pieClicked': 'false'
          });
          this.revertDataLabelsInner(elPath.node, this.donutDataLabels);
          var origPath = elPath.attr('data:pathOrig');
          elPath.attr({
            d: origPath
          });
          return;
        } else {
          // reset all elems
          var allEls = w.globals.dom.baseEl.getElementsByClassName('apexcharts-pie-area');
          Array.prototype.forEach.call(allEls, function (pieSlice) {
            pieSlice.setAttribute('data:pieClicked', 'false');
            var origPath = pieSlice.getAttribute('data:pathOrig');
            if (origPath) {
              pieSlice.setAttribute('d', origPath);
            }
          });
          w.globals.capturedDataPointIndex = i;
          elPath.attr('data:pieClicked', 'true');
        }
        var startAngle = parseInt(elPath.attr('data:startAngle'), 10);
        var angle = parseInt(elPath.attr('data:angle'), 10);
        path = me.getPiePath({
          me: me,
          startAngle: startAngle,
          angle: angle,
          size: size
        });
        if (angle === 360) return;
        elPath.plot(path);
      }
    }, {
      key: "getChangedPath",
      value: function getChangedPath(prevStartAngle, prevEndAngle) {
        var path = '';
        if (this.dynamicAnim && this.w.globals.dataChanged) {
          path = this.getPiePath({
            me: this,
            startAngle: prevStartAngle,
            angle: prevEndAngle - prevStartAngle,
            size: this.size
          });
        }
        return path;
      }
    }, {
      key: "getPiePath",
      value: function getPiePath(_ref) {
        var me = _ref.me,
          startAngle = _ref.startAngle,
          angle = _ref.angle,
          size = _ref.size;
        var path;
        var graphics = new Graphics(this.ctx);
        var startDeg = startAngle;
        var startRadians = Math.PI * (startDeg - 90) / 180;
        var endDeg = angle + startAngle;
        // prevent overlap
        if (Math.ceil(endDeg) >= this.fullAngle + this.w.config.plotOptions.pie.startAngle % this.fullAngle) {
          endDeg = this.fullAngle + this.w.config.plotOptions.pie.startAngle % this.fullAngle - 0.01;
        }
        if (Math.ceil(endDeg) > this.fullAngle) endDeg -= this.fullAngle;
        var endRadians = Math.PI * (endDeg - 90) / 180;
        var x1 = me.centerX + size * Math.cos(startRadians);
        var y1 = me.centerY + size * Math.sin(startRadians);
        var x2 = me.centerX + size * Math.cos(endRadians);
        var y2 = me.centerY + size * Math.sin(endRadians);
        var startInner = Utils$1.polarToCartesian(me.centerX, me.centerY, me.donutSize, endDeg);
        var endInner = Utils$1.polarToCartesian(me.centerX, me.centerY, me.donutSize, startDeg);
        var largeArc = angle > 180 ? 1 : 0;
        var pathBeginning = ['M', x1, y1, 'A', size, size, 0, largeArc, 1, x2, y2];
        if (me.chartType === 'donut') {
          path = [].concat(pathBeginning, ['L', startInner.x, startInner.y, 'A', me.donutSize, me.donutSize, 0, largeArc, 0, endInner.x, endInner.y, 'L', x1, y1, 'z']).join(' ');
        } else if (me.chartType === 'pie' || me.chartType === 'polarArea') {
          path = [].concat(pathBeginning, ['L', me.centerX, me.centerY, 'L', x1, y1]).join(' ');
        } else {
          path = [].concat(pathBeginning).join(' ');
        }
        return graphics.roundPathCorners(path, this.strokeWidth * 2);
      }
    }, {
      key: "drawPolarElements",
      value: function drawPolarElements(parent) {
        var w = this.w;
        var scale = new Scales(this.ctx);
        var graphics = new Graphics(this.ctx);
        var helpers = new CircularChartsHelpers(this.ctx);
        var gCircles = graphics.group();
        var gYAxis = graphics.group();
        var yScale = scale.niceScale(0, Math.ceil(this.maxY), 0);
        var yTexts = yScale.result.reverse();
        var len = yScale.result.length;
        this.maxY = yScale.niceMax;
        var circleSize = w.globals.radialSize;
        var diff = circleSize / (len - 1);
        for (var i = 0; i < len - 1; i++) {
          var circle = graphics.drawCircle(circleSize);
          circle.attr({
            cx: this.centerX,
            cy: this.centerY,
            fill: 'none',
            'stroke-width': w.config.plotOptions.polarArea.rings.strokeWidth,
            stroke: w.config.plotOptions.polarArea.rings.strokeColor
          });
          if (w.config.yaxis[0].show) {
            var yLabel = helpers.drawYAxisTexts(this.centerX, this.centerY - circleSize + parseInt(w.config.yaxis[0].labels.style.fontSize, 10) / 2, i, yTexts[i]);
            gYAxis.add(yLabel);
          }
          gCircles.add(circle);
          circleSize = circleSize - diff;
        }
        this.drawSpokes(parent);
        parent.add(gCircles);
        parent.add(gYAxis);
      }
    }, {
      key: "renderInnerDataLabels",
      value: function renderInnerDataLabels(dataLabelsGroup, dataLabelsConfig, opts) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var showTotal = dataLabelsConfig.total.show;
        dataLabelsGroup.node.innerHTML = '';
        dataLabelsGroup.node.style.opacity = opts.opacity;
        var x = opts.centerX;
        var y = !this.donutDataLabels.total.label ? opts.centerY - opts.centerY / 6 : opts.centerY;
        var labelColor, valueColor;
        if (dataLabelsConfig.name.color === undefined) {
          labelColor = w.globals.colors[0];
        } else {
          labelColor = dataLabelsConfig.name.color;
        }
        var labelFontSize = dataLabelsConfig.name.fontSize;
        var labelFontFamily = dataLabelsConfig.name.fontFamily;
        var labelFontWeight = dataLabelsConfig.name.fontWeight;
        if (dataLabelsConfig.value.color === undefined) {
          valueColor = w.config.chart.foreColor;
        } else {
          valueColor = dataLabelsConfig.value.color;
        }
        var lbFormatter = dataLabelsConfig.value.formatter;
        var val = '';
        var name = '';
        if (showTotal) {
          labelColor = dataLabelsConfig.total.color;
          labelFontSize = dataLabelsConfig.total.fontSize;
          labelFontFamily = dataLabelsConfig.total.fontFamily;
          labelFontWeight = dataLabelsConfig.total.fontWeight;
          name = !this.donutDataLabels.total.label ? '' : dataLabelsConfig.total.label;
          val = dataLabelsConfig.total.formatter(w);
        } else {
          if (w.globals.series.length === 1) {
            val = lbFormatter(w.globals.series[0], w);
            name = w.globals.seriesNames[0];
          }
        }
        if (name) {
          name = dataLabelsConfig.name.formatter(name, dataLabelsConfig.total.show, w);
        }
        if (dataLabelsConfig.name.show) {
          var elLabel = graphics.drawText({
            x: x,
            y: y + parseFloat(dataLabelsConfig.name.offsetY),
            text: name,
            textAnchor: 'middle',
            foreColor: labelColor,
            fontSize: labelFontSize,
            fontWeight: labelFontWeight,
            fontFamily: labelFontFamily
          });
          elLabel.node.classList.add('apexcharts-datalabel-label');
          dataLabelsGroup.add(elLabel);
        }
        if (dataLabelsConfig.value.show) {
          var valOffset = dataLabelsConfig.name.show ? parseFloat(dataLabelsConfig.value.offsetY) + 16 : dataLabelsConfig.value.offsetY;
          var elValue = graphics.drawText({
            x: x,
            y: y + valOffset,
            text: val,
            textAnchor: 'middle',
            foreColor: valueColor,
            fontWeight: dataLabelsConfig.value.fontWeight,
            fontSize: dataLabelsConfig.value.fontSize,
            fontFamily: dataLabelsConfig.value.fontFamily
          });
          elValue.node.classList.add('apexcharts-datalabel-value');
          dataLabelsGroup.add(elValue);
        }

        // for a multi-series circle chart, we need to show total value instead of first series labels

        return dataLabelsGroup;
      }

      /**
       *
       * @param {string} name - The name of the series
       * @param {string} val - The value of that series
       * @param {object} el - Optional el (indicates which series was hovered/clicked). If this param is not present, means we need to show total
       */
    }, {
      key: "printInnerLabels",
      value: function printInnerLabels(labelsConfig, name, val, el) {
        var w = this.w;
        var labelColor;
        if (el) {
          if (labelsConfig.name.color === undefined) {
            labelColor = w.globals.colors[parseInt(el.parentNode.getAttribute('rel'), 10) - 1];
          } else {
            labelColor = labelsConfig.name.color;
          }
        } else {
          if (w.globals.series.length > 1 && labelsConfig.total.show) {
            labelColor = labelsConfig.total.color;
          }
        }
        var elLabel = w.globals.dom.baseEl.querySelector('.apexcharts-datalabel-label');
        var elValue = w.globals.dom.baseEl.querySelector('.apexcharts-datalabel-value');
        var lbFormatter = labelsConfig.value.formatter;
        val = lbFormatter(val, w);

        // we need to show Total Val - so get the formatter of it
        if (!el && typeof labelsConfig.total.formatter === 'function') {
          val = labelsConfig.total.formatter(w);
        }
        var isTotal = name === labelsConfig.total.label;
        name = !this.donutDataLabels.total.label ? '' : labelsConfig.name.formatter(name, isTotal, w);
        if (elLabel !== null) {
          elLabel.textContent = name;
        }
        if (elValue !== null) {
          elValue.textContent = val;
        }
        if (elLabel !== null) {
          elLabel.style.fill = labelColor;
        }
      }
    }, {
      key: "printDataLabelsInner",
      value: function printDataLabelsInner(el, dataLabelsConfig) {
        var w = this.w;
        var val = el.getAttribute('data:value');
        var name = w.globals.seriesNames[parseInt(el.parentNode.getAttribute('rel'), 10) - 1];
        if (w.globals.series.length > 1) {
          this.printInnerLabels(dataLabelsConfig, name, val, el);
        }
        var dataLabelsGroup = w.globals.dom.baseEl.querySelector('.apexcharts-datalabels-group');
        if (dataLabelsGroup !== null) {
          dataLabelsGroup.style.opacity = 1;
        }
      }
    }, {
      key: "drawSpokes",
      value: function drawSpokes(parent) {
        var _this2 = this;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var spokeConfig = w.config.plotOptions.polarArea.spokes;
        if (spokeConfig.strokeWidth === 0) return;
        var spokes = [];
        var angleDivision = 360 / w.globals.series.length;
        for (var i = 0; i < w.globals.series.length; i++) {
          spokes.push(Utils$1.polarToCartesian(this.centerX, this.centerY, w.globals.radialSize, w.config.plotOptions.pie.startAngle + angleDivision * i));
        }
        spokes.forEach(function (p, i) {
          var line = graphics.drawLine(p.x, p.y, _this2.centerX, _this2.centerY, Array.isArray(spokeConfig.connectorColors) ? spokeConfig.connectorColors[i] : spokeConfig.connectorColors);
          parent.add(line);
        });
      }
    }, {
      key: "revertDataLabelsInner",
      value: function revertDataLabelsInner() {
        var w = this.w;
        if (this.donutDataLabels.show) {
          var dataLabelsGroup = w.globals.dom.Paper.select(".apexcharts-datalabels-group").members[0];
          var dataLabels = this.renderInnerDataLabels(dataLabelsGroup, this.donutDataLabels, {
            hollowSize: this.donutSize,
            centerX: this.centerX,
            centerY: this.centerY,
            opacity: this.donutDataLabels.show
          });
          var elPie = w.globals.dom.Paper.select('.apexcharts-radialbar, .apexcharts-pie').members[0];
          elPie.add(dataLabels);
        }
      }
    }]);
    return Pie;
  }();

  /**
   * ApexCharts Radar Class for Spider/Radar Charts.
   * @module Radar
   **/
  var Radar = /*#__PURE__*/function () {
    function Radar(ctx) {
      _classCallCheck(this, Radar);
      this.ctx = ctx;
      this.w = ctx.w;
      this.chartType = this.w.config.chart.type;
      this.initialAnim = this.w.config.chart.animations.enabled;
      this.dynamicAnim = this.initialAnim && this.w.config.chart.animations.dynamicAnimation.enabled;
      this.animDur = 0;
      var w = this.w;
      this.graphics = new Graphics(this.ctx);
      this.lineColorArr = w.globals.stroke.colors !== undefined ? w.globals.stroke.colors : w.globals.colors;
      this.defaultSize = w.globals.svgHeight < w.globals.svgWidth ? w.globals.gridHeight : w.globals.gridWidth;
      this.isLog = w.config.yaxis[0].logarithmic;
      this.logBase = w.config.yaxis[0].logBase;
      this.coreUtils = new CoreUtils(this.ctx);
      this.maxValue = this.isLog ? this.coreUtils.getLogVal(this.logBase, w.globals.maxY, 0) : w.globals.maxY;
      this.minValue = this.isLog ? this.coreUtils.getLogVal(this.logBase, this.w.globals.minY, 0) : w.globals.minY;
      this.polygons = w.config.plotOptions.radar.polygons;
      this.strokeWidth = w.config.stroke.show ? w.config.stroke.width : 0;
      this.size = this.defaultSize / 2.1 - this.strokeWidth - w.config.chart.dropShadow.blur;
      if (w.config.xaxis.labels.show) {
        this.size = this.size - w.globals.xAxisLabelsWidth / 1.75;
      }
      if (w.config.plotOptions.radar.size !== undefined) {
        this.size = w.config.plotOptions.radar.size;
      }
      this.dataRadiusOfPercent = [];
      this.dataRadius = [];
      this.angleArr = [];
      this.yaxisLabelsTextsPos = [];
    }
    _createClass(Radar, [{
      key: "draw",
      value: function draw(series) {
        var _this = this;
        var w = this.w;
        var fill = new Fill(this.ctx);
        var allSeries = [];
        var dataLabels = new DataLabels(this.ctx);
        if (series.length) {
          this.dataPointsLen = series[w.globals.maxValsInArrayIndex].length;
        }
        this.disAngle = Math.PI * 2 / this.dataPointsLen;
        var halfW = w.globals.gridWidth / 2;
        var halfH = w.globals.gridHeight / 2;
        var translateX = halfW + w.config.plotOptions.radar.offsetX;
        var translateY = halfH + w.config.plotOptions.radar.offsetY;
        var ret = this.graphics.group({
          class: 'apexcharts-radar-series apexcharts-plot-series',
          transform: "translate(".concat(translateX || 0, ", ").concat(translateY || 0, ")")
        });
        var dataPointsPos = [];
        var elPointsMain = null;
        var elDataPointsMain = null;
        this.yaxisLabels = this.graphics.group({
          class: 'apexcharts-yaxis'
        });
        series.forEach(function (s, i) {
          var longestSeries = s.length === w.globals.dataPoints;

          // el to which series will be drawn
          var elSeries = _this.graphics.group().attr({
            class: "apexcharts-series",
            'data:longestSeries': longestSeries,
            seriesName: Utils$1.escapeString(w.globals.seriesNames[i]),
            rel: i + 1,
            'data:realIndex': i
          });
          _this.dataRadiusOfPercent[i] = [];
          _this.dataRadius[i] = [];
          _this.angleArr[i] = [];
          s.forEach(function (dv, j) {
            var range = Math.abs(_this.maxValue - _this.minValue);
            dv = dv - _this.minValue;
            if (_this.isLog) {
              dv = _this.coreUtils.getLogVal(_this.logBase, dv, 0);
            }
            _this.dataRadiusOfPercent[i][j] = dv / range;
            _this.dataRadius[i][j] = _this.dataRadiusOfPercent[i][j] * _this.size;
            _this.angleArr[i][j] = j * _this.disAngle;
          });
          dataPointsPos = _this.getDataPointsPos(_this.dataRadius[i], _this.angleArr[i]);
          var paths = _this.createPaths(dataPointsPos, {
            x: 0,
            y: 0
          });

          // points
          elPointsMain = _this.graphics.group({
            class: 'apexcharts-series-markers-wrap apexcharts-element-hidden'
          });

          // datapoints
          elDataPointsMain = _this.graphics.group({
            class: "apexcharts-datalabels",
            'data:realIndex': i
          });
          w.globals.delayedElements.push({
            el: elPointsMain.node,
            index: i
          });
          var defaultRenderedPathOptions = {
            i: i,
            realIndex: i,
            animationDelay: i,
            initialSpeed: w.config.chart.animations.speed,
            dataChangeSpeed: w.config.chart.animations.dynamicAnimation.speed,
            className: "apexcharts-radar",
            shouldClipToGrid: false,
            bindEventsOnPaths: false,
            stroke: w.globals.stroke.colors[i],
            strokeLineCap: w.config.stroke.lineCap
          };
          var pathFrom = null;
          if (w.globals.previousPaths.length > 0) {
            pathFrom = _this.getPreviousPath(i);
          }
          for (var p = 0; p < paths.linePathsTo.length; p++) {
            var renderedLinePath = _this.graphics.renderPaths(_objectSpread2(_objectSpread2({}, defaultRenderedPathOptions), {}, {
              pathFrom: pathFrom === null ? paths.linePathsFrom[p] : pathFrom,
              pathTo: paths.linePathsTo[p],
              strokeWidth: Array.isArray(_this.strokeWidth) ? _this.strokeWidth[i] : _this.strokeWidth,
              fill: 'none',
              drawShadow: false
            }));
            elSeries.add(renderedLinePath);
            var pathFill = fill.fillPath({
              seriesNumber: i
            });
            var renderedAreaPath = _this.graphics.renderPaths(_objectSpread2(_objectSpread2({}, defaultRenderedPathOptions), {}, {
              pathFrom: pathFrom === null ? paths.areaPathsFrom[p] : pathFrom,
              pathTo: paths.areaPathsTo[p],
              strokeWidth: 0,
              fill: pathFill,
              drawShadow: false
            }));
            if (w.config.chart.dropShadow.enabled) {
              var filters = new Filters(_this.ctx);
              var shadow = w.config.chart.dropShadow;
              filters.dropShadow(renderedAreaPath, Object.assign({}, shadow, {
                noUserSpaceOnUse: true
              }), i);
            }
            elSeries.add(renderedAreaPath);
          }
          s.forEach(function (sj, j) {
            var markers = new Markers(_this.ctx);
            var opts = markers.getMarkerConfig({
              cssClass: 'apexcharts-marker',
              seriesIndex: i,
              dataPointIndex: j
            });
            var point = _this.graphics.drawMarker(dataPointsPos[j].x, dataPointsPos[j].y, opts);
            point.attr('rel', j);
            point.attr('j', j);
            point.attr('index', i);
            point.node.setAttribute('default-marker-size', opts.pSize);
            var elPointsWrap = _this.graphics.group({
              class: 'apexcharts-series-markers'
            });
            if (elPointsWrap) {
              elPointsWrap.add(point);
            }
            elPointsMain.add(elPointsWrap);
            elSeries.add(elPointsMain);
            var dataLabelsConfig = w.config.dataLabels;
            if (dataLabelsConfig.enabled) {
              var text = dataLabelsConfig.formatter(w.globals.series[i][j], {
                seriesIndex: i,
                dataPointIndex: j,
                w: w
              });
              dataLabels.plotDataLabelsText({
                x: dataPointsPos[j].x,
                y: dataPointsPos[j].y,
                text: text,
                textAnchor: 'middle',
                i: i,
                j: i,
                parent: elDataPointsMain,
                offsetCorrection: false,
                dataLabelsConfig: _objectSpread2({}, dataLabelsConfig)
              });
            }
            elSeries.add(elDataPointsMain);
          });
          allSeries.push(elSeries);
        });
        this.drawPolygons({
          parent: ret
        });
        if (w.config.xaxis.labels.show) {
          var xaxisTexts = this.drawXAxisTexts();
          ret.add(xaxisTexts);
        }
        allSeries.forEach(function (elS) {
          ret.add(elS);
        });
        ret.add(this.yaxisLabels);
        return ret;
      }
    }, {
      key: "drawPolygons",
      value: function drawPolygons(opts) {
        var _this2 = this;
        var w = this.w;
        var parent = opts.parent;
        var helpers = new CircularChartsHelpers(this.ctx);
        var yaxisTexts = w.globals.yAxisScale[0].result.reverse();
        var layers = yaxisTexts.length;
        var radiusSizes = [];
        var layerDis = this.size / (layers - 1);
        for (var i = 0; i < layers; i++) {
          radiusSizes[i] = layerDis * i;
        }
        radiusSizes.reverse();
        var polygonStrings = [];
        var lines = [];
        radiusSizes.forEach(function (radiusSize, r) {
          var polygon = Utils$1.getPolygonPos(radiusSize, _this2.dataPointsLen);
          var string = '';
          polygon.forEach(function (p, i) {
            if (r === 0) {
              var line = _this2.graphics.drawLine(p.x, p.y, 0, 0, Array.isArray(_this2.polygons.connectorColors) ? _this2.polygons.connectorColors[i] : _this2.polygons.connectorColors);
              lines.push(line);
            }
            if (i === 0) {
              _this2.yaxisLabelsTextsPos.push({
                x: p.x,
                y: p.y
              });
            }
            string += p.x + ',' + p.y + ' ';
          });
          polygonStrings.push(string);
        });
        polygonStrings.forEach(function (p, i) {
          var strokeColors = _this2.polygons.strokeColors;
          var strokeWidth = _this2.polygons.strokeWidth;
          var polygon = _this2.graphics.drawPolygon(p, Array.isArray(strokeColors) ? strokeColors[i] : strokeColors, Array.isArray(strokeWidth) ? strokeWidth[i] : strokeWidth, w.globals.radarPolygons.fill.colors[i]);
          parent.add(polygon);
        });
        lines.forEach(function (l) {
          parent.add(l);
        });
        if (w.config.yaxis[0].show) {
          this.yaxisLabelsTextsPos.forEach(function (p, i) {
            var yText = helpers.drawYAxisTexts(p.x, p.y, i, yaxisTexts[i]);
            _this2.yaxisLabels.add(yText);
          });
        }
      }
    }, {
      key: "drawXAxisTexts",
      value: function drawXAxisTexts() {
        var _this3 = this;
        var w = this.w;
        var xaxisLabelsConfig = w.config.xaxis.labels;
        var elXAxisWrap = this.graphics.group({
          class: 'apexcharts-xaxis'
        });
        var polygonPos = Utils$1.getPolygonPos(this.size, this.dataPointsLen);
        w.globals.labels.forEach(function (label, i) {
          var formatter = w.config.xaxis.labels.formatter;
          var dataLabels = new DataLabels(_this3.ctx);
          if (polygonPos[i]) {
            var textPos = _this3.getTextPos(polygonPos[i], _this3.size);
            var text = formatter(label, {
              seriesIndex: -1,
              dataPointIndex: i,
              w: w
            });
            var dataLabelText = dataLabels.plotDataLabelsText({
              x: textPos.newX,
              y: textPos.newY,
              text: text,
              textAnchor: textPos.textAnchor,
              i: i,
              j: i,
              parent: elXAxisWrap,
              className: 'apexcharts-xaxis-label',
              color: Array.isArray(xaxisLabelsConfig.style.colors) && xaxisLabelsConfig.style.colors[i] ? xaxisLabelsConfig.style.colors[i] : '#a8a8a8',
              dataLabelsConfig: _objectSpread2({
                textAnchor: textPos.textAnchor,
                dropShadow: {
                  enabled: false
                }
              }, xaxisLabelsConfig),
              offsetCorrection: false
            });
            dataLabelText.on('click', function (e) {
              if (typeof w.config.chart.events.xAxisLabelClick === 'function') {
                var opts = Object.assign({}, w, {
                  labelIndex: i
                });
                w.config.chart.events.xAxisLabelClick(e, _this3.ctx, opts);
              }
            });
          }
        });
        return elXAxisWrap;
      }
    }, {
      key: "createPaths",
      value: function createPaths(pos, origin) {
        var _this4 = this;
        var linePathsTo = [];
        var linePathsFrom = [];
        var areaPathsTo = [];
        var areaPathsFrom = [];
        if (pos.length) {
          linePathsFrom = [this.graphics.move(origin.x, origin.y)];
          areaPathsFrom = [this.graphics.move(origin.x, origin.y)];
          var linePathTo = this.graphics.move(pos[0].x, pos[0].y);
          var areaPathTo = this.graphics.move(pos[0].x, pos[0].y);
          pos.forEach(function (p, i) {
            linePathTo += _this4.graphics.line(p.x, p.y);
            areaPathTo += _this4.graphics.line(p.x, p.y);
            if (i === pos.length - 1) {
              linePathTo += 'Z';
              areaPathTo += 'Z';
            }
          });
          linePathsTo.push(linePathTo);
          areaPathsTo.push(areaPathTo);
        }
        return {
          linePathsFrom: linePathsFrom,
          linePathsTo: linePathsTo,
          areaPathsFrom: areaPathsFrom,
          areaPathsTo: areaPathsTo
        };
      }
    }, {
      key: "getTextPos",
      value: function getTextPos(pos, polygonSize) {
        var limit = 10;
        var textAnchor = 'middle';
        var newX = pos.x;
        var newY = pos.y;
        if (Math.abs(pos.x) >= limit) {
          if (pos.x > 0) {
            textAnchor = 'start';
            newX += 10;
          } else if (pos.x < 0) {
            textAnchor = 'end';
            newX -= 10;
          }
        } else {
          textAnchor = 'middle';
        }
        if (Math.abs(pos.y) >= polygonSize - limit) {
          if (pos.y < 0) {
            newY -= 10;
          } else if (pos.y > 0) {
            newY += 10;
          }
        }
        return {
          textAnchor: textAnchor,
          newX: newX,
          newY: newY
        };
      }
    }, {
      key: "getPreviousPath",
      value: function getPreviousPath(realIndex) {
        var w = this.w;
        var pathFrom = null;
        for (var pp = 0; pp < w.globals.previousPaths.length; pp++) {
          var gpp = w.globals.previousPaths[pp];
          if (gpp.paths.length > 0 && parseInt(gpp.realIndex, 10) === parseInt(realIndex, 10)) {
            if (typeof w.globals.previousPaths[pp].paths[0] !== 'undefined') {
              pathFrom = w.globals.previousPaths[pp].paths[0].d;
            }
          }
        }
        return pathFrom;
      }
    }, {
      key: "getDataPointsPos",
      value: function getDataPointsPos(dataRadiusArr, angleArr) {
        var dataPointsLen = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.dataPointsLen;
        dataRadiusArr = dataRadiusArr || [];
        angleArr = angleArr || [];
        var dataPointsPosArray = [];
        for (var j = 0; j < dataPointsLen; j++) {
          var curPointPos = {};
          curPointPos.x = dataRadiusArr[j] * Math.sin(angleArr[j]);
          curPointPos.y = -dataRadiusArr[j] * Math.cos(angleArr[j]);
          dataPointsPosArray.push(curPointPos);
        }
        return dataPointsPosArray;
      }
    }]);
    return Radar;
  }();

  /**
   * ApexCharts Radial Class for drawing Circle / Semi Circle Charts.
   * @module Radial
   **/
  var Radial = /*#__PURE__*/function (_Pie) {
    _inherits(Radial, _Pie);
    var _super = _createSuper(Radial);
    function Radial(ctx) {
      var _this;
      _classCallCheck(this, Radial);
      _this = _super.call(this, ctx);
      _this.ctx = ctx;
      _this.w = ctx.w;
      _this.animBeginArr = [0];
      _this.animDur = 0;
      var w = _this.w;
      _this.startAngle = w.config.plotOptions.radialBar.startAngle;
      _this.endAngle = w.config.plotOptions.radialBar.endAngle;
      _this.totalAngle = Math.abs(w.config.plotOptions.radialBar.endAngle - w.config.plotOptions.radialBar.startAngle);
      _this.trackStartAngle = w.config.plotOptions.radialBar.track.startAngle;
      _this.trackEndAngle = w.config.plotOptions.radialBar.track.endAngle;
      _this.barLabels = _this.w.config.plotOptions.radialBar.barLabels;
      _this.donutDataLabels = _this.w.config.plotOptions.radialBar.dataLabels;
      _this.radialDataLabels = _this.donutDataLabels; // make a copy for easy reference

      if (!_this.trackStartAngle) _this.trackStartAngle = _this.startAngle;
      if (!_this.trackEndAngle) _this.trackEndAngle = _this.endAngle;
      if (_this.endAngle === 360) _this.endAngle = 359.99;
      _this.margin = parseInt(w.config.plotOptions.radialBar.track.margin, 10);
      _this.onBarLabelClick = _this.onBarLabelClick.bind(_assertThisInitialized(_this));
      return _this;
    }
    _createClass(Radial, [{
      key: "draw",
      value: function draw(series) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var ret = graphics.group({
          class: 'apexcharts-radialbar'
        });
        if (w.globals.noData) return ret;
        var elSeries = graphics.group();
        var centerY = this.defaultSize / 2;
        var centerX = w.globals.gridWidth / 2;
        var size = this.defaultSize / 2.05;
        if (!w.config.chart.sparkline.enabled) {
          size = size - w.config.stroke.width - w.config.chart.dropShadow.blur;
        }
        var colorArr = w.globals.fill.colors;
        if (w.config.plotOptions.radialBar.track.show) {
          var elTracks = this.drawTracks({
            size: size,
            centerX: centerX,
            centerY: centerY,
            colorArr: colorArr,
            series: series
          });
          elSeries.add(elTracks);
        }
        var elG = this.drawArcs({
          size: size,
          centerX: centerX,
          centerY: centerY,
          colorArr: colorArr,
          series: series
        });
        var totalAngle = 360;
        if (w.config.plotOptions.radialBar.startAngle < 0) {
          totalAngle = this.totalAngle;
        }
        var angleRatio = (360 - totalAngle) / 360;
        w.globals.radialSize = size - size * angleRatio;
        if (this.radialDataLabels.value.show) {
          var offset = Math.max(this.radialDataLabels.value.offsetY, this.radialDataLabels.name.offsetY);
          w.globals.radialSize += offset * angleRatio;
        }
        elSeries.add(elG.g);
        if (w.config.plotOptions.radialBar.hollow.position === 'front') {
          elG.g.add(elG.elHollow);
          if (elG.dataLabels) {
            elG.g.add(elG.dataLabels);
          }
        }
        ret.add(elSeries);
        return ret;
      }
    }, {
      key: "drawTracks",
      value: function drawTracks(opts) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var g = graphics.group({
          class: 'apexcharts-tracks'
        });
        var filters = new Filters(this.ctx);
        var fill = new Fill(this.ctx);
        var strokeWidth = this.getStrokeWidth(opts);
        opts.size = opts.size - strokeWidth / 2;
        for (var i = 0; i < opts.series.length; i++) {
          var elRadialBarTrack = graphics.group({
            class: 'apexcharts-radialbar-track apexcharts-track'
          });
          g.add(elRadialBarTrack);
          elRadialBarTrack.attr({
            rel: i + 1
          });
          opts.size = opts.size - strokeWidth - this.margin;
          var trackConfig = w.config.plotOptions.radialBar.track;
          var pathFill = fill.fillPath({
            seriesNumber: 0,
            size: opts.size,
            fillColors: Array.isArray(trackConfig.background) ? trackConfig.background[i] : trackConfig.background,
            solid: true
          });
          var startAngle = this.trackStartAngle;
          var endAngle = this.trackEndAngle;
          if (Math.abs(endAngle) + Math.abs(startAngle) >= 360) endAngle = 360 - Math.abs(this.startAngle) - 0.1;
          var elPath = graphics.drawPath({
            d: '',
            stroke: pathFill,
            strokeWidth: strokeWidth * parseInt(trackConfig.strokeWidth, 10) / 100,
            fill: 'none',
            strokeOpacity: trackConfig.opacity,
            classes: 'apexcharts-radialbar-area'
          });
          if (trackConfig.dropShadow.enabled) {
            var shadow = trackConfig.dropShadow;
            filters.dropShadow(elPath, shadow);
          }
          elRadialBarTrack.add(elPath);
          elPath.attr('id', 'apexcharts-radialbarTrack-' + i);
          this.animatePaths(elPath, {
            centerX: opts.centerX,
            centerY: opts.centerY,
            endAngle: endAngle,
            startAngle: startAngle,
            size: opts.size,
            i: i,
            totalItems: 2,
            animBeginArr: 0,
            dur: 0,
            isTrack: true,
            easing: w.globals.easing
          });
        }
        return g;
      }
    }, {
      key: "drawArcs",
      value: function drawArcs(opts) {
        var w = this.w;
        // size, donutSize, centerX, centerY, colorArr, lineColorArr, sectorAngleArr, series

        var graphics = new Graphics(this.ctx);
        var fill = new Fill(this.ctx);
        var filters = new Filters(this.ctx);
        var g = graphics.group();
        var strokeWidth = this.getStrokeWidth(opts);
        opts.size = opts.size - strokeWidth / 2;
        var hollowFillID = w.config.plotOptions.radialBar.hollow.background;
        var hollowSize = opts.size - strokeWidth * opts.series.length - this.margin * opts.series.length - strokeWidth * parseInt(w.config.plotOptions.radialBar.track.strokeWidth, 10) / 100 / 2;
        var hollowRadius = hollowSize - w.config.plotOptions.radialBar.hollow.margin;
        if (w.config.plotOptions.radialBar.hollow.image !== undefined) {
          hollowFillID = this.drawHollowImage(opts, g, hollowSize, hollowFillID);
        }
        var elHollow = this.drawHollow({
          size: hollowRadius,
          centerX: opts.centerX,
          centerY: opts.centerY,
          fill: hollowFillID ? hollowFillID : 'transparent'
        });
        if (w.config.plotOptions.radialBar.hollow.dropShadow.enabled) {
          var shadow = w.config.plotOptions.radialBar.hollow.dropShadow;
          filters.dropShadow(elHollow, shadow);
        }
        var shown = 1;
        if (!this.radialDataLabels.total.show && w.globals.series.length > 1) {
          shown = 0;
        }
        var dataLabels = null;
        if (this.radialDataLabels.show) {
          var dataLabelsGroup = w.globals.dom.Paper.select(".apexcharts-datalabels-group").members[0];
          dataLabels = this.renderInnerDataLabels(dataLabelsGroup, this.radialDataLabels, {
            hollowSize: hollowSize,
            centerX: opts.centerX,
            centerY: opts.centerY,
            opacity: shown
          });
        }
        if (w.config.plotOptions.radialBar.hollow.position === 'back') {
          g.add(elHollow);
          if (dataLabels) {
            g.add(dataLabels);
          }
        }
        var reverseLoop = false;
        if (w.config.plotOptions.radialBar.inverseOrder) {
          reverseLoop = true;
        }
        for (var i = reverseLoop ? opts.series.length - 1 : 0; reverseLoop ? i >= 0 : i < opts.series.length; reverseLoop ? i-- : i++) {
          var elRadialBarArc = graphics.group({
            class: "apexcharts-series apexcharts-radial-series",
            seriesName: Utils$1.escapeString(w.globals.seriesNames[i])
          });
          g.add(elRadialBarArc);
          elRadialBarArc.attr({
            rel: i + 1,
            'data:realIndex': i
          });
          this.ctx.series.addCollapsedClassToSeries(elRadialBarArc, i);
          opts.size = opts.size - strokeWidth - this.margin;
          var pathFill = fill.fillPath({
            seriesNumber: i,
            size: opts.size,
            value: opts.series[i]
          });
          var startAngle = this.startAngle;
          var prevStartAngle = void 0;

          // if data exceeds 100, make it 100
          var dataValue = Utils$1.negToZero(opts.series[i] > 100 ? 100 : opts.series[i]) / 100;
          var endAngle = Math.round(this.totalAngle * dataValue) + this.startAngle;
          var prevEndAngle = void 0;
          if (w.globals.dataChanged) {
            prevStartAngle = this.startAngle;
            prevEndAngle = Math.round(this.totalAngle * Utils$1.negToZero(w.globals.previousPaths[i]) / 100) + prevStartAngle;
          }
          var currFullAngle = Math.abs(endAngle) + Math.abs(startAngle);
          if (currFullAngle > 360) {
            endAngle = endAngle - 0.01;
          }
          var prevFullAngle = Math.abs(prevEndAngle) + Math.abs(prevStartAngle);
          if (prevFullAngle > 360) {
            prevEndAngle = prevEndAngle - 0.01;
          }
          var angle = endAngle - startAngle;
          var dashArray = Array.isArray(w.config.stroke.dashArray) ? w.config.stroke.dashArray[i] : w.config.stroke.dashArray;
          var elPath = graphics.drawPath({
            d: '',
            stroke: pathFill,
            strokeWidth: strokeWidth,
            fill: 'none',
            fillOpacity: w.config.fill.opacity,
            classes: 'apexcharts-radialbar-area apexcharts-radialbar-slice-' + i,
            strokeDashArray: dashArray
          });
          Graphics.setAttrs(elPath.node, {
            'data:angle': angle,
            'data:value': opts.series[i]
          });
          if (w.config.chart.dropShadow.enabled) {
            var _shadow = w.config.chart.dropShadow;
            filters.dropShadow(elPath, _shadow, i);
          }
          filters.setSelectionFilter(elPath, 0, i);
          this.addListeners(elPath, this.radialDataLabels);
          elRadialBarArc.add(elPath);
          elPath.attr({
            index: 0,
            j: i
          });
          if (this.barLabels.enabled) {
            var barStartCords = Utils$1.polarToCartesian(opts.centerX, opts.centerY, opts.size, startAngle);
            var text = this.barLabels.formatter(w.globals.seriesNames[i], {
              seriesIndex: i,
              w: w
            });
            var classes = ['apexcharts-radialbar-label'];
            if (!this.barLabels.onClick) {
              classes.push('apexcharts-no-click');
            }
            var textColor = this.barLabels.useSeriesColors ? w.globals.colors[i] : w.config.chart.foreColor;
            if (!textColor) {
              textColor = w.config.chart.foreColor;
            }
            var x = barStartCords.x + this.barLabels.offsetX;
            var y = barStartCords.y + this.barLabels.offsetY;
            var elText = graphics.drawText({
              x: x,
              y: y,
              text: text,
              textAnchor: 'end',
              dominantBaseline: 'middle',
              fontFamily: this.barLabels.fontFamily,
              fontWeight: this.barLabels.fontWeight,
              fontSize: this.barLabels.fontSize,
              foreColor: textColor,
              cssClass: classes.join(' ')
            });
            elText.on('click', this.onBarLabelClick);
            elText.attr({
              rel: i + 1
            });
            if (startAngle !== 0) {
              elText.attr({
                'transform-origin': "".concat(x, " ").concat(y),
                transform: "rotate(".concat(startAngle, " 0 0)")
              });
            }
            elRadialBarArc.add(elText);
          }
          var dur = 0;
          if (this.initialAnim && !w.globals.resized && !w.globals.dataChanged) {
            dur = w.config.chart.animations.speed;
          }
          if (w.globals.dataChanged) {
            dur = w.config.chart.animations.dynamicAnimation.speed;
          }
          this.animDur = dur / (opts.series.length * 1.2) + this.animDur;
          this.animBeginArr.push(this.animDur);
          this.animatePaths(elPath, {
            centerX: opts.centerX,
            centerY: opts.centerY,
            endAngle: endAngle,
            startAngle: startAngle,
            prevEndAngle: prevEndAngle,
            prevStartAngle: prevStartAngle,
            size: opts.size,
            i: i,
            totalItems: 2,
            animBeginArr: this.animBeginArr,
            dur: dur,
            shouldSetPrevPaths: true,
            easing: w.globals.easing
          });
        }
        return {
          g: g,
          elHollow: elHollow,
          dataLabels: dataLabels
        };
      }
    }, {
      key: "drawHollow",
      value: function drawHollow(opts) {
        var graphics = new Graphics(this.ctx);
        var circle = graphics.drawCircle(opts.size * 2);
        circle.attr({
          class: 'apexcharts-radialbar-hollow',
          cx: opts.centerX,
          cy: opts.centerY,
          r: opts.size,
          fill: opts.fill
        });
        return circle;
      }
    }, {
      key: "drawHollowImage",
      value: function drawHollowImage(opts, g, hollowSize, hollowFillID) {
        var w = this.w;
        var fill = new Fill(this.ctx);
        var randID = Utils$1.randomId();
        var hollowFillImg = w.config.plotOptions.radialBar.hollow.image;
        if (w.config.plotOptions.radialBar.hollow.imageClipped) {
          fill.clippedImgArea({
            width: hollowSize,
            height: hollowSize,
            image: hollowFillImg,
            patternID: "pattern".concat(w.globals.cuid).concat(randID)
          });
          hollowFillID = "url(#pattern".concat(w.globals.cuid).concat(randID, ")");
        } else {
          var imgWidth = w.config.plotOptions.radialBar.hollow.imageWidth;
          var imgHeight = w.config.plotOptions.radialBar.hollow.imageHeight;
          if (imgWidth === undefined && imgHeight === undefined) {
            var image = w.globals.dom.Paper.image(hollowFillImg).loaded(function (loader) {
              this.move(opts.centerX - loader.width / 2 + w.config.plotOptions.radialBar.hollow.imageOffsetX, opts.centerY - loader.height / 2 + w.config.plotOptions.radialBar.hollow.imageOffsetY);
            });
            g.add(image);
          } else {
            var _image = w.globals.dom.Paper.image(hollowFillImg).loaded(function (loader) {
              this.move(opts.centerX - imgWidth / 2 + w.config.plotOptions.radialBar.hollow.imageOffsetX, opts.centerY - imgHeight / 2 + w.config.plotOptions.radialBar.hollow.imageOffsetY);
              this.size(imgWidth, imgHeight);
            });
            g.add(_image);
          }
        }
        return hollowFillID;
      }
    }, {
      key: "getStrokeWidth",
      value: function getStrokeWidth(opts) {
        var w = this.w;
        return opts.size * (100 - parseInt(w.config.plotOptions.radialBar.hollow.size, 10)) / 100 / (opts.series.length + 1) - this.margin;
      }
    }, {
      key: "onBarLabelClick",
      value: function onBarLabelClick(e) {
        var seriesIndex = parseInt(e.target.getAttribute('rel'), 10) - 1;
        var legendClick = this.barLabels.onClick;
        var w = this.w;
        if (legendClick) {
          legendClick(w.globals.seriesNames[seriesIndex], {
            w: w,
            seriesIndex: seriesIndex
          });
        }
      }
    }]);
    return Radial;
  }(Pie);

  /**
   * ApexCharts RangeBar Class responsible for drawing Range/Timeline Bars.
   *
   * @module RangeBar
   **/
  var RangeBar = /*#__PURE__*/function (_Bar) {
    _inherits(RangeBar, _Bar);
    var _super = _createSuper(RangeBar);
    function RangeBar() {
      _classCallCheck(this, RangeBar);
      return _super.apply(this, arguments);
    }
    _createClass(RangeBar, [{
      key: "draw",
      value: function draw(series, seriesIndex) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        this.rangeBarOptions = this.w.config.plotOptions.rangeBar;
        this.series = series;
        this.seriesRangeStart = w.globals.seriesRangeStart;
        this.seriesRangeEnd = w.globals.seriesRangeEnd;
        this.barHelpers.initVariables(series);
        var ret = graphics.group({
          class: 'apexcharts-rangebar-series apexcharts-plot-series'
        });
        for (var i = 0; i < series.length; i++) {
          var x = void 0,
            y = void 0,
            xDivision = void 0,
            // xDivision is the GRIDWIDTH divided by number of datapoints (columns)
            yDivision = void 0,
            // yDivision is the GRIDHEIGHT divided by number of datapoints (bars)
            zeroH = void 0,
            // zeroH is the baseline where 0 meets y axis
            zeroW = void 0; // zeroW is the baseline where 0 meets x axis

          var realIndex = w.globals.comboCharts ? seriesIndex[i] : i;
          var _this$barHelpers$getG = this.barHelpers.getGroupIndex(realIndex),
            columnGroupIndex = _this$barHelpers$getG.columnGroupIndex;

          // el to which series will be drawn
          var elSeries = graphics.group({
            class: "apexcharts-series",
            seriesName: Utils$1.escapeString(w.globals.seriesNames[realIndex]),
            rel: i + 1,
            'data:realIndex': realIndex
          });
          this.ctx.series.addCollapsedClassToSeries(elSeries, realIndex);
          if (series[i].length > 0) {
            this.visibleI = this.visibleI + 1;
          }
          var barHeight = 0;
          var barWidth = 0;
          var translationsIndex = 0;
          if (this.yRatio.length > 1) {
            this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex][0];
            translationsIndex = realIndex;
          }
          var initPositions = this.barHelpers.initialPositions();
          y = initPositions.y;
          zeroW = initPositions.zeroW;
          x = initPositions.x;
          barWidth = initPositions.barWidth;
          barHeight = initPositions.barHeight;
          xDivision = initPositions.xDivision;
          yDivision = initPositions.yDivision;
          zeroH = initPositions.zeroH;

          // eldatalabels
          var elDataLabelsWrap = graphics.group({
            class: 'apexcharts-datalabels',
            'data:realIndex': realIndex
          });
          var elGoalsMarkers = graphics.group({
            class: 'apexcharts-rangebar-goals-markers'
          });
          for (var j = 0; j < w.globals.dataPoints; j++) {
            var strokeWidth = this.barHelpers.getStrokeWidth(i, j, realIndex);
            var y1 = this.seriesRangeStart[i][j];
            var y2 = this.seriesRangeEnd[i][j];
            var paths = null;
            var barXPosition = null;
            var barYPosition = null;
            var params = {
              x: x,
              y: y,
              strokeWidth: strokeWidth,
              elSeries: elSeries
            };
            var seriesLen = this.seriesLen;
            if (w.config.plotOptions.bar.rangeBarGroupRows) {
              seriesLen = 1;
            }
            if (typeof w.config.series[i].data[j] === 'undefined') {
              // no data exists for further indexes, hence we need to get out the innr loop.
              // As we are iterating over total datapoints, there is a possiblity the series might not have data for j index
              break;
            }
            if (this.isHorizontal) {
              barYPosition = y + barHeight * this.visibleI;
              var srty = (yDivision - barHeight * seriesLen) / 2;
              if (w.config.series[i].data[j].x) {
                var positions = this.detectOverlappingBars({
                  i: i,
                  j: j,
                  barYPosition: barYPosition,
                  srty: srty,
                  barHeight: barHeight,
                  yDivision: yDivision,
                  initPositions: initPositions
                });
                barHeight = positions.barHeight;
                barYPosition = positions.barYPosition;
              }
              paths = this.drawRangeBarPaths(_objectSpread2({
                indexes: {
                  i: i,
                  j: j,
                  realIndex: realIndex
                },
                barHeight: barHeight,
                barYPosition: barYPosition,
                zeroW: zeroW,
                yDivision: yDivision,
                y1: y1,
                y2: y2
              }, params));
              barWidth = paths.barWidth;
            } else {
              if (w.globals.isXNumeric) {
                x = (w.globals.seriesX[i][j] - w.globals.minX) / this.xRatio - barWidth / 2;
              }
              barXPosition = x + barWidth * this.visibleI;
              var srtx = (xDivision - barWidth * seriesLen) / 2;
              if (w.config.series[i].data[j].x) {
                var _positions = this.detectOverlappingBars({
                  i: i,
                  j: j,
                  barXPosition: barXPosition,
                  srtx: srtx,
                  barWidth: barWidth,
                  xDivision: xDivision,
                  initPositions: initPositions
                });
                barWidth = _positions.barWidth;
                barXPosition = _positions.barXPosition;
              }
              paths = this.drawRangeColumnPaths(_objectSpread2({
                indexes: {
                  i: i,
                  j: j,
                  realIndex: realIndex,
                  translationsIndex: translationsIndex
                },
                barWidth: barWidth,
                barXPosition: barXPosition,
                zeroH: zeroH,
                xDivision: xDivision
              }, params));
              barHeight = paths.barHeight;
            }
            var barGoalLine = this.barHelpers.drawGoalLine({
              barXPosition: paths.barXPosition,
              barYPosition: barYPosition,
              goalX: paths.goalX,
              goalY: paths.goalY,
              barHeight: barHeight,
              barWidth: barWidth
            });
            if (barGoalLine) {
              elGoalsMarkers.add(barGoalLine);
            }
            y = paths.y;
            x = paths.x;
            var pathFill = this.barHelpers.getPathFillColor(series, i, j, realIndex);
            var lineFill = w.globals.stroke.colors[realIndex];
            this.renderSeries({
              realIndex: realIndex,
              pathFill: pathFill,
              lineFill: lineFill,
              j: j,
              i: i,
              x: x,
              y: y,
              y1: y1,
              y2: y2,
              pathFrom: paths.pathFrom,
              pathTo: paths.pathTo,
              strokeWidth: strokeWidth,
              elSeries: elSeries,
              series: series,
              barHeight: barHeight,
              barWidth: barWidth,
              barXPosition: barXPosition,
              barYPosition: barYPosition,
              columnGroupIndex: columnGroupIndex,
              elDataLabelsWrap: elDataLabelsWrap,
              elGoalsMarkers: elGoalsMarkers,
              visibleSeries: this.visibleI,
              type: 'rangebar'
            });
          }
          ret.add(elSeries);
        }
        return ret;
      }
    }, {
      key: "detectOverlappingBars",
      value: function detectOverlappingBars(_ref) {
        var i = _ref.i,
          j = _ref.j,
          barYPosition = _ref.barYPosition,
          barXPosition = _ref.barXPosition,
          srty = _ref.srty,
          srtx = _ref.srtx,
          barHeight = _ref.barHeight,
          barWidth = _ref.barWidth,
          yDivision = _ref.yDivision,
          xDivision = _ref.xDivision,
          initPositions = _ref.initPositions;
        var w = this.w;
        var overlaps = [];
        var rangeName = w.config.series[i].data[j].rangeName;
        var x = w.config.series[i].data[j].x;
        var labelX = Array.isArray(x) ? x.join(' ') : x;
        var rowIndex = w.globals.labels.map(function (_) {
          return Array.isArray(_) ? _.join(' ') : _;
        }).indexOf(labelX);
        var overlappedIndex = w.globals.seriesRange[i].findIndex(function (tx) {
          return tx.x === labelX && tx.overlaps.length > 0;
        });
        if (this.isHorizontal) {
          if (w.config.plotOptions.bar.rangeBarGroupRows) {
            barYPosition = srty + yDivision * rowIndex;
          } else {
            barYPosition = srty + barHeight * this.visibleI + yDivision * rowIndex;
          }
          if (overlappedIndex > -1 && !w.config.plotOptions.bar.rangeBarOverlap) {
            overlaps = w.globals.seriesRange[i][overlappedIndex].overlaps;
            if (overlaps.indexOf(rangeName) > -1) {
              barHeight = initPositions.barHeight / overlaps.length;
              barYPosition = barHeight * this.visibleI + yDivision * (100 - parseInt(this.barOptions.barHeight, 10)) / 100 / 2 + barHeight * (this.visibleI + overlaps.indexOf(rangeName)) + yDivision * rowIndex;
            }
          }
        } else {
          if (rowIndex > -1 && !w.globals.timescaleLabels.length) {
            if (w.config.plotOptions.bar.rangeBarGroupRows) {
              barXPosition = srtx + xDivision * rowIndex;
            } else {
              barXPosition = srtx + barWidth * this.visibleI + xDivision * rowIndex;
            }
          }
          if (overlappedIndex > -1 && !w.config.plotOptions.bar.rangeBarOverlap) {
            overlaps = w.globals.seriesRange[i][overlappedIndex].overlaps;
            if (overlaps.indexOf(rangeName) > -1) {
              barWidth = initPositions.barWidth / overlaps.length;
              barXPosition = barWidth * this.visibleI + xDivision * (100 - parseInt(this.barOptions.barWidth, 10)) / 100 / 2 + barWidth * (this.visibleI + overlaps.indexOf(rangeName)) + xDivision * rowIndex;
            }
          }
        }
        return {
          barYPosition: barYPosition,
          barXPosition: barXPosition,
          barHeight: barHeight,
          barWidth: barWidth
        };
      }
    }, {
      key: "drawRangeColumnPaths",
      value: function drawRangeColumnPaths(_ref2) {
        var indexes = _ref2.indexes,
          x = _ref2.x,
          xDivision = _ref2.xDivision,
          barWidth = _ref2.barWidth,
          barXPosition = _ref2.barXPosition,
          zeroH = _ref2.zeroH;
        var w = this.w;
        var i = indexes.i,
          j = indexes.j,
          realIndex = indexes.realIndex,
          translationsIndex = indexes.translationsIndex;
        var yRatio = this.yRatio[translationsIndex];
        var range = this.getRangeValue(realIndex, j);
        var y1 = Math.min(range.start, range.end);
        var y2 = Math.max(range.start, range.end);
        if (typeof this.series[i][j] === 'undefined' || this.series[i][j] === null) {
          y1 = zeroH;
        } else {
          y1 = zeroH - y1 / yRatio;
          y2 = zeroH - y2 / yRatio;
        }
        var barHeight = Math.abs(y2 - y1);
        var paths = this.barHelpers.getColumnPaths({
          barXPosition: barXPosition,
          barWidth: barWidth,
          y1: y1,
          y2: y2,
          strokeWidth: this.strokeWidth,
          series: this.seriesRangeEnd,
          realIndex: realIndex,
          i: realIndex,
          j: j,
          w: w
        });
        if (!w.globals.isXNumeric) {
          x = x + xDivision;
        } else {
          var xForNumericXAxis = this.getBarXForNumericXAxis({
            x: x,
            j: j,
            realIndex: realIndex,
            barWidth: barWidth
          });
          x = xForNumericXAxis.x;
          barXPosition = xForNumericXAxis.barXPosition;
        }
        return {
          pathTo: paths.pathTo,
          pathFrom: paths.pathFrom,
          barHeight: barHeight,
          x: x,
          y: range.start < 0 && range.end < 0 ? y1 : y2,
          goalY: this.barHelpers.getGoalValues('y', null, zeroH, i, j, translationsIndex),
          barXPosition: barXPosition
        };
      }
    }, {
      key: "preventBarOverflow",
      value: function preventBarOverflow(val) {
        var w = this.w;
        if (val < 0) {
          val = 0;
        }
        if (val > w.globals.gridWidth) {
          val = w.globals.gridWidth;
        }
        return val;
      }
    }, {
      key: "drawRangeBarPaths",
      value: function drawRangeBarPaths(_ref3) {
        var indexes = _ref3.indexes,
          y = _ref3.y,
          y1 = _ref3.y1,
          y2 = _ref3.y2,
          yDivision = _ref3.yDivision,
          barHeight = _ref3.barHeight,
          barYPosition = _ref3.barYPosition,
          zeroW = _ref3.zeroW;
        var w = this.w;
        var realIndex = indexes.realIndex,
          j = indexes.j;
        var x1 = this.preventBarOverflow(zeroW + y1 / this.invertedYRatio);
        var x2 = this.preventBarOverflow(zeroW + y2 / this.invertedYRatio);
        var range = this.getRangeValue(realIndex, j);
        var barWidth = Math.abs(x2 - x1);
        var paths = this.barHelpers.getBarpaths({
          barYPosition: barYPosition,
          barHeight: barHeight,
          x1: x1,
          x2: x2,
          strokeWidth: this.strokeWidth,
          series: this.seriesRangeEnd,
          i: realIndex,
          realIndex: realIndex,
          j: j,
          w: w
        });
        if (!w.globals.isXNumeric) {
          y = y + yDivision;
        }
        return {
          pathTo: paths.pathTo,
          pathFrom: paths.pathFrom,
          barWidth: barWidth,
          x: range.start < 0 && range.end < 0 ? x1 : x2,
          goalX: this.barHelpers.getGoalValues('x', zeroW, null, realIndex, j),
          y: y
        };
      }
    }, {
      key: "getRangeValue",
      value: function getRangeValue(i, j) {
        var w = this.w;
        return {
          start: w.globals.seriesRangeStart[i][j],
          end: w.globals.seriesRangeEnd[i][j]
        };
      }
    }]);
    return RangeBar;
  }(Bar);

  var Helpers = /*#__PURE__*/function () {
    function Helpers(lineCtx) {
      _classCallCheck(this, Helpers);
      this.w = lineCtx.w;
      this.lineCtx = lineCtx;
    }
    _createClass(Helpers, [{
      key: "sameValueSeriesFix",
      value: function sameValueSeriesFix(i, series) {
        var w = this.w;
        if (w.config.fill.type === 'gradient' || w.config.fill.type[i] === 'gradient') {
          var coreUtils = new CoreUtils(this.lineCtx.ctx, w);

          // applied only to LINE chart
          // a small adjustment to allow gradient line to draw correctly for all same values
          /* #fix https://github.com/apexcharts/apexcharts.js/issues/358 */
          if (coreUtils.seriesHaveSameValues(i)) {
            var gSeries = series[i].slice();
            gSeries[gSeries.length - 1] = gSeries[gSeries.length - 1] + 0.000001;
            series[i] = gSeries;
          }
        }
        return series;
      }
    }, {
      key: "calculatePoints",
      value: function calculatePoints(_ref) {
        var series = _ref.series,
          realIndex = _ref.realIndex,
          x = _ref.x,
          y = _ref.y,
          i = _ref.i,
          j = _ref.j,
          prevY = _ref.prevY;
        var w = this.w;
        var ptX = [];
        var ptY = [];
        if (j === 0) {
          var xPT1st = this.lineCtx.categoryAxisCorrection + w.config.markers.offsetX;
          // the first point for line series
          // we need to check whether it's not a time series, because a time series may
          // start from the middle of the x axis
          if (w.globals.isXNumeric) {
            xPT1st = (w.globals.seriesX[realIndex][0] - w.globals.minX) / this.lineCtx.xRatio + w.config.markers.offsetX;
          }

          // push 2 points for the first data values
          ptX.push(xPT1st);
          ptY.push(Utils$1.isNumber(series[i][0]) ? prevY + w.config.markers.offsetY : null);
          ptX.push(x + w.config.markers.offsetX);
          ptY.push(Utils$1.isNumber(series[i][j + 1]) ? y + w.config.markers.offsetY : null);
        } else {
          ptX.push(x + w.config.markers.offsetX);
          ptY.push(Utils$1.isNumber(series[i][j + 1]) ? y + w.config.markers.offsetY : null);
        }
        var pointsPos = {
          x: ptX,
          y: ptY
        };
        return pointsPos;
      }
    }, {
      key: "checkPreviousPaths",
      value: function checkPreviousPaths(_ref2) {
        var pathFromLine = _ref2.pathFromLine,
          pathFromArea = _ref2.pathFromArea,
          realIndex = _ref2.realIndex;
        var w = this.w;
        for (var pp = 0; pp < w.globals.previousPaths.length; pp++) {
          var gpp = w.globals.previousPaths[pp];
          if ((gpp.type === 'line' || gpp.type === 'area') && gpp.paths.length > 0 && parseInt(gpp.realIndex, 10) === parseInt(realIndex, 10)) {
            if (gpp.type === 'line') {
              this.lineCtx.appendPathFrom = false;
              pathFromLine = w.globals.previousPaths[pp].paths[0].d;
            } else if (gpp.type === 'area') {
              this.lineCtx.appendPathFrom = false;
              pathFromArea = w.globals.previousPaths[pp].paths[0].d;
              if (w.config.stroke.show && w.globals.previousPaths[pp].paths[1]) {
                pathFromLine = w.globals.previousPaths[pp].paths[1].d;
              }
            }
          }
        }
        return {
          pathFromLine: pathFromLine,
          pathFromArea: pathFromArea
        };
      }
    }, {
      key: "determineFirstPrevY",
      value: function determineFirstPrevY(_ref3) {
        var _this$w$config$series, _this$w$config$series2, _series$i;
        var i = _ref3.i,
          realIndex = _ref3.realIndex,
          series = _ref3.series,
          prevY = _ref3.prevY,
          lineYPosition = _ref3.lineYPosition,
          translationsIndex = _ref3.translationsIndex;
        var w = this.w;
        var stackSeries = w.config.chart.stacked && !w.globals.comboCharts || w.config.chart.stacked && w.globals.comboCharts && (!this.w.config.chart.stackOnlyBar || ((_this$w$config$series = this.w.config.series[realIndex]) === null || _this$w$config$series === void 0 ? void 0 : _this$w$config$series.type) === 'bar' || ((_this$w$config$series2 = this.w.config.series[realIndex]) === null || _this$w$config$series2 === void 0 ? void 0 : _this$w$config$series2.type) === 'column');
        if (typeof ((_series$i = series[i]) === null || _series$i === void 0 ? void 0 : _series$i[0]) !== 'undefined') {
          if (stackSeries) {
            if (i > 0) {
              // 1st y value of previous series
              lineYPosition = this.lineCtx.prevSeriesY[i - 1][0];
            } else {
              // the first series will not have prevY values
              lineYPosition = this.lineCtx.zeroY;
            }
          } else {
            lineYPosition = this.lineCtx.zeroY;
          }
          prevY = lineYPosition - series[i][0] / this.lineCtx.yRatio[translationsIndex] + (this.lineCtx.isReversed ? series[i][0] / this.lineCtx.yRatio[translationsIndex] : 0) * 2;
        } else {
          // the first value in the current series is null
          if (stackSeries && i > 0 && typeof series[i][0] === 'undefined') {
            // check for undefined value (undefined value will occur when we clear the series while user clicks on legend to hide serieses)
            for (var s = i - 1; s >= 0; s--) {
              // for loop to get to 1st previous value until we get it
              if (series[s][0] !== null && typeof series[s][0] !== 'undefined') {
                lineYPosition = this.lineCtx.prevSeriesY[s][0];
                prevY = lineYPosition;
                break;
              }
            }
          }
        }
        return {
          prevY: prevY,
          lineYPosition: lineYPosition
        };
      }
    }]);
    return Helpers;
  }();

  /**
   * 
   * @yr/monotone-cubic-spline (https://github.com/YR/monotone-cubic-spline)
   * 
   * The MIT License (MIT)
   * 
   * Copyright (c) 2015 yr.no
   * 
   * 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.
   */
  /**
   * Generate tangents for 'points'
   * @param {Array} points
   * @returns {Array}
   */
  var tangents = function tangents(points) {
    var m = finiteDifferences(points);
    var n = points.length - 1;
    var ε = 1e-6;
    var tgts = [];
    var a, b, d, s;
    for (var i = 0; i < n; i++) {
      d = slope(points[i], points[i + 1]);
      if (Math.abs(d) < ε) {
        m[i] = m[i + 1] = 0;
      } else {
        a = m[i] / d;
        b = m[i + 1] / d;
        s = a * a + b * b;
        if (s > 9) {
          s = d * 3 / Math.sqrt(s);
          m[i] = s * a;
          m[i + 1] = s * b;
        }
      }
    }
    for (var _i = 0; _i <= n; _i++) {
      s = (points[Math.min(n, _i + 1)][0] - points[Math.max(0, _i - 1)][0]) / (6 * (1 + m[_i] * m[_i]));
      tgts.push([s || 0, m[_i] * s || 0]);
    }
    return tgts;
  };

  /**
   * Convert 'points' to svg path
   * @param {Array} points
   * @returns {String}
   */
  var svgPath = function svgPath(points) {
    var p = '';
    for (var i = 0; i < points.length; i++) {
      var point = points[i];
      var n = point.length;
      if (n > 4) {
        p += "C".concat(point[0], ", ").concat(point[1]);
        p += ", ".concat(point[2], ", ").concat(point[3]);
        p += ", ".concat(point[4], ", ").concat(point[5]);
      } else if (n > 2) {
        p += "S".concat(point[0], ", ").concat(point[1]);
        p += ", ".concat(point[2], ", ").concat(point[3]);
      }
    }
    return p;
  };
  var spline = {
    /**
     * Convert 'points' to bezier
     * @param {Array} points
     * @returns {Array}
     */
    points: function points(_points) {
      var tgts = tangents(_points);
      var p = _points[1];
      var p0 = _points[0];
      var pts = [];
      var t = tgts[1];
      var t0 = tgts[0];

      // Add starting 'M' and 'C' points
      pts.push(p0, [p0[0] + t0[0], p0[1] + t0[1], p[0] - t[0], p[1] - t[1], p[0], p[1]]);

      // Add 'S' points
      for (var i = 2, n = tgts.length; i < n; i++) {
        var _p = _points[i];
        var _t = tgts[i];
        pts.push([_p[0] - _t[0], _p[1] - _t[1], _p[0], _p[1]]);
      }
      return pts;
    },
    /**
     * Slice out a segment of 'points'
     * @param {Array} points
     * @param {Number} start
     * @param {Number} end
     * @returns {Array}
     */
    slice: function slice(points, start, end) {
      var pts = points.slice(start, end);
      if (start) {
        // Add additional 'C' points
        if (end - start > 1 && pts[1].length < 6) {
          var n = pts[0].length;
          pts[1] = [pts[0][n - 2] * 2 - pts[0][n - 4], pts[0][n - 1] * 2 - pts[0][n - 3]].concat(pts[1]);
        }
        // Remove control points for 'M'
        pts[0] = pts[0].slice(-2);
      }
      return pts;
    }
  };

  /**
   * Compute slope from point 'p0' to 'p1'
   * @param {Array} p0
   * @param {Array} p1
   * @returns {Number}
   */
  function slope(p0, p1) {
    return (p1[1] - p0[1]) / (p1[0] - p0[0]);
  }

  /**
   * Compute three-point differences for 'points'
   * @param {Array} points
   * @returns {Array}
   */
  function finiteDifferences(points) {
    var m = [];
    var p0 = points[0];
    var p1 = points[1];
    var d = m[0] = slope(p0, p1);
    var i = 1;
    for (var n = points.length - 1; i < n; i++) {
      p0 = p1;
      p1 = points[i + 1];
      m[i] = (d + (d = slope(p0, p1))) * 0.5;
    }
    m[i] = d;
    return m;
  }

  /**
   * ApexCharts Line Class responsible for drawing Line / Area / RangeArea Charts.
   * This class is also responsible for generating values for Bubble/Scatter charts, so need to rename it to Axis Charts to avoid confusions
   * @module Line
   **/
  var Line = /*#__PURE__*/function () {
    function Line(ctx, xyRatios, isPointsChart) {
      _classCallCheck(this, Line);
      this.ctx = ctx;
      this.w = ctx.w;
      this.xyRatios = xyRatios;
      this.pointsChart = !(this.w.config.chart.type !== 'bubble' && this.w.config.chart.type !== 'scatter') || isPointsChart;
      this.scatter = new Scatter(this.ctx);
      this.noNegatives = this.w.globals.minX === Number.MAX_VALUE;
      this.lineHelpers = new Helpers(this);
      this.markers = new Markers(this.ctx);
      this.prevSeriesY = [];
      this.categoryAxisCorrection = 0;
      this.yaxisIndex = 0;
    }
    _createClass(Line, [{
      key: "draw",
      value: function draw(series, ctype, seriesIndex, seriesRangeEnd) {
        var _w$config$series$;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var type = w.globals.comboCharts ? ctype : w.config.chart.type;
        var ret = graphics.group({
          class: "apexcharts-".concat(type, "-series apexcharts-plot-series")
        });
        var coreUtils = new CoreUtils(this.ctx, w);
        this.yRatio = this.xyRatios.yRatio;
        this.zRatio = this.xyRatios.zRatio;
        this.xRatio = this.xyRatios.xRatio;
        this.baseLineY = this.xyRatios.baseLineY;
        series = coreUtils.getLogSeries(series);
        this.yRatio = coreUtils.getLogYRatios(this.yRatio);
        // We call draw() for each series group
        this.prevSeriesY = [];

        // push all series in an array, so we can draw in reverse order
        // (for stacked charts)
        var allSeries = [];
        for (var i = 0; i < series.length; i++) {
          series = this.lineHelpers.sameValueSeriesFix(i, series);
          var realIndex = w.globals.comboCharts ? seriesIndex[i] : i;
          var translationsIndex = this.yRatio.length > 1 ? realIndex : 0;
          this._initSerieVariables(series, i, realIndex);
          var yArrj = []; // hold y values of current iterating series
          var y2Arrj = []; // holds y2 values in range-area charts
          var xArrj = []; // hold x values of current iterating series

          var x = w.globals.padHorizontal + this.categoryAxisCorrection;
          var y = 1;
          var linePaths = [];
          var areaPaths = [];
          this.ctx.series.addCollapsedClassToSeries(this.elSeries, realIndex);
          if (w.globals.isXNumeric && w.globals.seriesX.length > 0) {
            x = (w.globals.seriesX[realIndex][0] - w.globals.minX) / this.xRatio;
          }
          xArrj.push(x);
          var pX = x;
          var pY = void 0;
          var pY2 = void 0;
          var prevX = pX;
          var prevY = this.zeroY;
          var prevY2 = this.zeroY;
          var lineYPosition = 0;

          // the first value in the current series is not null or undefined
          var firstPrevY = this.lineHelpers.determineFirstPrevY({
            i: i,
            realIndex: realIndex,
            series: series,
            prevY: prevY,
            lineYPosition: lineYPosition,
            translationsIndex: translationsIndex
          });
          prevY = firstPrevY.prevY;
          if (w.config.stroke.curve === 'monotoneCubic' && series[i][0] === null) {
            // we have to discard the y position if 1st dataPoint is null as it
            // causes issues with monotoneCubic path creation
            yArrj.push(null);
          } else {
            yArrj.push(prevY);
          }
          pY = prevY;

          // y2 are needed for range-area charts
          var firstPrevY2 = void 0;
          if (type === 'rangeArea') {
            firstPrevY2 = this.lineHelpers.determineFirstPrevY({
              i: i,
              realIndex: realIndex,
              series: seriesRangeEnd,
              prevY: prevY2,
              lineYPosition: lineYPosition,
              translationsIndex: translationsIndex
            });
            prevY2 = firstPrevY2.prevY;
            pY2 = prevY2;
            y2Arrj.push(yArrj[0] !== null ? prevY2 : null);
          }
          var pathsFrom = this._calculatePathsFrom({
            type: type,
            series: series,
            i: i,
            realIndex: realIndex,
            translationsIndex: translationsIndex,
            prevX: prevX,
            prevY: prevY,
            prevY2: prevY2
          });

          // RangeArea will resume with these for the upper path creation
          var rYArrj = [yArrj[0]];
          var rY2Arrj = [y2Arrj[0]];
          var iteratingOpts = {
            type: type,
            series: series,
            realIndex: realIndex,
            translationsIndex: translationsIndex,
            i: i,
            x: x,
            y: y,
            pX: pX,
            pY: pY,
            pathsFrom: pathsFrom,
            linePaths: linePaths,
            areaPaths: areaPaths,
            seriesIndex: seriesIndex,
            lineYPosition: lineYPosition,
            xArrj: xArrj,
            yArrj: yArrj,
            y2Arrj: y2Arrj,
            seriesRangeEnd: seriesRangeEnd
          };
          var paths = this._iterateOverDataPoints(_objectSpread2(_objectSpread2({}, iteratingOpts), {}, {
            iterations: type === 'rangeArea' ? series[i].length - 1 : undefined,
            isRangeStart: true
          }));
          if (type === 'rangeArea') {
            var pathsFrom2 = this._calculatePathsFrom({
              series: seriesRangeEnd,
              i: i,
              realIndex: realIndex,
              prevX: prevX,
              prevY: prevY2
            });
            var rangePaths = this._iterateOverDataPoints(_objectSpread2(_objectSpread2({}, iteratingOpts), {}, {
              series: seriesRangeEnd,
              xArrj: [x],
              yArrj: rYArrj,
              y2Arrj: rY2Arrj,
              pY: pY2,
              areaPaths: paths.areaPaths,
              pathsFrom: pathsFrom2,
              iterations: seriesRangeEnd[i].length - 1,
              isRangeStart: false
            }));

            // Path may be segmented by nulls in data.
            // paths.linePaths should hold (segments * 2) paths (upper and lower)
            // the first n segments belong to the lower and the last n segments
            // belong to the upper.
            // paths.linePaths and rangePaths.linepaths are actually equivalent
            // but we retain the distinction below for consistency with the
            // unsegmented paths conditional branch.
            var segments = paths.linePaths.length / 2;
            for (var s = 0; s < segments; s++) {
              paths.linePaths[s] = rangePaths.linePaths[s + segments] + paths.linePaths[s];
            }
            paths.linePaths.splice(segments);
            paths.pathFromLine = rangePaths.pathFromLine + paths.pathFromLine;
          } else {
            paths.pathFromArea += 'z';
          }
          this._handlePaths({
            type: type,
            realIndex: realIndex,
            i: i,
            paths: paths
          });
          this.elSeries.add(this.elPointsMain);
          this.elSeries.add(this.elDataLabelsWrap);
          allSeries.push(this.elSeries);
        }
        if (typeof ((_w$config$series$ = w.config.series[0]) === null || _w$config$series$ === void 0 ? void 0 : _w$config$series$.zIndex) !== 'undefined') {
          allSeries.sort(function (a, b) {
            return Number(a.node.getAttribute('zIndex')) - Number(b.node.getAttribute('zIndex'));
          });
        }
        if (w.config.chart.stacked) {
          for (var _s = allSeries.length - 1; _s >= 0; _s--) {
            ret.add(allSeries[_s]);
          }
        } else {
          for (var _s2 = 0; _s2 < allSeries.length; _s2++) {
            ret.add(allSeries[_s2]);
          }
        }
        return ret;
      }
    }, {
      key: "_initSerieVariables",
      value: function _initSerieVariables(series, i, realIndex) {
        var w = this.w;
        var graphics = new Graphics(this.ctx);

        // width divided into equal parts
        this.xDivision = w.globals.gridWidth / (w.globals.dataPoints - (w.config.xaxis.tickPlacement === 'on' ? 1 : 0));
        this.strokeWidth = Array.isArray(w.config.stroke.width) ? w.config.stroke.width[realIndex] : w.config.stroke.width;
        var translationsIndex = 0;
        if (this.yRatio.length > 1) {
          this.yaxisIndex = w.globals.seriesYAxisReverseMap[realIndex];
          translationsIndex = realIndex;
        }
        this.isReversed = w.config.yaxis[this.yaxisIndex] && w.config.yaxis[this.yaxisIndex].reversed;

        // zeroY is the 0 value in y series which can be used in negative charts
        this.zeroY = w.globals.gridHeight - this.baseLineY[translationsIndex] - (this.isReversed ? w.globals.gridHeight : 0) + (this.isReversed ? this.baseLineY[translationsIndex] * 2 : 0);
        this.areaBottomY = this.zeroY;
        if (this.zeroY > w.globals.gridHeight || w.config.plotOptions.area.fillTo === 'end') {
          this.areaBottomY = w.globals.gridHeight;
        }
        this.categoryAxisCorrection = this.xDivision / 2;

        // el to which series will be drawn
        this.elSeries = graphics.group({
          class: "apexcharts-series",
          zIndex: typeof w.config.series[realIndex].zIndex !== 'undefined' ? w.config.series[realIndex].zIndex : realIndex,
          seriesName: Utils$1.escapeString(w.globals.seriesNames[realIndex])
        });

        // points
        this.elPointsMain = graphics.group({
          class: 'apexcharts-series-markers-wrap',
          'data:realIndex': realIndex
        });

        // eldatalabels
        this.elDataLabelsWrap = graphics.group({
          class: 'apexcharts-datalabels',
          'data:realIndex': realIndex
        });
        var longestSeries = series[i].length === w.globals.dataPoints;
        this.elSeries.attr({
          'data:longestSeries': longestSeries,
          rel: i + 1,
          'data:realIndex': realIndex
        });
        this.appendPathFrom = true;
      }
    }, {
      key: "_calculatePathsFrom",
      value: function _calculatePathsFrom(_ref) {
        var type = _ref.type,
          series = _ref.series,
          i = _ref.i,
          realIndex = _ref.realIndex,
          translationsIndex = _ref.translationsIndex,
          prevX = _ref.prevX,
          prevY = _ref.prevY,
          prevY2 = _ref.prevY2;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var linePath, areaPath, pathFromLine, pathFromArea;
        if (series[i][0] === null) {
          // when the first value itself is null, we need to move the pointer to a location where a null value is not found
          for (var s = 0; s < series[i].length; s++) {
            if (series[i][s] !== null) {
              prevX = this.xDivision * s;
              prevY = this.zeroY - series[i][s] / this.yRatio[translationsIndex];
              linePath = graphics.move(prevX, prevY);
              areaPath = graphics.move(prevX, this.areaBottomY);
              break;
            }
          }
        } else {
          linePath = graphics.move(prevX, prevY);
          if (type === 'rangeArea') {
            linePath = graphics.move(prevX, prevY2) + graphics.line(prevX, prevY);
          }
          areaPath = graphics.move(prevX, this.areaBottomY) + graphics.line(prevX, prevY);
        }
        pathFromLine = graphics.move(0, this.zeroY) + graphics.line(0, this.zeroY);
        pathFromArea = graphics.move(0, this.zeroY) + graphics.line(0, this.zeroY);
        if (w.globals.previousPaths.length > 0) {
          var pathFrom = this.lineHelpers.checkPreviousPaths({
            pathFromLine: pathFromLine,
            pathFromArea: pathFromArea,
            realIndex: realIndex
          });
          pathFromLine = pathFrom.pathFromLine;
          pathFromArea = pathFrom.pathFromArea;
        }
        return {
          prevX: prevX,
          prevY: prevY,
          linePath: linePath,
          areaPath: areaPath,
          pathFromLine: pathFromLine,
          pathFromArea: pathFromArea
        };
      }
    }, {
      key: "_handlePaths",
      value: function _handlePaths(_ref2) {
        var type = _ref2.type,
          realIndex = _ref2.realIndex,
          i = _ref2.i,
          paths = _ref2.paths;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var fill = new Fill(this.ctx);

        // push all current y values array to main PrevY Array
        this.prevSeriesY.push(paths.yArrj);

        // push all x val arrays into main xArr
        w.globals.seriesXvalues[realIndex] = paths.xArrj;
        w.globals.seriesYvalues[realIndex] = paths.yArrj;
        var forecast = w.config.forecastDataPoints;
        if (forecast.count > 0 && type !== 'rangeArea') {
          var forecastCutoff = w.globals.seriesXvalues[realIndex][w.globals.seriesXvalues[realIndex].length - forecast.count - 1];
          var elForecastMask = graphics.drawRect(forecastCutoff, 0, w.globals.gridWidth, w.globals.gridHeight, 0);
          w.globals.dom.elForecastMask.appendChild(elForecastMask.node);
          var elNonForecastMask = graphics.drawRect(0, 0, forecastCutoff, w.globals.gridHeight, 0);
          w.globals.dom.elNonForecastMask.appendChild(elNonForecastMask.node);
        }

        // these elements will be shown after area path animation completes
        if (!this.pointsChart) {
          w.globals.delayedElements.push({
            el: this.elPointsMain.node,
            index: realIndex
          });
        }
        var defaultRenderedPathOptions = {
          i: i,
          realIndex: realIndex,
          animationDelay: i,
          initialSpeed: w.config.chart.animations.speed,
          dataChangeSpeed: w.config.chart.animations.dynamicAnimation.speed,
          className: "apexcharts-".concat(type)
        };
        if (type === 'area') {
          var pathFill = fill.fillPath({
            seriesNumber: realIndex
          });
          for (var p = 0; p < paths.areaPaths.length; p++) {
            var renderedPath = graphics.renderPaths(_objectSpread2(_objectSpread2({}, defaultRenderedPathOptions), {}, {
              pathFrom: paths.pathFromArea,
              pathTo: paths.areaPaths[p],
              stroke: 'none',
              strokeWidth: 0,
              strokeLineCap: null,
              fill: pathFill
            }));
            this.elSeries.add(renderedPath);
          }
        }
        if (w.config.stroke.show && !this.pointsChart) {
          var lineFill = null;
          if (type === 'line') {
            lineFill = fill.fillPath({
              seriesNumber: realIndex,
              i: i
            });
          } else {
            if (w.config.stroke.fill.type === 'solid') {
              lineFill = w.globals.stroke.colors[realIndex];
            } else {
              var prevFill = w.config.fill;
              w.config.fill = w.config.stroke.fill;
              lineFill = fill.fillPath({
                seriesNumber: realIndex,
                i: i
              });
              w.config.fill = prevFill;
            }
          }

          // range-area paths are drawn using linePaths
          for (var _p = 0; _p < paths.linePaths.length; _p++) {
            var _pathFill = lineFill;
            if (type === 'rangeArea') {
              _pathFill = fill.fillPath({
                seriesNumber: realIndex
              });
            }
            var linePathCommonOpts = _objectSpread2(_objectSpread2({}, defaultRenderedPathOptions), {}, {
              pathFrom: paths.pathFromLine,
              pathTo: paths.linePaths[_p],
              stroke: lineFill,
              strokeWidth: this.strokeWidth,
              strokeLineCap: w.config.stroke.lineCap,
              fill: type === 'rangeArea' ? _pathFill : 'none'
            });
            var _renderedPath = graphics.renderPaths(linePathCommonOpts);
            this.elSeries.add(_renderedPath);
            _renderedPath.attr('fill-rule', "evenodd");
            if (forecast.count > 0 && type !== 'rangeArea') {
              var renderedForecastPath = graphics.renderPaths(linePathCommonOpts);
              renderedForecastPath.node.setAttribute('stroke-dasharray', forecast.dashArray);
              if (forecast.strokeWidth) {
                renderedForecastPath.node.setAttribute('stroke-width', forecast.strokeWidth);
              }
              this.elSeries.add(renderedForecastPath);
              renderedForecastPath.attr('clip-path', "url(#forecastMask".concat(w.globals.cuid, ")"));
              _renderedPath.attr('clip-path', "url(#nonForecastMask".concat(w.globals.cuid, ")"));
            }
          }
        }
      }
    }, {
      key: "_iterateOverDataPoints",
      value: function _iterateOverDataPoints(_ref3) {
        var _this = this,
          _this$w$config$series,
          _this$w$config$series2;
        var type = _ref3.type,
          series = _ref3.series,
          iterations = _ref3.iterations,
          realIndex = _ref3.realIndex,
          translationsIndex = _ref3.translationsIndex,
          i = _ref3.i,
          x = _ref3.x,
          y = _ref3.y,
          pX = _ref3.pX,
          pY = _ref3.pY,
          pathsFrom = _ref3.pathsFrom,
          linePaths = _ref3.linePaths,
          areaPaths = _ref3.areaPaths,
          seriesIndex = _ref3.seriesIndex,
          lineYPosition = _ref3.lineYPosition,
          xArrj = _ref3.xArrj,
          yArrj = _ref3.yArrj,
          y2Arrj = _ref3.y2Arrj,
          isRangeStart = _ref3.isRangeStart,
          seriesRangeEnd = _ref3.seriesRangeEnd;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var yRatio = this.yRatio;
        var prevY = pathsFrom.prevY,
          linePath = pathsFrom.linePath,
          areaPath = pathsFrom.areaPath,
          pathFromLine = pathsFrom.pathFromLine,
          pathFromArea = pathsFrom.pathFromArea;
        var minY = Utils$1.isNumber(w.globals.minYArr[realIndex]) ? w.globals.minYArr[realIndex] : w.globals.minY;
        if (!iterations) {
          iterations = w.globals.dataPoints > 1 ? w.globals.dataPoints - 1 : w.globals.dataPoints;
        }
        var getY = function getY(_y, lineYPos) {
          return lineYPos - _y / yRatio[translationsIndex] + (_this.isReversed ? _y / yRatio[translationsIndex] : 0) * 2;
        };
        var y2 = y;
        var stackSeries = w.config.chart.stacked && !w.globals.comboCharts || w.config.chart.stacked && w.globals.comboCharts && (!this.w.config.chart.stackOnlyBar || ((_this$w$config$series = this.w.config.series[realIndex]) === null || _this$w$config$series === void 0 ? void 0 : _this$w$config$series.type) === 'bar' || ((_this$w$config$series2 = this.w.config.series[realIndex]) === null || _this$w$config$series2 === void 0 ? void 0 : _this$w$config$series2.type) === 'column');
        var curve = w.config.stroke.curve;
        if (Array.isArray(curve)) {
          if (Array.isArray(seriesIndex)) {
            curve = curve[seriesIndex[i]];
          } else {
            curve = curve[i];
          }
        }
        var pathState = 0;
        var segmentStartX;
        for (var j = 0; j < iterations; j++) {
          var isNull = typeof series[i][j + 1] === 'undefined' || series[i][j + 1] === null;
          if (w.globals.isXNumeric) {
            var sX = w.globals.seriesX[realIndex][j + 1];
            if (typeof w.globals.seriesX[realIndex][j + 1] === 'undefined') {
              /* fix #374 */
              sX = w.globals.seriesX[realIndex][iterations - 1];
            }
            x = (sX - w.globals.minX) / this.xRatio;
          } else {
            x = x + this.xDivision;
          }
          if (stackSeries) {
            if (i > 0 && w.globals.collapsedSeries.length < w.config.series.length - 1) {
              // a collapsed series in a stacked chart may provide wrong result
              // for the next series, hence find the prevIndex of prev series
              // which is not collapsed - fixes apexcharts.js#1372
              var prevIndex = function prevIndex(pi) {
                for (var pii = pi; pii > 0; pii--) {
                  if (w.globals.collapsedSeriesIndices.indexOf((seriesIndex === null || seriesIndex === void 0 ? void 0 : seriesIndex[pii]) || pii) > -1) {
                    pii--;
                  } else {
                    return pii;
                  }
                }
                return 0;
              };
              lineYPosition = this.prevSeriesY[prevIndex(i - 1)][j + 1];
            } else {
              // the first series will not have prevY values
              lineYPosition = this.zeroY;
            }
          } else {
            lineYPosition = this.zeroY;
          }
          if (isNull) {
            y = getY(minY, lineYPosition);
          } else {
            y = getY(series[i][j + 1], lineYPosition);
            if (type === 'rangeArea') {
              y2 = getY(seriesRangeEnd[i][j + 1], lineYPosition);
            }
          }

          // push current X
          xArrj.push(x);

          // push current Y that will be used as next series's bottom position
          if (isNull && (w.config.stroke.curve === 'smooth' || w.config.stroke.curve === 'monotoneCubic')) {
            yArrj.push(null);
            y2Arrj.push(null);
          } else {
            yArrj.push(y);
            y2Arrj.push(y2);
          }
          var pointsPos = this.lineHelpers.calculatePoints({
            series: series,
            x: x,
            y: y,
            realIndex: realIndex,
            i: i,
            j: j,
            prevY: prevY
          });
          var calculatedPaths = this._createPaths({
            type: type,
            series: series,
            i: i,
            realIndex: realIndex,
            j: j,
            x: x,
            y: y,
            y2: y2,
            xArrj: xArrj,
            yArrj: yArrj,
            y2Arrj: y2Arrj,
            pX: pX,
            pY: pY,
            pathState: pathState,
            segmentStartX: segmentStartX,
            linePath: linePath,
            areaPath: areaPath,
            linePaths: linePaths,
            areaPaths: areaPaths,
            curve: curve,
            isRangeStart: isRangeStart
          });
          areaPaths = calculatedPaths.areaPaths;
          linePaths = calculatedPaths.linePaths;
          pX = calculatedPaths.pX;
          pY = calculatedPaths.pY;
          pathState = calculatedPaths.pathState;
          segmentStartX = calculatedPaths.segmentStartX;
          areaPath = calculatedPaths.areaPath;
          linePath = calculatedPaths.linePath;
          if (this.appendPathFrom && !(curve === 'monotoneCubic' && type === 'rangeArea')) {
            pathFromLine += graphics.line(x, this.zeroY);
            pathFromArea += graphics.line(x, this.zeroY);
          }
          this.handleNullDataPoints(series, pointsPos, i, j, realIndex);
          this._handleMarkersAndLabels({
            type: type,
            pointsPos: pointsPos,
            i: i,
            j: j,
            realIndex: realIndex,
            isRangeStart: isRangeStart
          });
        }
        return {
          yArrj: yArrj,
          xArrj: xArrj,
          pathFromArea: pathFromArea,
          areaPaths: areaPaths,
          pathFromLine: pathFromLine,
          linePaths: linePaths,
          linePath: linePath,
          areaPath: areaPath
        };
      }
    }, {
      key: "_handleMarkersAndLabels",
      value: function _handleMarkersAndLabels(_ref4) {
        var type = _ref4.type,
          pointsPos = _ref4.pointsPos,
          isRangeStart = _ref4.isRangeStart,
          i = _ref4.i,
          j = _ref4.j,
          realIndex = _ref4.realIndex;
        var w = this.w;
        var dataLabels = new DataLabels(this.ctx);
        if (!this.pointsChart) {
          if (w.globals.series[i].length > 1) {
            this.elPointsMain.node.classList.add('apexcharts-element-hidden');
          }
          var elPointsWrap = this.markers.plotChartMarkers(pointsPos, realIndex, j + 1);
          if (elPointsWrap !== null) {
            this.elPointsMain.add(elPointsWrap);
          }
        } else {
          // scatter / bubble chart points creation
          this.scatter.draw(this.elSeries, j, {
            realIndex: realIndex,
            pointsPos: pointsPos,
            zRatio: this.zRatio,
            elParent: this.elPointsMain
          });
        }
        var drawnLabels = dataLabels.drawDataLabel({
          type: type,
          isRangeStart: isRangeStart,
          pos: pointsPos,
          i: realIndex,
          j: j + 1
        });
        if (drawnLabels !== null) {
          this.elDataLabelsWrap.add(drawnLabels);
        }
      }
    }, {
      key: "_createPaths",
      value: function _createPaths(_ref5) {
        var type = _ref5.type,
          series = _ref5.series,
          i = _ref5.i;
          _ref5.realIndex;
          var j = _ref5.j,
          x = _ref5.x,
          y = _ref5.y,
          xArrj = _ref5.xArrj,
          yArrj = _ref5.yArrj,
          y2 = _ref5.y2,
          y2Arrj = _ref5.y2Arrj,
          pX = _ref5.pX,
          pY = _ref5.pY,
          pathState = _ref5.pathState,
          segmentStartX = _ref5.segmentStartX,
          linePath = _ref5.linePath,
          areaPath = _ref5.areaPath,
          linePaths = _ref5.linePaths,
          areaPaths = _ref5.areaPaths,
          curve = _ref5.curve,
          isRangeStart = _ref5.isRangeStart;
        var graphics = new Graphics(this.ctx);
        var areaBottomY = this.areaBottomY;
        var rangeArea = type === 'rangeArea';
        var isLowerRangeAreaPath = type === 'rangeArea' && isRangeStart;
        switch (curve) {
          case 'monotoneCubic':
            var yAj = isRangeStart ? yArrj : y2Arrj;
            var getSmoothInputs = function getSmoothInputs(xArr, yArr) {
              return xArr.map(function (_, i) {
                return [_, yArr[i]];
              }).filter(function (_) {
                return _[1] !== null;
              });
            };
            var getSegmentLengths = function getSegmentLengths(yArr) {
              // Get the segment lengths so the segments can be extracted from
              // the null-filtered smoothInputs array
              var segLens = [];
              var count = 0;
              yArr.forEach(function (_) {
                if (_ !== null) {
                  count++;
                } else if (count > 0) {
                  segLens.push(count);
                  count = 0;
                }
              });
              if (count > 0) {
                segLens.push(count);
              }
              return segLens;
            };
            var getSegments = function getSegments(yArr, points) {
              var segLens = getSegmentLengths(yArr);
              var segments = [];
              for (var _i = 0, len = 0; _i < segLens.length; len += segLens[_i++]) {
                segments[_i] = spline.slice(points, len, len + segLens[_i]);
              }
              return segments;
            };
            switch (pathState) {
              case 0:
                // Find start of segment
                if (yAj[j + 1] === null) {
                  break;
                }
                pathState = 1;
              // continue through to pathState 1
              case 1:
                if (!(rangeArea ? xArrj.length === series[i].length : j === series[i].length - 2)) {
                  break;
                }
              // continue through to pathState 2
              case 2:
                // Interpolate the full series with nulls excluded then extract the
                // null delimited segments with interpolated points included.
                var _xAj = isRangeStart ? xArrj : xArrj.slice().reverse();
                var _yAj = isRangeStart ? yAj : yAj.slice().reverse();
                var smoothInputs = getSmoothInputs(_xAj, _yAj);
                var points = smoothInputs.length > 1 ? spline.points(smoothInputs) : smoothInputs;
                var smoothInputsLower = [];
                if (rangeArea) {
                  if (isLowerRangeAreaPath) {
                    // As we won't be needing it, borrow areaPaths to retain our
                    // rangeArea lower points.
                    areaPaths = smoothInputs;
                  } else {
                    // Retrieve the corresponding lower raw interpolated points so we
                    // can join onto its end points. Note: the upper Y2 segments will
                    // be in the reverse order relative to the lower segments.
                    smoothInputsLower = areaPaths.reverse();
                  }
                }
                var segmentCount = 0;
                var smoothInputsIndex = 0;
                getSegments(_yAj, points).forEach(function (_) {
                  segmentCount++;
                  var svgPoints = svgPath(_);
                  var _start = smoothInputsIndex;
                  smoothInputsIndex += _.length;
                  var _end = smoothInputsIndex - 1;
                  if (isLowerRangeAreaPath) {
                    linePath = graphics.move(smoothInputs[_start][0], smoothInputs[_start][1]) + svgPoints;
                  } else if (rangeArea) {
                    linePath = graphics.move(smoothInputsLower[_start][0], smoothInputsLower[_start][1]) + graphics.line(smoothInputs[_start][0], smoothInputs[_start][1]) + svgPoints + graphics.line(smoothInputsLower[_end][0], smoothInputsLower[_end][1]);
                  } else {
                    linePath = graphics.move(smoothInputs[_start][0], smoothInputs[_start][1]) + svgPoints;
                    areaPath = linePath + graphics.line(smoothInputs[_end][0], areaBottomY) + graphics.line(smoothInputs[_start][0], areaBottomY) + 'z';
                    areaPaths.push(areaPath);
                  }
                  linePaths.push(linePath);
                });
                if (rangeArea && segmentCount > 1 && !isLowerRangeAreaPath) {
                  // Reverse the order of the upper path segments
                  var upperLinePaths = linePaths.slice(segmentCount).reverse();
                  linePaths.splice(segmentCount);
                  upperLinePaths.forEach(function (u) {
                    return linePaths.push(u);
                  });
                }
                pathState = 0;
                break;
            }
            break;
          case 'smooth':
            var length = (x - pX) * 0.35;
            if (series[i][j] === null) {
              pathState = 0;
            } else {
              switch (pathState) {
                case 0:
                  // Beginning of segment
                  segmentStartX = pX;
                  if (isLowerRangeAreaPath) {
                    // Need to add path portion that will join to the upper path
                    linePath = graphics.move(pX, y2Arrj[j]) + graphics.line(pX, pY);
                  } else {
                    linePath = graphics.move(pX, pY);
                  }
                  areaPath = graphics.move(pX, pY);

                  // Check for single isolated point
                  if (series[i][j + 1] === null) {
                    linePaths.push(linePath);
                    areaPaths.push(areaPath);
                    // Stay in pathState = 0;
                    break;
                  }
                  pathState = 1;
                  if (j < series[i].length - 2) {
                    var p = graphics.curve(pX + length, pY, x - length, y, x, y);
                    linePath += p;
                    areaPath += p;
                    break;
                  }
                // Continue on with pathState 1 to finish the path and exit
                case 1:
                  // Continuing with segment
                  if (series[i][j + 1] === null) {
                    // Segment ends here
                    if (isLowerRangeAreaPath) {
                      linePath += graphics.line(pX, y2);
                    } else {
                      linePath += graphics.move(pX, pY);
                    }
                    areaPath += graphics.line(pX, areaBottomY) + graphics.line(segmentStartX, areaBottomY) + 'z';
                    linePaths.push(linePath);
                    areaPaths.push(areaPath);
                    pathState = -1;
                  } else {
                    var _p2 = graphics.curve(pX + length, pY, x - length, y, x, y);
                    linePath += _p2;
                    areaPath += _p2;
                    if (j >= series[i].length - 2) {
                      if (isLowerRangeAreaPath) {
                        // Need to add path portion that will join to the upper path
                        linePath += graphics.curve(x, y, x, y, x, y2) + graphics.move(x, y2);
                      }
                      areaPath += graphics.curve(x, y, x, y, x, areaBottomY) + graphics.line(segmentStartX, areaBottomY) + 'z';
                      linePaths.push(linePath);
                      areaPaths.push(areaPath);
                      pathState = -1;
                    }
                  }
                  break;
              }
            }
            pX = x;
            pY = y;
            break;
          default:
            var pathToPoint = function pathToPoint(curve, x, y) {
              var path = [];
              switch (curve) {
                case 'stepline':
                  path = graphics.line(x, null, 'H') + graphics.line(null, y, 'V');
                  break;
                case 'linestep':
                  path = graphics.line(null, y, 'V') + graphics.line(x, null, 'H');
                  break;
                case 'straight':
                  path = graphics.line(x, y);
                  break;
              }
              return path;
            };
            if (series[i][j] === null) {
              pathState = 0;
            } else {
              switch (pathState) {
                case 0:
                  // Beginning of segment
                  segmentStartX = pX;
                  if (isLowerRangeAreaPath) {
                    // Need to add path portion that will join to the upper path
                    linePath = graphics.move(pX, y2Arrj[j]) + graphics.line(pX, pY);
                  } else {
                    linePath = graphics.move(pX, pY);
                  }
                  areaPath = graphics.move(pX, pY);

                  // Check for single isolated point
                  if (series[i][j + 1] === null) {
                    linePaths.push(linePath);
                    areaPaths.push(areaPath);
                    // Stay in pathState = 0
                    break;
                  }
                  pathState = 1;
                  if (j < series[i].length - 2) {
                    var _p3 = pathToPoint(curve, x, y);
                    linePath += _p3;
                    areaPath += _p3;
                    break;
                  }
                // Continue on with pathState 1 to finish the path and exit
                case 1:
                  // Continuing with segment
                  if (series[i][j + 1] === null) {
                    // Segment ends here
                    if (isLowerRangeAreaPath) {
                      linePath += graphics.line(pX, y2);
                    } else {
                      linePath += graphics.move(pX, pY);
                    }
                    areaPath += graphics.line(pX, areaBottomY) + graphics.line(segmentStartX, areaBottomY) + 'z';
                    linePaths.push(linePath);
                    areaPaths.push(areaPath);
                    pathState = -1;
                  } else {
                    var _p4 = pathToPoint(curve, x, y);
                    linePath += _p4;
                    areaPath += _p4;
                    if (j >= series[i].length - 2) {
                      if (isLowerRangeAreaPath) {
                        // Need to add path portion that will join to the upper path
                        linePath += graphics.line(x, y2);
                      }
                      areaPath += graphics.line(x, areaBottomY) + graphics.line(segmentStartX, areaBottomY) + 'z';
                      linePaths.push(linePath);
                      areaPaths.push(areaPath);
                      pathState = -1;
                    }
                  }
                  break;
              }
            }
            pX = x;
            pY = y;
            break;
        }
        return {
          linePaths: linePaths,
          areaPaths: areaPaths,
          pX: pX,
          pY: pY,
          pathState: pathState,
          segmentStartX: segmentStartX,
          linePath: linePath,
          areaPath: areaPath
        };
      }
    }, {
      key: "handleNullDataPoints",
      value: function handleNullDataPoints(series, pointsPos, i, j, realIndex) {
        var w = this.w;
        if (series[i][j] === null && w.config.markers.showNullDataPoints || series[i].length === 1) {
          var pSize = this.strokeWidth - w.config.markers.strokeWidth / 2;
          if (!(pSize > 0)) {
            pSize = 0;
          }
          // fixes apexcharts.js#1282, #1252
          var elPointsWrap = this.markers.plotChartMarkers(pointsPos, realIndex, j + 1, pSize, true);
          if (elPointsWrap !== null) {
            this.elPointsMain.add(elPointsWrap);
          }
        }
      }
    }]);
    return Line;
  }();

  /*
   * treemap-squarify.js - open source implementation of squarified treemaps
   *
   * Treemap Squared 0.5 - Treemap Charting library
   *
   * https://github.com/imranghory/treemap-squared/
   *
   * Copyright (c) 2012 Imran Ghory (imranghory@gmail.com)
   * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
   *
   *
   * Implementation of the squarify treemap algorithm described in:
   *
   * Bruls, Mark; Huizing, Kees; van Wijk, Jarke J. (2000), "Squarified treemaps"
   * in de Leeuw, W.; van Liere, R., Data Visualization 2000:
   * Proc. Joint Eurographics and IEEE TCVG Symp. on Visualization, Springer-Verlag, pp. 33–42.
   *
   * Paper is available online at: http://www.win.tue.nl/~vanwijk/stm.pdf
   *
   * The code in this file is completeley decoupled from the drawing code so it should be trivial
   * to port it to any other vector drawing library. Given an array of datapoints this library returns
   * an array of cartesian coordinates that represent the rectangles that make up the treemap.
   *
   * The library also supports multidimensional data (nested treemaps) and performs normalization on the data.
   *
   * See the README file for more details.
   */

  window.TreemapSquared = {};
  (function () {

    window.TreemapSquared.generate = function () {
      function Container(xoffset, yoffset, width, height) {
        this.xoffset = xoffset; // offset from the the top left hand corner
        this.yoffset = yoffset; // ditto
        this.height = height;
        this.width = width;
        this.shortestEdge = function () {
          return Math.min(this.height, this.width);
        };

        // getCoordinates - for a row of boxes which we've placed
        //                  return an array of their cartesian coordinates
        this.getCoordinates = function (row) {
          var coordinates = [];
          var subxoffset = this.xoffset,
            subyoffset = this.yoffset; //our offset within the container
          var areawidth = sumArray(row) / this.height;
          var areaheight = sumArray(row) / this.width;
          var i;
          if (this.width >= this.height) {
            for (i = 0; i < row.length; i++) {
              coordinates.push([subxoffset, subyoffset, subxoffset + areawidth, subyoffset + row[i] / areawidth]);
              subyoffset = subyoffset + row[i] / areawidth;
            }
          } else {
            for (i = 0; i < row.length; i++) {
              coordinates.push([subxoffset, subyoffset, subxoffset + row[i] / areaheight, subyoffset + areaheight]);
              subxoffset = subxoffset + row[i] / areaheight;
            }
          }
          return coordinates;
        };

        // cutArea - once we've placed some boxes into an row we then need to identify the remaining area,
        //           this function takes the area of the boxes we've placed and calculates the location and
        //           dimensions of the remaining space and returns a container box defined by the remaining area
        this.cutArea = function (area) {
          var newcontainer;
          if (this.width >= this.height) {
            var areawidth = area / this.height;
            var newwidth = this.width - areawidth;
            newcontainer = new Container(this.xoffset + areawidth, this.yoffset, newwidth, this.height);
          } else {
            var areaheight = area / this.width;
            var newheight = this.height - areaheight;
            newcontainer = new Container(this.xoffset, this.yoffset + areaheight, this.width, newheight);
          }
          return newcontainer;
        };
      }

      // normalize - the Bruls algorithm assumes we're passing in areas that nicely fit into our
      //             container box, this method takes our raw data and normalizes the data values into
      //             area values so that this assumption is valid.
      function normalize(data, area) {
        var normalizeddata = [];
        var sum = sumArray(data);
        var multiplier = area / sum;
        var i;
        for (i = 0; i < data.length; i++) {
          normalizeddata[i] = data[i] * multiplier;
        }
        return normalizeddata;
      }

      // treemapMultidimensional - takes multidimensional data (aka [[23,11],[11,32]] - nested array)
      //                           and recursively calls itself using treemapSingledimensional
      //                           to create a patchwork of treemaps and merge them
      function treemapMultidimensional(data, width, height, xoffset, yoffset) {
        xoffset = typeof xoffset === 'undefined' ? 0 : xoffset;
        yoffset = typeof yoffset === 'undefined' ? 0 : yoffset;
        var mergeddata = [];
        var mergedtreemap;
        var results = [];
        var i;
        if (isArray(data[0])) {
          // if we've got more dimensions of depth
          for (i = 0; i < data.length; i++) {
            mergeddata[i] = sumMultidimensionalArray(data[i]);
          }
          mergedtreemap = treemapSingledimensional(mergeddata, width, height, xoffset, yoffset);
          for (i = 0; i < data.length; i++) {
            results.push(treemapMultidimensional(data[i], mergedtreemap[i][2] - mergedtreemap[i][0], mergedtreemap[i][3] - mergedtreemap[i][1], mergedtreemap[i][0], mergedtreemap[i][1]));
          }
        } else {
          results = treemapSingledimensional(data, width, height, xoffset, yoffset);
        }
        return results;
      }

      // treemapSingledimensional - simple wrapper around squarify
      function treemapSingledimensional(data, width, height, xoffset, yoffset) {
        xoffset = typeof xoffset === 'undefined' ? 0 : xoffset;
        yoffset = typeof yoffset === 'undefined' ? 0 : yoffset;
        var rawtreemap = squarify(normalize(data, width * height), [], new Container(xoffset, yoffset, width, height), []);
        return flattenTreemap(rawtreemap);
      }

      // flattenTreemap - squarify implementation returns an array of arrays of coordinates
      //                  because we have a new array everytime we switch to building a new row
      //                  this converts it into an array of coordinates.
      function flattenTreemap(rawtreemap) {
        var flattreemap = [];
        var i, j;
        for (i = 0; i < rawtreemap.length; i++) {
          for (j = 0; j < rawtreemap[i].length; j++) {
            flattreemap.push(rawtreemap[i][j]);
          }
        }
        return flattreemap;
      }

      // squarify  - as per the Bruls paper
      //             plus coordinates stack and containers so we get
      //             usable data out of it
      function squarify(data, currentrow, container, stack) {
        var length;
        var nextdatapoint;
        var newcontainer;
        if (data.length === 0) {
          stack.push(container.getCoordinates(currentrow));
          return;
        }
        length = container.shortestEdge();
        nextdatapoint = data[0];
        if (improvesRatio(currentrow, nextdatapoint, length)) {
          currentrow.push(nextdatapoint);
          squarify(data.slice(1), currentrow, container, stack);
        } else {
          newcontainer = container.cutArea(sumArray(currentrow), stack);
          stack.push(container.getCoordinates(currentrow));
          squarify(data, [], newcontainer, stack);
        }
        return stack;
      }

      // improveRatio - implements the worse calculation and comparision as given in Bruls
      //                (note the error in the original paper; fixed here)
      function improvesRatio(currentrow, nextnode, length) {
        var newrow;
        if (currentrow.length === 0) {
          return true;
        }
        newrow = currentrow.slice();
        newrow.push(nextnode);
        var currentratio = calculateRatio(currentrow, length);
        var newratio = calculateRatio(newrow, length);

        // the pseudocode in the Bruls paper has the direction of the comparison
        // wrong, this is the correct one.
        return currentratio >= newratio;
      }

      // calculateRatio - calculates the maximum width to height ratio of the
      //                  boxes in this row
      function calculateRatio(row, length) {
        var min = Math.min.apply(Math, row);
        var max = Math.max.apply(Math, row);
        var sum = sumArray(row);
        return Math.max(Math.pow(length, 2) * max / Math.pow(sum, 2), Math.pow(sum, 2) / (Math.pow(length, 2) * min));
      }

      // isArray - checks if arr is an array
      function isArray(arr) {
        return arr && arr.constructor === Array;
      }

      // sumArray - sums a single dimensional array
      function sumArray(arr) {
        var sum = 0;
        var i;
        for (i = 0; i < arr.length; i++) {
          sum += arr[i];
        }
        return sum;
      }

      // sumMultidimensionalArray - sums the values in a nested array (aka [[0,1],[[2,3]]])
      function sumMultidimensionalArray(arr) {
        var i,
          total = 0;
        if (isArray(arr[0])) {
          for (i = 0; i < arr.length; i++) {
            total += sumMultidimensionalArray(arr[i]);
          }
        } else {
          total = sumArray(arr);
        }
        return total;
      }
      return treemapMultidimensional;
    }();
  })();

  /**
   * ApexCharts TreemapChart Class.
   * @module TreemapChart
   **/
  var TreemapChart = /*#__PURE__*/function () {
    function TreemapChart(ctx, xyRatios) {
      _classCallCheck(this, TreemapChart);
      this.ctx = ctx;
      this.w = ctx.w;
      this.strokeWidth = this.w.config.stroke.width;
      this.helpers = new TreemapHelpers(ctx);
      this.dynamicAnim = this.w.config.chart.animations.dynamicAnimation;
      this.labels = [];
    }
    _createClass(TreemapChart, [{
      key: "draw",
      value: function draw(series) {
        var _this = this;
        var w = this.w;
        var graphics = new Graphics(this.ctx);
        var fill = new Fill(this.ctx);
        var ret = graphics.group({
          class: 'apexcharts-treemap'
        });
        if (w.globals.noData) return ret;
        var ser = [];
        series.forEach(function (s) {
          var d = s.map(function (v) {
            return Math.abs(v);
          });
          ser.push(d);
        });
        this.negRange = this.helpers.checkColorRange();
        w.config.series.forEach(function (s, i) {
          s.data.forEach(function (l) {
            if (!Array.isArray(_this.labels[i])) _this.labels[i] = [];
            _this.labels[i].push(l.x);
          });
        });
        var nodes = window.TreemapSquared.generate(ser, w.globals.gridWidth, w.globals.gridHeight);
        nodes.forEach(function (node, i) {
          var elSeries = graphics.group({
            class: "apexcharts-series apexcharts-treemap-series",
            seriesName: Utils$1.escapeString(w.globals.seriesNames[i]),
            rel: i + 1,
            'data:realIndex': i
          });
          if (w.config.chart.dropShadow.enabled) {
            var shadow = w.config.chart.dropShadow;
            var filters = new Filters(_this.ctx);
            filters.dropShadow(ret, shadow, i);
          }
          var elDataLabelWrap = graphics.group({
            class: 'apexcharts-data-labels'
          });
          node.forEach(function (r, j) {
            var x1 = r[0];
            var y1 = r[1];
            var x2 = r[2];
            var y2 = r[3];
            var elRect = graphics.drawRect(x1, y1, x2 - x1, y2 - y1, w.config.plotOptions.treemap.borderRadius, '#fff', 1, _this.strokeWidth, w.config.plotOptions.treemap.useFillColorAsStroke ? color : w.globals.stroke.colors[i]);
            elRect.attr({
              cx: x1,
              cy: y1,
              index: i,
              i: i,
              j: j,
              width: x2 - x1,
              height: y2 - y1
            });
            var colorProps = _this.helpers.getShadeColor(w.config.chart.type, i, j, _this.negRange);
            var color = colorProps.color;
            if (typeof w.config.series[i].data[j] !== 'undefined' && w.config.series[i].data[j].fillColor) {
              color = w.config.series[i].data[j].fillColor;
            }
            var pathFill = fill.fillPath({
              color: color,
              seriesNumber: i,
              dataPointIndex: j
            });
            elRect.node.classList.add('apexcharts-treemap-rect');
            elRect.attr({
              fill: pathFill
            });
            _this.helpers.addListeners(elRect);
            var fromRect = {
              x: x1 + (x2 - x1) / 2,
              y: y1 + (y2 - y1) / 2,
              width: 0,
              height: 0
            };
            var toRect = {
              x: x1,
              y: y1,
              width: x2 - x1,
              height: y2 - y1
            };
            if (w.config.chart.animations.enabled && !w.globals.dataChanged) {
              var speed = 1;
              if (!w.globals.resized) {
                speed = w.config.chart.animations.speed;
              }
              _this.animateTreemap(elRect, fromRect, toRect, speed);
            }
            if (w.globals.dataChanged) {
              var _speed = 1;
              if (_this.dynamicAnim.enabled && w.globals.shouldAnimate) {
                _speed = _this.dynamicAnim.speed;
                if (w.globals.previousPaths[i] && w.globals.previousPaths[i][j] && w.globals.previousPaths[i][j].rect) {
                  fromRect = w.globals.previousPaths[i][j].rect;
                }
                _this.animateTreemap(elRect, fromRect, toRect, _speed);
              }
            }
            var fontSize = _this.getFontSize(r);
            var formattedText = w.config.dataLabels.formatter(_this.labels[i][j], {
              value: w.globals.series[i][j],
              seriesIndex: i,
              dataPointIndex: j,
              w: w
            });
            if (w.config.plotOptions.treemap.dataLabels.format === 'truncate') {
              fontSize = parseInt(w.config.dataLabels.style.fontSize, 10);
              formattedText = _this.truncateLabels(formattedText, fontSize, x1, y1, x2, y2);
            }
            var dataLabels = null;
            if (w.globals.series[i][j]) {
              dataLabels = _this.helpers.calculateDataLabels({
                text: formattedText,
                x: (x1 + x2) / 2,
                y: (y1 + y2) / 2 + _this.strokeWidth / 2 + fontSize / 3,
                i: i,
                j: j,
                colorProps: colorProps,
                fontSize: fontSize,
                series: series
              });
            }
            if (w.config.dataLabels.enabled && dataLabels) {
              _this.rotateToFitLabel(dataLabels, fontSize, formattedText, x1, y1, x2, y2);
            }
            elSeries.add(elRect);
            if (dataLabels !== null) {
              elSeries.add(dataLabels);
            }
          });
          elSeries.add(elDataLabelWrap);
          ret.add(elSeries);
        });
        return ret;
      }

      // This calculates a font-size based upon
      // average label length and the size of the box the label is
      // going into. The maximum font size is set in chart config.
    }, {
      key: "getFontSize",
      value: function getFontSize(coordinates) {
        var w = this.w;

        // total length of labels (i.e [["Italy"],["Spain", "Greece"]] -> 16)
        function totalLabelLength(arr) {
          var i,
            total = 0;
          if (Array.isArray(arr[0])) {
            for (i = 0; i < arr.length; i++) {
              total += totalLabelLength(arr[i]);
            }
          } else {
            for (i = 0; i < arr.length; i++) {
              total += arr[i].length;
            }
          }
          return total;
        }

        // count of labels (i.e [["Italy"],["Spain", "Greece"]] -> 3)
        function countLabels(arr) {
          var i,
            total = 0;
          if (Array.isArray(arr[0])) {
            for (i = 0; i < arr.length; i++) {
              total += countLabels(arr[i]);
            }
          } else {
            for (i = 0; i < arr.length; i++) {
              total += 1;
            }
          }
          return total;
        }
        var averagelabelsize = totalLabelLength(this.labels) / countLabels(this.labels);
        function fontSize(width, height) {
          // the font size should be proportional to the size of the box (and the value)
          // otherwise you can end up creating a visual distortion where two boxes of identical
          // size have different sized labels, and thus make it look as if the two boxes
          // represent different sizes
          var area = width * height;
          var arearoot = Math.pow(area, 0.5);
          return Math.min(arearoot / averagelabelsize, parseInt(w.config.dataLabels.style.fontSize, 10));
        }
        return fontSize(coordinates[2] - coordinates[0], coordinates[3] - coordinates[1]);
      }
    }, {
      key: "rotateToFitLabel",
      value: function rotateToFitLabel(elText, fontSize, text, x1, y1, x2, y2) {
        var graphics = new Graphics(this.ctx);
        var textRect = graphics.getTextRects(text, fontSize);

        //if the label fits better sideways then rotate it
        if (textRect.width + this.w.config.stroke.width + 5 > x2 - x1 && textRect.width <= y2 - y1) {
          var labelRotatingCenter = graphics.rotateAroundCenter(elText.node);
          elText.node.setAttribute('transform', "rotate(-90 ".concat(labelRotatingCenter.x, " ").concat(labelRotatingCenter.y, ") translate(").concat(textRect.height / 3, ")"));
        }
      }

      // This is an alternative label formatting method that uses a
      // consistent font size, and trims the edge of long labels
    }, {
      key: "truncateLabels",
      value: function truncateLabels(text, fontSize, x1, y1, x2, y2) {
        var graphics = new Graphics(this.ctx);
        var textRect = graphics.getTextRects(text, fontSize);

        // Determine max width based on ideal orientation of text
        var labelMaxWidth = textRect.width + this.w.config.stroke.width + 5 > x2 - x1 && y2 - y1 > x2 - x1 ? y2 - y1 : x2 - x1;
        var truncatedText = graphics.getTextBasedOnMaxWidth({
          text: text,
          maxWidth: labelMaxWidth,
          fontSize: fontSize
        });

        // Return empty label when text has been trimmed for very small rects
        if (text.length !== truncatedText.length && labelMaxWidth / fontSize < 5) {
          return '';
        } else {
          return truncatedText;
        }
      }
    }, {
      key: "animateTreemap",
      value: function animateTreemap(el, fromRect, toRect, speed) {
        var animations = new Animations(this.ctx);
        animations.animateRect(el, {
          x: fromRect.x,
          y: fromRect.y,
          width: fromRect.width,
          height: fromRect.height
        }, {
          x: toRect.x,
          y: toRect.y,
          width: toRect.width,
          height: toRect.height
        }, speed, function () {
          animations.animationCompleted(el);
        });
      }
    }]);
    return TreemapChart;
  }();

  var MINUTES_IN_DAY = 24 * 60;
  var SECONDS_IN_DAY = MINUTES_IN_DAY * 60;
  var MIN_ZOOM_DAYS = 10 / SECONDS_IN_DAY;

  /**
   * ApexCharts TimeScale Class for generating time ticks for x-axis.
   *
   * @module TimeScale
   **/
  var TimeScale = /*#__PURE__*/function () {
    function TimeScale(ctx) {
      _classCallCheck(this, TimeScale);
      this.ctx = ctx;
      this.w = ctx.w;
      this.timeScaleArray = [];
      this.utc = this.w.config.xaxis.labels.datetimeUTC;
    }
    _createClass(TimeScale, [{
      key: "calculateTimeScaleTicks",
      value: function calculateTimeScaleTicks(minX, maxX) {
        var _this = this;
        var w = this.w;

        // null check when no series to show
        if (w.globals.allSeriesCollapsed) {
          w.globals.labels = [];
          w.globals.timescaleLabels = [];
          return [];
        }
        var dt = new DateTime(this.ctx);
        var daysDiff = (maxX - minX) / (1000 * SECONDS_IN_DAY);
        this.determineInterval(daysDiff);
        w.globals.disableZoomIn = false;
        w.globals.disableZoomOut = false;
        if (daysDiff < MIN_ZOOM_DAYS) {
          w.globals.disableZoomIn = true;
        } else if (daysDiff > 50000) {
          w.globals.disableZoomOut = true;
        }
        var timeIntervals = dt.getTimeUnitsfromTimestamp(minX, maxX, this.utc);
        var daysWidthOnXAxis = w.globals.gridWidth / daysDiff;
        var hoursWidthOnXAxis = daysWidthOnXAxis / 24;
        var minutesWidthOnXAxis = hoursWidthOnXAxis / 60;
        var secondsWidthOnXAxis = minutesWidthOnXAxis / 60;
        var numberOfHours = Math.floor(daysDiff * 24);
        var numberOfMinutes = Math.floor(daysDiff * MINUTES_IN_DAY);
        var numberOfSeconds = Math.floor(daysDiff * SECONDS_IN_DAY);
        var numberOfDays = Math.floor(daysDiff);
        var numberOfMonths = Math.floor(daysDiff / 30);
        var numberOfYears = Math.floor(daysDiff / 365);
        var firstVal = {
          minMillisecond: timeIntervals.minMillisecond,
          minSecond: timeIntervals.minSecond,
          minMinute: timeIntervals.minMinute,
          minHour: timeIntervals.minHour,
          minDate: timeIntervals.minDate,
          minMonth: timeIntervals.minMonth,
          minYear: timeIntervals.minYear
        };
        var currentMillisecond = firstVal.minMillisecond;
        var currentSecond = firstVal.minSecond;
        var currentMinute = firstVal.minMinute;
        var currentHour = firstVal.minHour;
        var currentMonthDate = firstVal.minDate;
        var currentDate = firstVal.minDate;
        var currentMonth = firstVal.minMonth;
        var currentYear = firstVal.minYear;
        var params = {
          firstVal: firstVal,
          currentMillisecond: currentMillisecond,
          currentSecond: currentSecond,
          currentMinute: currentMinute,
          currentHour: currentHour,
          currentMonthDate: currentMonthDate,
          currentDate: currentDate,
          currentMonth: currentMonth,
          currentYear: currentYear,
          daysWidthOnXAxis: daysWidthOnXAxis,
          hoursWidthOnXAxis: hoursWidthOnXAxis,
          minutesWidthOnXAxis: minutesWidthOnXAxis,
          secondsWidthOnXAxis: secondsWidthOnXAxis,
          numberOfSeconds: numberOfSeconds,
          numberOfMinutes: numberOfMinutes,
          numberOfHours: numberOfHours,
          numberOfDays: numberOfDays,
          numberOfMonths: numberOfMonths,
          numberOfYears: numberOfYears
        };
        switch (this.tickInterval) {
          case 'years':
            {
              this.generateYearScale(params);
              break;
            }
          case 'months':
          case 'half_year':
            {
              this.generateMonthScale(params);
              break;
            }
          case 'months_days':
          case 'months_fortnight':
          case 'days':
          case 'week_days':
            {
              this.generateDayScale(params);
              break;
            }
          case 'hours':
            {
              this.generateHourScale(params);
              break;
            }
          case 'minutes_fives':
          case 'minutes':
            this.generateMinuteScale(params);
            break;
          case 'seconds_tens':
          case 'seconds_fives':
          case 'seconds':
            this.generateSecondScale(params);
            break;
        }

        // first, we will adjust the month values index
        // as in the upper function, it is starting from 0
        // we will start them from 1
        var adjustedMonthInTimeScaleArray = this.timeScaleArray.map(function (ts) {
          var defaultReturn = {
            position: ts.position,
            unit: ts.unit,
            year: ts.year,
            day: ts.day ? ts.day : 1,
            hour: ts.hour ? ts.hour : 0,
            month: ts.month + 1
          };
          if (ts.unit === 'month') {
            return _objectSpread2(_objectSpread2({}, defaultReturn), {}, {
              day: 1,
              value: ts.value + 1
            });
          } else if (ts.unit === 'day' || ts.unit === 'hour') {
            return _objectSpread2(_objectSpread2({}, defaultReturn), {}, {
              value: ts.value
            });
          } else if (ts.unit === 'minute') {
            return _objectSpread2(_objectSpread2({}, defaultReturn), {}, {
              value: ts.value,
              minute: ts.value
            });
          } else if (ts.unit === 'second') {
            return _objectSpread2(_objectSpread2({}, defaultReturn), {}, {
              value: ts.value,
              minute: ts.minute,
              second: ts.second
            });
          }
          return ts;
        });
        var filteredTimeScale = adjustedMonthInTimeScaleArray.filter(function (ts) {
          var modulo = 1;
          var ticks = Math.ceil(w.globals.gridWidth / 120);
          var value = ts.value;
          if (w.config.xaxis.tickAmount !== undefined) {
            ticks = w.config.xaxis.tickAmount;
          }
          if (adjustedMonthInTimeScaleArray.length > ticks) {
            modulo = Math.floor(adjustedMonthInTimeScaleArray.length / ticks);
          }
          var shouldNotSkipUnit = false; // there is a big change in unit i.e days to months
          var shouldNotPrint = false; // should skip these values

          switch (_this.tickInterval) {
            case 'years':
              // make years label denser
              if (ts.unit === 'year') {
                shouldNotSkipUnit = true;
              }
              break;
            case 'half_year':
              modulo = 7;
              if (ts.unit === 'year') {
                shouldNotSkipUnit = true;
              }
              break;
            case 'months':
              modulo = 1;
              if (ts.unit === 'year') {
                shouldNotSkipUnit = true;
              }
              break;
            case 'months_fortnight':
              modulo = 15;
              if (ts.unit === 'year' || ts.unit === 'month') {
                shouldNotSkipUnit = true;
              }
              if (value === 30) {
                shouldNotPrint = true;
              }
              break;
            case 'months_days':
              modulo = 10;
              if (ts.unit === 'month') {
                shouldNotSkipUnit = true;
              }
              if (value === 30) {
                shouldNotPrint = true;
              }
              break;
            case 'week_days':
              modulo = 8;
              if (ts.unit === 'month') {
                shouldNotSkipUnit = true;
              }
              break;
            case 'days':
              modulo = 1;
              if (ts.unit === 'month') {
                shouldNotSkipUnit = true;
              }
              break;
            case 'hours':
              if (ts.unit === 'day') {
                shouldNotSkipUnit = true;
              }
              break;
            case 'minutes_fives':
              if (value % 5 !== 0) {
                shouldNotPrint = true;
              }
              break;
            case 'seconds_tens':
              if (value % 10 !== 0) {
                shouldNotPrint = true;
              }
              break;
            case 'seconds_fives':
              if (value % 5 !== 0) {
                shouldNotPrint = true;
              }
              break;
          }
          if (_this.tickInterval === 'hours' || _this.tickInterval === 'minutes_fives' || _this.tickInterval === 'seconds_tens' || _this.tickInterval === 'seconds_fives') {
            if (!shouldNotPrint) {
              return true;
            }
          } else {
            if ((value % modulo === 0 || shouldNotSkipUnit) && !shouldNotPrint) {
              return true;
            }
          }
        });
        return filteredTimeScale;
      }
    }, {
      key: "recalcDimensionsBasedOnFormat",
      value: function recalcDimensionsBasedOnFormat(filteredTimeScale, inverted) {
        var w = this.w;
        var reformattedTimescaleArray = this.formatDates(filteredTimeScale);
        var removedOverlappingTS = this.removeOverlappingTS(reformattedTimescaleArray);
        w.globals.timescaleLabels = removedOverlappingTS.slice();

        // at this stage, we need to re-calculate coords of the grid as timeline labels may have altered the xaxis labels coords
        // The reason we can't do this prior to this stage is because timeline labels depends on gridWidth, and as the ticks are calculated based on available gridWidth, there can be unknown number of ticks generated for different minX and maxX
        // Dependency on Dimensions(), need to refactor correctly
        // TODO - find an alternate way to avoid calling this Heavy method twice
        var dimensions = new Dimensions(this.ctx);
        dimensions.plotCoords();
      }
    }, {
      key: "determineInterval",
      value: function determineInterval(daysDiff) {
        var yearsDiff = daysDiff / 365;
        var hoursDiff = daysDiff * 24;
        var minutesDiff = hoursDiff * 60;
        var secondsDiff = minutesDiff * 60;
        switch (true) {
          case yearsDiff > 5:
            this.tickInterval = 'years';
            break;
          case daysDiff > 800:
            this.tickInterval = 'half_year';
            break;
          case daysDiff > 180:
            this.tickInterval = 'months';
            break;
          case daysDiff > 90:
            this.tickInterval = 'months_fortnight';
            break;
          case daysDiff > 60:
            this.tickInterval = 'months_days';
            break;
          case daysDiff > 30:
            this.tickInterval = 'week_days';
            break;
          case daysDiff > 2:
            this.tickInterval = 'days';
            break;
          case hoursDiff > 2.4:
            this.tickInterval = 'hours';
            break;
          case minutesDiff > 15:
            this.tickInterval = 'minutes_fives';
            break;
          case minutesDiff > 5:
            this.tickInterval = 'minutes';
            break;
          case minutesDiff > 1:
            this.tickInterval = 'seconds_tens';
            break;
          case secondsDiff > 20:
            this.tickInterval = 'seconds_fives';
            break;
          default:
            this.tickInterval = 'seconds';
            break;
        }
      }
    }, {
      key: "generateYearScale",
      value: function generateYearScale(_ref) {
        var firstVal = _ref.firstVal,
          currentMonth = _ref.currentMonth,
          currentYear = _ref.currentYear,
          daysWidthOnXAxis = _ref.daysWidthOnXAxis,
          numberOfYears = _ref.numberOfYears;
        var firstTickValue = firstVal.minYear;
        var firstTickPosition = 0;
        var dt = new DateTime(this.ctx);
        var unit = 'year';
        if (firstVal.minDate > 1 || firstVal.minMonth > 0) {
          var remainingDays = dt.determineRemainingDaysOfYear(firstVal.minYear, firstVal.minMonth, firstVal.minDate);

          // remainingDaysofFirstMonth is used to reacht the 2nd tick position
          var remainingDaysOfFirstYear = dt.determineDaysOfYear(firstVal.minYear) - remainingDays + 1;

          // calculate the first tick position
          firstTickPosition = remainingDaysOfFirstYear * daysWidthOnXAxis;
          firstTickValue = firstVal.minYear + 1;
          // push the first tick in the array
          this.timeScaleArray.push({
            position: firstTickPosition,
            value: firstTickValue,
            unit: unit,
            year: firstTickValue,
            month: Utils$1.monthMod(currentMonth + 1)
          });
        } else if (firstVal.minDate === 1 && firstVal.minMonth === 0) {
          // push the first tick in the array
          this.timeScaleArray.push({
            position: firstTickPosition,
            value: firstTickValue,
            unit: unit,
            year: currentYear,
            month: Utils$1.monthMod(currentMonth + 1)
          });
        }
        var year = firstTickValue;
        var pos = firstTickPosition;

        // keep drawing rest of the ticks
        for (var i = 0; i < numberOfYears; i++) {
          year++;
          pos = dt.determineDaysOfYear(year - 1) * daysWidthOnXAxis + pos;
          this.timeScaleArray.push({
            position: pos,
            value: year,
            unit: unit,
            year: year,
            month: 1
          });
        }
      }
    }, {
      key: "generateMonthScale",
      value: function generateMonthScale(_ref2) {
        var firstVal = _ref2.firstVal,
          currentMonthDate = _ref2.currentMonthDate,
          currentMonth = _ref2.currentMonth,
          currentYear = _ref2.currentYear,
          daysWidthOnXAxis = _ref2.daysWidthOnXAxis,
          numberOfMonths = _ref2.numberOfMonths;
        var firstTickValue = currentMonth;
        var firstTickPosition = 0;
        var dt = new DateTime(this.ctx);
        var unit = 'month';
        var yrCounter = 0;
        if (firstVal.minDate > 1) {
          // remainingDaysofFirstMonth is used to reacht the 2nd tick position
          var remainingDaysOfFirstMonth = dt.determineDaysOfMonths(currentMonth + 1, firstVal.minYear) - currentMonthDate + 1;

          // calculate the first tick position
          firstTickPosition = remainingDaysOfFirstMonth * daysWidthOnXAxis;
          firstTickValue = Utils$1.monthMod(currentMonth + 1);
          var year = currentYear + yrCounter;
          var _month = Utils$1.monthMod(firstTickValue);
          var value = firstTickValue;
          // it's Jan, so update the year
          if (firstTickValue === 0) {
            unit = 'year';
            value = year;
            _month = 1;
            yrCounter += 1;
            year = year + yrCounter;
          }

          // push the first tick in the array
          this.timeScaleArray.push({
            position: firstTickPosition,
            value: value,
            unit: unit,
            year: year,
            month: _month
          });
        } else {
          // push the first tick in the array
          this.timeScaleArray.push({
            position: firstTickPosition,
            value: firstTickValue,
            unit: unit,
            year: currentYear,
            month: Utils$1.monthMod(currentMonth)
          });
        }
        var month = firstTickValue + 1;
        var pos = firstTickPosition;

        // keep drawing rest of the ticks
        for (var i = 0, j = 1; i < numberOfMonths; i++, j++) {
          month = Utils$1.monthMod(month);
          if (month === 0) {
            unit = 'year';
            yrCounter += 1;
          } else {
            unit = 'month';
          }
          var _year = this._getYear(currentYear, month, yrCounter);
          pos = dt.determineDaysOfMonths(month, _year) * daysWidthOnXAxis + pos;
          var monthVal = month === 0 ? _year : month;
          this.timeScaleArray.push({
            position: pos,
            value: monthVal,
            unit: unit,
            year: _year,
            month: month === 0 ? 1 : month
          });
          month++;
        }
      }
    }, {
      key: "generateDayScale",
      value: function generateDayScale(_ref3) {
        var firstVal = _ref3.firstVal,
          currentMonth = _ref3.currentMonth,
          currentYear = _ref3.currentYear,
          hoursWidthOnXAxis = _ref3.hoursWidthOnXAxis,
          numberOfDays = _ref3.numberOfDays;
        var dt = new DateTime(this.ctx);
        var unit = 'day';
        var firstTickValue = firstVal.minDate + 1;
        var date = firstTickValue;
        var changeMonth = function changeMonth(dateVal, month, year) {
          var monthdays = dt.determineDaysOfMonths(month + 1, year);
          if (dateVal > monthdays) {
            month = month + 1;
            date = 1;
            unit = 'month';
            val = month;
            return month;
          }
          return month;
        };
        var remainingHours = 24 - firstVal.minHour;
        var yrCounter = 0;

        // calculate the first tick position
        var firstTickPosition = remainingHours * hoursWidthOnXAxis;
        var val = firstTickValue;
        var month = changeMonth(date, currentMonth, currentYear);
        if (firstVal.minHour === 0 && firstVal.minDate === 1) {
          // the first value is the first day of month
          firstTickPosition = 0;
          val = Utils$1.monthMod(firstVal.minMonth);
          unit = 'month';
          date = firstVal.minDate;
          // numberOfDays++
          // removed the above line to fix https://github.com/apexcharts/apexcharts.js/issues/305#issuecomment-1019520513
        } else if (firstVal.minDate !== 1 && firstVal.minHour === 0 && firstVal.minMinute === 0) {
          // fixes apexcharts/apexcharts.js/issues/1730
          firstTickPosition = 0;
          firstTickValue = firstVal.minDate;
          date = firstTickValue;
          val = firstTickValue;
          // in case it's the last date of month, we need to check it
          month = changeMonth(date, currentMonth, currentYear);
        }

        // push the first tick in the array
        this.timeScaleArray.push({
          position: firstTickPosition,
          value: val,
          unit: unit,
          year: this._getYear(currentYear, month, yrCounter),
          month: Utils$1.monthMod(month),
          day: date
        });
        var pos = firstTickPosition;
        // keep drawing rest of the ticks
        for (var i = 0; i < numberOfDays; i++) {
          date += 1;
          unit = 'day';
          month = changeMonth(date, month, this._getYear(currentYear, month, yrCounter));
          var year = this._getYear(currentYear, month, yrCounter);
          pos = 24 * hoursWidthOnXAxis + pos;
          var value = date === 1 ? Utils$1.monthMod(month) : date;
          this.timeScaleArray.push({
            position: pos,
            value: value,
            unit: unit,
            year: year,
            month: Utils$1.monthMod(month),
            day: value
          });
        }
      }
    }, {
      key: "generateHourScale",
      value: function generateHourScale(_ref4) {
        var firstVal = _ref4.firstVal,
          currentDate = _ref4.currentDate,
          currentMonth = _ref4.currentMonth,
          currentYear = _ref4.currentYear,
          minutesWidthOnXAxis = _ref4.minutesWidthOnXAxis,
          numberOfHours = _ref4.numberOfHours;
        var dt = new DateTime(this.ctx);
        var yrCounter = 0;
        var unit = 'hour';
        var changeDate = function changeDate(dateVal, month) {
          var monthdays = dt.determineDaysOfMonths(month + 1, currentYear);
          if (dateVal > monthdays) {
            date = 1;
            month = month + 1;
          }
          return {
            month: month,
            date: date
          };
        };
        var changeMonth = function changeMonth(dateVal, month) {
          var monthdays = dt.determineDaysOfMonths(month + 1, currentYear);
          if (dateVal > monthdays) {
            month = month + 1;
            return month;
          }
          return month;
        };

        // factor in minSeconds as well
        var remainingMins = 60 - (firstVal.minMinute + firstVal.minSecond / 60.0);
        var firstTickPosition = remainingMins * minutesWidthOnXAxis;
        var firstTickValue = firstVal.minHour + 1;
        var hour = firstTickValue;
        if (remainingMins === 60) {
          firstTickPosition = 0;
          firstTickValue = firstVal.minHour;
          hour = firstTickValue;
        }
        var date = currentDate;

        // we need to apply date switching logic here as well, to avoid duplicated labels
        if (hour >= 24) {
          hour = 0;
          date += 1;
          unit = 'day';
        }
        var checkNextMonth = changeDate(date, currentMonth);
        var month = checkNextMonth.month;
        month = changeMonth(date, month);

        // push the first tick in the array
        this.timeScaleArray.push({
          position: firstTickPosition,
          value: firstTickValue,
          unit: unit,
          day: date,
          hour: hour,
          year: currentYear,
          month: Utils$1.monthMod(month)
        });
        hour++;
        var pos = firstTickPosition;
        // keep drawing rest of the ticks
        for (var i = 0; i < numberOfHours; i++) {
          unit = 'hour';
          if (hour >= 24) {
            hour = 0;
            date += 1;
            unit = 'day';
            var _checkNextMonth = changeDate(date, month);
            month = _checkNextMonth.month;
            month = changeMonth(date, month);
          }
          var year = this._getYear(currentYear, month, yrCounter);
          pos = 60 * minutesWidthOnXAxis + pos;
          var val = hour === 0 ? date : hour;
          this.timeScaleArray.push({
            position: pos,
            value: val,
            unit: unit,
            hour: hour,
            day: date,
            year: year,
            month: Utils$1.monthMod(month)
          });
          hour++;
        }
      }
    }, {
      key: "generateMinuteScale",
      value: function generateMinuteScale(_ref5) {
        var currentMillisecond = _ref5.currentMillisecond,
          currentSecond = _ref5.currentSecond,
          currentMinute = _ref5.currentMinute,
          currentHour = _ref5.currentHour,
          currentDate = _ref5.currentDate,
          currentMonth = _ref5.currentMonth,
          currentYear = _ref5.currentYear,
          minutesWidthOnXAxis = _ref5.minutesWidthOnXAxis,
          secondsWidthOnXAxis = _ref5.secondsWidthOnXAxis,
          numberOfMinutes = _ref5.numberOfMinutes;
        var yrCounter = 0;
        var unit = 'minute';
        var remainingSecs = 60 - currentSecond;
        var firstTickPosition = (remainingSecs - currentMillisecond / 1000) * secondsWidthOnXAxis;
        var minute = currentMinute + 1;
        var date = currentDate;
        var month = currentMonth;
        var year = currentYear;
        var hour = currentHour;
        var pos = firstTickPosition;
        for (var i = 0; i < numberOfMinutes; i++) {
          if (minute >= 60) {
            minute = 0;
            hour += 1;
            if (hour === 24) {
              hour = 0;
            }
          }
          this.timeScaleArray.push({
            position: pos,
            value: minute,
            unit: unit,
            hour: hour,
            minute: minute,
            day: date,
            year: this._getYear(year, month, yrCounter),
            month: Utils$1.monthMod(month)
          });
          pos += minutesWidthOnXAxis;
          minute++;
        }
      }
    }, {
      key: "generateSecondScale",
      value: function generateSecondScale(_ref6) {
        var currentMillisecond = _ref6.currentMillisecond,
          currentSecond = _ref6.currentSecond,
          currentMinute = _ref6.currentMinute,
          currentHour = _ref6.currentHour,
          currentDate = _ref6.currentDate,
          currentMonth = _ref6.currentMonth,
          currentYear = _ref6.currentYear,
          secondsWidthOnXAxis = _ref6.secondsWidthOnXAxis,
          numberOfSeconds = _ref6.numberOfSeconds;
        var yrCounter = 0;
        var unit = 'second';
        var remainingMillisecs = 1000 - currentMillisecond;
        var firstTickPosition = remainingMillisecs / 1000 * secondsWidthOnXAxis;
        var second = currentSecond + 1;
        var minute = currentMinute;
        var date = currentDate;
        var month = currentMonth;
        var year = currentYear;
        var hour = currentHour;
        var pos = firstTickPosition;
        for (var i = 0; i < numberOfSeconds; i++) {
          if (second >= 60) {
            minute++;
            second = 0;
            if (minute >= 60) {
              hour++;
              minute = 0;
              if (hour === 24) {
                hour = 0;
              }
            }
          }
          this.timeScaleArray.push({
            position: pos,
            value: second,
            unit: unit,
            hour: hour,
            minute: minute,
            second: second,
            day: date,
            year: this._getYear(year, month, yrCounter),
            month: Utils$1.monthMod(month)
          });
          pos += secondsWidthOnXAxis;
          second++;
        }
      }
    }, {
      key: "createRawDateString",
      value: function createRawDateString(ts, value) {
        var raw = ts.year;
        if (ts.month === 0) {
          // invalid month, correct it
          ts.month = 1;
        }
        raw += '-' + ('0' + ts.month.toString()).slice(-2);

        // unit is day
        if (ts.unit === 'day') {
          raw += ts.unit === 'day' ? '-' + ('0' + value).slice(-2) : '-01';
        } else {
          raw += '-' + ('0' + (ts.day ? ts.day : '1')).slice(-2);
        }

        // unit is hour
        if (ts.unit === 'hour') {
          raw += ts.unit === 'hour' ? 'T' + ('0' + value).slice(-2) : 'T00';
        } else {
          raw += 'T' + ('0' + (ts.hour ? ts.hour : '0')).slice(-2);
        }
        if (ts.unit === 'minute') {
          raw += ':' + ('0' + value).slice(-2);
        } else {
          raw += ':' + (ts.minute ? ('0' + ts.minute).slice(-2) : '00');
        }
        if (ts.unit === 'second') {
          raw += ':' + ('0' + value).slice(-2);
        } else {
          raw += ':00';
        }
        if (this.utc) {
          raw += '.000Z';
        }
        return raw;
      }
    }, {
      key: "formatDates",
      value: function formatDates(filteredTimeScale) {
        var _this2 = this;
        var w = this.w;
        var reformattedTimescaleArray = filteredTimeScale.map(function (ts) {
          var value = ts.value.toString();
          var dt = new DateTime(_this2.ctx);
          var raw = _this2.createRawDateString(ts, value);
          var dateToFormat = dt.getDate(dt.parseDate(raw));
          if (!_this2.utc) {
            // Fixes #1726, #1544, #1485, #1255
            dateToFormat = dt.getDate(dt.parseDateWithTimezone(raw));
          }
          if (w.config.xaxis.labels.format === undefined) {
            var customFormat = 'dd MMM';
            var dtFormatter = w.config.xaxis.labels.datetimeFormatter;
            if (ts.unit === 'year') customFormat = dtFormatter.year;
            if (ts.unit === 'month') customFormat = dtFormatter.month;
            if (ts.unit === 'day') customFormat = dtFormatter.day;
            if (ts.unit === 'hour') customFormat = dtFormatter.hour;
            if (ts.unit === 'minute') customFormat = dtFormatter.minute;
            if (ts.unit === 'second') customFormat = dtFormatter.second;
            value = dt.formatDate(dateToFormat, customFormat);
          } else {
            value = dt.formatDate(dateToFormat, w.config.xaxis.labels.format);
          }
          return {
            dateString: raw,
            position: ts.position,
            value: value,
            unit: ts.unit,
            year: ts.year,
            month: ts.month
          };
        });
        return reformattedTimescaleArray;
      }
    }, {
      key: "removeOverlappingTS",
      value: function removeOverlappingTS(arr) {
        var _this3 = this;
        var graphics = new Graphics(this.ctx);
        var equalLabelLengthFlag = false; // These labels got same length?
        var constantLabelWidth; // If true, what is the constant length to use
        if (arr.length > 0 &&
        // check arr length
        arr[0].value &&
        // check arr[0] contains value
        arr.every(function (lb) {
          return lb.value.length === arr[0].value.length;
        }) // check every arr label value is the same as the first one
        ) {
          equalLabelLengthFlag = true; // These labels got same length
          constantLabelWidth = graphics.getTextRects(arr[0].value).width; // The constant label width to use
        }
        var lastDrawnIndex = 0;
        var filteredArray = arr.map(function (item, index) {
          if (index > 0 && _this3.w.config.xaxis.labels.hideOverlappingLabels) {
            var prevLabelWidth = !equalLabelLengthFlag // if vary in label length
            ? graphics.getTextRects(arr[lastDrawnIndex].value).width // get individual length
            : constantLabelWidth; // else: use constant length
            var prevPos = arr[lastDrawnIndex].position;
            var pos = item.position;
            if (pos > prevPos + prevLabelWidth + 10) {
              lastDrawnIndex = index;
              return item;
            } else {
              return null;
            }
          } else {
            return item;
          }
        });
        filteredArray = filteredArray.filter(function (f) {
          return f !== null;
        });
        return filteredArray;
      }
    }, {
      key: "_getYear",
      value: function _getYear(currentYear, month, yrCounter) {
        return currentYear + Math.floor(month / 12) + yrCounter;
      }
    }]);
    return TimeScale;
  }();

  /**
   * ApexCharts Core Class responsible for major calculations and creating elements.
   *
   * @module Core
   **/
  var Core = /*#__PURE__*/function () {
    function Core(el, ctx) {
      _classCallCheck(this, Core);
      this.ctx = ctx;
      this.w = ctx.w;
      this.el = el;
    }
    _createClass(Core, [{
      key: "setupElements",
      value: function setupElements() {
        var _this$w = this.w,
          gl = _this$w.globals,
          cnf = _this$w.config;
        var ct = cnf.chart.type;
        var axisChartsArrTypes = ['line', 'area', 'bar', 'rangeBar', 'rangeArea', 'candlestick', 'boxPlot', 'scatter', 'bubble', 'radar', 'heatmap', 'treemap'];
        var xyChartsArrTypes = ['line', 'area', 'bar', 'rangeBar', 'rangeArea', 'candlestick', 'boxPlot', 'scatter', 'bubble'];
        gl.axisCharts = axisChartsArrTypes.includes(ct);
        gl.xyCharts = xyChartsArrTypes.includes(ct);
        gl.isBarHorizontal = ['bar', 'rangeBar', 'boxPlot'].includes(ct) && cnf.plotOptions.bar.horizontal;
        gl.chartClass = ".apexcharts".concat(gl.chartID);
        gl.dom.baseEl = this.el;
        gl.dom.elWrap = document.createElement('div');
        Graphics.setAttrs(gl.dom.elWrap, {
          id: gl.chartClass.substring(1),
          class: "apexcharts-canvas ".concat(gl.chartClass.substring(1))
        });
        this.el.appendChild(gl.dom.elWrap);
        gl.dom.Paper = new window.SVG.Doc(gl.dom.elWrap);
        gl.dom.Paper.attr({
          class: 'apexcharts-svg',
          'xmlns:data': 'ApexChartsNS',
          transform: "translate(".concat(cnf.chart.offsetX, ", ").concat(cnf.chart.offsetY, ")")
        });
        gl.dom.Paper.node.style.background = cnf.theme.mode === 'dark' && !cnf.chart.background ? '#424242' : cnf.theme.mode === 'light' && !cnf.chart.background ? '#fff' : cnf.chart.background;
        this.setSVGDimensions();
        gl.dom.elLegendForeign = document.createElementNS(gl.SVGNS, 'foreignObject');
        Graphics.setAttrs(gl.dom.elLegendForeign, {
          x: 0,
          y: 0,
          width: gl.svgWidth,
          height: gl.svgHeight
        });
        gl.dom.elLegendWrap = document.createElement('div');
        gl.dom.elLegendWrap.classList.add('apexcharts-legend');
        gl.dom.elLegendWrap.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
        gl.dom.elLegendForeign.appendChild(gl.dom.elLegendWrap);
        gl.dom.Paper.node.appendChild(gl.dom.elLegendForeign);
        gl.dom.elGraphical = gl.dom.Paper.group().attr({
          class: 'apexcharts-inner apexcharts-graphical'
        });
        gl.dom.elDefs = gl.dom.Paper.defs();
        gl.dom.Paper.add(gl.dom.elGraphical);
        gl.dom.elGraphical.add(gl.dom.elDefs);
      }
    }, {
      key: "plotChartType",
      value: function plotChartType(ser, xyRatios) {
        var w = this.w,
          ctx = this.ctx;
        var cnf = w.config,
          gl = w.globals;
        var seriesTypes = {
          line: {
            series: [],
            i: []
          },
          area: {
            series: [],
            i: []
          },
          scatter: {
            series: [],
            i: []
          },
          bubble: {
            series: [],
            i: []
          },
          column: {
            series: [],
            i: []
          },
          candlestick: {
            series: [],
            i: []
          },
          boxPlot: {
            series: [],
            i: []
          },
          rangeBar: {
            series: [],
            i: []
          },
          rangeArea: {
            series: [],
            seriesRangeEnd: [],
            i: []
          }
        };
        var chartType = cnf.chart.type || 'line';
        var nonComboType = null;
        var comboCount = 0;
        gl.series.forEach(function (serie, st) {
          var seriesType = ser[st].type || chartType;
          if (seriesTypes[seriesType]) {
            if (seriesType === 'rangeArea') {
              seriesTypes[seriesType].series.push(gl.seriesRangeStart[st]);
              seriesTypes[seriesType].seriesRangeEnd.push(gl.seriesRangeEnd[st]);
            } else {
              seriesTypes[seriesType].series.push(serie);
            }
            seriesTypes[seriesType].i.push(st);
            if (seriesType === 'column' || seriesType === 'bar') w.globals.columnSeries = seriesTypes.column;
          } else if (['heatmap', 'treemap', 'pie', 'donut', 'polarArea', 'radialBar', 'radar'].includes(seriesType)) {
            nonComboType = seriesType;
          } else if (seriesType === 'bar') {
            seriesTypes['column'].series.push(serie);
            seriesTypes['column'].i.push(st);
          } else {
            console.warn("You have specified an unrecognized series type (".concat(seriesType, ")."));
          }
          if (chartType !== seriesType && seriesType !== 'scatter') comboCount++;
        });
        if (comboCount > 0) {
          if (nonComboType) {
            console.warn("Chart or series type ".concat(nonComboType, " cannot appear with other chart or series types."));
          }
          if (seriesTypes.column.series.length > 0 && cnf.plotOptions.bar.horizontal) {
            comboCount -= seriesTypes.column.series.length;
            seriesTypes.column = {
              series: [],
              i: []
            };
            w.globals.columnSeries = {
              series: [],
              i: []
            };
            console.warn('Horizontal bars are not supported in a mixed/combo chart. Please turn off `plotOptions.bar.horizontal`');
          }
        }
        gl.comboCharts || (gl.comboCharts = comboCount > 0);
        var line = new Line(ctx, xyRatios);
        var boxCandlestick = new BoxCandleStick(ctx, xyRatios);
        ctx.pie = new Pie(ctx);
        var radialBar = new Radial(ctx);
        ctx.rangeBar = new RangeBar(ctx, xyRatios);
        var radar = new Radar(ctx);
        var elGraph = [];
        if (gl.comboCharts) {
          var coreUtils = new CoreUtils(ctx);
          if (seriesTypes.area.series.length > 0) {
            var _elGraph;
            (_elGraph = elGraph).push.apply(_elGraph, _toConsumableArray(coreUtils.drawSeriesByGroup(seriesTypes.area, gl.areaGroups, 'area', line)));
          }
          if (seriesTypes.column.series.length > 0) {
            if (cnf.chart.stacked) {
              var barStacked = new BarStacked(ctx, xyRatios);
              elGraph.push(barStacked.draw(seriesTypes.column.series, seriesTypes.column.i));
            } else {
              ctx.bar = new Bar(ctx, xyRatios);
              elGraph.push(ctx.bar.draw(seriesTypes.column.series, seriesTypes.column.i));
            }
          }
          if (seriesTypes.rangeArea.series.length > 0) {
            elGraph.push(line.draw(seriesTypes.rangeArea.series, 'rangeArea', seriesTypes.rangeArea.i, seriesTypes.rangeArea.seriesRangeEnd));
          }
          if (seriesTypes.line.series.length > 0) {
            var _elGraph2;
            (_elGraph2 = elGraph).push.apply(_elGraph2, _toConsumableArray(coreUtils.drawSeriesByGroup(seriesTypes.line, gl.lineGroups, 'line', line)));
          }
          if (seriesTypes.candlestick.series.length > 0) {
            elGraph.push(boxCandlestick.draw(seriesTypes.candlestick.series, 'candlestick', seriesTypes.candlestick.i));
          }
          if (seriesTypes.boxPlot.series.length > 0) {
            elGraph.push(boxCandlestick.draw(seriesTypes.boxPlot.series, 'boxPlot', seriesTypes.boxPlot.i));
          }
          if (seriesTypes.rangeBar.series.length > 0) {
            elGraph.push(ctx.rangeBar.draw(seriesTypes.rangeBar.series, seriesTypes.rangeBar.i));
          }
          if (seriesTypes.scatter.series.length > 0) {
            var scatterLine = new Line(ctx, xyRatios, true);
            elGraph.push(scatterLine.draw(seriesTypes.scatter.series, 'scatter', seriesTypes.scatter.i));
          }
          if (seriesTypes.bubble.series.length > 0) {
            var bubbleLine = new Line(ctx, xyRatios, true);
            elGraph.push(bubbleLine.draw(seriesTypes.bubble.series, 'bubble', seriesTypes.bubble.i));
          }
        } else {
          switch (cnf.chart.type) {
            case 'line':
              elGraph = line.draw(gl.series, 'line');
              break;
            case 'area':
              elGraph = line.draw(gl.series, 'area');
              break;
            case 'bar':
              if (cnf.chart.stacked) {
                var _barStacked = new BarStacked(ctx, xyRatios);
                elGraph = _barStacked.draw(gl.series);
              } else {
                ctx.bar = new Bar(ctx, xyRatios);
                elGraph = ctx.bar.draw(gl.series);
              }
              break;
            case 'candlestick':
              var candleStick = new BoxCandleStick(ctx, xyRatios);
              elGraph = candleStick.draw(gl.series, 'candlestick');
              break;
            case 'boxPlot':
              var boxPlot = new BoxCandleStick(ctx, xyRatios);
              elGraph = boxPlot.draw(gl.series, cnf.chart.type);
              break;
            case 'rangeBar':
              elGraph = ctx.rangeBar.draw(gl.series);
              break;
            case 'rangeArea':
              elGraph = line.draw(gl.seriesRangeStart, 'rangeArea', undefined, gl.seriesRangeEnd);
              break;
            case 'heatmap':
              var heatmap = new HeatMap(ctx, xyRatios);
              elGraph = heatmap.draw(gl.series);
              break;
            case 'treemap':
              var treemap = new TreemapChart(ctx, xyRatios);
              elGraph = treemap.draw(gl.series);
              break;
            case 'pie':
            case 'donut':
            case 'polarArea':
              elGraph = ctx.pie.draw(gl.series);
              break;
            case 'radialBar':
              elGraph = radialBar.draw(gl.series);
              break;
            case 'radar':
              elGraph = radar.draw(gl.series);
              break;
            default:
              elGraph = line.draw(gl.series);
          }
        }
        return elGraph;
      }
    }, {
      key: "setSVGDimensions",
      value: function setSVGDimensions() {
        var _this$w2 = this.w,
          gl = _this$w2.globals,
          cnf = _this$w2.config;
        cnf.chart.width = cnf.chart.width || '100%';
        cnf.chart.height = cnf.chart.height || 'auto';
        gl.svgWidth = cnf.chart.width;
        gl.svgHeight = cnf.chart.height;
        var elDim = Utils$1.getDimensions(this.el);
        var widthUnit = cnf.chart.width.toString().split(/[0-9]+/g).pop();
        if (widthUnit === '%') {
          if (Utils$1.isNumber(elDim[0])) {
            if (elDim[0].width === 0) {
              elDim = Utils$1.getDimensions(this.el.parentNode);
            }
            gl.svgWidth = elDim[0] * parseInt(cnf.chart.width, 10) / 100;
          }
        } else if (widthUnit === 'px' || widthUnit === '') {
          gl.svgWidth = parseInt(cnf.chart.width, 10);
        }
        var heightUnit = String(cnf.chart.height).toString().split(/[0-9]+/g).pop();
        if (gl.svgHeight !== 'auto' && gl.svgHeight !== '') {
          if (heightUnit === '%') {
            var elParentDim = Utils$1.getDimensions(this.el.parentNode);
            gl.svgHeight = elParentDim[1] * parseInt(cnf.chart.height, 10) / 100;
          } else {
            gl.svgHeight = parseInt(cnf.chart.height, 10);
          }
        } else {
          gl.svgHeight = gl.axisCharts ? gl.svgWidth / 1.61 : gl.svgWidth / 1.2;
        }
        gl.svgWidth = Math.max(gl.svgWidth, 0);
        gl.svgHeight = Math.max(gl.svgHeight, 0);
        Graphics.setAttrs(gl.dom.Paper.node, {
          width: gl.svgWidth,
          height: gl.svgHeight
        });
        if (heightUnit !== '%') {
          var offsetY = cnf.chart.sparkline.enabled ? 0 : gl.axisCharts ? cnf.chart.parentHeightOffset : 0;
          gl.dom.Paper.node.parentNode.parentNode.style.minHeight = "".concat(gl.svgHeight + offsetY, "px");
        }
        gl.dom.elWrap.style.width = "".concat(gl.svgWidth, "px");
        gl.dom.elWrap.style.height = "".concat(gl.svgHeight, "px");
      }
    }, {
      key: "shiftGraphPosition",
      value: function shiftGraphPosition() {
        var gl = this.w.globals;
        var tY = gl.translateY,
          tX = gl.translateX;
        Graphics.setAttrs(gl.dom.elGraphical.node, {
          transform: "translate(".concat(tX, ", ").concat(tY, ")")
        });
      }
    }, {
      key: "resizeNonAxisCharts",
      value: function resizeNonAxisCharts() {
        var w = this.w;
        var gl = w.globals;
        var legendHeight = 0;
        var offY = w.config.chart.sparkline.enabled ? 1 : 15;
        offY += w.config.grid.padding.bottom;
        if (['top', 'bottom'].includes(w.config.legend.position) && w.config.legend.show && !w.config.legend.floating) {
          legendHeight = new Legend(this.ctx).legendHelpers.getLegendDimensions().clwh + 7;
        }
        var el = w.globals.dom.baseEl.querySelector('.apexcharts-radialbar, .apexcharts-pie');
        var chartInnerDimensions = w.globals.radialSize * 2.05;
        if (el && !w.config.chart.sparkline.enabled && w.config.plotOptions.radialBar.startAngle !== 0) {
          var elRadialRect = Utils$1.getBoundingClientRect(el);
          chartInnerDimensions = elRadialRect.bottom;
          var maxHeight = elRadialRect.bottom - elRadialRect.top;
          chartInnerDimensions = Math.max(w.globals.radialSize * 2.05, maxHeight);
        }
        var newHeight = Math.ceil(chartInnerDimensions + gl.translateY + legendHeight + offY);
        if (gl.dom.elLegendForeign) {
          gl.dom.elLegendForeign.setAttribute('height', newHeight);
        }
        if (w.config.chart.height && String(w.config.chart.height).includes('%')) return;
        gl.dom.elWrap.style.height = "".concat(newHeight, "px");
        Graphics.setAttrs(gl.dom.Paper.node, {
          height: newHeight
        });
        gl.dom.Paper.node.parentNode.parentNode.style.minHeight = "".concat(newHeight, "px");
      }
    }, {
      key: "coreCalculations",
      value: function coreCalculations() {
        new Range(this.ctx).init();
      }
    }, {
      key: "resetGlobals",
      value: function resetGlobals() {
        var _this = this;
        var resetxyValues = function resetxyValues() {
          return _this.w.config.series.map(function () {
            return [];
          });
        };
        var globalObj = new Globals();
        var gl = this.w.globals;
        globalObj.initGlobalVars(gl);
        gl.seriesXvalues = resetxyValues();
        gl.seriesYvalues = resetxyValues();
      }
    }, {
      key: "isMultipleY",
      value: function isMultipleY() {
        if (Array.isArray(this.w.config.yaxis) && this.w.config.yaxis.length > 1) {
          this.w.globals.isMultipleYAxis = true;
          return true;
        }
        return false;
      }
    }, {
      key: "xySettings",
      value: function xySettings() {
        var w = this.w;
        var xyRatios = null;
        if (w.globals.axisCharts) {
          if (w.config.xaxis.crosshairs.position === 'back') {
            new Crosshairs(this.ctx).drawXCrosshairs();
          }
          if (w.config.yaxis[0].crosshairs.position === 'back') {
            new Crosshairs(this.ctx).drawYCrosshairs();
          }
          if (w.config.xaxis.type === 'datetime' && w.config.xaxis.labels.formatter === undefined) {
            this.ctx.timeScale = new TimeScale(this.ctx);
            var formattedTimeScale = [];
            if (isFinite(w.globals.minX) && isFinite(w.globals.maxX) && !w.globals.isBarHorizontal) {
              formattedTimeScale = this.ctx.timeScale.calculateTimeScaleTicks(w.globals.minX, w.globals.maxX);
            } else if (w.globals.isBarHorizontal) {
              formattedTimeScale = this.ctx.timeScale.calculateTimeScaleTicks(w.globals.minY, w.globals.maxY);
            }
            this.ctx.timeScale.recalcDimensionsBasedOnFormat(formattedTimeScale);
          }
          var coreUtils = new CoreUtils(this.ctx);
          xyRatios = coreUtils.getCalculatedRatios();
        }
        return xyRatios;
      }
    }, {
      key: "updateSourceChart",
      value: function updateSourceChart(targetChart) {
        this.ctx.w.globals.selection = undefined;
        this.ctx.updateHelpers._updateOptions({
          chart: {
            selection: {
              xaxis: {
                min: targetChart.w.globals.minX,
                max: targetChart.w.globals.maxX
              }
            }
          }
        }, false, false);
      }
    }, {
      key: "setupBrushHandler",
      value: function setupBrushHandler() {
        var _this2 = this;
        var w = this.w;
        if (!w.config.chart.brush.enabled) return;
        if (typeof w.config.chart.events.selection !== 'function') {
          var targets = Array.isArray(w.config.chart.brush.targets) ? w.config.chart.brush.targets : [w.config.chart.brush.target];
          targets.forEach(function (target) {
            var targetChart = ApexCharts.getChartByID(target);
            targetChart.w.globals.brushSource = _this2.ctx;
            if (typeof targetChart.w.config.chart.events.zoomed !== 'function') {
              targetChart.w.config.chart.events.zoomed = function () {
                return _this2.updateSourceChart(targetChart);
              };
            }
            if (typeof targetChart.w.config.chart.events.scrolled !== 'function') {
              targetChart.w.config.chart.events.scrolled = function () {
                return _this2.updateSourceChart(targetChart);
              };
            }
          });
          w.config.chart.events.selection = function (chart, e) {
            targets.forEach(function (target) {
              var targetChart = ApexCharts.getChartByID(target);
              targetChart.ctx.updateHelpers._updateOptions({
                xaxis: {
                  min: e.xaxis.min,
                  max: e.xaxis.max
                }
              }, false, false, false, false);
            });
          };
        }
      }
    }]);
    return Core;
  }();

  var UpdateHelpers = /*#__PURE__*/function () {
    function UpdateHelpers(ctx) {
      _classCallCheck(this, UpdateHelpers);
      this.ctx = ctx;
      this.w = ctx.w;
    }

    /**
     * private method to update Options.
     *
     * @param {object} options - A new config object can be passed which will be merged with the existing config object
     * @param {boolean} redraw - should redraw from beginning or should use existing paths and redraw from there
     * @param {boolean} animate - should animate or not on updating Options
     * @param {boolean} overwriteInitialConfig - should update the initial config or not
     */
    _createClass(UpdateHelpers, [{
      key: "_updateOptions",
      value: function _updateOptions(options) {
        var _this = this;
        var redraw = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
        var animate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
        var updateSyncedCharts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
        var overwriteInitialConfig = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
        return new Promise(function (resolve) {
          var charts = [_this.ctx];
          if (updateSyncedCharts) {
            charts = _this.ctx.getSyncedCharts();
          }
          if (_this.ctx.w.globals.isExecCalled) {
            // If the user called exec method, we don't want to get grouped charts as user specifically provided a chartID to update
            charts = [_this.ctx];
            _this.ctx.w.globals.isExecCalled = false;
          }
          charts.forEach(function (ch, chartIndex) {
            var w = ch.w;
            w.globals.shouldAnimate = animate;
            if (!redraw) {
              w.globals.resized = true;
              w.globals.dataChanged = true;
              if (animate) {
                ch.series.getPreviousPaths();
              }
            }
            if (options && _typeof(options) === 'object') {
              ch.config = new Config(options);
              options = CoreUtils.extendArrayProps(ch.config, options, w);

              // fixes #914, #623
              if (ch.w.globals.chartID !== _this.ctx.w.globals.chartID) {
                // don't overwrite series of synchronized charts
                delete options.series;
              }
              w.config = Utils$1.extend(w.config, options);
              if (overwriteInitialConfig) {
                // we need to forget the lastXAxis and lastYAxis as user forcefully overwriteInitialConfig. If we do not do this, and next time when user zooms the chart after setting yaxis.min/max or xaxis.min/max - the stored lastXAxis will never allow the chart to use the updated min/max by user.
                w.globals.lastXAxis = options.xaxis ? Utils$1.clone(options.xaxis) : [];
                w.globals.lastYAxis = options.yaxis ? Utils$1.clone(options.yaxis) : [];

                // After forgetting lastAxes, we need to restore the new config in initialConfig/initialSeries
                w.globals.initialConfig = Utils$1.extend({}, w.config);
                w.globals.initialSeries = Utils$1.clone(w.config.series);
                if (options.series) {
                  // Replace the collapsed series data
                  for (var i = 0; i < w.globals.collapsedSeriesIndices.length; i++) {
                    var series = w.config.series[w.globals.collapsedSeriesIndices[i]];
                    w.globals.collapsedSeries[i].data = w.globals.axisCharts ? series.data.slice() : series;
                  }
                  for (var _i = 0; _i < w.globals.ancillaryCollapsedSeriesIndices.length; _i++) {
                    var _series = w.config.series[w.globals.ancillaryCollapsedSeriesIndices[_i]];
                    w.globals.ancillaryCollapsedSeries[_i].data = w.globals.axisCharts ? _series.data.slice() : _series;
                  }

                  // Ensure that auto-generated axes are scaled to the visible data
                  ch.series.emptyCollapsedSeries(w.config.series);
                }
              }
            }
            return ch.update(options).then(function () {
              if (chartIndex === charts.length - 1) {
                resolve(ch);
              }
            });
          });
        });
      }

      /**
       * Private method to update Series.
       *
       * @param {array} series - New series which will override the existing
       */
    }, {
      key: "_updateSeries",
      value: function _updateSeries(newSeries, animate) {
        var _this2 = this;
        var overwriteInitialSeries = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
        return new Promise(function (resolve) {
          var w = _this2.w;
          w.globals.shouldAnimate = animate;
          w.globals.dataChanged = true;
          if (animate) {
            _this2.ctx.series.getPreviousPaths();
          }
          var existingSeries;

          // axis charts
          if (w.globals.axisCharts) {
            existingSeries = newSeries.map(function (s, i) {
              return _this2._extendSeries(s, i);
            });
            if (existingSeries.length === 0) {
              existingSeries = [{
                data: []
              }];
            }
            w.config.series = existingSeries;
          } else {
            // non-axis chart (pie/radialbar)
            w.config.series = newSeries.slice();
          }
          if (overwriteInitialSeries) {
            w.globals.initialConfig.series = Utils$1.clone(w.config.series);
            w.globals.initialSeries = Utils$1.clone(w.config.series);
          }
          return _this2.ctx.update().then(function () {
            resolve(_this2.ctx);
          });
        });
      }
    }, {
      key: "_extendSeries",
      value: function _extendSeries(s, i) {
        var w = this.w;
        var ser = w.config.series[i];
        return _objectSpread2(_objectSpread2({}, w.config.series[i]), {}, {
          name: s.name ? s.name : ser === null || ser === void 0 ? void 0 : ser.name,
          color: s.color ? s.color : ser === null || ser === void 0 ? void 0 : ser.color,
          type: s.type ? s.type : ser === null || ser === void 0 ? void 0 : ser.type,
          group: s.group ? s.group : ser === null || ser === void 0 ? void 0 : ser.group,
          hidden: typeof s.hidden !== 'undefined' ? s.hidden : ser === null || ser === void 0 ? void 0 : ser.hidden,
          data: s.data ? s.data : ser === null || ser === void 0 ? void 0 : ser.data,
          zIndex: typeof s.zIndex !== 'undefined' ? s.zIndex : i
        });
      }
    }, {
      key: "toggleDataPointSelection",
      value: function toggleDataPointSelection(seriesIndex, dataPointIndex) {
        var w = this.w;
        var elPath = null;
        var parent = ".apexcharts-series[data\\:realIndex='".concat(seriesIndex, "']");
        if (w.globals.axisCharts) {
          elPath = w.globals.dom.Paper.select("".concat(parent, " path[j='").concat(dataPointIndex, "'], ").concat(parent, " circle[j='").concat(dataPointIndex, "'], ").concat(parent, " rect[j='").concat(dataPointIndex, "']")).members[0];
        } else {
          // dataPointIndex will be undefined here, hence using seriesIndex
          if (typeof dataPointIndex === 'undefined') {
            elPath = w.globals.dom.Paper.select("".concat(parent, " path[j='").concat(seriesIndex, "']")).members[0];
            if (w.config.chart.type === 'pie' || w.config.chart.type === 'polarArea' || w.config.chart.type === 'donut') {
              this.ctx.pie.pieClicked(seriesIndex);
            }
          }
        }
        if (elPath) {
          var graphics = new Graphics(this.ctx);
          graphics.pathMouseDown(elPath, null);
        } else {
          console.warn('toggleDataPointSelection: Element not found');
          return null;
        }
        return elPath.node ? elPath.node : null;
      }
    }, {
      key: "forceXAxisUpdate",
      value: function forceXAxisUpdate(options) {
        var w = this.w;
        var minmax = ['min', 'max'];
        minmax.forEach(function (a) {
          if (typeof options.xaxis[a] !== 'undefined') {
            w.config.xaxis[a] = options.xaxis[a];
            w.globals.lastXAxis[a] = options.xaxis[a];
          }
        });
        if (options.xaxis.categories && options.xaxis.categories.length) {
          w.config.xaxis.categories = options.xaxis.categories;
        }
        if (w.config.xaxis.convertedCatToNumeric) {
          var defaults = new Defaults(options);
          options = defaults.convertCatToNumericXaxis(options, this.ctx);
        }
        return options;
      }
    }, {
      key: "forceYAxisUpdate",
      value: function forceYAxisUpdate(options) {
        if (options.chart && options.chart.stacked && options.chart.stackType === '100%') {
          if (Array.isArray(options.yaxis)) {
            options.yaxis.forEach(function (yaxe, index) {
              options.yaxis[index].min = 0;
              options.yaxis[index].max = 100;
            });
          } else {
            options.yaxis.min = 0;
            options.yaxis.max = 100;
          }
        }
        return options;
      }

      /**
       * This function reverts the yaxis and xaxis min/max values to what it was when the chart was defined.
       * This function fixes an important bug where a user might load a new series after zooming in/out of previous series which resulted in wrong min/max
       * Also, this should never be called internally on zoom/pan - the reset should only happen when user calls the updateSeries() function externally
       * The function also accepts an object {xaxis, yaxis} which when present is set as the new xaxis/yaxis
       */
    }, {
      key: "revertDefaultAxisMinMax",
      value: function revertDefaultAxisMinMax(opts) {
        var _this3 = this;
        var w = this.w;
        var xaxis = w.globals.lastXAxis;
        var yaxis = w.globals.lastYAxis;
        if (opts && opts.xaxis) {
          xaxis = opts.xaxis;
        }
        if (opts && opts.yaxis) {
          yaxis = opts.yaxis;
        }
        w.config.xaxis.min = xaxis.min;
        w.config.xaxis.max = xaxis.max;
        var getLastYAxis = function getLastYAxis(index) {
          if (typeof yaxis[index] !== 'undefined') {
            w.config.yaxis[index].min = yaxis[index].min;
            w.config.yaxis[index].max = yaxis[index].max;
          }
        };
        w.config.yaxis.map(function (yaxe, index) {
          if (w.globals.zoomed) {
            // user has zoomed, check the last yaxis
            getLastYAxis(index);
          } else {
            // user hasn't zoomed, check the last yaxis first
            if (typeof yaxis[index] !== 'undefined') {
              getLastYAxis(index);
            } else {
              // if last y-axis don't exist, check the original yaxis
              if (typeof _this3.ctx.opts.yaxis[index] !== 'undefined') {
                yaxe.min = _this3.ctx.opts.yaxis[index].min;
                yaxe.max = _this3.ctx.opts.yaxis[index].max;
              }
            }
          }
        });
      }
    }]);
    return UpdateHelpers;
  }();

  (function (root, factory) {
    /* istanbul ignore next */
    if (typeof define === 'function' && define.amd) {
      define(function () {
        return factory(root, root.document);
      });
      /* below check fixes #412 */
    } else if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === 'object' && typeof module !== 'undefined') {
      module.exports = root.document ? factory(root, root.document) : function (w) {
        return factory(w, w.document);
      };
    } else {
      root.SVG = factory(root, root.document);
    }
  })(typeof window !== 'undefined' ? window : undefined, function (window, document) {
    // Find global reference - uses 'this' by default when available,
    // falls back to 'window' otherwise (for bundlers like Webpack)
    var globalRef = typeof this !== 'undefined' ? this : window;

    // The main wrapping element
    var SVG = globalRef.SVG = function (element) {
      if (SVG.supported) {
        element = new SVG.Doc(element);
        if (!SVG.parser.draw) {
          SVG.prepare();
        }
        return element;
      }
    };

    // Default namespaces
    SVG.ns = 'http://www.w3.org/2000/svg';
    SVG.xmlns = 'http://www.w3.org/2000/xmlns/';
    SVG.xlink = 'http://www.w3.org/1999/xlink';
    SVG.svgjs = 'http://svgjs.dev';

    // Svg support test
    SVG.supported = function () {
      return true;
      // !!document.createElementNS &&
      //     !! document.createElementNS(SVG.ns,'svg').createSVGRect
    }();

    // Don't bother to continue if SVG is not supported
    if (!SVG.supported) return false;

    // Element id sequence
    SVG.did = 1000;

    // Get next named element id
    SVG.eid = function (name) {
      return 'Svgjs' + capitalize(name) + SVG.did++;
    };

    // Method for element creation
    SVG.create = function (name) {
      // create element
      var element = document.createElementNS(this.ns, name);

      // apply unique id
      element.setAttribute('id', this.eid(name));
      return element;
    };

    // Method for extending objects
    SVG.extend = function () {
      var modules, methods;

      // Get list of modules
      modules = [].slice.call(arguments);

      // Get object with extensions
      methods = modules.pop();
      for (var i = modules.length - 1; i >= 0; i--) {
        if (modules[i]) {
          for (var key in methods) {
            modules[i].prototype[key] = methods[key];
          }
        }
      }

      // Make sure SVG.Set inherits any newly added methods
      if (SVG.Set && SVG.Set.inherit) {
        SVG.Set.inherit();
      }
    };

    // Invent new element
    SVG.invent = function (config) {
      // Create element initializer
      var initializer = typeof config.create === 'function' ? config.create : function () {
        this.constructor.call(this, SVG.create(config.create));
      };

      // Inherit prototype
      if (config.inherit) {
        initializer.prototype = new config.inherit();
      }

      // Extend with methods
      if (config.extend) {
        SVG.extend(initializer, config.extend);
      }

      // Attach construct method to parent
      if (config.construct) {
        SVG.extend(config.parent || SVG.Container, config.construct);
      }
      return initializer;
    };

    // Adopt existing svg elements
    SVG.adopt = function (node) {
      // check for presence of node
      if (!node) return null;

      // make sure a node isn't already adopted
      if (node.instance) return node.instance;

      // initialize variables
      var element;

      // adopt with element-specific settings
      if (node.nodeName == 'svg') {
        element = node.parentNode instanceof window.SVGElement ? new SVG.Nested() : new SVG.Doc();
      } else if (node.nodeName == 'linearGradient') {
        element = new SVG.Gradient('linear');
      } else if (node.nodeName == 'radialGradient') {
        element = new SVG.Gradient('radial');
      } else if (SVG[capitalize(node.nodeName)]) {
        element = new SVG[capitalize(node.nodeName)]();
      } else {
        element = new SVG.Element(node);
      }

      // ensure references
      element.type = node.nodeName;
      element.node = node;
      node.instance = element;

      // SVG.Class specific preparations
      if (element instanceof SVG.Doc) {
        element.namespace().defs();
      }

      // pull svgjs data from the dom (getAttributeNS doesn't work in html5)
      element.setData(JSON.parse(node.getAttribute('svgjs:data')) || {});
      return element;
    };

    // Initialize parsing element
    SVG.prepare = function () {
      // Select document body and create invisible svg element
      var body = document.getElementsByTagName('body')[0],
        draw = (body ? new SVG.Doc(body) : SVG.adopt(document.documentElement).nested()).size(2, 0);

      // Create parser object
      SVG.parser = {
        body: body || document.documentElement,
        draw: draw.style('opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden').node,
        poly: draw.polyline().node,
        path: draw.path().node,
        native: SVG.create('svg')
      };
    };
    SVG.parser = {
      native: SVG.create('svg')
    };
    document.addEventListener('DOMContentLoaded', function () {
      if (!SVG.parser.draw) {
        SVG.prepare();
      }
    }, false);

    // Storage for regular expressions
    SVG.regex = {
      // Parse unit value
      numberAndUnit: /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,
      // Parse hex value
      hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,
      // Parse rgb value
      rgb: /rgb\((\d+),(\d+),(\d+)\)/,
      // Parse reference id
      reference: /#([a-z0-9\-_]+)/i,
      // splits a transformation chain
      transforms: /\)\s*,?\s*/,
      // Whitespace
      whitespace: /\s/g,
      // Test hex value
      isHex: /^#[a-f0-9]{3,6}$/i,
      // Test rgb value
      isRgb: /^rgb\(/,
      // Test css declaration
      isCss: /[^:]+:[^;]+;?/,
      // Test for blank string
      isBlank: /^(\s+)?$/,
      // Test for numeric string
      isNumber: /^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,
      // Test for percent value
      isPercent: /^-?[\d\.]+%$/,
      // Test for image url
      isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,
      // split at whitespace and comma
      delimiter: /[\s,]+/,
      // The following regex are used to parse the d attribute of a path

      // Matches all hyphens which are not after an exponent
      hyphen: /([^e])\-/gi,
      // Replaces and tests for all path letters
      pathLetters: /[MLHVCSQTAZ]/gi,
      // yes we need this one, too
      isPathLetter: /[MLHVCSQTAZ]/i,
      // matches 0.154.23.45
      numbersWithDots: /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,
      // matches .
      dots: /\./g
    };
    SVG.utils = {
      // Map function
      map: function map(array, block) {
        var il = array.length,
          result = [];
        for (var i = 0; i < il; i++) {
          result.push(block(array[i]));
        }
        return result;
      },
      // Filter function
      filter: function filter(array, block) {
        var il = array.length,
          result = [];
        for (var i = 0; i < il; i++) {
          if (block(array[i])) {
            result.push(array[i]);
          }
        }
        return result;
      },
      filterSVGElements: function filterSVGElements(nodes) {
        return this.filter(nodes, function (el) {
          return el instanceof window.SVGElement;
        });
      }
    };
    SVG.defaults = {
      // Default attribute values
      attrs: {
        // fill and stroke
        'fill-opacity': 1,
        'stroke-opacity': 1,
        'stroke-width': 0,
        'stroke-linejoin': 'miter',
        'stroke-linecap': 'butt',
        fill: '#000000',
        stroke: '#000000',
        opacity: 1,
        // position
        x: 0,
        y: 0,
        cx: 0,
        cy: 0,
        // size
        width: 0,
        height: 0,
        // radius
        r: 0,
        rx: 0,
        ry: 0,
        // gradient
        offset: 0,
        'stop-opacity': 1,
        'stop-color': '#000000',
        // text
        'font-size': 16,
        'font-family': 'Helvetica, Arial, sans-serif',
        'text-anchor': 'start'
      }
    };
    // Module for color convertions
    SVG.Color = function (color) {
      var match;

      // initialize defaults
      this.r = 0;
      this.g = 0;
      this.b = 0;
      if (!color) return;

      // parse color
      if (typeof color === 'string') {
        if (SVG.regex.isRgb.test(color)) {
          // get rgb values
          match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace, ''));

          // parse numeric values
          this.r = parseInt(match[1]);
          this.g = parseInt(match[2]);
          this.b = parseInt(match[3]);
        } else if (SVG.regex.isHex.test(color)) {
          // get hex values
          match = SVG.regex.hex.exec(fullHex(color));

          // parse numeric values
          this.r = parseInt(match[1], 16);
          this.g = parseInt(match[2], 16);
          this.b = parseInt(match[3], 16);
        }
      } else if (_typeof(color) === 'object') {
        this.r = color.r;
        this.g = color.g;
        this.b = color.b;
      }
    };
    SVG.extend(SVG.Color, {
      // Default to hex conversion
      toString: function toString() {
        return this.toHex();
      },
      // Build hex value
      toHex: function toHex() {
        return '#' + compToHex(this.r) + compToHex(this.g) + compToHex(this.b);
      },
      // Build rgb value
      toRgb: function toRgb() {
        return 'rgb(' + [this.r, this.g, this.b].join() + ')';
      },
      // Calculate true brightness
      brightness: function brightness() {
        return this.r / 255 * 0.30 + this.g / 255 * 0.59 + this.b / 255 * 0.11;
      },
      // Make color morphable
      morph: function morph(color) {
        this.destination = new SVG.Color(color);
        return this;
      },
      // Get morphed color at given position
      at: function at(pos) {
        // make sure a destination is defined
        if (!this.destination) return this;

        // normalise pos
        pos = pos < 0 ? 0 : pos > 1 ? 1 : pos;

        // generate morphed color
        return new SVG.Color({
          r: ~~(this.r + (this.destination.r - this.r) * pos),
          g: ~~(this.g + (this.destination.g - this.g) * pos),
          b: ~~(this.b + (this.destination.b - this.b) * pos)
        });
      }
    });

    // Testers

    // Test if given value is a color string
    SVG.Color.test = function (color) {
      color += '';
      return SVG.regex.isHex.test(color) || SVG.regex.isRgb.test(color);
    };

    // Test if given value is a rgb object
    SVG.Color.isRgb = function (color) {
      return color && typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number';
    };

    // Test if given value is a color
    SVG.Color.isColor = function (color) {
      return SVG.Color.isRgb(color) || SVG.Color.test(color);
    };
    // Module for array conversion
    SVG.Array = function (array, fallback) {
      array = (array || []).valueOf();

      // if array is empty and fallback is provided, use fallback
      if (array.length == 0 && fallback) {
        array = fallback.valueOf();
      }

      // parse array
      this.value = this.parse(array);
    };
    SVG.extend(SVG.Array, {
      // Convert array to string
      toString: function toString() {
        return this.value.join(' ');
      },
      // Real value
      valueOf: function valueOf() {
        return this.value;
      },
      // Parse whitespace separated string
      parse: function parse(array) {
        array = array.valueOf();

        // if already is an array, no need to parse it
        if (Array.isArray(array)) return array;
        return this.split(array);
      }
    });
    // Poly points array
    SVG.PointArray = function (array, fallback) {
      SVG.Array.call(this, array, fallback || [[0, 0]]);
    };

    // Inherit from SVG.Array
    SVG.PointArray.prototype = new SVG.Array();
    SVG.PointArray.prototype.constructor = SVG.PointArray;
    var pathHandlers = {
      M: function M(c, p, p0) {
        p.x = p0.x = c[0];
        p.y = p0.y = c[1];
        return ['M', p.x, p.y];
      },
      L: function L(c, p) {
        p.x = c[0];
        p.y = c[1];
        return ['L', c[0], c[1]];
      },
      H: function H(c, p) {
        p.x = c[0];
        return ['H', c[0]];
      },
      V: function V(c, p) {
        p.y = c[0];
        return ['V', c[0]];
      },
      C: function C(c, p) {
        p.x = c[4];
        p.y = c[5];
        return ['C', c[0], c[1], c[2], c[3], c[4], c[5]];
      },
      Q: function Q(c, p) {
        p.x = c[2];
        p.y = c[3];
        return ['Q', c[0], c[1], c[2], c[3]];
      },
      S: function S(c, p) {
        p.x = c[2];
        p.y = c[3];
        return ['S', c[0], c[1], c[2], c[3]];
      },
      Z: function Z(c, p, p0) {
        p.x = p0.x;
        p.y = p0.y;
        return ['Z'];
      }
    };
    var mlhvqtcsa = 'mlhvqtcsaz'.split('');
    for (var i = 0, il = mlhvqtcsa.length; i < il; ++i) {
      pathHandlers[mlhvqtcsa[i]] = function (i) {
        return function (c, p, p0) {
          if (i == 'H') c[0] = c[0] + p.x;else if (i == 'V') c[0] = c[0] + p.y;else if (i == 'A') {
            c[5] = c[5] + p.x, c[6] = c[6] + p.y;
          } else {
            for (var j = 0, jl = c.length; j < jl; ++j) {
              c[j] = c[j] + (j % 2 ? p.y : p.x);
            }
          }
          if (pathHandlers && typeof pathHandlers[i] === 'function') {
            // this check fixes jest unit tests
            return pathHandlers[i](c, p, p0);
          }
        };
      }(mlhvqtcsa[i].toUpperCase());
    }

    // Path points array
    SVG.PathArray = function (array, fallback) {
      SVG.Array.call(this, array, fallback || [['M', 0, 0]]);
    };

    // Inherit from SVG.Array
    SVG.PathArray.prototype = new SVG.Array();
    SVG.PathArray.prototype.constructor = SVG.PathArray;
    SVG.extend(SVG.PathArray, {
      // Convert array to string
      toString: function toString() {
        return arrayToString(this.value);
      },
      // Move path string
      move: function move(x, y) {
        // get bounding box of current situation
        var box = this.bbox();

        // get relative offset
        x -= box.x;
        y -= box.y;
        return this;
      },
      // Get morphed path array at given position
      at: function at(pos) {
        // make sure a destination is defined
        if (!this.destination) return this;
        var sourceArray = this.value,
          destinationArray = this.destination.value,
          array = [],
          pathArray = new SVG.PathArray(),
          il,
          jl;

        // Animate has specified in the SVG spec
        // See: https://www.w3.org/TR/SVG11/paths.html#PathElement
        for (var i = 0, il = sourceArray.length; i < il; i++) {
          array[i] = [sourceArray[i][0]];
          for (var j = 1, jl = sourceArray[i].length; j < jl; j++) {
            array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos;
          }
          // For the two flags of the elliptical arc command, the SVG spec say:
          // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
          // Elliptical arc command as an array followed by corresponding indexes:
          // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
          //   0    1   2        3                 4             5      6  7
          if (array[i][0] === 'A') {
            array[i][4] = +(array[i][4] != 0);
            array[i][5] = +(array[i][5] != 0);
          }
        }

        // Directly modify the value of a path array, this is done this way for performance
        pathArray.value = array;
        return pathArray;
      },
      // Absolutize and parse path to array
      parse: function parse(array) {
        // if it's already a patharray, no need to parse it
        if (array instanceof SVG.PathArray) return array.valueOf();

        // prepare for parsing
        var s,
          arr,
          paramCnt = {
            'M': 2,
            'L': 2,
            'H': 1,
            'V': 1,
            'C': 6,
            'S': 4,
            'Q': 4,
            'T': 2,
            'A': 7,
            'Z': 0
          };
        if (typeof array === 'string') {
          array = array.replace(SVG.regex.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
          .replace(SVG.regex.pathLetters, ' $& ') // put some room between letters and numbers
          .replace(SVG.regex.hyphen, '$1 -') // add space before hyphen
          .trim() // trim
          .split(SVG.regex.delimiter); // split into array
        } else {
          array = array.reduce(function (prev, curr) {
            return [].concat.call(prev, curr);
          }, []);
        }

        // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
        var arr = [],
          p = new SVG.Point(),
          p0 = new SVG.Point(),
          index = 0,
          len = array.length;
        do {
          // Test if we have a path letter
          if (SVG.regex.isPathLetter.test(array[index])) {
            s = array[index];
            ++index;
            // If last letter was a move command and we got no new, it defaults to [L]ine
          } else if (s == 'M') {
            s = 'L';
          } else if (s == 'm') {
            s = 'l';
          }
          arr.push(pathHandlers[s].call(null, array.slice(index, index = index + paramCnt[s.toUpperCase()]).map(parseFloat), p, p0));
        } while (len > index);
        return arr;
      },
      // Get bounding box of path
      bbox: function bbox() {
        if (!SVG.parser.draw) {
          SVG.prepare();
        }
        SVG.parser.path.setAttribute('d', this.toString());
        return SVG.parser.path.getBBox();
      }
    });

    // Module for unit convertions
    SVG.Number = SVG.invent({
      // Initialize
      create: function create(value, unit) {
        // initialize defaults
        this.value = 0;
        this.unit = unit || '';

        // parse value
        if (typeof value === 'number') {
          // ensure a valid numeric value
          this.value = isNaN(value) ? 0 : !isFinite(value) ? value < 0 ? -3.4e+38 : +3.4e+38 : value;
        } else if (typeof value === 'string') {
          unit = value.match(SVG.regex.numberAndUnit);
          if (unit) {
            // make value numeric
            this.value = parseFloat(unit[1]);

            // normalize
            if (unit[5] == '%') {
              this.value /= 100;
            } else if (unit[5] == 's') {
              this.value *= 1000;
            }

            // store unit
            this.unit = unit[5];
          }
        } else {
          if (value instanceof SVG.Number) {
            this.value = value.valueOf();
            this.unit = value.unit;
          }
        }
      },
      // Add methods
      extend: {
        // Stringalize
        toString: function toString() {
          return (this.unit == '%' ? ~~(this.value * 1e8) / 1e6 : this.unit == 's' ? this.value / 1e3 : this.value) + this.unit;
        },
        toJSON: function toJSON() {
          return this.toString();
        },
        // Convert to primitive
        valueOf: function valueOf() {
          return this.value;
        },
        // Add number
        plus: function plus(number) {
          number = new SVG.Number(number);
          return new SVG.Number(this + number, this.unit || number.unit);
        },
        // Subtract number
        minus: function minus(number) {
          number = new SVG.Number(number);
          return new SVG.Number(this - number, this.unit || number.unit);
        },
        // Multiply number
        times: function times(number) {
          number = new SVG.Number(number);
          return new SVG.Number(this * number, this.unit || number.unit);
        },
        // Divide number
        divide: function divide(number) {
          number = new SVG.Number(number);
          return new SVG.Number(this / number, this.unit || number.unit);
        },
        // Convert to different unit
        to: function to(unit) {
          var number = new SVG.Number(this);
          if (typeof unit === 'string') {
            number.unit = unit;
          }
          return number;
        },
        // Make number morphable
        morph: function morph(number) {
          this.destination = new SVG.Number(number);
          if (number.relative) {
            this.destination.value += this.value;
          }
          return this;
        },
        // Get morphed number at given position
        at: function at(pos) {
          // Make sure a destination is defined
          if (!this.destination) return this;

          // Generate new morphed number
          return new SVG.Number(this.destination).minus(this).times(pos).plus(this);
        }
      }
    });
    SVG.Element = SVG.invent({
      // Initialize node
      create: function create(node) {
        // make stroke value accessible dynamically
        this._stroke = SVG.defaults.attrs.stroke;
        this._event = null;

        // initialize data object
        this.dom = {};

        // create circular reference
        if (this.node = node) {
          this.type = node.nodeName;
          this.node.instance = this;

          // store current attribute value
          this._stroke = node.getAttribute('stroke') || this._stroke;
        }
      },
      // Add class methods
      extend: {
        // Move over x-axis
        x: function x(_x) {
          return this.attr('x', _x);
        },
        // Move over y-axis
        y: function y(_y) {
          return this.attr('y', _y);
        },
        // Move by center over x-axis
        cx: function cx(x) {
          return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2);
        },
        // Move by center over y-axis
        cy: function cy(y) {
          return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2);
        },
        // Move element to given x and y values
        move: function move(x, y) {
          return this.x(x).y(y);
        },
        // Move element by its center
        center: function center(x, y) {
          return this.cx(x).cy(y);
        },
        // Set width of element
        width: function width(_width) {
          return this.attr('width', _width);
        },
        // Set height of element
        height: function height(_height) {
          return this.attr('height', _height);
        },
        // Set element size to given width and height
        size: function size(width, height) {
          var p = proportionalSize(this, width, height);
          return this.width(new SVG.Number(p.width)).height(new SVG.Number(p.height));
        },
        // Clone element
        clone: function clone(parent) {
          // write dom data to the dom so the clone can pickup the data
          this.writeDataToDom();

          // clone element and assign new id
          var clone = assignNewId(this.node.cloneNode(true));

          // insert the clone in the given parent or after myself
          if (parent) parent.add(clone);else this.after(clone);
          return clone;
        },
        // Remove element
        remove: function remove() {
          if (this.parent()) {
            this.parent().removeElement(this);
          }
          return this;
        },
        // Replace element
        replace: function replace(element) {
          this.after(element).remove();
          return element;
        },
        // Add element to given container and return self
        addTo: function addTo(parent) {
          return parent.put(this);
        },
        // Add element to given container and return container
        putIn: function putIn(parent) {
          return parent.add(this);
        },
        // Get / set id
        id: function id(_id) {
          return this.attr('id', _id);
        },
        // Show element
        show: function show() {
          return this.style('display', '');
        },
        // Hide element
        hide: function hide() {
          return this.style('display', 'none');
        },
        // Is element visible?
        visible: function visible() {
          return this.style('display') != 'none';
        },
        // Return id on string conversion
        toString: function toString() {
          return this.attr('id');
        },
        // Return array of classes on the node
        classes: function classes() {
          var attr = this.attr('class');
          return attr == null ? [] : attr.trim().split(SVG.regex.delimiter);
        },
        // Return true if class exists on the node, false otherwise
        hasClass: function hasClass(name) {
          return this.classes().indexOf(name) != -1;
        },
        // Add class to the node
        addClass: function addClass(name) {
          if (!this.hasClass(name)) {
            var array = this.classes();
            array.push(name);
            this.attr('class', array.join(' '));
          }
          return this;
        },
        // Remove class from the node
        removeClass: function removeClass(name) {
          if (this.hasClass(name)) {
            this.attr('class', this.classes().filter(function (c) {
              return c != name;
            }).join(' '));
          }
          return this;
        },
        // Toggle the presence of a class on the node
        toggleClass: function toggleClass(name) {
          return this.hasClass(name) ? this.removeClass(name) : this.addClass(name);
        },
        // Get referenced element form attribute value
        reference: function reference(attr) {
          return SVG.get(this.attr(attr));
        },
        // Returns the parent element instance
        parent: function parent(type) {
          var parent = this;

          // check for parent
          if (!parent.node.parentNode) return null;

          // get parent element
          parent = SVG.adopt(parent.node.parentNode);
          if (!type) return parent;

          // loop trough ancestors if type is given
          while (parent && parent.node instanceof window.SVGElement) {
            if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent;
            if (!parent.node.parentNode || parent.node.parentNode.nodeName == '#document') return null; // #759, #720
            parent = SVG.adopt(parent.node.parentNode);
          }
        },
        // Get parent document
        doc: function doc() {
          return this instanceof SVG.Doc ? this : this.parent(SVG.Doc);
        },
        // return array of all ancestors of given type up to the root svg
        parents: function parents(type) {
          var parents = [],
            parent = this;
          do {
            parent = parent.parent(type);
            if (!parent || !parent.node) break;
            parents.push(parent);
          } while (parent.parent);
          return parents;
        },
        // matches the element vs a css selector
        matches: function matches(selector) {
          return _matches(this.node, selector);
        },
        // Returns the svg node to call native svg methods on it
        native: function native() {
          return this.node;
        },
        // Import raw svg
        svg: function svg(_svg) {
          // create temporary holder
          var well = document.createElementNS('http://www.w3.org/2000/svg', 'svg');

          // act as a setter if svg is given
          if (_svg && this instanceof SVG.Parent) {
            // dump raw svg
            well.innerHTML = '<svg>' + _svg.replace(/\n/, '').replace(/<([\w:-]+)([^<]+?)\/>/g, '<$1$2></$1>') + '</svg>';

            // transplant nodes
            for (var i = 0, il = well.firstChild.childNodes.length; i < il; i++) {
              this.node.appendChild(well.firstChild.firstChild);
            }

            // otherwise act as a getter
          } else {
            // create a wrapping svg element in case of partial content
            well.appendChild(_svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'));

            // write svgjs data to the dom
            this.writeDataToDom();

            // insert a copy of this node
            _svg.appendChild(this.node.cloneNode(true));

            // return target element
            return well.innerHTML.replace(/^<svg>/, '').replace(/<\/svg>$/, '');
          }
          return this;
        },
        // write svgjs data to the dom
        writeDataToDom: function writeDataToDom() {
          // dump variables recursively
          if (this.each || this.lines) {
            var fn = this.each ? this : this.lines();
            fn.each(function () {
              this.writeDataToDom();
            });
          }

          // remove previously set data
          this.node.removeAttribute('svgjs:data');
          if (Object.keys(this.dom).length) {
            this.node.setAttribute('svgjs:data', JSON.stringify(this.dom));
          } // see #428

          return this;
        },
        // set given data to the elements data property
        setData: function setData(o) {
          this.dom = o;
          return this;
        },
        is: function is(obj) {
          return _is(this, obj);
        }
      }
    });
    SVG.easing = {
      '-': function _(pos) {
        return pos;
      },
      '<>': function _(pos) {
        return -Math.cos(pos * Math.PI) / 2 + 0.5;
      },
      '>': function _(pos) {
        return Math.sin(pos * Math.PI / 2);
      },
      '<': function _(pos) {
        return -Math.cos(pos * Math.PI / 2) + 1;
      }
    };
    SVG.morph = function (pos) {
      return function (from, to) {
        return new SVG.MorphObj(from, to).at(pos);
      };
    };
    SVG.Situation = SVG.invent({
      create: function create(o) {
        this.init = false;
        this.reversed = false;
        this.reversing = false;
        this.duration = new SVG.Number(o.duration).valueOf();
        this.delay = new SVG.Number(o.delay).valueOf();
        this.start = +new Date() + this.delay;
        this.finish = this.start + this.duration;
        this.ease = o.ease;

        // this.loop is incremented from 0 to this.loops
        // it is also incremented when in an infinite loop (when this.loops is true)
        this.loop = 0;
        this.loops = false;
        this.animations = {
          // functionToCall: [list of morphable objects]
          // e.g. move: [SVG.Number, SVG.Number]
        };
        this.attrs = {
          // holds all attributes which are not represented from a function svg.js provides
          // e.g. someAttr: SVG.Number
        };
        this.styles = {
          // holds all styles which should be animated
          // e.g. fill-color: SVG.Color
        };
        this.transforms = [
          // holds all transformations as transformation objects
          // e.g. [SVG.Rotate, SVG.Translate, SVG.Matrix]
        ];
        this.once = {
          // functions to fire at a specific position
          // e.g. "0.5": function foo(){}
        };
      }
    });
    SVG.FX = SVG.invent({
      create: function create(element) {
        this._target = element;
        this.situations = [];
        this.active = false;
        this.situation = null;
        this.paused = false;
        this.lastPos = 0;
        this.pos = 0;
        // The absolute position of an animation is its position in the context of its complete duration (including delay and loops)
        // When performing a delay, absPos is below 0 and when performing a loop, its value is above 1
        this.absPos = 0;
        this._speed = 1;
      },
      extend: {
        /**
         * sets or returns the target of this animation
         * @param o object || number In case of Object it holds all parameters. In case of number its the duration of the animation
         * @param ease function || string Function which should be used for easing or easing keyword
         * @param delay Number indicating the delay before the animation starts
         * @return target || this
         */
        animate: function animate(o, ease, delay) {
          if (_typeof(o) === 'object') {
            ease = o.ease;
            delay = o.delay;
            o = o.duration;
          }
          var situation = new SVG.Situation({
            duration: o || 1000,
            delay: delay || 0,
            ease: SVG.easing[ease || '-'] || ease
          });
          this.queue(situation);
          return this;
        },
        /**
        * sets a delay before the next element of the queue is called
        * @param delay Duration of delay in milliseconds
        * @return this.target()
        */

        /**
        * sets or returns the target of this animation
        * @param null || target SVG.Element which should be set as new target
        * @return target || this
        */
        target: function target(_target) {
          if (_target && _target instanceof SVG.Element) {
            this._target = _target;
            return this;
          }
          return this._target;
        },
        // returns the absolute position at a given time
        timeToAbsPos: function timeToAbsPos(timestamp) {
          return (timestamp - this.situation.start) / (this.situation.duration / this._speed);
        },
        // returns the timestamp from a given absolute positon
        absPosToTime: function absPosToTime(absPos) {
          return this.situation.duration / this._speed * absPos + this.situation.start;
        },
        // starts the animationloop
        startAnimFrame: function startAnimFrame() {
          this.stopAnimFrame();
          this.animationFrame = window.requestAnimationFrame(function () {
            this.step();
          }.bind(this));
        },
        // cancels the animationframe
        stopAnimFrame: function stopAnimFrame() {
          window.cancelAnimationFrame(this.animationFrame);
        },
        // kicks off the animation - only does something when the queue is currently not active and at least one situation is set
        start: function start() {
          // dont start if already started
          if (!this.active && this.situation) {
            this.active = true;
            this.startCurrent();
          }
          return this;
        },
        // start the current situation
        startCurrent: function startCurrent() {
          this.situation.start = +new Date() + this.situation.delay / this._speed;
          this.situation.finish = this.situation.start + this.situation.duration / this._speed;
          return this.initAnimations().step();
        },
        /**
        * adds a function / Situation to the animation queue
        * @param fn function / situation to add
        * @return this
        */
        queue: function queue(fn) {
          if (typeof fn === 'function' || fn instanceof SVG.Situation) {
            this.situations.push(fn);
          }
          if (!this.situation) this.situation = this.situations.shift();
          return this;
        },
        /**
        * pulls next element from the queue and execute it
        * @return this
        */
        dequeue: function dequeue() {
          // stop current animation
          this.stop();

          // get next animation from queue
          this.situation = this.situations.shift();
          if (this.situation) {
            if (this.situation instanceof SVG.Situation) {
              this.start();
            } else {
              // If it is not a SVG.Situation, then it is a function, we execute it
              this.situation.call(this);
            }
          }
          return this;
        },
        // updates all animations to the current state of the element
        // this is important when one property could be changed from another property
        initAnimations: function initAnimations() {
          var source;
          var s = this.situation;
          if (s.init) return this;
          for (var i in s.animations) {
            source = this.target()[i]();
            if (!Array.isArray(source)) {
              source = [source];
            }
            if (!Array.isArray(s.animations[i])) {
              s.animations[i] = [s.animations[i]];
            }

            // if(s.animations[i].length > source.length) {
            //  source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length))
            // }

            for (var j = source.length; j--;) {
              // The condition is because some methods return a normal number instead
              // of a SVG.Number
              if (s.animations[i][j] instanceof SVG.Number) {
                source[j] = new SVG.Number(source[j]);
              }
              s.animations[i][j] = source[j].morph(s.animations[i][j]);
            }
          }
          for (var i in s.attrs) {
            s.attrs[i] = new SVG.MorphObj(this.target().attr(i), s.attrs[i]);
          }
          for (var i in s.styles) {
            s.styles[i] = new SVG.MorphObj(this.target().style(i), s.styles[i]);
          }
          s.initialTransformation = this.target().matrixify();
          s.init = true;
          return this;
        },
        clearQueue: function clearQueue() {
          this.situations = [];
          return this;
        },
        clearCurrent: function clearCurrent() {
          this.situation = null;
          return this;
        },
        /** stops the animation immediately
        * @param jumpToEnd A Boolean indicating whether to complete the current animation immediately.
        * @param clearQueue A Boolean indicating whether to remove queued animation as well.
        * @return this
        */
        stop: function stop(jumpToEnd, clearQueue) {
          var active = this.active;
          this.active = false;
          if (clearQueue) {
            this.clearQueue();
          }
          if (jumpToEnd && this.situation) {
            // initialize the situation if it was not
            !active && this.startCurrent();
            this.atEnd();
          }
          this.stopAnimFrame();
          return this.clearCurrent();
        },
        after: function after(fn) {
          var c = this.last(),
            wrapper = function wrapper(e) {
              if (e.detail.situation == c) {
                fn.call(this, c);
                this.off('finished.fx', wrapper); // prevent memory leak
              }
            };
          this.target().on('finished.fx', wrapper);
          return this._callStart();
        },
        // adds a callback which is called whenever one animation step is performed
        during: function during(fn) {
          var c = this.last(),
            wrapper = function wrapper(e) {
              if (e.detail.situation == c) {
                fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, c);
              }
            };

          // see above
          this.target().off('during.fx', wrapper).on('during.fx', wrapper);
          this.after(function () {
            this.off('during.fx', wrapper);
          });
          return this._callStart();
        },
        // calls after ALL animations in the queue are finished
        afterAll: function afterAll(fn) {
          var wrapper = function wrapper(e) {
            fn.call(this);
            this.off('allfinished.fx', wrapper);
          };

          // see above
          this.target().off('allfinished.fx', wrapper).on('allfinished.fx', wrapper);
          return this._callStart();
        },
        last: function last() {
          return this.situations.length ? this.situations[this.situations.length - 1] : this.situation;
        },
        // adds one property to the animations
        add: function add(method, args, type) {
          this.last()[type || 'animations'][method] = args;
          return this._callStart();
        },
        /** perform one step of the animation
        *  @param ignoreTime Boolean indicating whether to ignore time and use position directly or recalculate position based on time
        *  @return this
        */
        step: function step(ignoreTime) {
          // convert current time to an absolute position
          if (!ignoreTime) this.absPos = this.timeToAbsPos(+new Date());

          // This part convert an absolute position to a position
          if (this.situation.loops !== false) {
            var absPos, absPosInt, lastLoop;

            // If the absolute position is below 0, we just treat it as if it was 0
            absPos = Math.max(this.absPos, 0);
            absPosInt = Math.floor(absPos);
            if (this.situation.loops === true || absPosInt < this.situation.loops) {
              this.pos = absPos - absPosInt;
              lastLoop = this.situation.loop;
              this.situation.loop = absPosInt;
            } else {
              this.absPos = this.situation.loops;
              this.pos = 1;
              // The -1 here is because we don't want to toggle reversed when all the loops have been completed
              lastLoop = this.situation.loop - 1;
              this.situation.loop = this.situation.loops;
            }
            if (this.situation.reversing) {
              // Toggle reversed if an odd number of loops as occured since the last call of step
              this.situation.reversed = this.situation.reversed != Boolean((this.situation.loop - lastLoop) % 2);
            }
          } else {
            // If there are no loop, the absolute position must not be above 1
            this.absPos = Math.min(this.absPos, 1);
            this.pos = this.absPos;
          }

          // while the absolute position can be below 0, the position must not be below 0
          if (this.pos < 0) this.pos = 0;
          if (this.situation.reversed) this.pos = 1 - this.pos;

          // apply easing
          var eased = this.situation.ease(this.pos);

          // call once-callbacks
          for (var i in this.situation.once) {
            if (i > this.lastPos && i <= eased) {
              this.situation.once[i].call(this.target(), this.pos, eased);
              delete this.situation.once[i];
            }
          }

          // fire during callback with position, eased position and current situation as parameter
          if (this.active) this.target().fire('during', {
            pos: this.pos,
            eased: eased,
            fx: this,
            situation: this.situation
          });

          // the user may call stop or finish in the during callback
          // so make sure that we still have a valid situation
          if (!this.situation) {
            return this;
          }

          // apply the actual animation to every property
          this.eachAt();

          // do final code when situation is finished
          if (this.pos == 1 && !this.situation.reversed || this.situation.reversed && this.pos == 0) {
            // stop animation callback
            this.stopAnimFrame();

            // fire finished callback with current situation as parameter
            this.target().fire('finished', {
              fx: this,
              situation: this.situation
            });
            if (!this.situations.length) {
              this.target().fire('allfinished');

              // Recheck the length since the user may call animate in the afterAll callback
              if (!this.situations.length) {
                this.target().off('.fx'); // there shouldnt be any binding left, but to make sure...
                this.active = false;
              }
            }

            // start next animation
            if (this.active) this.dequeue();else this.clearCurrent();
          } else if (!this.paused && this.active) {
            // we continue animating when we are not at the end
            this.startAnimFrame();
          }

          // save last eased position for once callback triggering
          this.lastPos = eased;
          return this;
        },
        // calculates the step for every property and calls block with it
        eachAt: function eachAt() {
          var len,
            at,
            self = this,
            target = this.target(),
            s = this.situation;

          // apply animations which can be called trough a method
          for (var i in s.animations) {
            at = [].concat(s.animations[i]).map(function (el) {
              return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el;
            });
            target[i].apply(target, at);
          }

          // apply animation which has to be applied with attr()
          for (var i in s.attrs) {
            at = [i].concat(s.attrs[i]).map(function (el) {
              return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el;
            });
            target.attr.apply(target, at);
          }

          // apply animation which has to be applied with style()
          for (var i in s.styles) {
            at = [i].concat(s.styles[i]).map(function (el) {
              return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el;
            });
            target.style.apply(target, at);
          }

          // animate initialTransformation which has to be chained
          if (s.transforms.length) {
            // get initial initialTransformation
            at = s.initialTransformation;
            for (var i = 0, len = s.transforms.length; i < len; i++) {
              // get next transformation in chain
              var a = s.transforms[i];

              // multiply matrix directly
              if (a instanceof SVG.Matrix) {
                if (a.relative) {
                  at = at.multiply(new SVG.Matrix().morph(a).at(s.ease(this.pos)));
                } else {
                  at = at.morph(a).at(s.ease(this.pos));
                }
                continue;
              }

              // when transformation is absolute we have to reset the needed transformation first
              if (!a.relative) {
                a.undo(at.extract());
              }

              // and reapply it after
              at = at.multiply(a.at(s.ease(this.pos)));
            }

            // set new matrix on element
            target.matrix(at);
          }
          return this;
        },
        // adds an once-callback which is called at a specific position and never again
        once: function once(pos, fn, isEased) {
          var c = this.last();
          if (!isEased) pos = c.ease(pos);
          c.once[pos] = fn;
          return this;
        },
        _callStart: function _callStart() {
          setTimeout(function () {
            this.start();
          }.bind(this), 0);
          return this;
        }
      },
      parent: SVG.Element,
      // Add method to parent elements
      construct: {
        // Get fx module or create a new one, then animate with given duration and ease
        animate: function animate(o, ease, delay) {
          return (this.fx || (this.fx = new SVG.FX(this))).animate(o, ease, delay);
        },
        delay: function delay(_delay) {
          return (this.fx || (this.fx = new SVG.FX(this))).delay(_delay);
        },
        stop: function stop(jumpToEnd, clearQueue) {
          if (this.fx) {
            this.fx.stop(jumpToEnd, clearQueue);
          }
          return this;
        },
        finish: function finish() {
          if (this.fx) {
            this.fx.finish();
          }
          return this;
        }
      }
    });

    // MorphObj is used whenever no morphable object is given
    SVG.MorphObj = SVG.invent({
      create: function create(from, to) {
        // prepare color for morphing
        if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to);
        // check if we have a list of values
        if (SVG.regex.delimiter.test(from)) {
          // prepare path for morphing
          if (SVG.regex.pathLetters.test(from)) return new SVG.PathArray(from).morph(to);
          // prepare value list for morphing
          else return new SVG.Array(from).morph(to);
        }
        // prepare number for morphing
        if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to);

        // prepare for plain morphing
        this.value = from;
        this.destination = to;
      },
      extend: {
        at: function at(pos, real) {
          return real < 1 ? this.value : this.destination;
        },
        valueOf: function valueOf() {
          return this.value;
        }
      }
    });
    SVG.extend(SVG.FX, {
      // Add animatable attributes
      attr: function attr(a, v, relative) {
        // apply attributes individually
        if (_typeof(a) === 'object') {
          for (var key in a) {
            this.attr(key, a[key]);
          }
        } else {
          this.add(a, v, 'attrs');
        }
        return this;
      },
      // Add animatable plot
      plot: function plot(a, b, c, d) {
        // Lines can be plotted with 4 arguments
        if (arguments.length == 4) {
          return this.plot([a, b, c, d]);
        }
        return this.add('plot', new (this.target().morphArray)(a));
      }
    });
    SVG.Box = SVG.invent({
      create: function create(x, y, width, height) {
        if (_typeof(x) === 'object' && !(x instanceof SVG.Element)) {
          // chromes getBoundingClientRect has no x and y property
          return SVG.Box.call(this, x.left != null ? x.left : x.x, x.top != null ? x.top : x.y, x.width, x.height);
        } else if (arguments.length == 4) {
          this.x = x;
          this.y = y;
          this.width = width;
          this.height = height;
        }

        // add center, right, bottom...
        fullBox(this);
      }
    });
    SVG.BBox = SVG.invent({
      // Initialize
      create: function create(element) {
        SVG.Box.apply(this, [].slice.call(arguments));

        // get values if element is given
        if (element instanceof SVG.Element) {
          var box;

          // yes this is ugly, but Firefox can be a pain when it comes to elements that are not yet rendered
          try {
            if (!document.documentElement.contains) {
              // This is IE - it does not support contains() for top-level SVGs
              var topParent = element.node;
              while (topParent.parentNode) {
                topParent = topParent.parentNode;
              }
              if (topParent != document) throw new Error('Element not in the dom');
            } else {
              // the element is NOT in the dom, throw error
              // disabling the check below which fixes issue #76
              // if (!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom')
            }

            // find native bbox
            box = element.node.getBBox();
          } catch (e) {
            if (element instanceof SVG.Shape) {
              if (!SVG.parser.draw) {
                // fixes apexcharts/vue-apexcharts #14
                SVG.prepare();
              }
              var clone = element.clone(SVG.parser.draw.instance).show();
              if (clone && clone.node && typeof clone.node.getBBox === 'function') {
                // this check fixes jest unit tests
                box = clone.node.getBBox();
              }
              if (clone && typeof clone.remove === 'function') {
                clone.remove();
              }
            } else {
              box = {
                x: element.node.clientLeft,
                y: element.node.clientTop,
                width: element.node.clientWidth,
                height: element.node.clientHeight
              };
            }
          }
          SVG.Box.call(this, box);
        }
      },
      // Define ancestor
      inherit: SVG.Box,
      // Define Parent
      parent: SVG.Element,
      // Constructor
      construct: {
        // Get bounding box
        bbox: function bbox() {
          return new SVG.BBox(this);
        }
      }
    });
    SVG.BBox.prototype.constructor = SVG.BBox;
    SVG.Matrix = SVG.invent({
      // Initialize
      create: function create(source) {
        var base = arrayToMatrix([1, 0, 0, 1, 0, 0]);

        // ensure source as object
        source = source === null ? base : source instanceof SVG.Element ? source.matrixify() : typeof source === 'string' ? arrayToMatrix(source.split(SVG.regex.delimiter).map(parseFloat)) : arguments.length == 6 ? arrayToMatrix([].slice.call(arguments)) : Array.isArray(source) ? arrayToMatrix(source) : source && _typeof(source) === 'object' ? source : base;

        // merge source
        for (var i = abcdef.length - 1; i >= 0; --i) {
          this[abcdef[i]] = source[abcdef[i]] != null ? source[abcdef[i]] : base[abcdef[i]];
        }
      },
      // Add methods
      extend: {
        // Extract individual transformations
        extract: function extract() {
          // find delta transform points
          var px = deltaTransformPoint(this, 0, 1);
            deltaTransformPoint(this, 1, 0);
            var skewX = 180 / Math.PI * Math.atan2(px.y, px.x) - 90;
          return {
            // translation
            x: this.e,
            y: this.f,
            transformedX: (this.e * Math.cos(skewX * Math.PI / 180) + this.f * Math.sin(skewX * Math.PI / 180)) / Math.sqrt(this.a * this.a + this.b * this.b),
            transformedY: (this.f * Math.cos(skewX * Math.PI / 180) + this.e * Math.sin(-skewX * Math.PI / 180)) / Math.sqrt(this.c * this.c + this.d * this.d),
            // rotation
            rotation: skewX,
            a: this.a,
            b: this.b,
            c: this.c,
            d: this.d,
            e: this.e,
            f: this.f,
            matrix: new SVG.Matrix(this)
          };
        },
        // Clone matrix
        clone: function clone() {
          return new SVG.Matrix(this);
        },
        // Morph one matrix into another
        morph: function morph(matrix) {
          // store new destination
          this.destination = new SVG.Matrix(matrix);
          return this;
        },
        // Multiplies by given matrix
        multiply: function multiply(matrix) {
          return new SVG.Matrix(this.native().multiply(parseMatrix(matrix).native()));
        },
        // Inverses matrix
        inverse: function inverse() {
          return new SVG.Matrix(this.native().inverse());
        },
        // Translate matrix
        translate: function translate(x, y) {
          return new SVG.Matrix(this.native().translate(x || 0, y || 0));
        },
        // Convert to native SVGMatrix
        native: function native() {
          // create new matrix
          var matrix = SVG.parser.native.createSVGMatrix();

          // update with current values
          for (var i = abcdef.length - 1; i >= 0; i--) {
            matrix[abcdef[i]] = this[abcdef[i]];
          }
          return matrix;
        },
        // Convert matrix to string
        toString: function toString() {
          // Construct the matrix directly, avoid values that are too small
          return 'matrix(' + float32String(this.a) + ',' + float32String(this.b) + ',' + float32String(this.c) + ',' + float32String(this.d) + ',' + float32String(this.e) + ',' + float32String(this.f) + ')';
        }
      },
      // Define parent
      parent: SVG.Element,
      // Add parent method
      construct: {
        // Get current matrix
        ctm: function ctm() {
          return new SVG.Matrix(this.node.getCTM());
        },
        // Get current screen matrix
        screenCTM: function screenCTM() {
          /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537
             This is needed because FF does not return the transformation matrix
             for the inner coordinate system when getScreenCTM() is called on nested svgs.
             However all other Browsers do that */
          if (this instanceof SVG.Nested) {
            var rect = this.rect(1, 1);
            var m = rect.node.getScreenCTM();
            rect.remove();
            return new SVG.Matrix(m);
          }
          return new SVG.Matrix(this.node.getScreenCTM());
        }
      }
    });
    SVG.Point = SVG.invent({
      // Initialize
      create: function create(x, y) {
        var source,
          base = {
            x: 0,
            y: 0
          };

        // ensure source as object
        source = Array.isArray(x) ? {
          x: x[0],
          y: x[1]
        } : _typeof(x) === 'object' ? {
          x: x.x,
          y: x.y
        } : x != null ? {
          x: x,
          y: y != null ? y : x
        } : base; // If y has no value, then x is used has its value

        // merge source
        this.x = source.x;
        this.y = source.y;
      },
      // Add methods
      extend: {
        // Clone point
        clone: function clone() {
          return new SVG.Point(this);
        },
        // Morph one point into another
        morph: function morph(x, y) {
          // store new destination
          this.destination = new SVG.Point(x, y);
          return this;
        }
      }
    });
    SVG.extend(SVG.Element, {
      // Get point
      point: function point(x, y) {
        return new SVG.Point(x, y).transform(this.screenCTM().inverse());
      }
    });
    SVG.extend(SVG.Element, {
      // Set svg element attribute
      attr: function attr(a, v, n) {
        // act as full getter
        if (a == null) {
          // get an object of attributes
          a = {};
          v = this.node.attributes;
          for (var n = v.length - 1; n >= 0; n--) {
            a[v[n].nodeName] = SVG.regex.isNumber.test(v[n].nodeValue) ? parseFloat(v[n].nodeValue) : v[n].nodeValue;
          }
          return a;
        } else if (_typeof(a) === 'object') {
          // apply every attribute individually if an object is passed
          for (var v_ in a) {
            this.attr(v_, a[v_]);
          }
        } else if (v === null) {
          // remove value
          this.node.removeAttribute(a);
        } else if (v == null) {
          // act as a getter if the first and only argument is not an object
          v = this.node.getAttribute(a);
          return v == null ? SVG.defaults.attrs[a] : SVG.regex.isNumber.test(v) ? parseFloat(v) : v;
        } else {
          // BUG FIX: some browsers will render a stroke if a color is given even though stroke width is 0
          if (a == 'stroke-width') {
            this.attr('stroke', parseFloat(v) > 0 ? this._stroke : null);
          } else if (a == 'stroke') {
            this._stroke = v;
          }

          // convert image fill and stroke to patterns
          if (a == 'fill' || a == 'stroke') {
            if (SVG.regex.isImage.test(v)) {
              v = this.doc().defs().image(v, 0, 0);
            }
            if (v instanceof SVG.Image) {
              v = this.doc().defs().pattern(0, 0, function () {
                this.add(v);
              });
            }
          }

          // ensure correct numeric values (also accepts NaN and Infinity)
          if (typeof v === 'number') {
            v = new SVG.Number(v);
          }

          // ensure full hex color
          else if (SVG.Color.isColor(v)) {
            v = new SVG.Color(v);
          }

          // parse array values
          else if (Array.isArray(v)) {
            v = new SVG.Array(v);
          }

          // if the passed attribute is leading...
          if (a == 'leading') {
            // ... call the leading method instead
            if (this.leading) {
              this.leading(v);
            }
          } else {
            // set given attribute on node
            typeof n === 'string' ? this.node.setAttributeNS(n, a, v.toString()) : this.node.setAttribute(a, v.toString());
          }

          // rebuild if required
          if (this.rebuild && (a == 'font-size' || a == 'x')) {
            this.rebuild(a, v);
          }
        }
        return this;
      }
    });
    SVG.extend(SVG.Element, {
      // Add transformations
      transform: function transform(o, relative) {
        // get target in case of the fx module, otherwise reference this
        var target = this,
          matrix;

        // act as a getter
        if (_typeof(o) !== 'object') {
          // get current matrix
          matrix = new SVG.Matrix(target).extract();
          return typeof o === 'string' ? matrix[o] : matrix;
        }

        // get current matrix
        matrix = new SVG.Matrix(target);

        // ensure relative flag
        relative = !!relative || !!o.relative;

        // act on matrix
        if (o.a != null) {
          matrix = relative
          // relative
          ? matrix.multiply(new SVG.Matrix(o))
          // absolute
          : new SVG.Matrix(o);
        }
        return this.attr('transform', matrix);
      }
    });
    SVG.extend(SVG.Element, {
      // Reset all transformations
      untransform: function untransform() {
        return this.attr('transform', null);
      },
      // merge the whole transformation chain into one matrix and returns it
      matrixify: function matrixify() {
        var matrix = (this.attr('transform') || ''
        // split transformations
        ).split(SVG.regex.transforms).slice(0, -1).map(function (str) {
          // generate key => value pairs
          var kv = str.trim().split('(');
          return [kv[0], kv[1].split(SVG.regex.delimiter).map(function (str) {
            return parseFloat(str);
          })];
        })
        // merge every transformation into one matrix
        .reduce(function (matrix, transform) {
          if (transform[0] == 'matrix') return matrix.multiply(arrayToMatrix(transform[1]));
          return matrix[transform[0]].apply(matrix, transform[1]);
        }, new SVG.Matrix());
        return matrix;
      },
      // add an element to another parent without changing the visual representation on the screen
      toParent: function toParent(parent) {
        if (this == parent) return this;
        var ctm = this.screenCTM();
        var pCtm = parent.screenCTM().inverse();
        this.addTo(parent).untransform().transform(pCtm.multiply(ctm));
        return this;
      },
      // same as above with parent equals root-svg
      toDoc: function toDoc() {
        return this.toParent(this.doc());
      }
    });
    SVG.Transformation = SVG.invent({
      create: function create(source, inversed) {
        if (arguments.length > 1 && typeof inversed !== 'boolean') {
          return this.constructor.call(this, [].slice.call(arguments));
        }
        if (Array.isArray(source)) {
          for (var i = 0, len = this.arguments.length; i < len; ++i) {
            this[this.arguments[i]] = source[i];
          }
        } else if (source && _typeof(source) === 'object') {
          for (var i = 0, len = this.arguments.length; i < len; ++i) {
            this[this.arguments[i]] = source[this.arguments[i]];
          }
        }
        this.inversed = false;
        if (inversed === true) {
          this.inversed = true;
        }
      }
    });
    SVG.Translate = SVG.invent({
      parent: SVG.Matrix,
      inherit: SVG.Transformation,
      create: function create(source, inversed) {
        this.constructor.apply(this, [].slice.call(arguments));
      },
      extend: {
        arguments: ['transformedX', 'transformedY'],
        method: 'translate'
      }
    });
    SVG.extend(SVG.Element, {
      // Dynamic style generator
      style: function style(s, v) {
        if (arguments.length == 0) {
          // get full style
          return this.node.style.cssText || '';
        } else if (arguments.length < 2) {
          // apply every style individually if an object is passed
          if (_typeof(s) === 'object') {
            for (var v_ in s) {
              this.style(v_, s[v_]);
            }
          } else if (SVG.regex.isCss.test(s)) {
            // parse css string
            s = s.split(/\s*;\s*/)
            // filter out suffix ; and stuff like ;;
            .filter(function (e) {
              return !!e;
            }).map(function (e) {
              return e.split(/\s*:\s*/);
            });

            // apply every definition individually
            while (v = s.pop()) {
              this.style(v[0], v[1]);
            }
          } else {
            // act as a getter if the first and only argument is not an object
            return this.node.style[camelCase(s)];
          }
        } else {
          this.node.style[camelCase(s)] = v === null || SVG.regex.isBlank.test(v) ? '' : v;
        }
        return this;
      }
    });
    SVG.Parent = SVG.invent({
      // Initialize node
      create: function create(element) {
        this.constructor.call(this, element);
      },
      // Inherit from
      inherit: SVG.Element,
      // Add class methods
      extend: {
        // Returns all child elements
        children: function children() {
          return SVG.utils.map(SVG.utils.filterSVGElements(this.node.childNodes), function (node) {
            return SVG.adopt(node);
          });
        },
        // Add given element at a position
        add: function add(element, i) {
          if (i == null) {
            this.node.appendChild(element.node);
          } else if (element.node != this.node.childNodes[i]) {
            this.node.insertBefore(element.node, this.node.childNodes[i]);
          }
          return this;
        },
        // Basically does the same as `add()` but returns the added element instead
        put: function put(element, i) {
          this.add(element, i);
          return element;
        },
        // Checks if the given element is a child
        has: function has(element) {
          return this.index(element) >= 0;
        },
        // Gets index of given element
        index: function index(element) {
          return [].slice.call(this.node.childNodes).indexOf(element.node);
        },
        // Get a element at the given index
        get: function get(i) {
          return SVG.adopt(this.node.childNodes[i]);
        },
        // Get first child
        first: function first() {
          return this.get(0);
        },
        // Get the last child
        last: function last() {
          return this.get(this.node.childNodes.length - 1);
        },
        // Iterates over all children and invokes a given block
        each: function each(block, deep) {
          var il,
            children = this.children();
          for (var i = 0, il = children.length; i < il; i++) {
            if (children[i] instanceof SVG.Element) {
              block.apply(children[i], [i, children]);
            }
            if (deep && children[i] instanceof SVG.Container) {
              children[i].each(block, deep);
            }
          }
          return this;
        },
        // Remove a given child
        removeElement: function removeElement(element) {
          this.node.removeChild(element.node);
          return this;
        },
        // Remove all elements in this container
        clear: function clear() {
          // remove children
          while (this.node.hasChildNodes()) {
            this.node.removeChild(this.node.lastChild);
          }

          // remove defs reference
          delete this._defs;
          return this;
        },
        // Get defs
        defs: function defs() {
          return this.doc().defs();
        }
      }
    });
    SVG.extend(SVG.Parent, {
      ungroup: function ungroup(parent, depth) {
        if (depth === 0 || this instanceof SVG.Defs || this.node == SVG.parser.draw) return this;
        parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent));
        depth = depth || Infinity;
        this.each(function () {
          if (this instanceof SVG.Defs) return this;
          if (this instanceof SVG.Parent) return this.ungroup(parent, depth - 1);
          return this.toParent(parent);
        });
        this.node.firstChild || this.remove();
        return this;
      },
      flatten: function flatten(parent, depth) {
        return this.ungroup(parent, depth);
      }
    });
    SVG.Container = SVG.invent({
      // Initialize node
      create: function create(element) {
        this.constructor.call(this, element);
      },
      // Inherit from
      inherit: SVG.Parent
    });
    SVG.ViewBox = SVG.invent({
      // Define parent
      parent: SVG.Container,
      // Add parent method
      construct: {}
    })
    // Add events to elements
    ;
    ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove',
    // , 'mouseenter' -> not supported by IE
    // , 'mouseleave' -> not supported by IE
    'touchstart', 'touchmove', 'touchleave', 'touchend', 'touchcancel'].forEach(function (event) {
      // add event to SVG.Element
      SVG.Element.prototype[event] = function (f) {
        // bind event to element rather than element node
        SVG.on(this.node, event, f);
        return this;
      };
    });

    // Initialize listeners stack
    SVG.listeners = [];
    SVG.handlerMap = [];
    SVG.listenerId = 0;

    // Add event binder in the SVG namespace
    SVG.on = function (node, event, listener, binding, options) {
      // create listener, get object-index
      var l = listener.bind(binding || node.instance || node),
        index = (SVG.handlerMap.indexOf(node) + 1 || SVG.handlerMap.push(node)) - 1,
        ev = event.split('.')[0],
        ns = event.split('.')[1] || '*';

      // ensure valid object
      SVG.listeners[index] = SVG.listeners[index] || {};
      SVG.listeners[index][ev] = SVG.listeners[index][ev] || {};
      SVG.listeners[index][ev][ns] = SVG.listeners[index][ev][ns] || {};
      if (!listener._svgjsListenerId) {
        listener._svgjsListenerId = ++SVG.listenerId;
      }

      // reference listener
      SVG.listeners[index][ev][ns][listener._svgjsListenerId] = l;

      // add listener
      node.addEventListener(ev, l, options || {
        passive: false
      });
    };

    // Add event unbinder in the SVG namespace
    SVG.off = function (node, event, listener) {
      var index = SVG.handlerMap.indexOf(node),
        ev = event && event.split('.')[0],
        ns = event && event.split('.')[1],
        namespace = '';
      if (index == -1) return;
      if (listener) {
        if (typeof listener === 'function') listener = listener._svgjsListenerId;
        if (!listener) return;

        // remove listener reference
        if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns || '*']) {
          // remove listener
          node.removeEventListener(ev, SVG.listeners[index][ev][ns || '*'][listener], false);
          delete SVG.listeners[index][ev][ns || '*'][listener];
        }
      } else if (ns && ev) {
        // remove all listeners for a namespaced event
        if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns]) {
          for (var listener_ in SVG.listeners[index][ev][ns]) {
            SVG.off(node, [ev, ns].join('.'), listener_);
          }
          delete SVG.listeners[index][ev][ns];
        }
      } else if (ns) {
        // remove all listeners for a specific namespace
        for (var event_ in SVG.listeners[index]) {
          for (var namespace in SVG.listeners[index][event_]) {
            if (ns === namespace) {
              SVG.off(node, [event_, ns].join('.'));
            }
          }
        }
      } else if (ev) {
        // remove all listeners for the event
        if (SVG.listeners[index][ev]) {
          for (var namespace in SVG.listeners[index][ev]) {
            SVG.off(node, [ev, namespace].join('.'));
          }
          delete SVG.listeners[index][ev];
        }
      } else {
        // remove all listeners on a given node
        for (var event_ in SVG.listeners[index]) {
          SVG.off(node, event_);
        }
        delete SVG.listeners[index];
        delete SVG.handlerMap[index];
      }
    };

    //
    SVG.extend(SVG.Element, {
      // Bind given event to listener
      on: function on(event, listener, binding, options) {
        SVG.on(this.node, event, listener, binding, options);
        return this;
      },
      // Unbind event from listener
      off: function off(event, listener) {
        SVG.off(this.node, event, listener);
        return this;
      },
      // Fire given event
      fire: function fire(event, data) {
        // Dispatch event
        if (event instanceof window.Event) {
          this.node.dispatchEvent(event);
        } else {
          this.node.dispatchEvent(event = new SVG.CustomEvent(event, {
            detail: data,
            cancelable: true
          }));
        }
        this._event = event;
        return this;
      },
      event: function event() {
        return this._event;
      }
    });
    SVG.Defs = SVG.invent({
      // Initialize node
      create: 'defs',
      // Inherit from
      inherit: SVG.Container
    });
    SVG.G = SVG.invent({
      // Initialize node
      create: 'g',
      // Inherit from
      inherit: SVG.Container,
      // Add class methods
      extend: {
        // Move over x-axis
        x: function x(_x2) {
          return _x2 == null ? this.transform('x') : this.transform({
            x: _x2 - this.x()
          }, true);
        }
      },
      // Add parent method
      construct: {
        // Create a group element
        group: function group() {
          return this.put(new SVG.G());
        }
      }
    });
    SVG.Doc = SVG.invent({
      // Initialize node
      create: function create(element) {
        if (element) {
          // ensure the presence of a dom element
          element = typeof element === 'string' ? document.getElementById(element) : element;

          // If the target is an svg element, use that element as the main wrapper.
          // This allows svg.js to work with svg documents as well.
          if (element.nodeName == 'svg') {
            this.constructor.call(this, element);
          } else {
            this.constructor.call(this, SVG.create('svg'));
            element.appendChild(this.node);
            this.size('100%', '100%');
          }

          // set svg element attributes and ensure defs node
          this.namespace().defs();
        }
      },
      // Inherit from
      inherit: SVG.Container,
      // Add class methods
      extend: {
        // Add namespaces
        namespace: function namespace() {
          return this.attr({
            xmlns: SVG.ns,
            version: '1.1'
          }).attr('xmlns:xlink', SVG.xlink, SVG.xmlns).attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns);
        },
        // Creates and returns defs element
        defs: function defs() {
          if (!this._defs) {
            var defs;

            // Find or create a defs element in this instance
            if (defs = this.node.getElementsByTagName('defs')[0]) {
              this._defs = SVG.adopt(defs);
            } else {
              this._defs = new SVG.Defs();
            }

            // Make sure the defs node is at the end of the stack
            this.node.appendChild(this._defs.node);
          }
          return this._defs;
        },
        // custom parent method
        parent: function parent() {
          if (!this.node.parentNode || this.node.parentNode.nodeName == '#document') return null;
          return this.node.parentNode;
        },
        // Removes the doc from the DOM
        remove: function remove() {
          if (this.parent()) {
            this.parent().removeChild(this.node);
          }
          return this;
        },
        clear: function clear() {
          // remove children
          while (this.node.hasChildNodes()) {
            this.node.removeChild(this.node.lastChild);
          }

          // remove defs reference
          delete this._defs;

          // add back parser
          if (SVG.parser.draw && !SVG.parser.draw.parentNode) {
            this.node.appendChild(SVG.parser.draw);
          }
          return this;
        },
        clone: function clone(parent) {
          // write dom data to the dom so the clone can pickup the data
          this.writeDataToDom();

          // get reference to node
          var node = this.node;

          // clone element and assign new id
          var clone = assignNewId(node.cloneNode(true));

          // insert the clone in the given parent or after myself
          if (parent) {
            (parent.node || parent).appendChild(clone.node);
          } else {
            node.parentNode.insertBefore(clone.node, node.nextSibling);
          }
          return clone;
        }
      }
    });

    // ### This module adds backward / forward functionality to elements.

    //
    SVG.extend(SVG.Element, {
      // Get all siblings, including myself
    });
    SVG.Gradient = SVG.invent({
      // Initialize node
      create: function create(type) {
        this.constructor.call(this, SVG.create(type + 'Gradient'));

        // store type
        this.type = type;
      },
      // Inherit from
      inherit: SVG.Container,
      // Add class methods
      extend: {
        // Add a color stop
        at: function at(offset, color, opacity) {
          return this.put(new SVG.Stop()).update(offset, color, opacity);
        },
        // Update gradient
        update: function update(block) {
          // remove all stops
          this.clear();

          // invoke passed block
          if (typeof block === 'function') {
            block.call(this, this);
          }
          return this;
        },
        // Return the fill id
        fill: function fill() {
          return 'url(#' + this.id() + ')';
        },
        // Alias string convertion to fill
        toString: function toString() {
          return this.fill();
        },
        // custom attr to handle transform
        attr: function attr(a, b, c) {
          if (a == 'transform') a = 'gradientTransform';
          return SVG.Container.prototype.attr.call(this, a, b, c);
        }
      },
      // Add parent method
      construct: {
        // Create gradient element in defs
        gradient: function gradient(type, block) {
          return this.defs().gradient(type, block);
        }
      }
    });

    // Add animatable methods to both gradient and fx module
    SVG.extend(SVG.Gradient, SVG.FX, {
      // From position
      from: function from(x, y) {
        return (this._target || this).type == 'radial' ? this.attr({
          fx: new SVG.Number(x),
          fy: new SVG.Number(y)
        }) : this.attr({
          x1: new SVG.Number(x),
          y1: new SVG.Number(y)
        });
      },
      // To position
      to: function to(x, y) {
        return (this._target || this).type == 'radial' ? this.attr({
          cx: new SVG.Number(x),
          cy: new SVG.Number(y)
        }) : this.attr({
          x2: new SVG.Number(x),
          y2: new SVG.Number(y)
        });
      }
    });

    // Base gradient generation
    SVG.extend(SVG.Defs, {
      // define gradient
      gradient: function gradient(type, block) {
        return this.put(new SVG.Gradient(type)).update(block);
      }
    });
    SVG.Stop = SVG.invent({
      // Initialize node
      create: 'stop',
      // Inherit from
      inherit: SVG.Element,
      // Add class methods
      extend: {
        // add color stops
        update: function update(o) {
          if (typeof o === 'number' || o instanceof SVG.Number) {
            o = {
              offset: arguments[0],
              color: arguments[1],
              opacity: arguments[2]
            };
          }

          // set attributes
          if (o.opacity != null) this.attr('stop-opacity', o.opacity);
          if (o.color != null) this.attr('stop-color', o.color);
          if (o.offset != null) this.attr('offset', new SVG.Number(o.offset));
          return this;
        }
      }
    });
    SVG.Pattern = SVG.invent({
      // Initialize node
      create: 'pattern',
      // Inherit from
      inherit: SVG.Container,
      // Add class methods
      extend: {
        // Return the fill id
        fill: function fill() {
          return 'url(#' + this.id() + ')';
        },
        // Update pattern by rebuilding
        update: function update(block) {
          // remove content
          this.clear();

          // invoke passed block
          if (typeof block === 'function') {
            block.call(this, this);
          }
          return this;
        },
        // Alias string convertion to fill
        toString: function toString() {
          return this.fill();
        },
        // custom attr to handle transform
        attr: function attr(a, b, c) {
          if (a == 'transform') a = 'patternTransform';
          return SVG.Container.prototype.attr.call(this, a, b, c);
        }
      },
      // Add parent method
      construct: {
        // Create pattern element in defs
        pattern: function pattern(width, height, block) {
          return this.defs().pattern(width, height, block);
        }
      }
    });
    SVG.extend(SVG.Defs, {
      // Define gradient
      pattern: function pattern(width, height, block) {
        return this.put(new SVG.Pattern()).update(block).attr({
          x: 0,
          y: 0,
          width: width,
          height: height,
          patternUnits: 'userSpaceOnUse'
        });
      }
    });
    SVG.Shape = SVG.invent({
      // Initialize node
      create: function create(element) {
        this.constructor.call(this, element);
      },
      // Inherit from
      inherit: SVG.Element
    });
    SVG.Symbol = SVG.invent({
      // Initialize node
      create: 'symbol',
      // Inherit from
      inherit: SVG.Container,
      construct: {
        // create symbol
        symbol: function symbol() {
          return this.put(new SVG.Symbol());
        }
      }
    });
    SVG.Use = SVG.invent({
      // Initialize node
      create: 'use',
      // Inherit from
      inherit: SVG.Shape,
      // Add class methods
      extend: {
        // Use element as a reference
        element: function element(_element, file) {
          // Set lined element
          return this.attr('href', (file || '') + '#' + _element, SVG.xlink);
        }
      },
      // Add parent method
      construct: {
        // Create a use element
        use: function use(element, file) {
          return this.put(new SVG.Use()).element(element, file);
        }
      }
    });
    SVG.Rect = SVG.invent({
      // Initialize node
      create: 'rect',
      // Inherit from
      inherit: SVG.Shape,
      // Add parent method
      construct: {
        // Create a rect element
        rect: function rect(width, height) {
          return this.put(new SVG.Rect()).size(width, height);
        }
      }
    });
    SVG.Circle = SVG.invent({
      // Initialize node
      create: 'circle',
      // Inherit from
      inherit: SVG.Shape,
      // Add parent method
      construct: {
        // Create circle element, based on ellipse
        circle: function circle(size) {
          return this.put(new SVG.Circle()).rx(new SVG.Number(size).divide(2)).move(0, 0);
        }
      }
    });
    SVG.extend(SVG.Circle, SVG.FX, {
      // Radius x value
      rx: function rx(_rx) {
        return this.attr('r', _rx);
      },
      // Alias radius x value
      ry: function ry(_ry) {
        return this.rx(_ry);
      }
    });
    SVG.Ellipse = SVG.invent({
      // Initialize node
      create: 'ellipse',
      // Inherit from
      inherit: SVG.Shape,
      // Add parent method
      construct: {
        // Create an ellipse
        ellipse: function ellipse(width, height) {
          return this.put(new SVG.Ellipse()).size(width, height).move(0, 0);
        }
      }
    });
    SVG.extend(SVG.Ellipse, SVG.Rect, SVG.FX, {
      // Radius x value
      rx: function rx(_rx2) {
        return this.attr('rx', _rx2);
      },
      // Radius y value
      ry: function ry(_ry2) {
        return this.attr('ry', _ry2);
      }
    });

    // Add common method
    SVG.extend(SVG.Circle, SVG.Ellipse, {
      // Move over x-axis
      x: function x(_x3) {
        return _x3 == null ? this.cx() - this.rx() : this.cx(_x3 + this.rx());
      },
      // Move over y-axis
      y: function y(_y2) {
        return _y2 == null ? this.cy() - this.ry() : this.cy(_y2 + this.ry());
      },
      // Move by center over x-axis
      cx: function cx(x) {
        return x == null ? this.attr('cx') : this.attr('cx', x);
      },
      // Move by center over y-axis
      cy: function cy(y) {
        return y == null ? this.attr('cy') : this.attr('cy', y);
      },
      // Set width of element
      width: function width(_width2) {
        return _width2 == null ? this.rx() * 2 : this.rx(new SVG.Number(_width2).divide(2));
      },
      // Set height of element
      height: function height(_height2) {
        return _height2 == null ? this.ry() * 2 : this.ry(new SVG.Number(_height2).divide(2));
      },
      // Custom size function
      size: function size(width, height) {
        var p = proportionalSize(this, width, height);
        return this.rx(new SVG.Number(p.width).divide(2)).ry(new SVG.Number(p.height).divide(2));
      }
    });
    SVG.Line = SVG.invent({
      // Initialize node
      create: 'line',
      // Inherit from
      inherit: SVG.Shape,
      // Add class methods
      extend: {
        // Get array
        array: function array() {
          return new SVG.PointArray([[this.attr('x1'), this.attr('y1')], [this.attr('x2'), this.attr('y2')]]);
        },
        // Overwrite native plot() method
        plot: function plot(x1, y1, x2, y2) {
          if (x1 == null) {
            return this.array();
          } else if (typeof y1 !== 'undefined') {
            x1 = {
              x1: x1,
              y1: y1,
              x2: x2,
              y2: y2
            };
          } else {
            x1 = new SVG.PointArray(x1).toLine();
          }
          return this.attr(x1);
        },
        // Move by left top corner
        move: function move(x, y) {
          return this.attr(this.array().move(x, y).toLine());
        },
        // Set element size to given width and height
        size: function size(width, height) {
          var p = proportionalSize(this, width, height);
          return this.attr(this.array().size(p.width, p.height).toLine());
        }
      },
      // Add parent method
      construct: {
        // Create a line element
        line: function line(x1, y1, x2, y2) {
          // make sure plot is called as a setter
          // x1 is not necessarily a number, it can also be an array, a string and a SVG.PointArray
          return SVG.Line.prototype.plot.apply(this.put(new SVG.Line()), x1 != null ? [x1, y1, x2, y2] : [0, 0, 0, 0]);
        }
      }
    });
    SVG.Polyline = SVG.invent({
      // Initialize node
      create: 'polyline',
      // Inherit from
      inherit: SVG.Shape,
      // Add parent method
      construct: {
        // Create a wrapped polyline element
        polyline: function polyline(p) {
          // make sure plot is called as a setter
          return this.put(new SVG.Polyline()).plot(p || new SVG.PointArray());
        }
      }
    });
    SVG.Polygon = SVG.invent({
      // Initialize node
      create: 'polygon',
      // Inherit from
      inherit: SVG.Shape,
      // Add parent method
      construct: {
        // Create a wrapped polygon element
        polygon: function polygon(p) {
          // make sure plot is called as a setter
          return this.put(new SVG.Polygon()).plot(p || new SVG.PointArray());
        }
      }
    });

    // Add polygon-specific functions
    SVG.extend(SVG.Polyline, SVG.Polygon, {
      // Get array
      array: function array() {
        return this._array || (this._array = new SVG.PointArray(this.attr('points')));
      },
      // Plot new path
      plot: function plot(p) {
        return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new SVG.PointArray(p));
      },
      // Clear array cache
      clear: function clear() {
        delete this._array;
        return this;
      },
      // Move by left top corner
      move: function move(x, y) {
        return this.attr('points', this.array().move(x, y));
      },
      // Set element size to given width and height
      size: function size(width, height) {
        var p = proportionalSize(this, width, height);
        return this.attr('points', this.array().size(p.width, p.height));
      }
    });

    // unify all point to point elements
    SVG.extend(SVG.Line, SVG.Polyline, SVG.Polygon, {
      // Define morphable array
      morphArray: SVG.PointArray,
      // Move by left top corner over x-axis
      x: function x(_x4) {
        return _x4 == null ? this.bbox().x : this.move(_x4, this.bbox().y);
      },
      // Move by left top corner over y-axis
      y: function y(_y3) {
        return _y3 == null ? this.bbox().y : this.move(this.bbox().x, _y3);
      },
      // Set width of element
      width: function width(_width3) {
        var b = this.bbox();
        return _width3 == null ? b.width : this.size(_width3, b.height);
      },
      // Set height of element
      height: function height(_height3) {
        var b = this.bbox();
        return _height3 == null ? b.height : this.size(b.width, _height3);
      }
    });
    SVG.Path = SVG.invent({
      // Initialize node
      create: 'path',
      // Inherit from
      inherit: SVG.Shape,
      // Add class methods
      extend: {
        // Define morphable array
        morphArray: SVG.PathArray,
        // Get array
        array: function array() {
          return this._array || (this._array = new SVG.PathArray(this.attr('d')));
        },
        // Plot new path
        plot: function plot(d) {
          return d == null ? this.array() : this.clear().attr('d', typeof d === 'string' ? d : this._array = new SVG.PathArray(d));
        },
        // Clear array cache
        clear: function clear() {
          delete this._array;
          return this;
        }
      },
      // Add parent method
      construct: {
        // Create a wrapped path element
        path: function path(d) {
          // make sure plot is called as a setter
          return this.put(new SVG.Path()).plot(d || new SVG.PathArray());
        }
      }
    });
    SVG.Image = SVG.invent({
      // Initialize node
      create: 'image',
      // Inherit from
      inherit: SVG.Shape,
      // Add class methods
      extend: {
        // (re)load image
        load: function load(url) {
          if (!url) return this;
          var self = this,
            img = new window.Image();

          // preload image
          SVG.on(img, 'load', function () {
            SVG.off(img);
            var p = self.parent(SVG.Pattern);
            if (p === null) return;

            // ensure image size
            if (self.width() == 0 && self.height() == 0) {
              self.size(img.width, img.height);
            }

            // ensure pattern size if not set
            if (p && p.width() == 0 && p.height() == 0) {
              p.size(self.width(), self.height());
            }

            // callback
            if (typeof self._loaded === 'function') {
              self._loaded.call(self, {
                width: img.width,
                height: img.height,
                ratio: img.width / img.height,
                url: url
              });
            }
          });
          SVG.on(img, 'error', function (e) {
            SVG.off(img);
            if (typeof self._error === 'function') {
              self._error.call(self, e);
            }
          });
          return this.attr('href', img.src = this.src = url, SVG.xlink);
        },
        // Add loaded callback
        loaded: function loaded(_loaded) {
          this._loaded = _loaded;
          return this;
        },
        error: function error(_error) {
          this._error = _error;
          return this;
        }
      },
      // Add parent method
      construct: {
        // create image element, load image and set its size
        image: function image(source, width, height) {
          return this.put(new SVG.Image()).load(source).size(width || 0, height || width || 0);
        }
      }
    });
    SVG.Text = SVG.invent({
      // Initialize node
      create: function create() {
        this.constructor.call(this, SVG.create('text'));
        this.dom.leading = new SVG.Number(1.3); // store leading value for rebuilding
        this._rebuild = true; // enable automatic updating of dy values
        this._build = false; // disable build mode for adding multiple lines

        // set default font
        this.attr('font-family', SVG.defaults.attrs['font-family']);
      },
      // Inherit from
      inherit: SVG.Shape,
      // Add class methods
      extend: {
        // Move over x-axis
        x: function x(_x5) {
          // act as getter
          if (_x5 == null) {
            return this.attr('x');
          }
          return this.attr('x', _x5);
        },
        // Set the text content
        text: function text(_text) {
          // act as getter
          if (typeof _text === 'undefined') {
            var _text = '';
            var children = this.node.childNodes;
            for (var i = 0, len = children.length; i < len; ++i) {
              // add newline if its not the first child and newLined is set to true
              if (i != 0 && children[i].nodeType != 3 && SVG.adopt(children[i]).dom.newLined == true) {
                _text += '\n';
              }

              // add content of this node
              _text += children[i].textContent;
            }
            return _text;
          }

          // remove existing content
          this.clear().build(true);
          if (typeof _text === 'function') {
            // call block
            _text.call(this, this);
          } else {
            // store text and make sure text is not blank
            _text = _text.split('\n');

            // build new lines
            for (var i = 0, il = _text.length; i < il; i++) {
              this.tspan(_text[i]).newLine();
            }
          }

          // disable build mode and rebuild lines
          return this.build(false).rebuild();
        },
        // Set font size
        size: function size(_size) {
          return this.attr('font-size', _size).rebuild();
        },
        // Set / get leading
        leading: function leading(value) {
          // act as getter
          if (value == null) {
            return this.dom.leading;
          }

          // act as setter
          this.dom.leading = new SVG.Number(value);
          return this.rebuild();
        },
        // Get all the first level lines
        lines: function lines() {
          var node = (this.textPath && this.textPath() || this).node;

          // filter tspans and map them to SVG.js instances
          var lines = SVG.utils.map(SVG.utils.filterSVGElements(node.childNodes), function (el) {
            return SVG.adopt(el);
          });

          // return an instance of SVG.set
          return new SVG.Set(lines);
        },
        // Rebuild appearance type
        rebuild: function rebuild(_rebuild) {
          // store new rebuild flag if given
          if (typeof _rebuild === 'boolean') {
            this._rebuild = _rebuild;
          }

          // define position of all lines
          if (this._rebuild) {
            var self = this,
              blankLineOffset = 0,
              dy = this.dom.leading * new SVG.Number(this.attr('font-size'));
            this.lines().each(function () {
              if (this.dom.newLined) {
                if (!self.textPath()) {
                  this.attr('x', self.attr('x'));
                }
                if (this.text() == '\n') {
                  blankLineOffset += dy;
                } else {
                  this.attr('dy', dy + blankLineOffset);
                  blankLineOffset = 0;
                }
              }
            });
            this.fire('rebuild');
          }
          return this;
        },
        // Enable / disable build mode
        build: function build(_build) {
          this._build = !!_build;
          return this;
        },
        // overwrite method from parent to set data properly
        setData: function setData(o) {
          this.dom = o;
          this.dom.leading = new SVG.Number(o.leading || 1.3);
          return this;
        }
      },
      // Add parent method
      construct: {
        // Create text element
        text: function text(_text2) {
          return this.put(new SVG.Text()).text(_text2);
        },
        // Create plain text element
        plain: function plain(text) {
          return this.put(new SVG.Text()).plain(text);
        }
      }
    });
    SVG.Tspan = SVG.invent({
      // Initialize node
      create: 'tspan',
      // Inherit from
      inherit: SVG.Shape,
      // Add class methods
      extend: {
        // Set text content
        text: function text(_text3) {
          if (_text3 == null) return this.node.textContent + (this.dom.newLined ? '\n' : '');
          typeof _text3 === 'function' ? _text3.call(this, this) : this.plain(_text3);
          return this;
        },
        // Shortcut dx
        dx: function dx(_dx) {
          return this.attr('dx', _dx);
        },
        // Shortcut dy
        dy: function dy(_dy) {
          return this.attr('dy', _dy);
        },
        // Create new line
        newLine: function newLine() {
          // fetch text parent
          var t = this.parent(SVG.Text);

          // mark new line
          this.dom.newLined = true;

          // apply new hy¡n
          return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x());
        }
      }
    });
    SVG.extend(SVG.Text, SVG.Tspan, {
      // Create plain text node
      plain: function plain(text) {
        // clear if build mode is disabled
        if (this._build === false) {
          this.clear();
        }

        // create text node
        this.node.appendChild(document.createTextNode(text));
        return this;
      },
      // Create a tspan
      tspan: function tspan(text) {
        var node = (this.textPath && this.textPath() || this).node,
          tspan = new SVG.Tspan();

        // clear if build mode is disabled
        if (this._build === false) {
          this.clear();
        }

        // add new tspan
        node.appendChild(tspan.node);
        return tspan.text(text);
      },
      // Clear all lines
      clear: function clear() {
        var node = (this.textPath && this.textPath() || this).node;

        // remove existing child nodes
        while (node.hasChildNodes()) {
          node.removeChild(node.lastChild);
        }
        return this;
      },
      // Get length of text element
      length: function length() {
        return this.node.getComputedTextLength();
      }
    });
    SVG.TextPath = SVG.invent({
      // Initialize node
      create: 'textPath',
      // Inherit from
      inherit: SVG.Parent,
      // Define parent class
      parent: SVG.Text,
      // Add parent method
      construct: {
        morphArray: SVG.PathArray,
        // return the array of the path track element
        array: function array() {
          var track = this.track();
          return track ? track.array() : null;
        },
        // Plot path if any
        plot: function plot(d) {
          var track = this.track(),
            pathArray = null;
          if (track) {
            pathArray = track.plot(d);
          }
          return d == null ? pathArray : this;
        },
        // Get the path track element
        track: function track() {
          var path = this.textPath();
          if (path) {
            return path.reference('href');
          }
        },
        // Get the textPath child
        textPath: function textPath() {
          if (this.node.firstChild && this.node.firstChild.nodeName == 'textPath') {
            return SVG.adopt(this.node.firstChild);
          }
        }
      }
    });
    SVG.Nested = SVG.invent({
      // Initialize node
      create: function create() {
        this.constructor.call(this, SVG.create('svg'));
        this.style('overflow', 'visible');
      },
      // Inherit from
      inherit: SVG.Container,
      // Add parent method
      construct: {
        // Create nested svg document
        nested: function nested() {
          return this.put(new SVG.Nested());
        }
      }
    });

    // Define list of available attributes for stroke and fill
    var sugar = {
      stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'],
      fill: ['color', 'opacity', 'rule'],
      prefix: function prefix(t, a) {
        return a == 'color' ? t : t + '-' + a;
      }
    }

    // Add sugar for fill and stroke
    ;
    ['fill', 'stroke'].forEach(function (m) {
      var extension = {};
      extension[m] = function (o) {
        if (typeof o === 'undefined') {
          return this;
        }
        if (typeof o === 'string' || SVG.Color.isRgb(o) || o && typeof o.fill === 'function') {
          this.attr(m, o);
        } else
          // set all attributes from sugar.fill and sugar.stroke list
          {
            for (var i = sugar[m].length - 1; i >= 0; i--) {
              if (o[sugar[m][i]] != null) {
                this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]);
              }
            }
          }
        return this;
      };
      SVG.extend(SVG.Element, SVG.FX, extension);
    });
    SVG.extend(SVG.Element, SVG.FX, {
      // Map translate to transform
      translate: function translate(x, y) {
        return this.transform({
          x: x,
          y: y
        });
      },
      // Map matrix to transform
      matrix: function matrix(m) {
        return this.attr('transform', new SVG.Matrix(arguments.length == 6 ? [].slice.call(arguments) : m));
      },
      // Opacity
      opacity: function opacity(value) {
        return this.attr('opacity', value);
      },
      // Relative move over x axis
      dx: function dx(x) {
        return this.x(new SVG.Number(x).plus(this instanceof SVG.FX ? 0 : this.x()), true);
      },
      // Relative move over y axis
      dy: function dy(y) {
        return this.y(new SVG.Number(y).plus(this instanceof SVG.FX ? 0 : this.y()), true);
      }
    });
    SVG.extend(SVG.Path, {
      // Get path length
      length: function length() {
        return this.node.getTotalLength();
      },
      // Get point at length
      pointAt: function pointAt(length) {
        return this.node.getPointAtLength(length);
      }
    });
    SVG.Set = SVG.invent({
      // Initialize
      create: function create(members) {
        // Set initial state
        Array.isArray(members) ? this.members = members : this.clear();
      },
      // Add class methods
      extend: {
        // Add element to set
        add: function add() {
          var il,
            elements = [].slice.call(arguments);
          for (var i = 0, il = elements.length; i < il; i++) {
            this.members.push(elements[i]);
          }
          return this;
        },
        // Remove element from set
        remove: function remove(element) {
          var i = this.index(element);

          // remove given child
          if (i > -1) {
            this.members.splice(i, 1);
          }
          return this;
        },
        // Iterate over all members
        each: function each(block) {
          for (var i = 0, il = this.members.length; i < il; i++) {
            block.apply(this.members[i], [i, this.members]);
          }
          return this;
        },
        // Restore to defaults
        clear: function clear() {
          // initialize store
          this.members = [];
          return this;
        },
        // Get the length of a set
        length: function length() {
          return this.members.length;
        },
        // Checks if a given element is present in set
        has: function has(element) {
          return this.index(element) >= 0;
        },
        // retuns index of given element in set
        index: function index(element) {
          return this.members.indexOf(element);
        },
        // Get member at given index
        get: function get(i) {
          return this.members[i];
        },
        // Get first member
        first: function first() {
          return this.get(0);
        },
        // Get last member
        last: function last() {
          return this.get(this.members.length - 1);
        },
        // Default value
        valueOf: function valueOf() {
          return this.members;
        }
      },
      // Add parent method
      construct: {
        // Create a new set
        set: function set(members) {
          return new SVG.Set(members);
        }
      }
    });
    SVG.FX.Set = SVG.invent({
      // Initialize node
      create: function create(set) {
        // store reference to set
        this.set = set;
      }
    });

    // Alias methods
    SVG.Set.inherit = function () {
      var methods = [];

      // gather shape methods
      for (var m in SVG.Shape.prototype) {
        if (typeof SVG.Shape.prototype[m] === 'function' && typeof SVG.Set.prototype[m] !== 'function') {
          methods.push(m);
        }
      }

      // apply shape aliasses
      methods.forEach(function (method) {
        SVG.Set.prototype[method] = function () {
          for (var i = 0, il = this.members.length; i < il; i++) {
            if (this.members[i] && typeof this.members[i][method] === 'function') {
              this.members[i][method].apply(this.members[i], arguments);
            }
          }
          return method == 'animate' ? this.fx || (this.fx = new SVG.FX.Set(this)) : this;
        };
      });

      // clear methods for the next round
      methods = [];

      // gather fx methods
      for (var m in SVG.FX.prototype) {
        if (typeof SVG.FX.prototype[m] === 'function' && typeof SVG.FX.Set.prototype[m] !== 'function') {
          methods.push(m);
        }
      }

      // apply fx aliasses
      methods.forEach(function (method) {
        SVG.FX.Set.prototype[method] = function () {
          for (var i = 0, il = this.set.members.length; i < il; i++) {
            this.set.members[i].fx[method].apply(this.set.members[i].fx, arguments);
          }
          return this;
        };
      });
    };
    SVG.extend(SVG.Element, {});
    SVG.extend(SVG.Element, {
      // Remember arbitrary data
      remember: function remember(k, v) {
        // remember every item in an object individually
        if (_typeof(arguments[0]) === 'object') {
          for (var v_ in k) {
            this.remember(v_, k[v_]);
          }
        }

        // retrieve memory
        else if (arguments.length == 1) {
          return this.memory()[k];
        }

        // store memory
        else {
          this.memory()[k] = v;
        }
        return this;
      },
      // Erase a given memory
      forget: function forget() {
        if (arguments.length == 0) {
          this._memory = {};
        } else {
          for (var i = arguments.length - 1; i >= 0; i--) {
            delete this.memory()[arguments[i]];
          }
        }
        return this;
      },
      // Initialize or return local memory object
      memory: function memory() {
        return this._memory || (this._memory = {});
      }
    });
    // Method for getting an element by id
    SVG.get = function (id) {
      var node = document.getElementById(idFromReference(id) || id);
      return SVG.adopt(node);
    };

    // Select elements by query string
    SVG.select = function (query, parent) {
      return new SVG.Set(SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
        return SVG.adopt(node);
      }));
    };
    SVG.extend(SVG.Parent, {
      // Scoped select method
      select: function select(query) {
        return SVG.select(query, this.node);
      }
    });
    function pathRegReplace(a, b, c, d) {
      return c + d.replace(SVG.regex.dots, ' .');
    }

    // tests if a given element is instance of an object
    function _is(el, obj) {
      return el instanceof obj;
    }

    // tests if a given selector matches an element
    function _matches(el, selector) {
      return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector);
    }

    // Convert dash-separated-string to camelCase
    function camelCase(s) {
      return s.toLowerCase().replace(/-(.)/g, function (m, g) {
        return g.toUpperCase();
      });
    }

    // Capitalize first letter of a string
    function capitalize(s) {
      return s.charAt(0).toUpperCase() + s.slice(1);
    }

    // Ensure to six-based hex
    function fullHex(hex) {
      return hex.length == 4 ? ['#', hex.substring(1, 2), hex.substring(1, 2), hex.substring(2, 3), hex.substring(2, 3), hex.substring(3, 4), hex.substring(3, 4)].join('') : hex;
    }

    // Component to hex value
    function compToHex(comp) {
      var hex = comp.toString(16);
      return hex.length == 1 ? '0' + hex : hex;
    }

    // Calculate proportional width and height values when necessary
    function proportionalSize(element, width, height) {
      if (width == null || height == null) {
        var box = element.bbox();
        if (width == null) {
          width = box.width / box.height * height;
        } else if (height == null) {
          height = box.height / box.width * width;
        }
      }
      return {
        width: width,
        height: height
      };
    }

    // Delta transform point
    function deltaTransformPoint(matrix, x, y) {
      return {
        x: x * matrix.a + y * matrix.c + 0,
        y: x * matrix.b + y * matrix.d + 0
      };
    }

    // Map matrix array to object
    function arrayToMatrix(a) {
      return {
        a: a[0],
        b: a[1],
        c: a[2],
        d: a[3],
        e: a[4],
        f: a[5]
      };
    }

    // Parse matrix if required
    function parseMatrix(matrix) {
      if (!(matrix instanceof SVG.Matrix)) {
        matrix = new SVG.Matrix(matrix);
      }
      return matrix;
    }

    // PathArray Helpers
    function arrayToString(a) {
      for (var i = 0, il = a.length, s = ''; i < il; i++) {
        s += a[i][0];
        if (a[i][1] != null) {
          s += a[i][1];
          if (a[i][2] != null) {
            s += ' ';
            s += a[i][2];
            if (a[i][3] != null) {
              s += ' ';
              s += a[i][3];
              s += ' ';
              s += a[i][4];
              if (a[i][5] != null) {
                s += ' ';
                s += a[i][5];
                s += ' ';
                s += a[i][6];
                if (a[i][7] != null) {
                  s += ' ';
                  s += a[i][7];
                }
              }
            }
          }
        }
      }
      return s + ' ';
    }

    // Deep new id assignment
    function assignNewId(node) {
      // do the same for SVG child nodes as well
      for (var i = node.childNodes.length - 1; i >= 0; i--) {
        if (node.childNodes[i] instanceof window.SVGElement) {
          assignNewId(node.childNodes[i]);
        }
      }
      return SVG.adopt(node).id(SVG.eid(node.nodeName));
    }

    // Add more bounding box properties
    function fullBox(b) {
      if (b.x == null) {
        b.x = 0;
        b.y = 0;
        b.width = 0;
        b.height = 0;
      }
      b.w = b.width;
      b.h = b.height;
      b.x2 = b.x + b.width;
      b.y2 = b.y + b.height;
      b.cx = b.x + b.width / 2;
      b.cy = b.y + b.height / 2;
      return b;
    }

    // Get id from reference string
    function idFromReference(url) {
      var m = (url || '').toString().match(SVG.regex.reference);
      if (m) return m[1];
    }

    // If values like 1e-88 are passed, this is not a valid 32 bit float,
    // but in those cases, we are so close to 0 that 0 works well!
    function float32String(v) {
      return Math.abs(v) > 1e-37 ? v : 0;
    }

    // Create matrix array for looping
    var abcdef = 'abcdef'.split('');

    // Add CustomEvent to IE9 and IE10
    if (typeof window.CustomEvent !== 'function') {
      // Code from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
      var CustomEventPoly = function CustomEventPoly(event, options) {
        options = options || {
          bubbles: false,
          cancelable: false,
          detail: undefined
        };
        var e = document.createEvent('CustomEvent');
        e.initCustomEvent(event, options.bubbles, options.cancelable, options.detail);
        return e;
      };
      CustomEventPoly.prototype = window.Event.prototype;
      SVG.CustomEvent = CustomEventPoly;
    } else {
      SVG.CustomEvent = window.CustomEvent;
    }
    return SVG;
  });

  /*! svg.filter.js - v2.0.2 - 2016-02-24
  * https://github.com/wout/svg.filter.js
  * Copyright (c) 2016 Wout Fierens; Licensed MIT */
  (function() {

    // Main filter class
    SVG.Filter = SVG.invent({
      create: 'filter',
      inherit: SVG.Parent,
      extend: {
        // Static strings
        source:           'SourceGraphic',
        sourceAlpha:      'SourceAlpha',
        background:       'BackgroundImage',
        backgroundAlpha:  'BackgroundAlpha',
        fill:             'FillPaint',
        stroke:           'StrokePaint',

        autoSetIn: true,
        // Custom put method for leaner code
        put: function(element, i) {
          this.add(element, i);

          if(!element.attr('in') && this.autoSetIn){
            element.attr('in',this.source);
          }
          if(!element.attr('result')){
            element.attr('result',element);
          }

          return element
        },
        // Blend effect
        blend: function(in1, in2, mode) {
          return this.put(new SVG.BlendEffect(in1, in2, mode))
        },
        // ColorMatrix effect
        colorMatrix: function(type, values) {
          return this.put(new SVG.ColorMatrixEffect(type, values))
        },
        // ConvolveMatrix effect
        convolveMatrix: function(matrix) {
          return this.put(new SVG.ConvolveMatrixEffect(matrix))
        },
        // ComponentTransfer effect
        componentTransfer: function(components) {
          return this.put(new SVG.ComponentTransferEffect(components))
        },
        // Composite effect
        composite: function(in1, in2, operator) {
          return this.put(new SVG.CompositeEffect(in1, in2, operator))
        },
        // Flood effect
        flood: function(color, opacity) {
          return this.put(new SVG.FloodEffect(color, opacity))
        },
        // Offset effect
        offset: function(x, y) {
          return this.put(new SVG.OffsetEffect(x,y))
        },
        // Image effect
        image: function(src) {
          return this.put(new SVG.ImageEffect(src))
        },
        // Merge effect
        merge: function() {
          //pass the array of arguments to the constructor because we dont know if the user gave us an array as the first arguemnt or wether they listed the effects in the arguments
          var args = [undefined];
          for(var i in arguments) args.push(arguments[i]);
          return this.put(new (SVG.MergeEffect.bind.apply(SVG.MergeEffect,args)))
        },
        // Gaussian Blur effect
        gaussianBlur: function(x,y) {
          return this.put(new SVG.GaussianBlurEffect(x,y))
        },
        // Morphology effect
        morphology: function(operator,radius){
          return this.put(new SVG.MorphologyEffect(operator,radius))
        },
        // DiffuseLighting effect
        diffuseLighting: function(surfaceScale,diffuseConstant,kernelUnitLength){
          return this.put(new SVG.DiffuseLightingEffect(surfaceScale,diffuseConstant,kernelUnitLength))
        },
        // DisplacementMap effect
        displacementMap: function(in1,in2,scale,xChannelSelector,yChannelSelector){
          return this.put(new SVG.DisplacementMapEffect(in1,in2,scale,xChannelSelector,yChannelSelector))
        },
        // SpecularLighting effect
        specularLighting: function(surfaceScale,diffuseConstant,specularExponent,kernelUnitLength){
          return this.put(new SVG.SpecularLightingEffect(surfaceScale,diffuseConstant,specularExponent,kernelUnitLength))
        },
        // Tile effect
        tile: function(){
          return this.put(new SVG.TileEffect());
        },
        // Turbulence effect
        turbulence: function(baseFrequency,numOctaves,seed,stitchTiles,type){
          return this.put(new SVG.TurbulenceEffect(baseFrequency,numOctaves,seed,stitchTiles,type))
        },
        // Default string value
        toString: function() {
          return 'url(#' + this.attr('id') + ')'
        }
      }
    });

    //add .filter function
    SVG.extend(SVG.Defs, {
      // Define filter
      filter: function(block) {
        var filter = this.put(new SVG.Filter);

        /* invoke passed block */
        if (typeof block === 'function')
          block.call(filter, filter);

        return filter
      }
    });
    SVG.extend(SVG.Container, {
      // Define filter on defs
      filter: function(block) {
        return this.defs().filter(block)
      }
    });
    SVG.extend(SVG.Element, SVG.G, SVG.Nested, {
      // Create filter element in defs and store reference
      filter: function(block) {
        this.filterer = block instanceof SVG.Element ?
          block : this.doc().filter(block);

        if(this.doc() && this.filterer.doc() !== this.doc()){
          this.doc().defs().add(this.filterer);
        }

        this.attr('filter', this.filterer);

        return this.filterer
      },
      // Remove filter
      unfilter: function(remove) {
        /* also remove the filter node */
        if (this.filterer && remove === true)
          this.filterer.remove();

        /* delete reference to filterer */
        delete this.filterer;

        /* remove filter attribute */
        return this.attr('filter', null)
      }
    });

    // Create SVG.Effect class
    SVG.Effect = SVG.invent({
      create: function(){
        this.constructor.call(this);
      },
      inherit: SVG.Element,
      extend: {
        // Set in attribute
        in: function(effect) {
          return effect == null? this.parent() && this.parent().select('[result="'+this.attr('in')+'"]').get(0) || this.attr('in') : this.attr('in', effect)
        },
        // Named result
        result: function(result) {
          return result == null? this.attr('result') : this.attr('result',result)
        },
        // Stringification
        toString: function() {
          return this.result()
        }
      }
    });

    // create class for parent effects like merge
    // Inherit from SVG.Parent
    SVG.ParentEffect = SVG.invent({
      create: function(){
        this.constructor.call(this);
      },
      inherit: SVG.Parent,
      extend: {
        // Set in attribute
        in: function(effect) {
          return effect == null? this.parent() && this.parent().select('[result="'+this.attr('in')+'"]').get(0) || this.attr('in') : this.attr('in', effect)
        },
        // Named result
        result: function(result) {
          return result == null? this.attr('result') : this.attr('result',result)
        },
        // Stringification
        toString: function() {
          return this.result()
        }
      }
    });

    //chaining
    var chainingEffects = {
      // Blend effect
      blend: function(in2, mode) {
        return this.parent() && this.parent().blend(this, in2, mode) //pass this as the first input
      },
      // ColorMatrix effect
      colorMatrix: function(type, values) {
        return this.parent() && this.parent().colorMatrix(type, values).in(this)
      },
      // ConvolveMatrix effect
      convolveMatrix: function(matrix) {
        return this.parent() && this.parent().convolveMatrix(matrix).in(this)
      },
      // ComponentTransfer effect
      componentTransfer: function(components) {
        return this.parent() && this.parent().componentTransfer(components).in(this)
      },
      // Composite effect
      composite: function(in2, operator) {
        return this.parent() && this.parent().composite(this, in2, operator) //pass this as the first input
      },
      // Flood effect
      flood: function(color, opacity) {
        return this.parent() && this.parent().flood(color, opacity) //this effect dont have inputs
      },
      // Offset effect
      offset: function(x, y) {
        return this.parent() && this.parent().offset(x,y).in(this)
      },
      // Image effect
      image: function(src) {
        return this.parent() && this.parent().image(src) //this effect dont have inputs
      },
      // Merge effect
      merge: function() {
        return this.parent() && this.parent().merge.apply(this.parent(),[this].concat(arguments)) //pass this as the first argument
      },
      // Gaussian Blur effect
      gaussianBlur: function(x,y) {
        return this.parent() && this.parent().gaussianBlur(x,y).in(this)
      },
      // Morphology effect
      morphology: function(operator,radius){
        return this.parent() && this.parent().morphology(operator,radius).in(this)
      },
      // DiffuseLighting effect
      diffuseLighting: function(surfaceScale,diffuseConstant,kernelUnitLength){
        return this.parent() && this.parent().diffuseLighting(surfaceScale,diffuseConstant,kernelUnitLength).in(this)
      },
      // DisplacementMap effect
      displacementMap: function(in2,scale,xChannelSelector,yChannelSelector){
        return this.parent() && this.parent().displacementMap(this,in2,scale,xChannelSelector,yChannelSelector) //pass this as the first input
      },
      // SpecularLighting effect
      specularLighting: function(surfaceScale,diffuseConstant,specularExponent,kernelUnitLength){
        return this.parent() && this.parent().specularLighting(surfaceScale,diffuseConstant,specularExponent,kernelUnitLength).in(this)
      },
      // Tile effect
      tile: function(){
        return this.parent() && this.parent().tile().in(this)
      },
      // Turbulence effect
      turbulence: function(baseFrequency,numOctaves,seed,stitchTiles,type){
        return this.parent() && this.parent().turbulence(baseFrequency,numOctaves,seed,stitchTiles,type).in(this)
      }
    };
    SVG.extend(SVG.Effect,chainingEffects);
    SVG.extend(SVG.ParentEffect,chainingEffects);

    //crea class for child effects, like MergeNode, FuncR and lights
    SVG.ChildEffect = SVG.invent({
      create: function(){
        this.constructor.call(this);
      },
      inherit: SVG.Element,
      extend: {
      in: function(effect){
        this.attr('in',effect);
      }
      //dont include any "result" functions because these types of nodes dont have them
      }
    });

    // Create all different effects
    var effects = {
      blend: function(in1,in2,mode){
        this.attr({
          in: in1,
          in2: in2,
          mode: mode || 'normal'
        });
      },
      colorMatrix: function(type,values){
        if (type == 'matrix')
          values = normaliseMatrix(values);

        this.attr({
          type:   type
        , values: typeof values == 'undefined' ? null : values
        });
      },
      convolveMatrix: function(matrix){
        matrix = normaliseMatrix(matrix);

        this.attr({
          order:        Math.sqrt(matrix.split(' ').length)
        , kernelMatrix: matrix
        });
      },
      composite: function(in1, in2, operator){
        this.attr({
          in: in1,
          in2: in2,
          operator: operator
        });
      },
      flood: function(color,opacity){
        this.attr('flood-color',color);
        if(opacity != null) this.attr('flood-opacity',opacity);
      },
      offset: function(x,y){
        this.attr({
          dx: x,
          dy: y
        });
      },
      image: function(src){
        this.attr('href', src, SVG.xlink);
      },
      displacementMap: function(in1,in2,scale,xChannelSelector,yChannelSelector){
        this.attr({
          in: in1,
          in2: in2,
          scale: scale,
          xChannelSelector: xChannelSelector,
          yChannelSelector: yChannelSelector
        });
      },
      gaussianBlur: function(x,y){
        if(x != null || y != null)
          this.attr('stdDeviation', listString(Array.prototype.slice.call(arguments)));
        else
          this.attr('stdDeviation', '0 0');
      },
      morphology: function(operator,radius){
        this.attr({
          operator: operator,
          radius: radius
        });
      },
      tile: function(){

      },
      turbulence: function(baseFrequency,numOctaves,seed,stitchTiles,type){
        this.attr({
          numOctaves: numOctaves,
          seed: seed,
          stitchTiles: stitchTiles,
          baseFrequency: baseFrequency,
          type: type
        });
      }
    };

    // Create all parent effects
    var parentEffects = {
      merge: function(){
        var children;

        //test to see if we have a set
        if(arguments[0] instanceof SVG.Set){
          var that = this;
          arguments[0].each(function(i){
            if(this instanceof SVG.MergeNode)
              that.put(this);
            else if(this instanceof SVG.Effect || this instanceof SVG.ParentEffect)
              that.put(new SVG.MergeNode(this));
          });
        }
        else {
          //if the first argument is an array use it
          if(Array.isArray(arguments[0]))
            children = arguments[0];
          else
            children = arguments;

          for(var i = 0; i < children.length; i++){
            if(children[i] instanceof SVG.MergeNode){
              this.put(children[i]);
            }
            else this.put(new SVG.MergeNode(children[i]));
          }
        }
      },
      componentTransfer: function(compontents){
        /* create rgb set */
        this.rgb = new SVG.Set

        /* create components */
        ;(['r', 'g', 'b', 'a']).forEach(function(c) {
          /* create component */
          this[c] = new SVG['Func' + c.toUpperCase()]('identity');

          /* store component in set */
          this.rgb.add(this[c]);

          /* add component node */
          this.node.appendChild(this[c].node);
        }.bind(this)); //lost context in foreach

        /* set components */
        if (compontents) {
          if (compontents.rgb) {
  (['r', 'g', 'b']).forEach(function(c) {
              this[c].attr(compontents.rgb);
            }.bind(this));

            delete compontents.rgb;
          }

          /* set individual components */
          for (var c in compontents)
            this[c].attr(compontents[c]);
        }
      },
      diffuseLighting: function(surfaceScale,diffuseConstant,kernelUnitLength){
        this.attr({
          surfaceScale: surfaceScale,
          diffuseConstant: diffuseConstant,
          kernelUnitLength: kernelUnitLength
        });
      },
      specularLighting: function(surfaceScale,diffuseConstant,specularExponent,kernelUnitLength){
        this.attr({
          surfaceScale: surfaceScale,
          diffuseConstant: diffuseConstant,
          specularExponent: specularExponent,
          kernelUnitLength: kernelUnitLength
        });
      },
    };

    // Create child effects like PointLight and MergeNode
    var childEffects = {
      distantLight: function(azimuth, elevation){
        this.attr({
          azimuth: azimuth,
          elevation: elevation
        });
      },
      pointLight: function(x,y,z){
        this.attr({
          x: x,
          y: y,
          z: z
        });
      },
      spotLight: function(x,y,z,pointsAtX,pointsAtY,pointsAtZ){
        this.attr({
          x: x,
          y: y,
          z: z,
          pointsAtX: pointsAtX,
          pointsAtY: pointsAtY,
          pointsAtZ: pointsAtZ
        });
      },
      mergeNode: function(in1){
        this.attr('in',in1);
      }
    }

    // Create compontent functions
    ;(['r', 'g', 'b', 'a']).forEach(function(c) {
      /* create class */
      childEffects['Func' + c.toUpperCase()] = function(type) {
        this.attr('type',type);

        // take diffent arguments based on the type
        switch(type){
          case 'table':
            this.attr('tableValues',arguments[1]);
            break
          case 'linear':
            this.attr('slope',arguments[1]);
            this.attr('intercept',arguments[2]);
            break
          case 'gamma':
            this.attr('amplitude',arguments[1]);
            this.attr('exponent',arguments[2]);
            this.attr('offset',arguments[2]);
            break
        }
      };
    });

    //create effects
    foreach(effects,function(effect,i){

      /* capitalize name */
      var name = i.charAt(0).toUpperCase() + i.slice(1);
      var proto = {};

      /* create class */
      SVG[name + 'Effect'] = SVG.invent({
        create: function() {
          //call super
          this.constructor.call(this, SVG.create('fe' + name));

          //call constructor for this effect
          effect.apply(this,arguments);

          //set the result
          this.result(this.attr('id') + 'Out');
        },
        inherit: SVG.Effect,
        extend: proto
      });
    });

    //create parent effects
    foreach(parentEffects,function(effect,i){

      /* capitalize name */
      var name = i.charAt(0).toUpperCase() + i.slice(1);
      var proto = {};

      /* create class */
      SVG[name + 'Effect'] = SVG.invent({
        create: function() {
          //call super
          this.constructor.call(this, SVG.create('fe' + name));

          //call constructor for this effect
          effect.apply(this,arguments);

          //set the result
          this.result(this.attr('id') + 'Out');
        },
        inherit: SVG.ParentEffect,
        extend: proto
      });
    });

    //create child effects
    foreach(childEffects,function(effect,i){

      /* capitalize name */
      var name = i.charAt(0).toUpperCase() + i.slice(1);
      var proto = {};

      /* create class */
      SVG[name] = SVG.invent({
        create: function() {
          //call super
          this.constructor.call(this, SVG.create('fe' + name));

          //call constructor for this effect
          effect.apply(this,arguments);
        },
        inherit: SVG.ChildEffect,
        extend: proto
      });
    });

    // Effect-specific extensions
    SVG.extend(SVG.MergeEffect,{
      in: function(effect){
        if(effect instanceof SVG.MergeNode)
          this.add(effect,0);
        else
          this.add(new SVG.MergeNode(effect),0);

        return this
      }
    });
    SVG.extend(SVG.CompositeEffect,SVG.BlendEffect,SVG.DisplacementMapEffect,{
      in2: function(effect){
          return effect == null? this.parent() && this.parent().select('[result="'+this.attr('in2')+'"]').get(0) || this.attr('in2') : this.attr('in2', effect)
      }
    });

    // Presets
    SVG.filter = {
      sepiatone:  [ .343, .669, .119, 0, 0
                  , .249, .626, .130, 0, 0
                  , .172, .334, .111, 0, 0
                  , .000, .000, .000, 1, 0 ]
    };

    // Helpers
    function normaliseMatrix(matrix) {
      /* convert possible array value to string */
      if (Array.isArray(matrix))
        matrix = new SVG.Array(matrix);

      /* ensure there are no leading, tailing or double spaces */
      return matrix.toString().replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g, ' ')
    }

    function listString(list) {
      if (!Array.isArray(list))
        return list

      for (var i = 0, l = list.length, s = []; i < l; i++)
        s.push(list[i]);

      return s.join(' ')
    }

    function foreach(){ //loops through mutiple objects
      var fn = function(){};
      if(typeof arguments[arguments.length-1] == 'function'){
        fn = arguments[arguments.length-1];
        Array.prototype.splice.call(arguments,arguments.length-1,1);
      }
      for(var k in arguments){
        for(var i in arguments[k]){
          fn(arguments[k][i],i,arguments[k]);
        }
      }
    }

  }).call(undefined);

  (function() {

  SVG.extend(SVG.PathArray, {
    morph: function(array) {

      var startArr = this.value
        ,  destArr = this.parse(array);

      var startOffsetM = 0
        ,  destOffsetM = 0;

      var startOffsetNextM = false
        ,  destOffsetNextM = false;

      while(true){
        // stop if there is no M anymore
        if(startOffsetM === false && destOffsetM === false) break

        // find the next M in path array
        startOffsetNextM = findNextM(startArr, startOffsetM === false ? false : startOffsetM+1);
         destOffsetNextM = findNextM( destArr,  destOffsetM === false ? false :  destOffsetM+1);

        // We have to add one M to the startArray
        if(startOffsetM === false){
          var bbox = new SVG.PathArray(result.start).bbox();

          // when the last block had no bounding box we simply take the first M we got
          if(bbox.height == 0 || bbox.width == 0){
            startOffsetM =  startArr.push(startArr[0]) - 1;
          }else {
            // we take the middle of the bbox instead when we got one
            startOffsetM = startArr.push( ['M', bbox.x + bbox.width/2, bbox.y + bbox.height/2 ] ) - 1;
          }
        }

        // We have to add one M to the destArray
        if( destOffsetM === false){
          var bbox = new SVG.PathArray(result.dest).bbox();

          if(bbox.height == 0 || bbox.width == 0){
            destOffsetM =  destArr.push(destArr[0]) - 1;
          }else {
            destOffsetM =  destArr.push( ['M', bbox.x + bbox.width/2, bbox.y + bbox.height/2 ] ) - 1;
          }
        }

        // handle block from M to next M
        var result = handleBlock(startArr, startOffsetM, startOffsetNextM, destArr, destOffsetM, destOffsetNextM);

        // update the arrays to their new values
        startArr = startArr.slice(0, startOffsetM).concat(result.start, startOffsetNextM === false ? [] : startArr.slice(startOffsetNextM));
         destArr =  destArr.slice(0,  destOffsetM).concat(result.dest ,  destOffsetNextM === false ? [] :  destArr.slice( destOffsetNextM));

        // update offsets
        startOffsetM = startOffsetNextM === false ? false : startOffsetM + result.start.length;
         destOffsetM =  destOffsetNextM === false ? false :  destOffsetM + result.dest.length;

      }

      // copy back arrays
      this.value = startArr;
      this.destination = new SVG.PathArray();
      this.destination.value = destArr;

      return this
    }
  });



  // sorry for the long declaration
  // slices out one block (from M to M) and syncronize it so the types and length match
  function handleBlock(startArr, startOffsetM, startOffsetNextM, destArr, destOffsetM, destOffsetNextM, undefined$1){

    // slice out the block we need
    var startArrTemp = startArr.slice(startOffsetM, startOffsetNextM || undefined$1)
      ,  destArrTemp =  destArr.slice( destOffsetM,  destOffsetNextM || undefined$1);

    var i = 0
      , posStart = {pos:[0,0], start:[0,0]}
      , posDest  = {pos:[0,0], start:[0,0]};

    do{

      // convert shorthand types to long form
      startArrTemp[i] = simplyfy.call(posStart, startArrTemp[i]);
       destArrTemp[i] = simplyfy.call(posDest ,  destArrTemp[i]);

      // check if both shape types match
      // 2 elliptical arc curve commands ('A'), are considered different if the
      // flags (large-arc-flag, sweep-flag) don't match
      if(startArrTemp[i][0] != destArrTemp[i][0] || startArrTemp[i][0] == 'M' ||
          (startArrTemp[i][0] == 'A' &&
            (startArrTemp[i][4] != destArrTemp[i][4] || startArrTemp[i][5] != destArrTemp[i][5])
          )
        ) {

        // if not, convert shapes to beziere
        Array.prototype.splice.apply(startArrTemp, [i, 1].concat(toBeziere.call(posStart, startArrTemp[i])));
         Array.prototype.splice.apply(destArrTemp, [i, 1].concat(toBeziere.call(posDest, destArrTemp[i])));

      } else {

        // only update positions otherwise
        startArrTemp[i] = setPosAndReflection.call(posStart, startArrTemp[i]);
         destArrTemp[i] = setPosAndReflection.call(posDest ,  destArrTemp[i]);

      }

      // we are at the end at both arrays. stop here
      if(++i == startArrTemp.length && i == destArrTemp.length) break

      // destArray is longer. Add one element
      if(i == startArrTemp.length){
        startArrTemp.push([
          'C',
          posStart.pos[0],
          posStart.pos[1],
          posStart.pos[0],
          posStart.pos[1],
          posStart.pos[0],
          posStart.pos[1],
        ]);
      }

      // startArr is longer. Add one element
      if(i == destArrTemp.length){
        destArrTemp.push([
          'C',
          posDest.pos[0],
          posDest.pos[1],
          posDest.pos[0],
          posDest.pos[1],
          posDest.pos[0],
          posDest.pos[1]
        ]);
      }


    }while(true)

    // return the updated block
    return {start:startArrTemp, dest:destArrTemp}
  }

  // converts shorthand types to long form
  function simplyfy(val){

    switch(val[0]){
      case 'z': // shorthand line to start
      case 'Z':
        val[0] = 'L';
        val[1] = this.start[0];
        val[2] = this.start[1];
        break
      case 'H': // shorthand horizontal line
        val[0] = 'L';
        val[2] = this.pos[1];
        break
      case 'V': // shorthand vertical line
        val[0] = 'L';
        val[2] = val[1];
        val[1] = this.pos[0];
        break
      case 'T': // shorthand quadratic beziere
        val[0] = 'Q';
        val[3] = val[1];
        val[4] = val[2];
        val[1] = this.reflection[1];
        val[2] = this.reflection[0];
        break
      case 'S': // shorthand cubic beziere
        val[0] = 'C';
        val[6] = val[4];
        val[5] = val[3];
        val[4] = val[2];
        val[3] = val[1];
        val[2] = this.reflection[1];
        val[1] = this.reflection[0];
        break
    }

    return val

  }

  // updates reflection point and current position
  function setPosAndReflection(val){

    var len = val.length;

    this.pos = [ val[len-2], val[len-1] ];

    if('SCQT'.indexOf(val[0]) != -1)
      this.reflection = [ 2 * this.pos[0] - val[len-4], 2 * this.pos[1] - val[len-3] ];

    return val
  }

  // converts all types to cubic beziere
  function toBeziere(val){
    var retVal = [val];

    switch(val[0]){
      case 'M': // special handling for M
        this.pos = this.start = [val[1], val[2]];
        return retVal
      case 'L':
        val[5] = val[3] = val[1];
        val[6] = val[4] = val[2];
        val[1] = this.pos[0];
        val[2] = this.pos[1];
        break
      case 'Q':
        val[6] = val[4];
        val[5] = val[3];
        val[4] = val[4] * 1/3 + val[2] * 2/3;
        val[3] = val[3] * 1/3 + val[1] * 2/3;
        val[2] = this.pos[1] * 1/3 + val[2] * 2/3;
        val[1] = this.pos[0] * 1/3 + val[1] * 2/3;
        break
      case 'A':
        retVal = arcToBeziere(this.pos, val);
        val = retVal[0];
        break
    }

    val[0] = 'C';
    this.pos = [val[5], val[6]];
    this.reflection = [2 * val[5] - val[3], 2 * val[6] - val[4]];

    return retVal

  }

  // finds the next position of type M
  function findNextM(arr, offset){

    if(offset === false) return false

    for(var i = offset, len = arr.length;i < len;++i){

      if(arr[i][0] == 'M') return i

    }

    return false
  }



  // Convert an arc segment into equivalent cubic Bezier curves
  // Depending on the arc, up to 4 curves might be used to represent it since a
  // curve gives a good approximation for only a quarter of an ellipse
  // The curves are returned as an array of SVG curve commands:
  // [ ['C', x1, y1, x2, y2, x, y] ... ]
  function arcToBeziere(pos, val) {
      // Parameters extraction, handle out-of-range parameters as specified in the SVG spec
      // See: https://www.w3.org/TR/SVG11/implnote.html#ArcOutOfRangeParameters
      var rx = Math.abs(val[1]), ry = Math.abs(val[2]), xAxisRotation = val[3] % 360
        , largeArcFlag = val[4], sweepFlag = val[5], x = val[6], y = val[7]
        , A = new SVG.Point(pos), B = new SVG.Point(x, y)
        , primedCoord, lambda, mat, k, c, cSquare, t, O, OA, OB, tetaStart, tetaEnd
        , deltaTeta, nbSectors, f, arcSegPoints, angle, sinAngle, cosAngle, pt, i, il
        , retVal = [], x1, y1, x2, y2;

      // Ensure radii are non-zero
      if(rx === 0 || ry === 0 || (A.x === B.x && A.y === B.y)) {
        // treat this arc as a straight line segment
        return [['C', A.x, A.y, B.x, B.y, B.x, B.y]]
      }

      // Ensure radii are large enough using the algorithm provided in the SVG spec
      // See: https://www.w3.org/TR/SVG11/implnote.html#ArcCorrectionOutOfRangeRadii
      primedCoord = new SVG.Point((A.x-B.x)/2, (A.y-B.y)/2).transform(new SVG.Matrix().rotate(xAxisRotation));
      lambda = (primedCoord.x * primedCoord.x) / (rx * rx) + (primedCoord.y * primedCoord.y) / (ry * ry);
      if(lambda > 1) {
        lambda = Math.sqrt(lambda);
        rx = lambda*rx;
        ry = lambda*ry;
      }

      // To simplify calculations, we make the arc part of a unit circle (rayon is 1) instead of an ellipse
      mat = new SVG.Matrix().rotate(xAxisRotation).scale(1/rx, 1/ry).rotate(-xAxisRotation);
      A = A.transform(mat);
      B = B.transform(mat);

      // Calculate the horizontal and vertical distance between the initial and final point of the arc
      k = [B.x-A.x, B.y-A.y];

      // Find the length of the chord formed by A and B
      cSquare = k[0]*k[0] + k[1]*k[1];
      c = Math.sqrt(cSquare);

      // Calculate the ratios of the horizontal and vertical distance on the length of the chord
      k[0] /= c;
      k[1] /= c;

      // Calculate the distance between the circle center and the chord midpoint
      // using this formula: t = sqrt(r^2 - c^2 / 4)
      // where t is the distance between the cirle center and the chord midpoint,
      //       r is the rayon of the circle and c is the chord length
      // From: http://www.ajdesigner.com/phpcircle/circle_segment_chord_t.php
      // Because of the imprecision of floating point numbers, cSquare might end
      // up being slightly above 4 which would result in a negative radicand
      // To prevent that, a test is made before computing the square root
      t = (cSquare < 4) ? Math.sqrt(1 - cSquare/4) : 0;

      // For most situations, there are actually two different ellipses that
      // satisfy the constraints imposed by the points A and B, the radii rx and ry,
      // and the xAxisRotation
      // When the flags largeArcFlag and sweepFlag are equal, it means that the
      // second ellipse is used as a solution
      // See: https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
      if(largeArcFlag === sweepFlag) {
          t *= -1;
      }

      // Calculate the coordinates of the center of the circle from the midpoint of the chord
      // This is done by multiplying the ratios calculated previously by the distance between
      // the circle center and the chord midpoint and using these values to go from the midpoint
      // to the center of the circle
      // The negative of the vertical distance ratio is used to modify the x coordinate while
      // the horizontal distance ratio is used to modify the y coordinate
      // That is because the center of the circle is perpendicular to the chord and perpendicular
      // lines are negative reciprocals
      O = new SVG.Point((B.x+A.x)/2 + t*-k[1], (B.y+A.y)/2 + t*k[0]);
      // Move the center of the circle at the origin
      OA = new SVG.Point(A.x-O.x, A.y-O.y);
      OB = new SVG.Point(B.x-O.x, B.y-O.y);

      // Calculate the start and end angle
      tetaStart = Math.acos(OA.x/Math.sqrt(OA.x*OA.x + OA.y*OA.y));
      if (OA.y < 0) {
        tetaStart *= -1;
      }
      tetaEnd = Math.acos(OB.x/Math.sqrt(OB.x*OB.x + OB.y*OB.y));
      if (OB.y < 0) {
        tetaEnd *= -1;
      }

      // If sweep-flag is '1', then the arc will be drawn in a "positive-angle" direction,
      // make sure that the end angle is above the start angle
      if (sweepFlag && tetaStart > tetaEnd) {
        tetaEnd += 2*Math.PI;
      }
      // If sweep-flag is '0', then the arc will be drawn in a "negative-angle" direction,
      // make sure that the end angle is below the start angle
      if (!sweepFlag && tetaStart < tetaEnd) {
        tetaEnd -= 2*Math.PI;
      }

      // Find the number of Bezier curves that are required to represent the arc
      // A cubic Bezier curve gives a good enough approximation when representing at most a quarter of a circle
      nbSectors = Math.ceil(Math.abs(tetaStart-tetaEnd) * 2/Math.PI);

      // Calculate the coordinates of the points of all the Bezier curves required to represent the arc
      // For an in-depth explanation of this part see: http://pomax.github.io/bezierinfo/#circles_cubic
      arcSegPoints = [];
      angle = tetaStart;
      deltaTeta = (tetaEnd-tetaStart)/nbSectors;
      f = 4*Math.tan(deltaTeta/4)/3;
      for (i = 0; i <= nbSectors; i++) { // The <= is because a Bezier curve have a start and a endpoint
        cosAngle = Math.cos(angle);
        sinAngle = Math.sin(angle);

        pt = new SVG.Point(O.x+cosAngle, O.y+sinAngle);
        arcSegPoints[i] = [new SVG.Point(pt.x+f*sinAngle, pt.y-f*cosAngle), pt, new SVG.Point(pt.x-f*sinAngle, pt.y+f*cosAngle)];

        angle += deltaTeta;
      }

      // Remove the first control point of the first segment point and remove the second control point of the last segment point
      // These two control points are not used in the approximation of the arc, that is why they are removed
      arcSegPoints[0][0] = arcSegPoints[0][1].clone();
      arcSegPoints[arcSegPoints.length-1][2] = arcSegPoints[arcSegPoints.length-1][1].clone();

      // Revert the transformation that was applied to make the arc part of a unit circle instead of an ellipse
      mat = new SVG.Matrix().rotate(xAxisRotation).scale(rx, ry).rotate(-xAxisRotation);
      for (i = 0, il = arcSegPoints.length; i < il; i++) {
        arcSegPoints[i][0] = arcSegPoints[i][0].transform(mat);
        arcSegPoints[i][1] = arcSegPoints[i][1].transform(mat);
        arcSegPoints[i][2] = arcSegPoints[i][2].transform(mat);
      }


      // Convert the segments points to SVG curve commands
      for (i = 1, il = arcSegPoints.length; i < il; i++) {
        pt = arcSegPoints[i-1][2];
        x1 = pt.x;
        y1 = pt.y;

        pt = arcSegPoints[i][0];
        x2 = pt.x;
        y2 = pt.y;

        pt = arcSegPoints[i][1];
        x = pt.x;
        y = pt.y;

        retVal.push(['C', x1, y1, x2, y2, x, y]);
      }

      return retVal
  }
  }());

  /*! svg.draggable.js - v2.2.2 - 2019-01-08
  * https://github.com/svgdotjs/svg.draggable.js
  * Copyright (c) 2019 Wout Fierens; Licensed MIT */
  (function() {

    // creates handler, saves it
    function DragHandler(el){
      el.remember('_draggable', this);
      this.el = el;
    }


    // Sets new parameter, starts dragging
    DragHandler.prototype.init = function(constraint, val){
      var _this = this;
      this.constraint = constraint;
      this.value = val;
      this.el.on('mousedown.drag', function(e){ _this.start(e); });
      this.el.on('touchstart.drag', function(e){ _this.start(e); });
    };

    // transforms one point from screen to user coords
    DragHandler.prototype.transformPoint = function(event, offset){
        event = event || window.event;
        var touches = event.changedTouches && event.changedTouches[0] || event;
        this.p.x = touches.clientX - (offset || 0);
        this.p.y = touches.clientY;
        return this.p.matrixTransform(this.m)
    };

    // gets elements bounding box with special handling of groups, nested and use
    DragHandler.prototype.getBBox = function(){

      var box = this.el.bbox();

      if(this.el instanceof SVG.Nested) box = this.el.rbox();

      if (this.el instanceof SVG.G || this.el instanceof SVG.Use || this.el instanceof SVG.Nested) {
        box.x = this.el.x();
        box.y = this.el.y();
      }

      return box
    };

    // start dragging
    DragHandler.prototype.start = function(e){

      // check for left button
      if(e.type == 'click'|| e.type == 'mousedown' || e.type == 'mousemove'){
        if((e.which || e.buttons) != 1){
            return
        }
      }

      var _this = this;

      // fire beforedrag event
      this.el.fire('beforedrag', { event: e, handler: this });
      if(this.el.event().defaultPrevented) return;

      // prevent browser drag behavior as soon as possible
      e.preventDefault();

      // prevent propagation to a parent that might also have dragging enabled
      e.stopPropagation();

      // search for parent on the fly to make sure we can call
      // draggable() even when element is not in the dom currently
      this.parent = this.parent || this.el.parent(SVG.Nested) || this.el.parent(SVG.Doc);
      this.p = this.parent.node.createSVGPoint();

      // save current transformation matrix
      this.m = this.el.node.getScreenCTM().inverse();

      var box = this.getBBox();

      var anchorOffset;

      // fix text-anchor in text-element (#37)
      if(this.el instanceof SVG.Text){
        anchorOffset = this.el.node.getComputedTextLength();

        switch(this.el.attr('text-anchor')){
          case 'middle':
            anchorOffset /= 2;
            break
          case 'start':
            anchorOffset = 0;
            break;
        }
      }

      this.startPoints = {
        // We take absolute coordinates since we are just using a delta here
        point: this.transformPoint(e, anchorOffset),
        box:   box,
        transform: this.el.transform()
      };

      // add drag and end events to window
      SVG.on(window, 'mousemove.drag', function(e){ _this.drag(e); });
      SVG.on(window, 'touchmove.drag', function(e){ _this.drag(e); });
      SVG.on(window, 'mouseup.drag', function(e){ _this.end(e); });
      SVG.on(window, 'touchend.drag', function(e){ _this.end(e); });

      // fire dragstart event
      this.el.fire('dragstart', {event: e, p: this.startPoints.point, m: this.m, handler: this});
    };

    // while dragging
    DragHandler.prototype.drag = function(e){

      var box = this.getBBox()
        , p   = this.transformPoint(e)
        , x   = this.startPoints.box.x + p.x - this.startPoints.point.x
        , y   = this.startPoints.box.y + p.y - this.startPoints.point.y
        , c   = this.constraint
        , gx  = p.x - this.startPoints.point.x
        , gy  = p.y - this.startPoints.point.y;

      this.el.fire('dragmove', {
          event: e
        , p: p
        , m: this.m
        , handler: this
      });

      if(this.el.event().defaultPrevented) return p

      // move the element to its new position, if possible by constraint
      if (typeof c == 'function') {

        var coord = c.call(this.el, x, y, this.m);

        // bool, just show us if movement is allowed or not
        if (typeof coord == 'boolean') {
          coord = {
            x: coord,
            y: coord
          };
        }

        // if true, we just move. If !false its a number and we move it there
        if (coord.x === true) {
          this.el.x(x);
        } else if (coord.x !== false) {
          this.el.x(coord.x);
        }

        if (coord.y === true) {
          this.el.y(y);
        } else if (coord.y !== false) {
          this.el.y(coord.y);
        }

      } else if (typeof c == 'object') {

        // keep element within constrained box
        if (c.minX != null && x < c.minX) {
          x = c.minX;
          gx = x - this.startPoints.box.x;
        } else if (c.maxX != null && x > c.maxX - box.width) {
          x = c.maxX - box.width;
          gx = x - this.startPoints.box.x;
        } if (c.minY != null && y < c.minY) {
          y = c.minY;
          gy = y - this.startPoints.box.y;
        } else if (c.maxY != null && y > c.maxY - box.height) {
          y = c.maxY - box.height;
          gy = y - this.startPoints.box.y;
        }

        if (c.snapToGrid != null) {
          x = x - (x % c.snapToGrid);
          y = y - (y % c.snapToGrid);
          gx = gx - (gx % c.snapToGrid);
          gy = gy - (gy % c.snapToGrid);
        }

        if(this.el instanceof SVG.G)
          this.el.matrix(this.startPoints.transform).transform({x:gx, y: gy}, true);
        else
          this.el.move(x, y);
      }

      // so we can use it in the end-method, too
      return p
    };

    DragHandler.prototype.end = function(e){

      // final drag
      var p = this.drag(e);

      // fire dragend event
      this.el.fire('dragend', { event: e, p: p, m: this.m, handler: this });

      // unbind events
      SVG.off(window, 'mousemove.drag');
      SVG.off(window, 'touchmove.drag');
      SVG.off(window, 'mouseup.drag');
      SVG.off(window, 'touchend.drag');

    };

    SVG.extend(SVG.Element, {
      // Make element draggable
      // Constraint might be an object (as described in readme.md) or a function in the form "function (x, y)" that gets called before every move.
      // The function can return a boolean or an object of the form {x, y}, to which the element will be moved. "False" skips moving, true moves to raw x, y.
      draggable: function(value, constraint) {

        // Check the parameters and reassign if needed
        if (typeof value == 'function' || typeof value == 'object') {
          constraint = value;
          value = true;
        }

        var dragHandler = this.remember('_draggable') || new DragHandler(this);

        // When no parameter is given, value is true
        value = typeof value === 'undefined' ? true : value;

        if(value) dragHandler.init(constraint || {}, value);
        else {
          this.off('mousedown.drag');
          this.off('touchstart.drag');
        }

        return this
      }

    });

  }).call(undefined);

  (function() {

  function SelectHandler(el) {

      this.el = el;
      el.remember('_selectHandler', this);
      this.pointSelection = {isSelected: false};
      this.rectSelection = {isSelected: false};

      // helper list with position settings of each type of point
      this.pointsList = {
        lt: [ 0, 0 ],
        rt: [ 'width', 0 ],
        rb: [ 'width', 'height' ],
        lb: [ 0, 'height' ],
        t: [ 'width', 0 ],
        r: [ 'width', 'height' ],
        b: [ 'width', 'height' ],
        l: [ 0, 'height' ]
      };

      // helper function to get point coordinates based on settings above and an object (bbox in our case)
      this.pointCoord = function (setting, object, isPointCentered) {
        var coord = typeof setting !== 'string' ? setting : object[setting];
        // Top, bottom, right and left points are placed in the center of element width/height
        return isPointCentered ? coord / 2 : coord
      };

      this.pointCoords = function (point, object) {
        var settings = this.pointsList[point];

        return {
          x: this.pointCoord(settings[0], object, (point === 't' || point === 'b')),
          y: this.pointCoord(settings[1], object, (point === 'r' || point === 'l'))
        }
      };
  }

  SelectHandler.prototype.init = function (value, options) {

      var bbox = this.el.bbox();
      this.options = {};

      // store defaults list of points in order to verify users config
      var points = this.el.selectize.defaults.points;

      // Merging the defaults and the options-object together
      for (var i in this.el.selectize.defaults) {
          this.options[i] = this.el.selectize.defaults[i];
          if (options[i] !== undefined) {
              this.options[i] = options[i];
          }
      }

      // prepare & validate list of points to be added (or excluded)
      var pointsLists = ['points', 'pointsExclude'];

      for (var i in pointsLists) {
        var option = this.options[pointsLists[i]];

        if (typeof option === 'string') {
          if (option.length > 0) {
            // if set as comma separated string list => convert it into an array
            option = option.split(/\s*,\s*/i);
          } else {
            option = [];
          }
        } else if (typeof option === 'boolean' && pointsLists[i] === 'points') {
          // this is not needed, but let's have it for legacy support
          option = option ? points : [];
        }

        this.options[pointsLists[i]] = option;
      }

      // intersect correct all points options with users config (exclude unwanted points)
      // ES5 -> NO arrow functions nor Array.includes()
      this.options.points = [ points, this.options.points ].reduce(
        function (a, b) {
          return a.filter(
            function (c) {
              return b.indexOf(c) > -1;
            }
          )
        }
      );

      // exclude pointsExclude, if wanted
      this.options.points = [ this.options.points, this.options.pointsExclude ].reduce(
        function (a, b) {
          return a.filter(
            function (c) {
              return b.indexOf(c) < 0;
            }
          )
        }
      );

      this.parent = this.el.parent();
      this.nested = (this.nested || this.parent.group());
      this.nested.matrix(new SVG.Matrix(this.el).translate(bbox.x, bbox.y));

      // When deepSelect is enabled and the element is a line/polyline/polygon, draw only points for moving
      if (this.options.deepSelect && ['line', 'polyline', 'polygon'].indexOf(this.el.type) !== -1) {
          this.selectPoints(value);
      } else {
          this.selectRect(value);
      }

      this.observe();
      this.cleanup();

  };

  SelectHandler.prototype.selectPoints = function (value) {

      this.pointSelection.isSelected = value;

      // When set is already there we dont have to create one
      if (this.pointSelection.set) {
          return this;
      }

      // Create our set of elements
      this.pointSelection.set = this.parent.set();
      // draw the points and mark the element as selected
      this.drawPoints();

      return this;

  };

  // create the point-array which contains the 2 points of a line or simply the points-array of polyline/polygon
  SelectHandler.prototype.getPointArray = function () {
      var bbox = this.el.bbox();

      return this.el.array().valueOf().map(function (el) {
          return [el[0] - bbox.x, el[1] - bbox.y];
      });
  };

  // Draws a points
  SelectHandler.prototype.drawPoints = function () {

      var _this = this, array = this.getPointArray();

      // go through the array of points
      for (var i = 0, len = array.length; i < len; ++i) {

          var curriedEvent = (function (k) {
              return function (ev) {
                  ev = ev || window.event;
                  ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
                  ev.stopPropagation();

                  var x = ev.pageX || ev.touches[0].pageX;
                  var y = ev.pageY || ev.touches[0].pageY;
                  _this.el.fire('point', {x: x, y: y, i: k, event: ev});
              };
          })(i);

          // add every point to the set
          // add css-classes and a touchstart-event which fires our event for moving points
          var point = this.drawPoint(array[i][0], array[i][1])
                          .addClass(this.options.classPoints)
                          .addClass(this.options.classPoints + '_point')
                          .on('touchstart', curriedEvent)
                          .on('mousedown', curriedEvent);
          this.pointSelection.set.add(point);
      }
  };

  // The function to draw single point
  SelectHandler.prototype.drawPoint = function (cx, cy) {
      var pointType = this.options.pointType;

      switch (pointType) {
          case 'circle':
              return this.drawCircle(cx, cy);
          case 'rect':
              return this.drawRect(cx, cy);
          default:
              if (typeof pointType === 'function') {
                  return pointType.call(this, cx, cy);
              }

              throw new Error('Unknown ' + pointType + ' point type!');
      }
  };

  // The function to draw the circle point
  SelectHandler.prototype.drawCircle = function (cx, cy) {
      return this.nested.circle(this.options.pointSize)
                        .center(cx, cy);
  };

  // The function to draw the rect point
  SelectHandler.prototype.drawRect = function (cx, cy) {
      return this.nested.rect(this.options.pointSize, this.options.pointSize)
                        .center(cx, cy);
  };

  // every time a point is moved, we have to update the positions of our point
  SelectHandler.prototype.updatePointSelection = function () {
      var array = this.getPointArray();

      this.pointSelection.set.each(function (i) {
          if (this.cx() === array[i][0] && this.cy() === array[i][1]) {
              return;
          }
          this.center(array[i][0], array[i][1]);
      });
  };

  SelectHandler.prototype.updateRectSelection = function () {
      var _this = this, bbox = this.el.bbox();

      this.rectSelection.set.get(0).attr({
          width: bbox.width,
          height: bbox.height
      });

      // set.get(1) is always in the upper left corner. no need to move it
      if (this.options.points.length) {
        this.options.points.map(function (point, index) {
          var coords = _this.pointCoords(point, bbox);

          _this.rectSelection.set.get(index + 1).center(coords.x, coords.y);
        });
      }

      if (this.options.rotationPoint) {
          var length = this.rectSelection.set.length();

          this.rectSelection.set.get(length - 1).center(bbox.width / 2, 20);
      }
  };

  SelectHandler.prototype.selectRect = function (value) {

      var _this = this, bbox = this.el.bbox();

      this.rectSelection.isSelected = value;

      // when set is already p
      this.rectSelection.set = this.rectSelection.set || this.parent.set();

      // helperFunction to create a mouse-down function which triggers the event specified in `eventName`
      function getMoseDownFunc(eventName) {
          return function (ev) {
              ev = ev || window.event;
              ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
              ev.stopPropagation();

              var x = ev.pageX || ev.touches[0].pageX;
              var y = ev.pageY || ev.touches[0].pageY;
              _this.el.fire(eventName, {x: x, y: y, event: ev});
          };
      }

      // create the selection-rectangle and add the css-class
      if (!this.rectSelection.set.get(0)) {
          this.rectSelection.set.add(this.nested.rect(bbox.width, bbox.height).addClass(this.options.classRect));
      }

      // Draw Points at the edges, if enabled
      if (this.options.points.length && this.rectSelection.set.length() < 2) {
          var ename ="touchstart", mname = "mousedown";

          this.options.points.map(function (point, index) {
              var coords = _this.pointCoords(point, bbox);

              var pointElement = _this.drawPoint(coords.x, coords.y)
                                      .attr('class', _this.options.classPoints + '_' + point)
                                      .on(mname, getMoseDownFunc(point))
                                      .on(ename, getMoseDownFunc(point));
              _this.rectSelection.set.add(pointElement);
          });

          this.rectSelection.set.each(function () {
              this.addClass(_this.options.classPoints);
          });
      }

      // draw rotationPint, if enabled
      if (this.options.rotationPoint && ((this.options.points && !this.rectSelection.set.get(9)) || (!this.options.points && !this.rectSelection.set.get(1)))) {

          var curriedEvent = function (ev) {
              ev = ev || window.event;
              ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
              ev.stopPropagation();

              var x = ev.pageX || ev.touches[0].pageX;
              var y = ev.pageY || ev.touches[0].pageY;
              _this.el.fire('rot', {x: x, y: y, event: ev});
          };

          var pointElement = this.drawPoint(bbox.width / 2, 20)
                                .attr('class', this.options.classPoints + '_rot')
                                .on("touchstart", curriedEvent)
                                .on("mousedown", curriedEvent);
          this.rectSelection.set.add(pointElement);
      }

  };

  SelectHandler.prototype.handler = function () {

      var bbox = this.el.bbox();
      this.nested.matrix(new SVG.Matrix(this.el).translate(bbox.x, bbox.y));

      if (this.rectSelection.isSelected) {
          this.updateRectSelection();
      }

      if (this.pointSelection.isSelected) {
          this.updatePointSelection();
      }

  };

  SelectHandler.prototype.observe = function () {
      var _this = this;

      if (MutationObserver) {
          if (this.rectSelection.isSelected || this.pointSelection.isSelected) {
              this.observerInst = this.observerInst || new MutationObserver(function () {
                  _this.handler();
              });
              this.observerInst.observe(this.el.node, {attributes: true});
          } else {
              try {
                  this.observerInst.disconnect();
                  delete this.observerInst;
              } catch (e) {
              }
          }
      } else {
          this.el.off('DOMAttrModified.select');

          if (this.rectSelection.isSelected || this.pointSelection.isSelected) {
              this.el.on('DOMAttrModified.select', function () {
                  _this.handler();
              });
          }
      }
  };

  SelectHandler.prototype.cleanup = function () {

      //var _this = this;

      if (!this.rectSelection.isSelected && this.rectSelection.set) {
          // stop watching the element, remove the selection
          this.rectSelection.set.each(function () {
              this.remove();
          });

          this.rectSelection.set.clear();
          delete this.rectSelection.set;
      }

      if (!this.pointSelection.isSelected && this.pointSelection.set) {
          // Remove all points, clear the set, stop watching the element
          this.pointSelection.set.each(function () {
              this.remove();
          });

          this.pointSelection.set.clear();
          delete this.pointSelection.set;
      }

      if (!this.pointSelection.isSelected && !this.rectSelection.isSelected) {
          this.nested.remove();
          delete this.nested;

      }
  };


  SVG.extend(SVG.Element, {
      // Select element with mouse
      selectize: function (value, options) {

          // Check the parameters and reassign if needed
          if (typeof value === 'object') {
              options = value;
              value = true;
          }

          var selectHandler = this.remember('_selectHandler') || new SelectHandler(this);

          selectHandler.init(value === undefined ? true : value, options || {});

          return this;

      }
  });

  SVG.Element.prototype.selectize.defaults = {
      points: ['lt', 'rt', 'rb', 'lb', 't', 'r', 'b', 'l'],    // which points to draw, default all
      pointsExclude: [],                       // easier option if to exclude few than rewrite all
      classRect: 'svg_select_boundingRect',    // Css-class added to the rect
      classPoints: 'svg_select_points',        // Css-class added to the points
      pointSize: 7,                            // size of point
      rotationPoint: true,                     // If true, rotation point is drawn. Needed for rotation!
      deepSelect: false,                       // If true, moving of single points is possible (only line, polyline, polyon)
      pointType: 'circle'                      // Point type: circle or rect, default circle
  };
  }());

  (function() {
  (function () {

      function ResizeHandler(el) {

          el.remember('_resizeHandler', this);

          this.el = el;
          this.parameters = {};
          this.lastUpdateCall = null;
          this.p = el.doc().node.createSVGPoint();
      }

      ResizeHandler.prototype.transformPoint = function(x, y, m){

          this.p.x = x - (this.offset.x - window.pageXOffset);
          this.p.y = y - (this.offset.y - window.pageYOffset);

          return this.p.matrixTransform(m || this.m);

      };

      ResizeHandler.prototype._extractPosition = function(event) {
          // Extract a position from a mouse/touch event.
          // Returns { x: .., y: .. }
          return {
              x: event.clientX != null ? event.clientX : event.touches[0].clientX,
              y: event.clientY != null ? event.clientY : event.touches[0].clientY
          }
      };

      ResizeHandler.prototype.init = function (options) {

          var _this = this;

          this.stop();

          if (options === 'stop') {
              return;
          }

          this.options = {};

          // Merge options and defaults
          for (var i in this.el.resize.defaults) {
              this.options[i] = this.el.resize.defaults[i];
              if (typeof options[i] !== 'undefined') {
                  this.options[i] = options[i];
              }
          }

          // We listen to all these events which are specifying different edges
          this.el.on('lt.resize', function(e){ _this.resize(e || window.event); });  // Left-Top
          this.el.on('rt.resize', function(e){ _this.resize(e || window.event); });  // Right-Top
          this.el.on('rb.resize', function(e){ _this.resize(e || window.event); });  // Right-Bottom
          this.el.on('lb.resize', function(e){ _this.resize(e || window.event); });  // Left-Bottom

          this.el.on('t.resize', function(e){ _this.resize(e || window.event); });   // Top
          this.el.on('r.resize', function(e){ _this.resize(e || window.event); });   // Right
          this.el.on('b.resize', function(e){ _this.resize(e || window.event); });   // Bottom
          this.el.on('l.resize', function(e){ _this.resize(e || window.event); });   // Left

          this.el.on('rot.resize', function(e){ _this.resize(e || window.event); }); // Rotation

          this.el.on('point.resize', function(e){ _this.resize(e || window.event); }); // Point-Moving

          // This call ensures, that the plugin reacts to a change of snapToGrid immediately
          this.update();

      };

      ResizeHandler.prototype.stop = function(){
          this.el.off('lt.resize');
          this.el.off('rt.resize');
          this.el.off('rb.resize');
          this.el.off('lb.resize');

          this.el.off('t.resize');
          this.el.off('r.resize');
          this.el.off('b.resize');
          this.el.off('l.resize');

          this.el.off('rot.resize');

          this.el.off('point.resize');

          return this;
      };

      ResizeHandler.prototype.resize = function (event) {

          var _this = this;

          this.m = this.el.node.getScreenCTM().inverse();
          this.offset = { x: window.pageXOffset, y: window.pageYOffset };

          var txPt = this._extractPosition(event.detail.event);
          this.parameters = {
              type: this.el.type, // the type of element
              p: this.transformPoint(txPt.x, txPt.y),
              x: event.detail.x,      // x-position of the mouse when resizing started
              y: event.detail.y,      // y-position of the mouse when resizing started
              box: this.el.bbox(),    // The bounding-box of the element
              rotation: this.el.transform().rotation  // The current rotation of the element
          };

          // Add font-size parameter if the element type is text
          if (this.el.type === "text") {
              this.parameters.fontSize = this.el.attr()["font-size"];
          }

          // the i-param in the event holds the index of the point which is moved, when using `deepSelect`
          if (event.detail.i !== undefined) {

              // get the point array
              var array = this.el.array().valueOf();

              // Save the index and the point which is moved
              this.parameters.i = event.detail.i;
              this.parameters.pointCoords = [array[event.detail.i][0], array[event.detail.i][1]];
          }

          // Lets check which edge of the bounding-box was clicked and resize the this.el according to this
          switch (event.type) {

              // Left-Top-Edge
              case 'lt':
                  // We build a calculating function for every case which gives us the new position of the this.el
                  this.calc = function (diffX, diffY) {
                      // The procedure is always the same
                      // First we snap the edge to the given grid (snapping to 1px grid is normal resizing)
                      var snap = this.snapToGrid(diffX, diffY);

                      // Now we check if the new height and width still valid (> 0)
                      if (this.parameters.box.width - snap[0] > 0 && this.parameters.box.height - snap[1] > 0) {
                          // ...if valid, we resize the this.el (which can include moving because the coord-system starts at the left-top and this edge is moving sometimes when resized)

                          /*
                           * but first check if the element is text box, so we can change the font size instead of
                           * the width and height
                           */

                          if (this.parameters.type === "text") {
                              this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y);
                              this.el.attr("font-size", this.parameters.fontSize - snap[0]);
                              return;
                          }

                          snap = this.checkAspectRatio(snap);

                          this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y + snap[1]).size(this.parameters.box.width - snap[0], this.parameters.box.height - snap[1]);
                      }
                  };
                  break;

              // Right-Top
              case 'rt':
                  // s.a.
                  this.calc = function (diffX, diffY) {
                      var snap = this.snapToGrid(diffX, diffY, 1 << 1);
                      if (this.parameters.box.width + snap[0] > 0 && this.parameters.box.height - snap[1] > 0) {
                          if (this.parameters.type === "text") {
                              this.el.move(this.parameters.box.x - snap[0], this.parameters.box.y);
                              this.el.attr("font-size", this.parameters.fontSize + snap[0]);
                              return;
                          }

                          snap = this.checkAspectRatio(snap, true);

                          this.el.move(this.parameters.box.x, this.parameters.box.y + snap[1]).size(this.parameters.box.width + snap[0], this.parameters.box.height - snap[1]);
                      }
                  };
                  break;

              // Right-Bottom
              case 'rb':
                  // s.a.
                  this.calc = function (diffX, diffY) {
                      var snap = this.snapToGrid(diffX, diffY, 0);
                      if (this.parameters.box.width + snap[0] > 0 && this.parameters.box.height + snap[1] > 0) {
                          if (this.parameters.type === "text") {
                              this.el.move(this.parameters.box.x - snap[0], this.parameters.box.y);
                              this.el.attr("font-size", this.parameters.fontSize + snap[0]);
                              return;
                          }

                          snap = this.checkAspectRatio(snap);

                          this.el.move(this.parameters.box.x, this.parameters.box.y).size(this.parameters.box.width + snap[0], this.parameters.box.height + snap[1]);
                      }
                  };
                  break;

              // Left-Bottom
              case 'lb':
                  // s.a.
                  this.calc = function (diffX, diffY) {
                      var snap = this.snapToGrid(diffX, diffY, 1);
                      if (this.parameters.box.width - snap[0] > 0 && this.parameters.box.height + snap[1] > 0) {
                          if (this.parameters.type === "text") {
                              this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y);
                              this.el.attr("font-size", this.parameters.fontSize - snap[0]);
                              return;
                          }

                          snap = this.checkAspectRatio(snap, true);

                          this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y).size(this.parameters.box.width - snap[0], this.parameters.box.height + snap[1]);
                      }
                  };
                  break;

              // Top
              case 't':
                  // s.a.
                  this.calc = function (diffX, diffY) {
                      var snap = this.snapToGrid(diffX, diffY, 1 << 1);
                      if (this.parameters.box.height - snap[1] > 0) {
                          // Disable the font-resizing if it is not from the corner of bounding-box
                          if (this.parameters.type === "text") {
                              return;
                          }

                          this.el.move(this.parameters.box.x, this.parameters.box.y + snap[1]).height(this.parameters.box.height - snap[1]);
                      }
                  };
                  break;

              // Right
              case 'r':
                  // s.a.
                  this.calc = function (diffX, diffY) {
                      var snap = this.snapToGrid(diffX, diffY, 0);
                      if (this.parameters.box.width + snap[0] > 0) {
                          if (this.parameters.type === "text") {
                              return;
                          }

                          this.el.move(this.parameters.box.x, this.parameters.box.y).width(this.parameters.box.width + snap[0]);
                      }
                  };
                  break;

              // Bottom
              case 'b':
                  // s.a.
                  this.calc = function (diffX, diffY) {
                      var snap = this.snapToGrid(diffX, diffY, 0);
                      if (this.parameters.box.height + snap[1] > 0) {
                          if (this.parameters.type === "text") {
                              return;
                          }

                          this.el.move(this.parameters.box.x, this.parameters.box.y).height(this.parameters.box.height + snap[1]);
                      }
                  };
                  break;

              // Left
              case 'l':
                  // s.a.
                  this.calc = function (diffX, diffY) {
                      var snap = this.snapToGrid(diffX, diffY, 1);
                      if (this.parameters.box.width - snap[0] > 0) {
                          if (this.parameters.type === "text") {
                              return;
                          }

                          this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y).width(this.parameters.box.width - snap[0]);
                      }
                  };
                  break;

              // Rotation
              case 'rot':
                  // s.a.
                  this.calc = function (diffX, diffY) {

                      // yes this is kinda stupid but we need the mouse coords back...
                      var current = {x: diffX + this.parameters.p.x, y: diffY + this.parameters.p.y};

                      // start minus middle
                      var sAngle = Math.atan2((this.parameters.p.y - this.parameters.box.y - this.parameters.box.height / 2), (this.parameters.p.x - this.parameters.box.x - this.parameters.box.width / 2));

                      // end minus middle
                      var pAngle = Math.atan2((current.y - this.parameters.box.y - this.parameters.box.height / 2), (current.x - this.parameters.box.x - this.parameters.box.width / 2));

                      var angle = this.parameters.rotation + (pAngle - sAngle) * 180 / Math.PI + this.options.snapToAngle / 2;

                      // We have to move the element to the center of the box first and change the rotation afterwards
                      // because rotation always works around a rotation-center, which is changed when moving the element
                      // We also set the new rotation center to the center of the box.
                      this.el.center(this.parameters.box.cx, this.parameters.box.cy).rotate(angle - (angle % this.options.snapToAngle), this.parameters.box.cx, this.parameters.box.cy);
                  };
                  break;

              // Moving one single Point (needed when an element is deepSelected which means you can move every single point of the object)
              case 'point':
                  this.calc = function (diffX, diffY) {

                      // Snapping the point to the grid
                      var snap = this.snapToGrid(diffX, diffY, this.parameters.pointCoords[0], this.parameters.pointCoords[1]);

                      // Get the point array
                      var array = this.el.array().valueOf();

                      // Changing the moved point in the array
                      array[this.parameters.i][0] = this.parameters.pointCoords[0] + snap[0];
                      array[this.parameters.i][1] = this.parameters.pointCoords[1] + snap[1];

                      // And plot the new this.el
                      this.el.plot(array);
                  };
          }

          this.el.fire('resizestart', {dx: this.parameters.x, dy: this.parameters.y, event: event});
          // When resizing started, we have to register events for...
          // Touches.
          SVG.on(window, 'touchmove.resize', function(e) {
              _this.update(e || window.event);
          });
          SVG.on(window, 'touchend.resize', function() {
              _this.done();
          });
          // Mouse.
          SVG.on(window, 'mousemove.resize', function (e) {
              _this.update(e || window.event);
          });
          SVG.on(window, 'mouseup.resize', function () {
              _this.done();
          });

      };

      // The update-function redraws the element every time the mouse is moving
      ResizeHandler.prototype.update = function (event) {

          if (!event) {
              if (this.lastUpdateCall) {
                  this.calc(this.lastUpdateCall[0], this.lastUpdateCall[1]);
              }
              return;
          }

          // Calculate the difference between the mouseposition at start and now
          var txPt = this._extractPosition(event);
          var p = this.transformPoint(txPt.x, txPt.y);

          var diffX = p.x - this.parameters.p.x,
              diffY = p.y - this.parameters.p.y;

          this.lastUpdateCall = [diffX, diffY];

          // Calculate the new position and height / width of the element
          this.calc(diffX, diffY);

         // Emit an event to say we have changed.
          this.el.fire('resizing', {dx: diffX, dy: diffY, event: event});
      };

      // Is called on mouseup.
      // Removes the update-function from the mousemove event
      ResizeHandler.prototype.done = function () {
          this.lastUpdateCall = null;
          SVG.off(window, 'mousemove.resize');
          SVG.off(window, 'mouseup.resize');
          SVG.off(window, 'touchmove.resize');
          SVG.off(window, 'touchend.resize');
          this.el.fire('resizedone');
      };

      // The flag is used to determine whether the resizing is used with a left-Point (first bit) and top-point (second bit)
      // In this cases the temp-values are calculated differently
      ResizeHandler.prototype.snapToGrid = function (diffX, diffY, flag, pointCoordsY) {

          var temp;

          // If `pointCoordsY` is given, a single Point has to be snapped (deepSelect). That's why we need a different temp-value
          if (typeof pointCoordsY !== 'undefined') {
              // Note that flag = pointCoordsX in this case
              temp = [(flag + diffX) % this.options.snapToGrid, (pointCoordsY + diffY) % this.options.snapToGrid];
          } else {
              // We check if the flag is set and if not we set a default-value (both bits set - which means upper-left-edge)
              flag = flag == null ? 1 | 1 << 1 : flag;
              temp = [(this.parameters.box.x + diffX + (flag & 1 ? 0 : this.parameters.box.width)) % this.options.snapToGrid, (this.parameters.box.y + diffY + (flag & (1 << 1) ? 0 : this.parameters.box.height)) % this.options.snapToGrid];
          }

          if(diffX < 0) {
              temp[0] -= this.options.snapToGrid;
          }
          if(diffY < 0) {
              temp[1] -= this.options.snapToGrid;
          }

          diffX -= (Math.abs(temp[0]) < this.options.snapToGrid / 2 ?
                    temp[0] :
                    temp[0] - (diffX < 0 ? -this.options.snapToGrid : this.options.snapToGrid));
          diffY -= (Math.abs(temp[1]) < this.options.snapToGrid / 2 ?
                    temp[1] :
                    temp[1] - (diffY < 0 ? -this.options.snapToGrid : this.options.snapToGrid));

          return this.constraintToBox(diffX, diffY, flag, pointCoordsY);

      };

      // keep element within constrained box
      ResizeHandler.prototype.constraintToBox = function (diffX, diffY, flag, pointCoordsY) {
          //return [diffX, diffY]
          var c = this.options.constraint || {};
          var orgX, orgY;

          if (typeof pointCoordsY !== 'undefined') {
            orgX = flag;
            orgY = pointCoordsY;
          } else {
            orgX = this.parameters.box.x + (flag & 1 ? 0 : this.parameters.box.width);
            orgY = this.parameters.box.y + (flag & (1<<1) ? 0 : this.parameters.box.height);
          }

          if (typeof c.minX !== 'undefined' && orgX + diffX < c.minX) {
            diffX = c.minX - orgX;
          }

          if (typeof c.maxX !== 'undefined' && orgX + diffX > c.maxX) {
            diffX = c.maxX - orgX;
          }

          if (typeof c.minY !== 'undefined' && orgY + diffY < c.minY) {
            diffY = c.minY - orgY;
          }

          if (typeof c.maxY !== 'undefined' && orgY + diffY > c.maxY) {
            diffY = c.maxY - orgY;
          }

          return [diffX, diffY];
      };

      ResizeHandler.prototype.checkAspectRatio = function (snap, isReverse) {
          if (!this.options.saveAspectRatio) {
              return snap;
          }

          var updatedSnap = snap.slice();
          var aspectRatio = this.parameters.box.width / this.parameters.box.height;
          var newW = this.parameters.box.width + snap[0];
          var newH = this.parameters.box.height - snap[1];
          var newAspectRatio = newW / newH;

          if (newAspectRatio < aspectRatio) {
              // Height is too big. Adapt it
              updatedSnap[1] = newW / aspectRatio - this.parameters.box.height;
              isReverse && (updatedSnap[1] = -updatedSnap[1]);
          } else if (newAspectRatio > aspectRatio) {
              // Width is too big. Adapt it
              updatedSnap[0] = this.parameters.box.width - newH * aspectRatio;
              isReverse && (updatedSnap[0] = -updatedSnap[0]);
          }

          return updatedSnap;
      };

      SVG.extend(SVG.Element, {
          // Resize element with mouse
          resize: function (options) {

              (this.remember('_resizeHandler') || new ResizeHandler(this)).init(options || {});

              return this;

          }

      });

      SVG.Element.prototype.resize.defaults = {
          snapToAngle: 0.1,       // Specifies the speed the rotation is happening when moving the mouse
          snapToGrid: 1,          // Snaps to a grid of `snapToGrid` Pixels
          constraint: {},         // keep element within constrained box
          saveAspectRatio: false  // Save aspect ratio when resizing using lt, rt, rb or lb points
      };

  }).call(this);
  }());

  // global Apex object which user can use to override chart's defaults globally
  if (typeof window.Apex === 'undefined') {
    window.Apex = {};
  }
  var InitCtxVariables = /*#__PURE__*/function () {
    function InitCtxVariables(ctx) {
      _classCallCheck(this, InitCtxVariables);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(InitCtxVariables, [{
      key: "initModules",
      value: function initModules() {
        this.ctx.publicMethods = ['updateOptions', 'updateSeries', 'appendData', 'appendSeries', 'isSeriesHidden', 'highlightSeries', 'toggleSeries', 'showSeries', 'hideSeries', 'setLocale', 'resetSeries', 'zoomX', 'toggleDataPointSelection', 'dataURI', 'exportToCSV', 'addXaxisAnnotation', 'addYaxisAnnotation', 'addPointAnnotation', 'clearAnnotations', 'removeAnnotation', 'paper', 'destroy'];
        this.ctx.eventList = ['click', 'mousedown', 'mousemove', 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'mouseup', 'touchend'];
        this.ctx.animations = new Animations(this.ctx);
        this.ctx.axes = new Axes(this.ctx);
        this.ctx.core = new Core(this.ctx.el, this.ctx);
        this.ctx.config = new Config({});
        this.ctx.data = new Data(this.ctx);
        this.ctx.grid = new Grid(this.ctx);
        this.ctx.graphics = new Graphics(this.ctx);
        this.ctx.coreUtils = new CoreUtils(this.ctx);
        this.ctx.crosshairs = new Crosshairs(this.ctx);
        this.ctx.events = new Events(this.ctx);
        this.ctx.exports = new Exports(this.ctx);
        this.ctx.fill = new Fill(this.ctx);
        this.ctx.localization = new Localization(this.ctx);
        this.ctx.options = new Options();
        this.ctx.responsive = new Responsive(this.ctx);
        this.ctx.series = new Series(this.ctx);
        this.ctx.theme = new Theme(this.ctx);
        this.ctx.formatters = new Formatters(this.ctx);
        this.ctx.titleSubtitle = new TitleSubtitle(this.ctx);
        this.ctx.legend = new Legend(this.ctx);
        this.ctx.toolbar = new Toolbar(this.ctx);
        this.ctx.tooltip = new Tooltip(this.ctx);
        this.ctx.dimensions = new Dimensions(this.ctx);
        this.ctx.updateHelpers = new UpdateHelpers(this.ctx);
        this.ctx.zoomPanSelection = new ZoomPanSelection(this.ctx);
        this.ctx.w.globals.tooltip = new Tooltip(this.ctx);
      }
    }]);
    return InitCtxVariables;
  }();

  var Destroy = /*#__PURE__*/function () {
    function Destroy(ctx) {
      _classCallCheck(this, Destroy);
      this.ctx = ctx;
      this.w = ctx.w;
    }
    _createClass(Destroy, [{
      key: "clear",
      value: function clear(_ref) {
        var isUpdating = _ref.isUpdating;
        if (this.ctx.zoomPanSelection) {
          this.ctx.zoomPanSelection.destroy();
        }
        if (this.ctx.toolbar) {
          this.ctx.toolbar.destroy();
        }
        this.ctx.animations = null;
        this.ctx.axes = null;
        this.ctx.annotations = null;
        this.ctx.core = null;
        this.ctx.data = null;
        this.ctx.grid = null;
        this.ctx.series = null;
        this.ctx.responsive = null;
        this.ctx.theme = null;
        this.ctx.formatters = null;
        this.ctx.titleSubtitle = null;
        this.ctx.legend = null;
        this.ctx.dimensions = null;
        this.ctx.options = null;
        this.ctx.crosshairs = null;
        this.ctx.zoomPanSelection = null;
        this.ctx.updateHelpers = null;
        this.ctx.toolbar = null;
        this.ctx.localization = null;
        this.ctx.w.globals.tooltip = null;
        this.clearDomElements({
          isUpdating: isUpdating
        });
      }
    }, {
      key: "killSVG",
      value: function killSVG(draw) {
        draw.each(function () {
          this.removeClass('*');
          this.off();
          this.stop();
        }, true);
        draw.ungroup();
        draw.clear();
      }
    }, {
      key: "clearDomElements",
      value: function clearDomElements(_ref2) {
        var _this = this;
        var isUpdating = _ref2.isUpdating;
        var elSVG = this.w.globals.dom.Paper.node;
        // fixes apexcharts.js#1654 & vue-apexcharts#256
        if (elSVG.parentNode && elSVG.parentNode.parentNode && !isUpdating) {
          elSVG.parentNode.parentNode.style.minHeight = 'unset';
        }

        // detach root event
        var baseEl = this.w.globals.dom.baseEl;
        if (baseEl) {
          // see https://github.com/apexcharts/vue-apexcharts/issues/275
          this.ctx.eventList.forEach(function (event) {
            baseEl.removeEventListener(event, _this.ctx.events.documentEvent);
          });
        }
        var domEls = this.w.globals.dom;
        if (this.ctx.el !== null) {
          // remove all child elements - resetting the whole chart
          while (this.ctx.el.firstChild) {
            this.ctx.el.removeChild(this.ctx.el.firstChild);
          }
        }
        this.killSVG(domEls.Paper);
        domEls.Paper.remove();
        domEls.elWrap = null;
        domEls.elGraphical = null;
        domEls.elLegendWrap = null;
        domEls.elLegendForeign = null;
        domEls.baseEl = null;
        domEls.elGridRect = null;
        domEls.elGridRectMask = null;
        domEls.elGridRectBarMask = null;
        domEls.elGridRectMarkerMask = null;
        domEls.elForecastMask = null;
        domEls.elNonForecastMask = null;
        domEls.elDefs = null;
      }
    }]);
    return Destroy;
  }();

  // Helpers to react to element resizes, regardless of what caused them
  // TODO Currently this creates a new ResizeObserver every time we want to observe an element for resizes
  // Ideally, we should be able to use a single observer for all elements
  var ros = new WeakMap(); // Map callbacks to ResizeObserver instances for easy removal

  function addResizeListener(el, fn) {
    var called = false;
    if (el.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
      var elRect = el.getBoundingClientRect();
      if (el.style.display === 'none' || elRect.width === 0) {
        // if elRect.width=0, the chart is not rendered at all
        // (it has either display none or hidden in a different tab)
        // fixes https://github.com/apexcharts/apexcharts.js/issues/2825
        // fixes https://github.com/apexcharts/apexcharts.js/issues/2991
        // fixes https://github.com/apexcharts/apexcharts.js/issues/2992
        called = true;
      }
    }
    var ro = new ResizeObserver(function (r) {
      // ROs fire immediately after being created,
      // per spec: https://drafts.csswg.org/resize-observer/#ref-for-element%E2%91%A3
      // we don't want that so we just discard the first run
      if (called) {
        fn.call(el, r);
      }
      called = true;
    });
    if (el.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
      // Document fragment, observe children instead (needed for Shadow DOM, see #1332)
      Array.from(el.children).forEach(function (c) {
        return ro.observe(c);
      });
    } else {
      ro.observe(el);
    }
    ros.set(fn, ro);
  }
  function removeResizeListener(el, fn) {
    var ro = ros.get(fn);
    if (ro) {
      ro.disconnect();
      ros.delete(fn);
    }
  }

  var css_248z = "@keyframes opaque {\n  0% {\n    opacity: 0\n  }\n\n  to {\n    opacity: 1\n  }\n}\n\n@keyframes resizeanim {\n\n  0%,\n  to {\n    opacity: 0\n  }\n}\n\n.apexcharts-canvas {\n  position: relative;\n  direction: ltr !important;\n  user-select: none\n}\n\n.apexcharts-canvas ::-webkit-scrollbar {\n  -webkit-appearance: none;\n  width: 6px\n}\n\n.apexcharts-canvas ::-webkit-scrollbar-thumb {\n  border-radius: 4px;\n  background-color: rgba(0, 0, 0, .5);\n  box-shadow: 0 0 1px rgba(255, 255, 255, .5);\n  -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, .5)\n}\n\n.apexcharts-inner {\n  position: relative\n}\n\n.apexcharts-text tspan {\n  font-family: inherit\n}\n\nrect.legend-mouseover-inactive,\n.legend-mouseover-inactive rect,\n.legend-mouseover-inactive path,\n.legend-mouseover-inactive circle,\n.legend-mouseover-inactive line,\n.legend-mouseover-inactive text.apexcharts-yaxis-title-text,\n.legend-mouseover-inactive text.apexcharts-yaxis-label {\n  transition: .15s ease all;\n  opacity: .2\n}\n\n.apexcharts-legend-text {\n  padding-left: 15px;\n  margin-left: -15px;\n}\n\n.apexcharts-series-collapsed {\n  opacity: 0\n}\n\n.apexcharts-tooltip {\n  border-radius: 5px;\n  box-shadow: 2px 2px 6px -4px #999;\n  cursor: default;\n  font-size: 14px;\n  left: 62px;\n  opacity: 0;\n  pointer-events: none;\n  position: absolute;\n  top: 20px;\n  display: flex;\n  flex-direction: column;\n  overflow: hidden;\n  white-space: nowrap;\n  z-index: 12;\n  transition: .15s ease all\n}\n\n.apexcharts-tooltip.apexcharts-active {\n  opacity: 1;\n  transition: .15s ease all\n}\n\n.apexcharts-tooltip.apexcharts-theme-light {\n  border: 1px solid #e3e3e3;\n  background: rgba(255, 255, 255, .96)\n}\n\n.apexcharts-tooltip.apexcharts-theme-dark {\n  color: #fff;\n  background: rgba(30, 30, 30, .8)\n}\n\n.apexcharts-tooltip * {\n  font-family: inherit\n}\n\n.apexcharts-tooltip-title {\n  padding: 6px;\n  font-size: 15px;\n  margin-bottom: 4px\n}\n\n.apexcharts-tooltip.apexcharts-theme-light .apexcharts-tooltip-title {\n  background: #eceff1;\n  border-bottom: 1px solid #ddd\n}\n\n.apexcharts-tooltip.apexcharts-theme-dark .apexcharts-tooltip-title {\n  background: rgba(0, 0, 0, .7);\n  border-bottom: 1px solid #333\n}\n\n.apexcharts-tooltip-text-goals-value,\n.apexcharts-tooltip-text-y-value,\n.apexcharts-tooltip-text-z-value {\n  display: inline-block;\n  margin-left: 5px;\n  font-weight: 600\n}\n\n.apexcharts-tooltip-text-goals-label:empty,\n.apexcharts-tooltip-text-goals-value:empty,\n.apexcharts-tooltip-text-y-label:empty,\n.apexcharts-tooltip-text-y-value:empty,\n.apexcharts-tooltip-text-z-value:empty,\n.apexcharts-tooltip-title:empty {\n  display: none\n}\n\n.apexcharts-tooltip-text-goals-label,\n.apexcharts-tooltip-text-goals-value {\n  padding: 6px 0 5px\n}\n\n.apexcharts-tooltip-goals-group,\n.apexcharts-tooltip-text-goals-label,\n.apexcharts-tooltip-text-goals-value {\n  display: flex\n}\n\n.apexcharts-tooltip-text-goals-label:not(:empty),\n.apexcharts-tooltip-text-goals-value:not(:empty) {\n  margin-top: -6px\n}\n\n.apexcharts-tooltip-marker {\n  width: 12px;\n  height: 12px;\n  position: relative;\n  top: 0;\n  margin-right: 10px;\n  border-radius: 50%\n}\n\n.apexcharts-tooltip-series-group {\n  padding: 0 10px;\n  display: none;\n  text-align: left;\n  justify-content: left;\n  align-items: center\n}\n\n.apexcharts-tooltip-series-group.apexcharts-active .apexcharts-tooltip-marker {\n  opacity: 1\n}\n\n.apexcharts-tooltip-series-group.apexcharts-active,\n.apexcharts-tooltip-series-group:last-child {\n  padding-bottom: 4px\n}\n\n.apexcharts-tooltip-y-group {\n  padding: 6px 0 5px\n}\n\n.apexcharts-custom-tooltip,\n.apexcharts-tooltip-box {\n  padding: 4px 8px\n}\n\n.apexcharts-tooltip-boxPlot {\n  display: flex;\n  flex-direction: column-reverse\n}\n\n.apexcharts-tooltip-box>div {\n  margin: 4px 0\n}\n\n.apexcharts-tooltip-box span.value {\n  font-weight: 700\n}\n\n.apexcharts-tooltip-rangebar {\n  padding: 5px 8px\n}\n\n.apexcharts-tooltip-rangebar .category {\n  font-weight: 600;\n  color: #777\n}\n\n.apexcharts-tooltip-rangebar .series-name {\n  font-weight: 700;\n  display: block;\n  margin-bottom: 5px\n}\n\n.apexcharts-xaxistooltip,\n.apexcharts-yaxistooltip {\n  opacity: 0;\n  pointer-events: none;\n  color: #373d3f;\n  font-size: 13px;\n  text-align: center;\n  border-radius: 2px;\n  position: absolute;\n  z-index: 10;\n  background: #eceff1;\n  border: 1px solid #90a4ae\n}\n\n.apexcharts-xaxistooltip {\n  padding: 9px 10px;\n  transition: .15s ease all\n}\n\n.apexcharts-xaxistooltip.apexcharts-theme-dark {\n  background: rgba(0, 0, 0, .7);\n  border: 1px solid rgba(0, 0, 0, .5);\n  color: #fff\n}\n\n.apexcharts-xaxistooltip:after,\n.apexcharts-xaxistooltip:before {\n  left: 50%;\n  border: solid transparent;\n  content: \" \";\n  height: 0;\n  width: 0;\n  position: absolute;\n  pointer-events: none\n}\n\n.apexcharts-xaxistooltip:after {\n  border-color: transparent;\n  border-width: 6px;\n  margin-left: -6px\n}\n\n.apexcharts-xaxistooltip:before {\n  border-color: transparent;\n  border-width: 7px;\n  margin-left: -7px\n}\n\n.apexcharts-xaxistooltip-bottom:after,\n.apexcharts-xaxistooltip-bottom:before {\n  bottom: 100%\n}\n\n.apexcharts-xaxistooltip-top:after,\n.apexcharts-xaxistooltip-top:before {\n  top: 100%\n}\n\n.apexcharts-xaxistooltip-bottom:after {\n  border-bottom-color: #eceff1\n}\n\n.apexcharts-xaxistooltip-bottom:before {\n  border-bottom-color: #90a4ae\n}\n\n.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:after,\n.apexcharts-xaxistooltip-bottom.apexcharts-theme-dark:before {\n  border-bottom-color: rgba(0, 0, 0, .5)\n}\n\n.apexcharts-xaxistooltip-top:after {\n  border-top-color: #eceff1\n}\n\n.apexcharts-xaxistooltip-top:before {\n  border-top-color: #90a4ae\n}\n\n.apexcharts-xaxistooltip-top.apexcharts-theme-dark:after,\n.apexcharts-xaxistooltip-top.apexcharts-theme-dark:before {\n  border-top-color: rgba(0, 0, 0, .5)\n}\n\n.apexcharts-xaxistooltip.apexcharts-active {\n  opacity: 1;\n  transition: .15s ease all\n}\n\n.apexcharts-yaxistooltip {\n  padding: 4px 10px\n}\n\n.apexcharts-yaxistooltip.apexcharts-theme-dark {\n  background: rgba(0, 0, 0, .7);\n  border: 1px solid rgba(0, 0, 0, .5);\n  color: #fff\n}\n\n.apexcharts-yaxistooltip:after,\n.apexcharts-yaxistooltip:before {\n  top: 50%;\n  border: solid transparent;\n  content: \" \";\n  height: 0;\n  width: 0;\n  position: absolute;\n  pointer-events: none\n}\n\n.apexcharts-yaxistooltip:after {\n  border-color: transparent;\n  border-width: 6px;\n  margin-top: -6px\n}\n\n.apexcharts-yaxistooltip:before {\n  border-color: transparent;\n  border-width: 7px;\n  margin-top: -7px\n}\n\n.apexcharts-yaxistooltip-left:after,\n.apexcharts-yaxistooltip-left:before {\n  left: 100%\n}\n\n.apexcharts-yaxistooltip-right:after,\n.apexcharts-yaxistooltip-right:before {\n  right: 100%\n}\n\n.apexcharts-yaxistooltip-left:after {\n  border-left-color: #eceff1\n}\n\n.apexcharts-yaxistooltip-left:before {\n  border-left-color: #90a4ae\n}\n\n.apexcharts-yaxistooltip-left.apexcharts-theme-dark:after,\n.apexcharts-yaxistooltip-left.apexcharts-theme-dark:before {\n  border-left-color: rgba(0, 0, 0, .5)\n}\n\n.apexcharts-yaxistooltip-right:after {\n  border-right-color: #eceff1\n}\n\n.apexcharts-yaxistooltip-right:before {\n  border-right-color: #90a4ae\n}\n\n.apexcharts-yaxistooltip-right.apexcharts-theme-dark:after,\n.apexcharts-yaxistooltip-right.apexcharts-theme-dark:before {\n  border-right-color: rgba(0, 0, 0, .5)\n}\n\n.apexcharts-yaxistooltip.apexcharts-active {\n  opacity: 1\n}\n\n.apexcharts-yaxistooltip-hidden {\n  display: none\n}\n\n.apexcharts-xcrosshairs,\n.apexcharts-ycrosshairs {\n  pointer-events: none;\n  opacity: 0;\n  transition: .15s ease all\n}\n\n.apexcharts-xcrosshairs.apexcharts-active,\n.apexcharts-ycrosshairs.apexcharts-active {\n  opacity: 1;\n  transition: .15s ease all\n}\n\n.apexcharts-ycrosshairs-hidden {\n  opacity: 0\n}\n\n.apexcharts-selection-rect {\n  cursor: move\n}\n\n.svg_select_boundingRect,\n.svg_select_points_rot {\n  pointer-events: none;\n  opacity: 0;\n  visibility: hidden\n}\n\n.apexcharts-selection-rect+g .svg_select_boundingRect,\n.apexcharts-selection-rect+g .svg_select_points_rot {\n  opacity: 0;\n  visibility: hidden\n}\n\n.apexcharts-selection-rect+g .svg_select_points_l,\n.apexcharts-selection-rect+g .svg_select_points_r {\n  cursor: ew-resize;\n  opacity: 1;\n  visibility: visible\n}\n\n.svg_select_points {\n  fill: #efefef;\n  stroke: #333;\n  rx: 2\n}\n\n.apexcharts-svg.apexcharts-zoomable.hovering-zoom {\n  cursor: crosshair\n}\n\n.apexcharts-svg.apexcharts-zoomable.hovering-pan {\n  cursor: move\n}\n\n.apexcharts-menu-icon,\n.apexcharts-pan-icon,\n.apexcharts-reset-icon,\n.apexcharts-selection-icon,\n.apexcharts-toolbar-custom-icon,\n.apexcharts-zoom-icon,\n.apexcharts-zoomin-icon,\n.apexcharts-zoomout-icon {\n  cursor: pointer;\n  width: 20px;\n  height: 20px;\n  line-height: 24px;\n  color: #6e8192;\n  text-align: center\n}\n\n.apexcharts-menu-icon svg,\n.apexcharts-reset-icon svg,\n.apexcharts-zoom-icon svg,\n.apexcharts-zoomin-icon svg,\n.apexcharts-zoomout-icon svg {\n  fill: #6e8192\n}\n\n.apexcharts-selection-icon svg {\n  fill: #444;\n  transform: scale(.76)\n}\n\n.apexcharts-theme-dark .apexcharts-menu-icon svg,\n.apexcharts-theme-dark .apexcharts-pan-icon svg,\n.apexcharts-theme-dark .apexcharts-reset-icon svg,\n.apexcharts-theme-dark .apexcharts-selection-icon svg,\n.apexcharts-theme-dark .apexcharts-toolbar-custom-icon svg,\n.apexcharts-theme-dark .apexcharts-zoom-icon svg,\n.apexcharts-theme-dark .apexcharts-zoomin-icon svg,\n.apexcharts-theme-dark .apexcharts-zoomout-icon svg {\n  fill: #f3f4f5\n}\n\n.apexcharts-canvas .apexcharts-reset-zoom-icon.apexcharts-selected svg,\n.apexcharts-canvas .apexcharts-selection-icon.apexcharts-selected svg,\n.apexcharts-canvas .apexcharts-zoom-icon.apexcharts-selected svg {\n  fill: #008ffb\n}\n\n.apexcharts-theme-light .apexcharts-menu-icon:hover svg,\n.apexcharts-theme-light .apexcharts-reset-icon:hover svg,\n.apexcharts-theme-light .apexcharts-selection-icon:not(.apexcharts-selected):hover svg,\n.apexcharts-theme-light .apexcharts-zoom-icon:not(.apexcharts-selected):hover svg,\n.apexcharts-theme-light .apexcharts-zoomin-icon:hover svg,\n.apexcharts-theme-light .apexcharts-zoomout-icon:hover svg {\n  fill: #333\n}\n\n.apexcharts-menu-icon,\n.apexcharts-selection-icon {\n  position: relative\n}\n\n.apexcharts-reset-icon {\n  margin-left: 5px\n}\n\n.apexcharts-menu-icon,\n.apexcharts-reset-icon,\n.apexcharts-zoom-icon {\n  transform: scale(.85)\n}\n\n.apexcharts-zoomin-icon,\n.apexcharts-zoomout-icon {\n  transform: scale(.7)\n}\n\n.apexcharts-zoomout-icon {\n  margin-right: 3px\n}\n\n.apexcharts-pan-icon {\n  transform: scale(.62);\n  position: relative;\n  left: 1px;\n  top: 0\n}\n\n.apexcharts-pan-icon svg {\n  fill: #fff;\n  stroke: #6e8192;\n  stroke-width: 2\n}\n\n.apexcharts-pan-icon.apexcharts-selected svg {\n  stroke: #008ffb\n}\n\n.apexcharts-pan-icon:not(.apexcharts-selected):hover svg {\n  stroke: #333\n}\n\n.apexcharts-toolbar {\n  position: absolute;\n  z-index: 11;\n  max-width: 176px;\n  text-align: right;\n  border-radius: 3px;\n  padding: 0 6px 2px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center\n}\n\n.apexcharts-menu {\n  background: #fff;\n  position: absolute;\n  top: 100%;\n  border: 1px solid #ddd;\n  border-radius: 3px;\n  padding: 3px;\n  right: 10px;\n  opacity: 0;\n  min-width: 110px;\n  transition: .15s ease all;\n  pointer-events: none\n}\n\n.apexcharts-menu.apexcharts-menu-open {\n  opacity: 1;\n  pointer-events: all;\n  transition: .15s ease all\n}\n\n.apexcharts-menu-item {\n  padding: 6px 7px;\n  font-size: 12px;\n  cursor: pointer\n}\n\n.apexcharts-theme-light .apexcharts-menu-item:hover {\n  background: #eee\n}\n\n.apexcharts-theme-dark .apexcharts-menu {\n  background: rgba(0, 0, 0, .7);\n  color: #fff\n}\n\n@media screen and (min-width:768px) {\n  .apexcharts-canvas:hover .apexcharts-toolbar {\n    opacity: 1\n  }\n}\n\n.apexcharts-canvas .apexcharts-element-hidden,\n.apexcharts-datalabel.apexcharts-element-hidden,\n.apexcharts-hide .apexcharts-series-points {\n  opacity: 0;\n}\n\n.apexcharts-hidden-element-shown {\n  opacity: 1;\n  transition: 0.25s ease all;\n}\n\n.apexcharts-datalabel,\n.apexcharts-datalabel-label,\n.apexcharts-datalabel-value,\n.apexcharts-datalabels,\n.apexcharts-pie-label {\n  cursor: default;\n  pointer-events: none\n}\n\n.apexcharts-pie-label-delay {\n  opacity: 0;\n  animation-name: opaque;\n  animation-duration: .3s;\n  animation-fill-mode: forwards;\n  animation-timing-function: ease\n}\n\n.apexcharts-radialbar-label {\n  cursor: pointer;\n}\n\n.apexcharts-annotation-rect,\n.apexcharts-area-series .apexcharts-area,\n.apexcharts-area-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,\n.apexcharts-gridline,\n.apexcharts-line,\n.apexcharts-line-series .apexcharts-series-markers .apexcharts-marker.no-pointer-events,\n.apexcharts-point-annotation-label,\n.apexcharts-radar-series path:not(.apexcharts-marker),\n.apexcharts-radar-series polygon,\n.apexcharts-toolbar svg,\n.apexcharts-tooltip .apexcharts-marker,\n.apexcharts-xaxis-annotation-label,\n.apexcharts-yaxis-annotation-label,\n.apexcharts-zoom-rect {\n  pointer-events: none\n}\n\n.apexcharts-tooltip-active .apexcharts-marker {\n  transition: .15s ease all\n}\n\n.resize-triggers {\n  animation: 1ms resizeanim;\n  visibility: hidden;\n  opacity: 0;\n  height: 100%;\n  width: 100%;\n  overflow: hidden\n}\n\n.contract-trigger:before,\n.resize-triggers,\n.resize-triggers>div {\n  content: \" \";\n  display: block;\n  position: absolute;\n  top: 0;\n  left: 0\n}\n\n.resize-triggers>div {\n  height: 100%;\n  width: 100%;\n  background: #eee;\n  overflow: auto\n}\n\n.contract-trigger:before {\n  overflow: hidden;\n  width: 200%;\n  height: 200%\n}\n\n.apexcharts-bar-goals-markers {\n  pointer-events: none\n}\n\n.apexcharts-bar-shadows {\n  pointer-events: none\n}\n\n.apexcharts-rangebar-goals-markers {\n  pointer-events: none\n}\n";

  /**
   *
   * @module ApexCharts
   **/
  var ApexCharts$1 = /*#__PURE__*/function () {
    function ApexCharts(el, opts) {
      _classCallCheck(this, ApexCharts);
      this.opts = opts;
      this.ctx = this;

      // Pass the user supplied options to the Base Class where these options will be extended with defaults. The returned object from Base Class will become the config object in the entire codebase.
      this.w = new Base(opts).init();
      this.el = el;
      this.w.globals.cuid = Utils$1.randomId();
      this.w.globals.chartID = this.w.config.chart.id ? Utils$1.escapeString(this.w.config.chart.id) : this.w.globals.cuid;
      var initCtx = new InitCtxVariables(this);
      initCtx.initModules();
      this.create = Utils$1.bind(this.create, this);
      this.windowResizeHandler = this._windowResizeHandler.bind(this);
      this.parentResizeHandler = this._parentResizeCallback.bind(this);
    }

    /**
     * The primary method user will call to render the chart.
     */
    _createClass(ApexCharts, [{
      key: "render",
      value: function render() {
        var _this = this;
        // main method
        return new Promise(function (resolve, reject) {
          // only draw chart, if element found
          if (_this.el !== null) {
            if (typeof Apex._chartInstances === 'undefined') {
              Apex._chartInstances = [];
            }
            if (_this.w.config.chart.id) {
              Apex._chartInstances.push({
                id: _this.w.globals.chartID,
                group: _this.w.config.chart.group,
                chart: _this
              });
            }

            // set the locale here
            _this.setLocale(_this.w.config.chart.defaultLocale);
            var beforeMount = _this.w.config.chart.events.beforeMount;
            if (typeof beforeMount === 'function') {
              beforeMount(_this, _this.w);
            }
            _this.events.fireEvent('beforeMount', [_this, _this.w]);
            window.addEventListener('resize', _this.windowResizeHandler);
            addResizeListener(_this.el.parentNode, _this.parentResizeHandler);
            var rootNode = _this.el.getRootNode && _this.el.getRootNode();
            var inShadowRoot = Utils$1.is('ShadowRoot', rootNode);
            var doc = _this.el.ownerDocument;
            var css = inShadowRoot ? rootNode.getElementById('apexcharts-css') : doc.getElementById('apexcharts-css');
            if (!css) {
              var _this$opts$chart;
              css = document.createElement('style');
              css.id = 'apexcharts-css';
              css.textContent = css_248z;
              var nonce = ((_this$opts$chart = _this.opts.chart) === null || _this$opts$chart === void 0 ? void 0 : _this$opts$chart.nonce) || _this.w.config.chart.nonce;
              if (nonce) {
                css.setAttribute('nonce', nonce);
              }
              if (inShadowRoot) {
                // We are in Shadow DOM, add to shadow root
                rootNode.prepend(css);
              } else {
                // Add to <head> of element's document
                doc.head.appendChild(css);
              }
            }
            var graphData = _this.create(_this.w.config.series, {});
            if (!graphData) return resolve(_this);
            _this.mount(graphData).then(function () {
              if (typeof _this.w.config.chart.events.mounted === 'function') {
                _this.w.config.chart.events.mounted(_this, _this.w);
              }
              _this.events.fireEvent('mounted', [_this, _this.w]);
              resolve(graphData);
            }).catch(function (e) {
              reject(e);
              // handle error in case no data or element not found
            });
          } else {
            reject(new Error('Element not found'));
          }
        });
      }
    }, {
      key: "create",
      value: function create(ser, opts) {
        var _this2 = this;
        var w = this.w;
        var initCtx = new InitCtxVariables(this);
        initCtx.initModules();
        var gl = this.w.globals;
        gl.noData = false;
        gl.animationEnded = false;
        this.responsive.checkResponsiveConfig(opts);
        if (w.config.xaxis.convertedCatToNumeric) {
          var defaults = new Defaults(w.config);
          defaults.convertCatToNumericXaxis(w.config, this.ctx);
        }
        if (this.el === null) {
          gl.animationEnded = true;
          return null;
        }
        this.core.setupElements();
        if (w.config.chart.type === 'treemap') {
          w.config.grid.show = false;
          w.config.yaxis[0].show = false;
        }
        if (gl.svgWidth === 0) {
          // if the element is hidden, skip drawing
          gl.animationEnded = true;
          return null;
        }
        var series = ser;
        ser.forEach(function (s, realIndex) {
          if (s.hidden) {
            series = _this2.legend.legendHelpers.getSeriesAfterCollapsing({
              realIndex: realIndex
            });
          }
        });
        var combo = CoreUtils.checkComboSeries(series, w.config.chart.type);
        gl.comboCharts = combo.comboCharts;
        gl.comboBarCount = combo.comboBarCount;
        var allSeriesAreEmpty = series.every(function (s) {
          return s.data && s.data.length === 0;
        });
        if (series.length === 0 || allSeriesAreEmpty && gl.collapsedSeries.length < 1) {
          this.series.handleNoData();
        }
        this.events.setupEventHandlers();

        // Handle the data inputted by user and set some of the global variables (for eg, if data is datetime / numeric / category). Don't calculate the range / min / max at this time
        this.data.parseData(series);

        // this is a good time to set theme colors first
        this.theme.init();

        // as markers accepts array, we need to setup global markers for easier access
        var markers = new Markers(this);
        markers.setGlobalMarkerSize();

        // labelFormatters should be called before dimensions as in dimensions we need text labels width
        this.formatters.setLabelFormatters();
        this.titleSubtitle.draw();

        // legend is calculated here before coreCalculations because it affects the plottable area
        // if there is some data to show or user collapsed all series, then proceed drawing legend
        if (!gl.noData || gl.collapsedSeries.length === gl.series.length || w.config.legend.showForSingleSeries) {
          this.legend.init();
        }

        // check whether in multiple series, all series share the same X
        this.series.hasAllSeriesEqualX();

        // coreCalculations will give the min/max range and yaxis/axis values. It should be called here to set series variable from config to globals
        if (gl.axisCharts) {
          this.core.coreCalculations();
          if (w.config.xaxis.type !== 'category') {
            // as we have minX and maxX values, determine the default DateTimeFormat for time series
            this.formatters.setLabelFormatters();
          }
          this.ctx.toolbar.minX = w.globals.minX;
          this.ctx.toolbar.maxX = w.globals.maxX;
        }

        // we need to generate yaxis for heatmap separately as we are not showing numerics there, but seriesNames. There are some tweaks which are required for heatmap to align labels correctly which are done in below function
        // Also we need to do this before calculating Dimensions plotCoords() method of Dimensions
        this.formatters.heatmapLabelFormatters();

        // get the largest marker size which will be needed in dimensions calc
        var coreUtils = new CoreUtils(this);
        coreUtils.getLargestMarkerSize();

        // We got plottable area here, next task would be to calculate axis areas
        this.dimensions.plotCoords();
        var xyRatios = this.core.xySettings();
        this.grid.createGridMask();
        var elGraph = this.core.plotChartType(series, xyRatios);
        var dataLabels = new DataLabels(this);
        dataLabels.bringForward();
        if (w.config.dataLabels.background.enabled) {
          dataLabels.dataLabelsBackground();
        }

        // after all the drawing calculations, shift the graphical area (actual charts/bars) excluding legends
        this.core.shiftGraphPosition();
        var dim = {
          plot: {
            left: w.globals.translateX,
            top: w.globals.translateY,
            width: w.globals.gridWidth,
            height: w.globals.gridHeight
          }
        };
        return {
          elGraph: elGraph,
          xyRatios: xyRatios,
          dimensions: dim
        };
      }
    }, {
      key: "mount",
      value: function mount() {
        var _this3 = this;
        var graphData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
        var me = this;
        var w = me.w;
        return new Promise(function (resolve, reject) {
          // no data to display
          if (me.el === null) {
            return reject(new Error('Not enough data to display or target element not found'));
          } else if (graphData === null || w.globals.allSeriesCollapsed) {
            me.series.handleNoData();
          }
          me.grid = new Grid(me);
          var elgrid = me.grid.drawGrid();
          me.annotations = new Annotations(me);
          me.annotations.drawImageAnnos();
          me.annotations.drawTextAnnos();
          if (w.config.grid.position === 'back') {
            var _elgrid$elGridBorders;
            if (elgrid) {
              w.globals.dom.elGraphical.add(elgrid.el);
            }
            if (elgrid !== null && elgrid !== void 0 && (_elgrid$elGridBorders = elgrid.elGridBorders) !== null && _elgrid$elGridBorders !== void 0 && _elgrid$elGridBorders.node) {
              w.globals.dom.elGraphical.add(elgrid.elGridBorders);
            }
          }
          if (Array.isArray(graphData.elGraph)) {
            for (var g = 0; g < graphData.elGraph.length; g++) {
              w.globals.dom.elGraphical.add(graphData.elGraph[g]);
            }
          } else {
            w.globals.dom.elGraphical.add(graphData.elGraph);
          }
          if (w.config.grid.position === 'front') {
            var _elgrid$elGridBorders2;
            if (elgrid) {
              w.globals.dom.elGraphical.add(elgrid.el);
            }
            if (elgrid !== null && elgrid !== void 0 && (_elgrid$elGridBorders2 = elgrid.elGridBorders) !== null && _elgrid$elGridBorders2 !== void 0 && _elgrid$elGridBorders2.node) {
              w.globals.dom.elGraphical.add(elgrid.elGridBorders);
            }
          }
          if (w.config.xaxis.crosshairs.position === 'front') {
            me.crosshairs.drawXCrosshairs();
          }
          if (w.config.yaxis[0].crosshairs.position === 'front') {
            me.crosshairs.drawYCrosshairs();
          }
          if (w.config.chart.type !== 'treemap') {
            me.axes.drawAxis(w.config.chart.type, elgrid);
          }
          var xAxis = new XAxis(_this3.ctx, elgrid);
          var yaxis = new YAxis(_this3.ctx, elgrid);
          if (elgrid !== null) {
            xAxis.xAxisLabelCorrections(elgrid.xAxisTickWidth);
            yaxis.setYAxisTextAlignments();
            w.config.yaxis.map(function (yaxe, index) {
              if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1) {
                yaxis.yAxisTitleRotate(index, yaxe.opposite);
              }
            });
          }
          me.annotations.drawAxesAnnotations();
          if (!w.globals.noData) {
            // draw tooltips at the end
            if (w.config.tooltip.enabled && !w.globals.noData) {
              me.w.globals.tooltip.drawTooltip(graphData.xyRatios);
            }
            if (w.globals.axisCharts && (w.globals.isXNumeric || w.config.xaxis.convertedCatToNumeric || w.globals.isRangeBar)) {
              if (w.config.chart.zoom.enabled || w.config.chart.selection && w.config.chart.selection.enabled || w.config.chart.pan && w.config.chart.pan.enabled) {
                me.zoomPanSelection.init({
                  xyRatios: graphData.xyRatios
                });
              }
            } else {
              var tools = w.config.chart.toolbar.tools;
              var toolsArr = ['zoom', 'zoomin', 'zoomout', 'selection', 'pan', 'reset'];
              toolsArr.forEach(function (t) {
                tools[t] = false;
              });
            }
            if (w.config.chart.toolbar.show && !w.globals.allSeriesCollapsed) {
              me.toolbar.createToolbar();
            }
          }
          if (w.globals.memory.methodsToExec.length > 0) {
            w.globals.memory.methodsToExec.forEach(function (fn) {
              fn.method(fn.params, false, fn.context);
            });
          }
          if (!w.globals.axisCharts && !w.globals.noData) {
            me.core.resizeNonAxisCharts();
          }
          resolve(me);
        });
      }

      /**
       * Destroy the chart instance by removing all elements which also clean up event listeners on those elements.
       */
    }, {
      key: "destroy",
      value: function destroy() {
        window.removeEventListener('resize', this.windowResizeHandler);
        removeResizeListener(this.el.parentNode, this.parentResizeHandler);
        // remove the chart's instance from the global Apex._chartInstances
        var chartID = this.w.config.chart.id;
        if (chartID) {
          Apex._chartInstances.forEach(function (c, i) {
            if (c.id === Utils$1.escapeString(chartID)) {
              Apex._chartInstances.splice(i, 1);
            }
          });
        }
        new Destroy(this.ctx).clear({
          isUpdating: false
        });
      }

      /**
       * Allows users to update Options after the chart has rendered.
       *
       * @param {object} options - A new config object can be passed which will be merged with the existing config object
       * @param {boolean} redraw - should redraw from beginning or should use existing paths and redraw from there
       * @param {boolean} animate - should animate or not on updating Options
       */
    }, {
      key: "updateOptions",
      value: function updateOptions(options) {
        var _this4 = this;
        var redraw = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
        var animate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
        var updateSyncedCharts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
        var overwriteInitialConfig = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
        var w = this.w;

        // when called externally, clear some global variables
        // fixes apexcharts.js#1488
        w.globals.selection = undefined;
        if (options.series) {
          this.series.resetSeries(false, true, false);
          if (options.series.length && options.series[0].data) {
            options.series = options.series.map(function (s, i) {
              return _this4.updateHelpers._extendSeries(s, i);
            });
          }

          // user updated the series via updateOptions() function.
          // Hence, we need to reset axis min/max to avoid zooming issues
          this.updateHelpers.revertDefaultAxisMinMax();
        }
        // user has set x-axis min/max externally - hence we need to forcefully set the xaxis min/max
        if (options.xaxis) {
          options = this.updateHelpers.forceXAxisUpdate(options);
        }
        if (options.yaxis) {
          options = this.updateHelpers.forceYAxisUpdate(options);
        }
        if (w.globals.collapsedSeriesIndices.length > 0) {
          this.series.clearPreviousPaths();
        }
        /* update theme mode#459 */
        if (options.theme) {
          options = this.theme.updateThemeOptions(options);
        }
        return this.updateHelpers._updateOptions(options, redraw, animate, updateSyncedCharts, overwriteInitialConfig);
      }

      /**
       * Allows users to update Series after the chart has rendered.
       *
       * @param {array} series - New series which will override the existing
       */
    }, {
      key: "updateSeries",
      value: function updateSeries() {
        var newSeries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
        var animate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var overwriteInitialSeries = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
        this.series.resetSeries(false);
        this.updateHelpers.revertDefaultAxisMinMax();
        return this.updateHelpers._updateSeries(newSeries, animate, overwriteInitialSeries);
      }

      /**
       * Allows users to append a new series after the chart has rendered.
       *
       * @param {array} newSerie - New serie which will be appended to the existing series
       */
    }, {
      key: "appendSeries",
      value: function appendSeries(newSerie) {
        var animate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var overwriteInitialSeries = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
        var newSeries = this.w.config.series.slice();
        newSeries.push(newSerie);
        this.series.resetSeries(false);
        this.updateHelpers.revertDefaultAxisMinMax();
        return this.updateHelpers._updateSeries(newSeries, animate, overwriteInitialSeries);
      }

      /**
       * Allows users to append Data to series.
       *
       * @param {array} newData - New data in the same format as series
       */
    }, {
      key: "appendData",
      value: function appendData(newData) {
        var overwriteInitialSeries = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var me = this;
        me.w.globals.dataChanged = true;
        me.series.getPreviousPaths();
        var newSeries = me.w.config.series.slice();
        for (var i = 0; i < newSeries.length; i++) {
          if (newData[i] !== null && typeof newData[i] !== 'undefined') {
            for (var j = 0; j < newData[i].data.length; j++) {
              newSeries[i].data.push(newData[i].data[j]);
            }
          }
        }
        me.w.config.series = newSeries;
        if (overwriteInitialSeries) {
          me.w.globals.initialSeries = Utils$1.clone(me.w.config.series);
        }
        return this.update();
      }
    }, {
      key: "update",
      value: function update(options) {
        var _this5 = this;
        return new Promise(function (resolve, reject) {
          new Destroy(_this5.ctx).clear({
            isUpdating: true
          });
          var graphData = _this5.create(_this5.w.config.series, options);
          if (!graphData) return resolve(_this5);
          _this5.mount(graphData).then(function () {
            if (typeof _this5.w.config.chart.events.updated === 'function') {
              _this5.w.config.chart.events.updated(_this5, _this5.w);
            }
            _this5.events.fireEvent('updated', [_this5, _this5.w]);
            _this5.w.globals.isDirty = true;
            resolve(_this5);
          }).catch(function (e) {
            reject(e);
          });
        });
      }

      /**
       * Get all charts in the same "group" (including the instance which is called upon) to sync them when user zooms in/out or pan.
       */
    }, {
      key: "getSyncedCharts",
      value: function getSyncedCharts() {
        var chartGroups = this.getGroupedCharts();
        var allCharts = [this];
        if (chartGroups.length) {
          allCharts = [];
          chartGroups.forEach(function (ch) {
            allCharts.push(ch);
          });
        }
        return allCharts;
      }

      /**
       * Get charts in the same "group" (excluding the instance which is called upon) to perform operations on the other charts of the same group (eg., tooltip hovering)
       */
    }, {
      key: "getGroupedCharts",
      value: function getGroupedCharts() {
        var _this6 = this;
        return Apex._chartInstances.filter(function (ch) {
          if (ch.group) {
            return true;
          }
        }).map(function (ch) {
          return _this6.w.config.chart.group === ch.group ? ch.chart : _this6;
        });
      }
    }, {
      key: "toggleSeries",
      value: function toggleSeries(seriesName) {
        return this.series.toggleSeries(seriesName);
      }
    }, {
      key: "highlightSeriesOnLegendHover",
      value: function highlightSeriesOnLegendHover(e, targetElement) {
        return this.series.toggleSeriesOnHover(e, targetElement);
      }
    }, {
      key: "showSeries",
      value: function showSeries(seriesName) {
        this.series.showSeries(seriesName);
      }
    }, {
      key: "hideSeries",
      value: function hideSeries(seriesName) {
        this.series.hideSeries(seriesName);
      }
    }, {
      key: "highlightSeries",
      value: function highlightSeries(seriesName) {
        this.series.highlightSeries(seriesName);
      }
    }, {
      key: "isSeriesHidden",
      value: function isSeriesHidden(seriesName) {
        this.series.isSeriesHidden(seriesName);
      }
    }, {
      key: "resetSeries",
      value: function resetSeries() {
        var shouldUpdateChart = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
        var shouldResetZoom = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        this.series.resetSeries(shouldUpdateChart, shouldResetZoom);
      }

      // Public method to add event listener on chart context
    }, {
      key: "addEventListener",
      value: function addEventListener(name, handler) {
        this.events.addEventListener(name, handler);
      }

      // Public method to remove event listener on chart context
    }, {
      key: "removeEventListener",
      value: function removeEventListener(name, handler) {
        this.events.removeEventListener(name, handler);
      }
    }, {
      key: "addXaxisAnnotation",
      value: function addXaxisAnnotation(opts) {
        var pushToMemory = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
        var me = this;
        if (context) {
          me = context;
        }
        me.annotations.addXaxisAnnotationExternal(opts, pushToMemory, me);
      }
    }, {
      key: "addYaxisAnnotation",
      value: function addYaxisAnnotation(opts) {
        var pushToMemory = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
        var me = this;
        if (context) {
          me = context;
        }
        me.annotations.addYaxisAnnotationExternal(opts, pushToMemory, me);
      }
    }, {
      key: "addPointAnnotation",
      value: function addPointAnnotation(opts) {
        var pushToMemory = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
        var me = this;
        if (context) {
          me = context;
        }
        me.annotations.addPointAnnotationExternal(opts, pushToMemory, me);
      }
    }, {
      key: "clearAnnotations",
      value: function clearAnnotations() {
        var context = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
        var me = this;
        if (context) {
          me = context;
        }
        me.annotations.clearAnnotations(me);
      }
    }, {
      key: "removeAnnotation",
      value: function removeAnnotation(id) {
        var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
        var me = this;
        if (context) {
          me = context;
        }
        me.annotations.removeAnnotation(me, id);
      }
    }, {
      key: "getChartArea",
      value: function getChartArea() {
        var el = this.w.globals.dom.baseEl.querySelector('.apexcharts-inner');
        return el;
      }
    }, {
      key: "getSeriesTotalXRange",
      value: function getSeriesTotalXRange(minX, maxX) {
        return this.coreUtils.getSeriesTotalsXRange(minX, maxX);
      }
    }, {
      key: "getHighestValueInSeries",
      value: function getHighestValueInSeries() {
        var seriesIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        var range = new Range(this.ctx);
        return range.getMinYMaxY(seriesIndex).highestY;
      }
    }, {
      key: "getLowestValueInSeries",
      value: function getLowestValueInSeries() {
        var seriesIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
        var range = new Range(this.ctx);
        return range.getMinYMaxY(seriesIndex).lowestY;
      }
    }, {
      key: "getSeriesTotal",
      value: function getSeriesTotal() {
        return this.w.globals.seriesTotals;
      }
    }, {
      key: "toggleDataPointSelection",
      value: function toggleDataPointSelection(seriesIndex, dataPointIndex) {
        return this.updateHelpers.toggleDataPointSelection(seriesIndex, dataPointIndex);
      }
    }, {
      key: "zoomX",
      value: function zoomX(min, max) {
        this.ctx.toolbar.zoomUpdateOptions(min, max);
      }
    }, {
      key: "setLocale",
      value: function setLocale(localeName) {
        this.localization.setCurrentLocaleValues(localeName);
      }
    }, {
      key: "dataURI",
      value: function dataURI(options) {
        var exp = new Exports(this.ctx);
        return exp.dataURI(options);
      }
    }, {
      key: "exportToCSV",
      value: function exportToCSV() {
        var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var exp = new Exports(this.ctx);
        return exp.exportToCSV(options);
      }
    }, {
      key: "paper",
      value: function paper() {
        return this.w.globals.dom.Paper;
      }
    }, {
      key: "_parentResizeCallback",
      value: function _parentResizeCallback() {
        if (this.w.globals.animationEnded && this.w.config.chart.redrawOnParentResize) {
          this._windowResize();
        }
      }

      /**
       * Handle window resize and re-draw the whole chart.
       */
    }, {
      key: "_windowResize",
      value: function _windowResize() {
        var _this7 = this;
        clearTimeout(this.w.globals.resizeTimer);
        this.w.globals.resizeTimer = window.setTimeout(function () {
          _this7.w.globals.resized = true;
          _this7.w.globals.dataChanged = false;

          // we need to redraw the whole chart on window resize (with a small delay).
          _this7.ctx.update();
        }, 150);
      }
    }, {
      key: "_windowResizeHandler",
      value: function _windowResizeHandler() {
        var redraw = this.w.config.chart.redrawOnWindowResize;
        if (typeof redraw === 'function') {
          redraw = redraw();
        }
        redraw && this._windowResize();
      }
    }], [{
      key: "getChartByID",
      value: function getChartByID(id) {
        var chartId = Utils$1.escapeString(id);
        if (!Apex._chartInstances) return undefined;
        var c = Apex._chartInstances.filter(function (ch) {
          return ch.id === chartId;
        })[0];
        return c && c.chart;
      }

      /**
       * Allows the user to provide data attrs in the element and the chart will render automatically when this method is called by searching for the elements containing 'data-apexcharts' attribute
       */
    }, {
      key: "initOnLoad",
      value: function initOnLoad() {
        var els = document.querySelectorAll('[data-apexcharts]');
        for (var i = 0; i < els.length; i++) {
          var el = els[i];
          var options = JSON.parse(els[i].getAttribute('data-options'));
          var apexChart = new ApexCharts(el, options);
          apexChart.render();
        }
      }

      /**
       * This static method allows users to call chart methods without necessarily from the
       * instance of the chart in case user has assigned chartID to the targeted chart.
       * The chartID is used for mapping the instance stored in Apex._chartInstances global variable
       *
       * This is helpful in cases when you don't have reference of the chart instance
       * easily and need to call the method from anywhere.
       * For eg, in React/Vue applications when you have many parent/child components,
       * and need easy reference to other charts for performing dynamic operations
       *
       * @param {string} chartID - The unique identifier which will be used to call methods
       * on that chart instance
       * @param {function} fn - The method name to call
       * @param {object} opts - The parameters which are accepted in the original method will be passed here in the same order.
       */
    }, {
      key: "exec",
      value: function exec(chartID, fn) {
        var chart = this.getChartByID(chartID);
        if (!chart) return;

        // turn on the global exec flag to indicate this method was called
        chart.w.globals.isExecCalled = true;
        var ret = null;
        if (chart.publicMethods.indexOf(fn) !== -1) {
          for (var _len = arguments.length, opts = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
            opts[_key - 2] = arguments[_key];
          }
          ret = chart[fn].apply(chart, opts);
        }
        return ret;
      }
    }, {
      key: "merge",
      value: function merge(target, source) {
        return Utils$1.extend(target, source);
      }
    }]);
    return ApexCharts;
  }();

  return ApexCharts$1;

}));


;(function(){

/**
 * Require the module at `name`.
 *
 * @param {String} name
 * @return {Object} exports
 * @api public
 */

function require(name) {
  var module = require.modules[name];
  if (!module) throw new Error('failed to require "' + name + '"');

  if (!('exports' in module) && typeof module.definition === 'function') {
    module.client = module.component = true;
    module.definition.call(this, module.exports = {}, module);
    delete module.definition;
  }

  return module.exports;
}

/**
 * Meta info, accessible in the global scope unless you use AMD option.
 */

require.loader = 'component';

/**
 * Internal helper object, contains a sorting function for semantiv versioning
 */
require.helper = {};
require.helper.semVerSort = function(a, b) {
  var aArray = a.version.split('.');
  var bArray = b.version.split('.');
  for (var i=0; i<aArray.length; ++i) {
    var aInt = parseInt(aArray[i], 10);
    var bInt = parseInt(bArray[i], 10);
    if (aInt === bInt) {
      var aLex = aArray[i].substr((""+aInt).length);
      var bLex = bArray[i].substr((""+bInt).length);
      if (aLex === '' && bLex !== '') return 1;
      if (aLex !== '' && bLex === '') return -1;
      if (aLex !== '' && bLex !== '') return aLex > bLex ? 1 : -1;
      continue;
    } else if (aInt > bInt) {
      return 1;
    } else {
      return -1;
    }
  }
  return 0;
}

/**
 * Find and require a module which name starts with the provided name.
 * If multiple modules exists, the highest semver is used.
 * This function can only be used for remote dependencies.

 * @param {String} name - module name: `user~repo`
 * @param {Boolean} returnPath - returns the canonical require path if true,
 *                               otherwise it returns the epxorted module
 */
require.latest = function (name, returnPath) {
  function showError(name) {
    throw new Error('failed to find latest module of "' + name + '"');
  }
  // only remotes with semvers, ignore local files conataining a '/'
  var versionRegexp = /(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/;
  var remoteRegexp = /(.*)~(.*)/;
  if (!remoteRegexp.test(name)) showError(name);
  var moduleNames = Object.keys(require.modules);
  var semVerCandidates = [];
  var otherCandidates = []; // for instance: name of the git branch
  for (var i=0; i<moduleNames.length; i++) {
    var moduleName = moduleNames[i];
    if (new RegExp(name + '@').test(moduleName)) {
        var version = moduleName.substr(name.length+1);
        var semVerMatch = versionRegexp.exec(moduleName);
        if (semVerMatch != null) {
          semVerCandidates.push({version: version, name: moduleName});
        } else {
          otherCandidates.push({version: version, name: moduleName});
        }
    }
  }
  if (semVerCandidates.concat(otherCandidates).length === 0) {
    showError(name);
  }
  if (semVerCandidates.length > 0) {
    var module = semVerCandidates.sort(require.helper.semVerSort).pop().name;
    if (returnPath === true) {
      return module;
    }
    return require(module);
  }
  // if the build contains more than one branch of the same module
  // you should not use this funciton
  var module = otherCandidates.sort(function(a, b) {return a.name > b.name})[0].name;
  if (returnPath === true) {
    return module;
  }
  return require(module);
}

/**
 * Registered modules.
 */

require.modules = {};

/**
 * Register module at `name` with callback `definition`.
 *
 * @param {String} name
 * @param {Function} definition
 * @api private
 */

require.register = function (name, definition) {
  require.modules[name] = {
    definition: definition
  };
};

/**
 * Define a module's exports immediately with `exports`.
 *
 * @param {String} name
 * @param {Generic} exports
 * @api private
 */

require.define = function (name, exports) {
  require.modules[name] = {
    exports: exports
  };
};
require.register("abpetkov~transitionize@0.0.3", function (exports, module) {

/**
 * Transitionize 0.0.2
 * https://github.com/abpetkov/transitionize
 *
 * Authored by Alexander Petkov
 * https://github.com/abpetkov
 *
 * Copyright 2013, Alexander Petkov
 * License: The MIT License (MIT)
 * http://opensource.org/licenses/MIT
 *
 */

/**
 * Expose `Transitionize`.
 */

module.exports = Transitionize;

/**
 * Initialize new Transitionize.
 *
 * @param {Object} element
 * @param {Object} props
 * @api public
 */

function Transitionize(element, props) {
  if (!(this instanceof Transitionize)) return new Transitionize(element, props);

  this.element = element;
  this.props = props || {};
  this.init();
}

/**
 * Detect if Safari.
 *
 * @returns {Boolean}
 * @api private
 */

Transitionize.prototype.isSafari = function() {
  return (/Safari/).test(navigator.userAgent) && (/Apple Computer/).test(navigator.vendor);
};

/**
 * Loop though the object and push the keys and values in an array.
 * Apply the CSS3 transition to the element and prefix with -webkit- for Safari.
 *
 * @api private
 */

Transitionize.prototype.init = function() {
  var transitions = [];

  for (var key in this.props) {
    transitions.push(key + ' ' + this.props[key]);
  }

  this.element.style.transition = transitions.join(', ');
  if (this.isSafari()) this.element.style.webkitTransition = transitions.join(', ');
};
});

require.register("ftlabs~fastclick@v0.6.11", function (exports, module) {
/**
 * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
 *
 * @version 0.6.11
 * @codingstandard ftlabs-jsv2
 * @copyright The Financial Times Limited [All Rights Reserved]
 * @license MIT License (see LICENSE.txt)
 */

/*jslint browser:true, node:true*/
/*global define, Event, Node*/


/**
 * Instantiate fast-clicking listeners on the specificed layer.
 *
 * @constructor
 * @param {Element} layer The layer to listen on
 */
function FastClick(layer) {
	'use strict';
	var oldOnClick, self = this;


	/**
	 * Whether a click is currently being tracked.
	 *
	 * @type boolean
	 */
	this.trackingClick = false;


	/**
	 * Timestamp for when when click tracking started.
	 *
	 * @type number
	 */
	this.trackingClickStart = 0;


	/**
	 * The element being tracked for a click.
	 *
	 * @type EventTarget
	 */
	this.targetElement = null;


	/**
	 * X-coordinate of touch start event.
	 *
	 * @type number
	 */
	this.touchStartX = 0;


	/**
	 * Y-coordinate of touch start event.
	 *
	 * @type number
	 */
	this.touchStartY = 0;


	/**
	 * ID of the last touch, retrieved from Touch.identifier.
	 *
	 * @type number
	 */
	this.lastTouchIdentifier = 0;


	/**
	 * Touchmove boundary, beyond which a click will be cancelled.
	 *
	 * @type number
	 */
	this.touchBoundary = 10;


	/**
	 * The FastClick layer.
	 *
	 * @type Element
	 */
	this.layer = layer;

	if (!layer || !layer.nodeType) {
		throw new TypeError('Layer must be a document node');
	}

	/** @type function() */
	this.onClick = function() { return FastClick.prototype.onClick.apply(self, arguments); };

	/** @type function() */
	this.onMouse = function() { return FastClick.prototype.onMouse.apply(self, arguments); };

	/** @type function() */
	this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); };

	/** @type function() */
	this.onTouchMove = function() { return FastClick.prototype.onTouchMove.apply(self, arguments); };

	/** @type function() */
	this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); };

	/** @type function() */
	this.onTouchCancel = function() { return FastClick.prototype.onTouchCancel.apply(self, arguments); };

	if (FastClick.notNeeded(layer)) {
		return;
	}

	// Set up event handlers as required
	if (this.deviceIsAndroid) {
		layer.addEventListener('mouseover', this.onMouse, true);
		layer.addEventListener('mousedown', this.onMouse, true);
		layer.addEventListener('mouseup', this.onMouse, true);
	}

	layer.addEventListener('click', this.onClick, true);
	layer.addEventListener('touchstart', this.onTouchStart, false);
	layer.addEventListener('touchmove', this.onTouchMove, false);
	layer.addEventListener('touchend', this.onTouchEnd, false);
	layer.addEventListener('touchcancel', this.onTouchCancel, false);

	// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
	// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
	// layer when they are cancelled.
	if (!Event.prototype.stopImmediatePropagation) {
		layer.removeEventListener = function(type, callback, capture) {
			var rmv = Node.prototype.removeEventListener;
			if (type === 'click') {
				rmv.call(layer, type, callback.hijacked || callback, capture);
			} else {
				rmv.call(layer, type, callback, capture);
			}
		};

		layer.addEventListener = function(type, callback, capture) {
			var adv = Node.prototype.addEventListener;
			if (type === 'click') {
				adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
					if (!event.propagationStopped) {
						callback(event);
					}
				}), capture);
			} else {
				adv.call(layer, type, callback, capture);
			}
		};
	}

	// If a handler is already declared in the element's onclick attribute, it will be fired before
	// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
	// adding it as listener.
	if (typeof layer.onclick === 'function') {

		// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
		// - the old one won't work if passed to addEventListener directly.
		oldOnClick = layer.onclick;
		layer.addEventListener('click', function(event) {
			oldOnClick(event);
		}, false);
		layer.onclick = null;
	}
}


/**
 * Android requires exceptions.
 *
 * @type boolean
 */
FastClick.prototype.deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0;


/**
 * iOS requires exceptions.
 *
 * @type boolean
 */
FastClick.prototype.deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent);


/**
 * iOS 4 requires an exception for select elements.
 *
 * @type boolean
 */
FastClick.prototype.deviceIsIOS4 = FastClick.prototype.deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);


/**
 * iOS 6.0(+?) requires the target element to be manually derived
 *
 * @type boolean
 */
FastClick.prototype.deviceIsIOSWithBadTarget = FastClick.prototype.deviceIsIOS && (/OS ([6-9]|\d{2})_\d/).test(navigator.userAgent);


/**
 * Determine whether a given element requires a native click.
 *
 * @param {EventTarget|Element} target Target DOM element
 * @returns {boolean} Returns true if the element needs a native click
 */
FastClick.prototype.needsClick = function(target) {
	'use strict';
	switch (target.nodeName.toLowerCase()) {

	// Don't send a synthetic click to disabled inputs (issue #62)
	case 'button':
	case 'select':
	case 'textarea':
		if (target.disabled) {
			return true;
		}

		break;
	case 'input':

		// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
		if ((this.deviceIsIOS && target.type === 'file') || target.disabled) {
			return true;
		}

		break;
	case 'label':
	case 'video':
		return true;
	}

	return (/\bneedsclick\b/).test(target.className);
};


/**
 * Determine whether a given element requires a call to focus to simulate click into element.
 *
 * @param {EventTarget|Element} target Target DOM element
 * @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
 */
FastClick.prototype.needsFocus = function(target) {
	'use strict';
	switch (target.nodeName.toLowerCase()) {
	case 'textarea':
		return true;
	case 'select':
		return !this.deviceIsAndroid;
	case 'input':
		switch (target.type) {
		case 'button':
		case 'checkbox':
		case 'file':
		case 'image':
		case 'radio':
		case 'submit':
			return false;
		}

		// No point in attempting to focus disabled inputs
		return !target.disabled && !target.readOnly;
	default:
		return (/\bneedsfocus\b/).test(target.className);
	}
};


/**
 * Send a click event to the specified element.
 *
 * @param {EventTarget|Element} targetElement
 * @param {Event} event
 */
FastClick.prototype.sendClick = function(targetElement, event) {
	'use strict';
	var clickEvent, touch;

	// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
	if (document.activeElement && document.activeElement !== targetElement) {
		document.activeElement.blur();
	}

	touch = event.changedTouches[0];

	// Synthesise a click event, with an extra attribute so it can be tracked
	clickEvent = document.createEvent('MouseEvents');
	clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
	clickEvent.forwardedTouchEvent = true;
	targetElement.dispatchEvent(clickEvent);
};

FastClick.prototype.determineEventType = function(targetElement) {
	'use strict';

	//Issue #159: Android Chrome Select Box does not open with a synthetic click event
	if (this.deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
		return 'mousedown';
	}

	return 'click';
};


/**
 * @param {EventTarget|Element} targetElement
 */
FastClick.prototype.focus = function(targetElement) {
	'use strict';
	var length;

	// Issue #160: on iOS 7, some input elements (e.g. date datetime) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
	if (this.deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time') {
		length = targetElement.value.length;
		targetElement.setSelectionRange(length, length);
	} else {
		targetElement.focus();
	}
};


/**
 * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
 *
 * @param {EventTarget|Element} targetElement
 */
FastClick.prototype.updateScrollParent = function(targetElement) {
	'use strict';
	var scrollParent, parentElement;

	scrollParent = targetElement.fastClickScrollParent;

	// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
	// target element was moved to another parent.
	if (!scrollParent || !scrollParent.contains(targetElement)) {
		parentElement = targetElement;
		do {
			if (parentElement.scrollHeight > parentElement.offsetHeight) {
				scrollParent = parentElement;
				targetElement.fastClickScrollParent = parentElement;
				break;
			}

			parentElement = parentElement.parentElement;
		} while (parentElement);
	}

	// Always update the scroll top tracker if possible.
	if (scrollParent) {
		scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
	}
};


/**
 * @param {EventTarget} targetElement
 * @returns {Element|EventTarget}
 */
FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
	'use strict';

	// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
	if (eventTarget.nodeType === Node.TEXT_NODE) {
		return eventTarget.parentNode;
	}

	return eventTarget;
};


/**
 * On touch start, record the position and scroll offset.
 *
 * @param {Event} event
 * @returns {boolean}
 */
FastClick.prototype.onTouchStart = function(event) {
	'use strict';
	var targetElement, touch, selection;

	// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
	if (event.targetTouches.length > 1) {
		return true;
	}

	targetElement = this.getTargetElementFromEventTarget(event.target);
	touch = event.targetTouches[0];

	if (this.deviceIsIOS) {

		// Only trusted events will deselect text on iOS (issue #49)
		selection = window.getSelection();
		if (selection.rangeCount && !selection.isCollapsed) {
			return true;
		}

		if (!this.deviceIsIOS4) {

			// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
			// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
			// with the same identifier as the touch event that previously triggered the click that triggered the alert.
			// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
			// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
			if (touch.identifier === this.lastTouchIdentifier) {
				event.preventDefault();
				return false;
			}

			this.lastTouchIdentifier = touch.identifier;

			// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
			// 1) the user does a fling scroll on the scrollable layer
			// 2) the user stops the fling scroll with another tap
			// then the event.target of the last 'touchend' event will be the element that was under the user's finger
			// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
			// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
			this.updateScrollParent(targetElement);
		}
	}

	this.trackingClick = true;
	this.trackingClickStart = event.timeStamp;
	this.targetElement = targetElement;

	this.touchStartX = touch.pageX;
	this.touchStartY = touch.pageY;

	// Prevent phantom clicks on fast double-tap (issue #36)
	if ((event.timeStamp - this.lastClickTime) < 200) {
		event.preventDefault();
	}

	return true;
};


/**
 * Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
 *
 * @param {Event} event
 * @returns {boolean}
 */
FastClick.prototype.touchHasMoved = function(event) {
	'use strict';
	var touch = event.changedTouches[0], boundary = this.touchBoundary;

	if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
		return true;
	}

	return false;
};


/**
 * Update the last position.
 *
 * @param {Event} event
 * @returns {boolean}
 */
FastClick.prototype.onTouchMove = function(event) {
	'use strict';
	if (!this.trackingClick) {
		return true;
	}

	// If the touch has moved, cancel the click tracking
	if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
		this.trackingClick = false;
		this.targetElement = null;
	}

	return true;
};


/**
 * Attempt to find the labelled control for the given label element.
 *
 * @param {EventTarget|HTMLLabelElement} labelElement
 * @returns {Element|null}
 */
FastClick.prototype.findControl = function(labelElement) {
	'use strict';

	// Fast path for newer browsers supporting the HTML5 control attribute
	if (labelElement.control !== undefined) {
		return labelElement.control;
	}

	// All browsers under test that support touch events also support the HTML5 htmlFor attribute
	if (labelElement.htmlFor) {
		return document.getElementById(labelElement.htmlFor);
	}

	// If no for attribute exists, attempt to retrieve the first labellable descendant element
	// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
	return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
};


/**
 * On touch end, determine whether to send a click event at once.
 *
 * @param {Event} event
 * @returns {boolean}
 */
FastClick.prototype.onTouchEnd = function(event) {
	'use strict';
	var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;

	if (!this.trackingClick) {
		return true;
	}

	// Prevent phantom clicks on fast double-tap (issue #36)
	if ((event.timeStamp - this.lastClickTime) < 200) {
		this.cancelNextClick = true;
		return true;
	}

	// Reset to prevent wrong click cancel on input (issue #156).
	this.cancelNextClick = false;

	this.lastClickTime = event.timeStamp;

	trackingClickStart = this.trackingClickStart;
	this.trackingClick = false;
	this.trackingClickStart = 0;

	// On some iOS devices, the targetElement supplied with the event is invalid if the layer
	// is performing a transition or scroll, and has to be re-detected manually. Note that
	// for this to function correctly, it must be called *after* the event target is checked!
	// See issue #57; also filed as rdar://13048589 .
	if (this.deviceIsIOSWithBadTarget) {
		touch = event.changedTouches[0];

		// In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
		targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
		targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
	}

	targetTagName = targetElement.tagName.toLowerCase();
	if (targetTagName === 'label') {
		forElement = this.findControl(targetElement);
		if (forElement) {
			this.focus(targetElement);
			if (this.deviceIsAndroid) {
				return false;
			}

			targetElement = forElement;
		}
	} else if (this.needsFocus(targetElement)) {

		// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
		// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
		if ((event.timeStamp - trackingClickStart) > 100 || (this.deviceIsIOS && window.top !== window && targetTagName === 'input')) {
			this.targetElement = null;
			return false;
		}

		this.focus(targetElement);

		// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
		if (!this.deviceIsIOS4 || targetTagName !== 'select') {
			this.targetElement = null;
			event.preventDefault();
		}

		return false;
	}

	if (this.deviceIsIOS && !this.deviceIsIOS4) {

		// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
		// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
		scrollParent = targetElement.fastClickScrollParent;
		if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
			return true;
		}
	}

	// Prevent the actual click from going though - unless the target node is marked as requiring
	// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
	if (!this.needsClick(targetElement)) {
		event.preventDefault();
		this.sendClick(targetElement, event);
	}

	return false;
};


/**
 * On touch cancel, stop tracking the click.
 *
 * @returns {void}
 */
FastClick.prototype.onTouchCancel = function() {
	'use strict';
	this.trackingClick = false;
	this.targetElement = null;
};


/**
 * Determine mouse events which should be permitted.
 *
 * @param {Event} event
 * @returns {boolean}
 */
FastClick.prototype.onMouse = function(event) {
	'use strict';

	// If a target element was never set (because a touch event was never fired) allow the event
	if (!this.targetElement) {
		return true;
	}

	if (event.forwardedTouchEvent) {
		return true;
	}

	// Programmatically generated events targeting a specific element should be permitted
	if (!event.cancelable) {
		return true;
	}

	// Derive and check the target element to see whether the mouse event needs to be permitted;
	// unless explicitly enabled, prevent non-touch click events from triggering actions,
	// to prevent ghost/doubleclicks.
	if (!this.needsClick(this.targetElement) || this.cancelNextClick) {

		// Prevent any user-added listeners declared on FastClick element from being fired.
		if (event.stopImmediatePropagation) {
			event.stopImmediatePropagation();
		} else {

			// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
			event.propagationStopped = true;
		}

		// Cancel the event
		event.stopPropagation();
		event.preventDefault();

		return false;
	}

	// If the mouse event is permitted, return true for the action to go through.
	return true;
};


/**
 * On actual clicks, determine whether this is a touch-generated click, a click action occurring
 * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
 * an actual click which should be permitted.
 *
 * @param {Event} event
 * @returns {boolean}
 */
FastClick.prototype.onClick = function(event) {
	'use strict';
	var permitted;

	// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
	if (this.trackingClick) {
		this.targetElement = null;
		this.trackingClick = false;
		return true;
	}

	// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
	if (event.target.type === 'submit' && event.detail === 0) {
		return true;
	}

	permitted = this.onMouse(event);

	// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
	if (!permitted) {
		this.targetElement = null;
	}

	// If clicks are permitted, return true for the action to go through.
	return permitted;
};


/**
 * Remove all FastClick's event listeners.
 *
 * @returns {void}
 */
FastClick.prototype.destroy = function() {
	'use strict';
	var layer = this.layer;

	if (this.deviceIsAndroid) {
		layer.removeEventListener('mouseover', this.onMouse, true);
		layer.removeEventListener('mousedown', this.onMouse, true);
		layer.removeEventListener('mouseup', this.onMouse, true);
	}

	layer.removeEventListener('click', this.onClick, true);
	layer.removeEventListener('touchstart', this.onTouchStart, false);
	layer.removeEventListener('touchmove', this.onTouchMove, false);
	layer.removeEventListener('touchend', this.onTouchEnd, false);
	layer.removeEventListener('touchcancel', this.onTouchCancel, false);
};


/**
 * Check whether FastClick is needed.
 *
 * @param {Element} layer The layer to listen on
 */
FastClick.notNeeded = function(layer) {
	'use strict';
	var metaViewport;
	var chromeVersion;

	// Devices that don't support touch don't need FastClick
	if (typeof window.ontouchstart === 'undefined') {
		return true;
	}

	// Chrome version - zero for other browsers
	chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];

	if (chromeVersion) {

		if (FastClick.prototype.deviceIsAndroid) {
			metaViewport = document.querySelector('meta[name=viewport]');

			if (metaViewport) {
				// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
				if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
					return true;
				}
				// Chrome 32 and above with width=device-width or less don't need FastClick
				if (chromeVersion > 31 && window.innerWidth <= window.screen.width) {
					return true;
				}
			}

		// Chrome desktop doesn't need FastClick (issue #15)
		} else {
			return true;
		}
	}

	// IE10 with -ms-touch-action: none, which disables double-tap-to-zoom (issue #97)
	if (layer.style.msTouchAction === 'none') {
		return true;
	}

	return false;
};


/**
 * Factory method for creating a FastClick object
 *
 * @param {Element} layer The layer to listen on
 */
FastClick.attach = function(layer) {
	'use strict';
	return new FastClick(layer);
};


if (typeof define !== 'undefined' && define.amd) {

	// AMD. Register as an anonymous module.
	define(function() {
		'use strict';
		return FastClick;
	});
} else if (typeof module !== 'undefined' && module.exports) {
	module.exports = FastClick.attach;
	module.exports.FastClick = FastClick;
} else {
	window.FastClick = FastClick;
}

});

require.register("component~indexof@0.0.3", function (exports, module) {
module.exports = function(arr, obj){
  if (arr.indexOf) return arr.indexOf(obj);
  for (var i = 0; i < arr.length; ++i) {
    if (arr[i] === obj) return i;
  }
  return -1;
};
});

require.register("component~classes@1.2.1", function (exports, module) {
/**
 * Module dependencies.
 */

var index = require('component~indexof@0.0.3');

/**
 * Whitespace regexp.
 */

var re = /\s+/;

/**
 * toString reference.
 */

var toString = Object.prototype.toString;

/**
 * Wrap `el` in a `ClassList`.
 *
 * @param {Element} el
 * @return {ClassList}
 * @api public
 */

module.exports = function(el){
  return new ClassList(el);
};

/**
 * Initialize a new ClassList for `el`.
 *
 * @param {Element} el
 * @api private
 */

function ClassList(el) {
  if (!el) throw new Error('A DOM element reference is required');
  this.el = el;
  this.list = el.classList;
}

/**
 * Add class `name` if not already present.
 *
 * @param {String} name
 * @return {ClassList}
 * @api public
 */

ClassList.prototype.add = function(name){
  // classList
  if (this.list) {
    this.list.add(name);
    return this;
  }

  // fallback
  var arr = this.array();
  var i = index(arr, name);
  if (!~i) arr.push(name);
  this.el.className = arr.join(' ');
  return this;
};

/**
 * Remove class `name` when present, or
 * pass a regular expression to remove
 * any which match.
 *
 * @param {String|RegExp} name
 * @return {ClassList}
 * @api public
 */

ClassList.prototype.remove = function(name){
  if ('[object RegExp]' == toString.call(name)) {
    return this.removeMatching(name);
  }

  // classList
  if (this.list) {
    this.list.remove(name);
    return this;
  }

  // fallback
  var arr = this.array();
  var i = index(arr, name);
  if (~i) arr.splice(i, 1);
  this.el.className = arr.join(' ');
  return this;
};

/**
 * Remove all classes matching `re`.
 *
 * @param {RegExp} re
 * @return {ClassList}
 * @api private
 */

ClassList.prototype.removeMatching = function(re){
  var arr = this.array();
  for (var i = 0; i < arr.length; i++) {
    if (re.test(arr[i])) {
      this.remove(arr[i]);
    }
  }
  return this;
};

/**
 * Toggle class `name`, can force state via `force`.
 *
 * For browsers that support classList, but do not support `force` yet,
 * the mistake will be detected and corrected.
 *
 * @param {String} name
 * @param {Boolean} force
 * @return {ClassList}
 * @api public
 */

ClassList.prototype.toggle = function(name, force){
  // classList
  if (this.list) {
    if ("undefined" !== typeof force) {
      if (force !== this.list.toggle(name, force)) {
        this.list.toggle(name); // toggle again to correct
      }
    } else {
      this.list.toggle(name);
    }
    return this;
  }

  // fallback
  if ("undefined" !== typeof force) {
    if (!force) {
      this.remove(name);
    } else {
      this.add(name);
    }
  } else {
    if (this.has(name)) {
      this.remove(name);
    } else {
      this.add(name);
    }
  }

  return this;
};

/**
 * Return an array of classes.
 *
 * @return {Array}
 * @api public
 */

ClassList.prototype.array = function(){
  var str = this.el.className.replace(/^\s+|\s+$/g, '');
  var arr = str.split(re);
  if ('' === arr[0]) arr.shift();
  return arr;
};

/**
 * Check if class `name` is present.
 *
 * @param {String} name
 * @return {ClassList}
 * @api public
 */

ClassList.prototype.has =
ClassList.prototype.contains = function(name){
  return this.list
    ? this.list.contains(name)
    : !! ~index(this.array(), name);
};

});

require.register("component~event@0.1.4", function (exports, module) {
var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
    unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
    prefix = bind !== 'addEventListener' ? 'on' : '';

/**
 * Bind `el` event `type` to `fn`.
 *
 * @param {Element} el
 * @param {String} type
 * @param {Function} fn
 * @param {Boolean} capture
 * @return {Function}
 * @api public
 */

exports.bind = function(el, type, fn, capture){
  el[bind](prefix + type, fn, capture || false);
  return fn;
};

/**
 * Unbind `el` event `type`'s callback `fn`.
 *
 * @param {Element} el
 * @param {String} type
 * @param {Function} fn
 * @param {Boolean} capture
 * @return {Function}
 * @api public
 */

exports.unbind = function(el, type, fn, capture){
  el[unbind](prefix + type, fn, capture || false);
  return fn;
};
});

require.register("component~query@0.0.3", function (exports, module) {
function one(selector, el) {
  return el.querySelector(selector);
}

exports = module.exports = function(selector, el){
  el = el || document;
  return one(selector, el);
};

exports.all = function(selector, el){
  el = el || document;
  return el.querySelectorAll(selector);
};

exports.engine = function(obj){
  if (!obj.one) throw new Error('.one callback required');
  if (!obj.all) throw new Error('.all callback required');
  one = obj.one;
  exports.all = obj.all;
  return exports;
};

});

require.register("component~matches-selector@0.1.5", function (exports, module) {
/**
 * Module dependencies.
 */

var query = require('component~query@0.0.3');

/**
 * Element prototype.
 */

var proto = Element.prototype;

/**
 * Vendor function.
 */

var vendor = proto.matches
  || proto.webkitMatchesSelector
  || proto.mozMatchesSelector
  || proto.msMatchesSelector
  || proto.oMatchesSelector;

/**
 * Expose `match()`.
 */

module.exports = match;

/**
 * Match `el` to `selector`.
 *
 * @param {Element} el
 * @param {String} selector
 * @return {Boolean}
 * @api public
 */

function match(el, selector) {
  if (!el || el.nodeType !== 1) return false;
  if (vendor) return vendor.call(el, selector);
  var nodes = query.all(selector, el.parentNode);
  for (var i = 0; i < nodes.length; ++i) {
    if (nodes[i] == el) return true;
  }
  return false;
}

});

require.register("component~closest@0.1.4", function (exports, module) {
var matches = require('component~matches-selector@0.1.5')

module.exports = function (element, selector, checkYoSelf, root) {
  element = checkYoSelf ? {parentNode: element} : element

  root = root || document

  // Make sure `element !== document` and `element != null`
  // otherwise we get an illegal invocation
  while ((element = element.parentNode) && element !== document) {
    if (matches(element, selector))
      return element
    // After `matches` on the edge case that
    // the selector matches the root
    // (when the root is not the document)
    if (element === root)
      return
  }
}

});

require.register("component~delegate@0.2.3", function (exports, module) {
/**
 * Module dependencies.
 */

var closest = require('component~closest@0.1.4')
  , event = require('component~event@0.1.4');

/**
 * Delegate event `type` to `selector`
 * and invoke `fn(e)`. A callback function
 * is returned which may be passed to `.unbind()`.
 *
 * @param {Element} el
 * @param {String} selector
 * @param {String} type
 * @param {Function} fn
 * @param {Boolean} capture
 * @return {Function}
 * @api public
 */

exports.bind = function(el, selector, type, fn, capture){
  return event.bind(el, type, function(e){
    var target = e.target || e.srcElement;
    e.delegateTarget = closest(target, selector, true, el);
    if (e.delegateTarget) fn.call(el, e);
  }, capture);
};

/**
 * Unbind event `type`'s callback `fn`.
 *
 * @param {Element} el
 * @param {String} type
 * @param {Function} fn
 * @param {Boolean} capture
 * @api public
 */

exports.unbind = function(el, type, fn, capture){
  event.unbind(el, type, fn, capture);
};

});

require.register("component~events@1.0.9", function (exports, module) {

/**
 * Module dependencies.
 */

var events = require('component~event@0.1.4');
var delegate = require('component~delegate@0.2.3');

/**
 * Expose `Events`.
 */

module.exports = Events;

/**
 * Initialize an `Events` with the given
 * `el` object which events will be bound to,
 * and the `obj` which will receive method calls.
 *
 * @param {Object} el
 * @param {Object} obj
 * @api public
 */

function Events(el, obj) {
  if (!(this instanceof Events)) return new Events(el, obj);
  if (!el) throw new Error('element required');
  if (!obj) throw new Error('object required');
  this.el = el;
  this.obj = obj;
  this._events = {};
}

/**
 * Subscription helper.
 */

Events.prototype.sub = function(event, method, cb){
  this._events[event] = this._events[event] || {};
  this._events[event][method] = cb;
};

/**
 * Bind to `event` with optional `method` name.
 * When `method` is undefined it becomes `event`
 * with the "on" prefix.
 *
 * Examples:
 *
 *  Direct event handling:
 *
 *    events.bind('click') // implies "onclick"
 *    events.bind('click', 'remove')
 *    events.bind('click', 'sort', 'asc')
 *
 *  Delegated event handling:
 *
 *    events.bind('click li > a')
 *    events.bind('click li > a', 'remove')
 *    events.bind('click a.sort-ascending', 'sort', 'asc')
 *    events.bind('click a.sort-descending', 'sort', 'desc')
 *
 * @param {String} event
 * @param {String|function} [method]
 * @return {Function} callback
 * @api public
 */

Events.prototype.bind = function(event, method){
  var e = parse(event);
  var el = this.el;
  var obj = this.obj;
  var name = e.name;
  var method = method || 'on' + name;
  var args = [].slice.call(arguments, 2);

  // callback
  function cb(){
    var a = [].slice.call(arguments).concat(args);
    obj[method].apply(obj, a);
  }

  // bind
  if (e.selector) {
    cb = delegate.bind(el, e.selector, name, cb);
  } else {
    events.bind(el, name, cb);
  }

  // subscription for unbinding
  this.sub(name, method, cb);

  return cb;
};

/**
 * Unbind a single binding, all bindings for `event`,
 * or all bindings within the manager.
 *
 * Examples:
 *
 *  Unbind direct handlers:
 *
 *     events.unbind('click', 'remove')
 *     events.unbind('click')
 *     events.unbind()
 *
 * Unbind delegate handlers:
 *
 *     events.unbind('click', 'remove')
 *     events.unbind('click')
 *     events.unbind()
 *
 * @param {String|Function} [event]
 * @param {String|Function} [method]
 * @api public
 */

Events.prototype.unbind = function(event, method){
  if (0 == arguments.length) return this.unbindAll();
  if (1 == arguments.length) return this.unbindAllOf(event);

  // no bindings for this event
  var bindings = this._events[event];
  if (!bindings) return;

  // no bindings for this method
  var cb = bindings[method];
  if (!cb) return;

  events.unbind(this.el, event, cb);
};

/**
 * Unbind all events.
 *
 * @api private
 */

Events.prototype.unbindAll = function(){
  for (var event in this._events) {
    this.unbindAllOf(event);
  }
};

/**
 * Unbind all events for `event`.
 *
 * @param {String} event
 * @api private
 */

Events.prototype.unbindAllOf = function(event){
  var bindings = this._events[event];
  if (!bindings) return;

  for (var method in bindings) {
    this.unbind(event, method);
  }
};

/**
 * Parse `event`.
 *
 * @param {String} event
 * @return {Object}
 * @api private
 */

function parse(event) {
  var parts = event.split(/ +/);
  return {
    name: parts.shift(),
    selector: parts.join(' ')
  }
}

});

require.register("switchery", function (exports, module) {
/**
 * Switchery 0.8.1
 * http://abpetkov.github.io/switchery/
 *
 * Authored by Alexander Petkov
 * https://github.com/abpetkov
 *
 * Copyright 2013-2015, Alexander Petkov
 * License: The MIT License (MIT)
 * http://opensource.org/licenses/MIT
 *
 */

/**
 * External dependencies.
 */

var transitionize = require('abpetkov~transitionize@0.0.3')
  , fastclick = require('ftlabs~fastclick@v0.6.11')
  , classes = require('component~classes@1.2.1')
  , events = require('component~events@1.0.9');

/**
 * Expose `Switchery`.
 */

module.exports = Switchery;

/**
 * Set Switchery default values.
 *
 * @api public
 */

var defaults = {
    color             : '#64bd63'
  , secondaryColor    : '#dfdfdf'
  , jackColor         : '#fff'
  , jackSecondaryColor: null
  , className         : 'switchery'
  , disabled          : false
  , disabledOpacity   : 0.5
  , speed             : '0.4s'
  , size              : 'default'
};

/**
 * Create Switchery object.
 *
 * @param {Object} element
 * @param {Object} options
 * @api public
 */

function Switchery(element, options) {
  if (!(this instanceof Switchery)) return new Switchery(element, options);

  this.element = element;
  this.options = options || {};

  for (var i in defaults) {
    if (this.options[i] == null) {
      this.options[i] = defaults[i];
    }
  }

  if (this.element != null && this.element.type == 'checkbox') this.init();
  if (this.isDisabled() === true) this.disable();
}

/**
 * Hide the target element.
 *
 * @api private
 */

Switchery.prototype.hide = function() {
  this.element.style.display = 'none';
};

/**
 * Show custom switch after the target element.
 *
 * @api private
 */

Switchery.prototype.show = function() {
  var switcher = this.create();
  this.insertAfter(this.element, switcher);
};

/**
 * Create custom switch.
 *
 * @returns {Object} this.switcher
 * @api private
 */

Switchery.prototype.create = function() {
  this.switcher = document.createElement('span');
  this.jack = document.createElement('small');
  this.switcher.appendChild(this.jack);
  this.switcher.className = this.options.className;
  this.events = events(this.switcher, this);

  return this.switcher;
};

/**
 * Insert after element after another element.
 *
 * @param {Object} reference
 * @param {Object} target
 * @api private
 */

Switchery.prototype.insertAfter = function(reference, target) {
  reference.parentNode.insertBefore(target, reference.nextSibling);
};

/**
 * Set switch jack proper position.
 *
 * @param {Boolean} clicked - we need this in order to uncheck the input when the switch is clicked
 * @api private
 */

Switchery.prototype.setPosition = function (clicked) {
  var checked = this.isChecked()
    , switcher = this.switcher
    , jack = this.jack;

  if (clicked && checked) checked = false;
  else if (clicked && !checked) checked = true;

  if (checked === true) {
    this.element.checked = true;

    if (window.getComputedStyle) jack.style.left = parseInt(window.getComputedStyle(switcher).width) - parseInt(window.getComputedStyle(jack).width) + 'px';
    else jack.style.left = parseInt(switcher.currentStyle['width']) - parseInt(jack.currentStyle['width']) + 'px';

    if (this.options.color) this.colorize();
    this.setSpeed();
  } else {
    jack.style.left = 0;
    this.element.checked = false;
    this.switcher.style.boxShadow = 'inset 0 0 0 0 ' + this.options.secondaryColor;
    this.switcher.style.borderColor = this.options.secondaryColor;
    this.switcher.style.backgroundColor = (this.options.secondaryColor !== defaults.secondaryColor) ? this.options.secondaryColor : '#fff';
    this.jack.style.backgroundColor = (this.options.jackSecondaryColor !== this.options.jackColor) ? this.options.jackSecondaryColor : this.options.jackColor;
    this.setSpeed();
  }
};

/**
 * Set speed.
 *
 * @api private
 */

Switchery.prototype.setSpeed = function() {
  var switcherProp = {}
    , jackProp = {
        'background-color': this.options.speed
      , 'left': this.options.speed.replace(/[a-z]/, '') / 2 + 's'
    };

  if (this.isChecked()) {
    switcherProp = {
        'border': this.options.speed
      , 'box-shadow': this.options.speed
      , 'background-color': this.options.speed.replace(/[a-z]/, '') * 3 + 's'
    };
  } else {
    switcherProp = {
        'border': this.options.speed
      , 'box-shadow': this.options.speed
    };
  }

  transitionize(this.switcher, switcherProp);
  transitionize(this.jack, jackProp);
};

/**
 * Set switch size.
 *
 * @api private
 */

Switchery.prototype.setSize = function() {
  var small = 'switchery-small'
    , normal = 'switchery-default'
    , large = 'switchery-large';

  switch (this.options.size) {
    case 'small':
      classes(this.switcher).add(small)
      break;
    case 'large':
      classes(this.switcher).add(large)
      break;
    default:
      classes(this.switcher).add(normal)
      break;
  }
};

/**
 * Set switch color.
 *
 * @api private
 */

Switchery.prototype.colorize = function() {
  var switcherHeight = this.switcher.offsetHeight / 2;

  this.switcher.style.backgroundColor = this.options.color;
  this.switcher.style.borderColor = this.options.color;
  this.switcher.style.boxShadow = 'inset 0 0 0 ' + switcherHeight + 'px ' + this.options.color;
  this.jack.style.backgroundColor = this.options.jackColor;
};

/**
 * Handle the onchange event.
 *
 * @param {Boolean} state
 * @api private
 */

Switchery.prototype.handleOnchange = function(state) {
  if (document.dispatchEvent) {
    var event = document.createEvent('HTMLEvents');
    event.initEvent('change', true, true);
    this.element.dispatchEvent(event);
  } else {
    this.element.fireEvent('onchange');
  }
};

/**
 * Handle the native input element state change.
 * A `change` event must be fired in order to detect the change.
 *
 * @api private
 */

Switchery.prototype.handleChange = function() {
  var self = this
    , el = this.element;

  if (el.addEventListener) {
    el.addEventListener('change', function() {
      self.setPosition();
    });
  } else {
    el.attachEvent('onchange', function() {
      self.setPosition();
    });
  }
};

/**
 * Handle the switch click event.
 *
 * @api private
 */

Switchery.prototype.handleClick = function() {
  var switcher = this.switcher;

  fastclick(switcher);
  this.events.bind('click', 'bindClick');
};

/**
 * Attach all methods that need to happen on switcher click.
 *
 * @api private
 */

Switchery.prototype.bindClick = function() {
  var parent = this.element.parentNode.tagName.toLowerCase()
    , labelParent = (parent === 'label') ? false : true;

  this.setPosition(labelParent);
  this.handleOnchange(this.element.checked);
};

/**
 * Mark an individual switch as already handled.
 *
 * @api private
 */

Switchery.prototype.markAsSwitched = function() {
  this.element.setAttribute('data-switchery', true);
};

/**
 * Check if an individual switch is already handled.
 *
 * @api private
 */

Switchery.prototype.markedAsSwitched = function() {
  return this.element.getAttribute('data-switchery');
};

/**
 * Initialize Switchery.
 *
 * @api private
 */

Switchery.prototype.init = function() {
  this.hide();
  this.show();
  this.setSize();
  this.setPosition();
  this.markAsSwitched();
  this.handleChange();
  this.handleClick();
};

/**
 * See if input is checked.
 *
 * @returns {Boolean}
 * @api public
 */

Switchery.prototype.isChecked = function() {
  return this.element.checked;
};

/**
 * See if switcher should be disabled.
 *
 * @returns {Boolean}
 * @api public
 */

Switchery.prototype.isDisabled = function() {
  return this.options.disabled || this.element.disabled || this.element.readOnly;
};

/**
 * Destroy all event handlers attached to the switch.
 *
 * @api public
 */

Switchery.prototype.destroy = function() {
  this.events.unbind();
};

/**
 * Enable disabled switch element.
 *
 * @api public
 */

Switchery.prototype.enable = function() {
  if (!this.options.disabled) return;
  if (this.options.disabled) this.options.disabled = false;
  if (this.element.disabled) this.element.disabled = false;
  if (this.element.readOnly) this.element.readOnly = false;
  this.switcher.style.opacity = 1;
  this.events.bind('click', 'bindClick');
};

/**
 * Disable switch element.
 *
 * @api public
 */

Switchery.prototype.disable = function() {
  if (this.options.disabled) return;
  if (!this.options.disabled) this.options.disabled = true;
  if (!this.element.disabled) this.element.disabled = true;
  if (!this.element.readOnly) this.element.readOnly = true;
  this.switcher.style.opacity = this.options.disabledOpacity;
  this.destroy();
};

});

if (typeof exports == "object") {
  module.exports = require("switchery");
} else if (typeof define == "function" && define.amd) {
  define("Switchery", [], function(){ return require("switchery"); });
} else {
  (this || window)["Switchery"] = require("switchery");
}
})();

/* BoxRefresh()
 * =========
 * Adds AJAX content control to a box.
 *
 * @Usage: $('#my-box').boxRefresh(options)
 *         or add [data-widget="box-refresh"] to the box element
 *         Pass any option as data-option="value"
 */
+function ($) {
  'use strict';

  var DataKey = 'lte.boxrefresh';

  var Default = {
    source         : '',
    params         : {},
    trigger        : '.refresh-btn',
    content        : '.box-body',
    loadInContent  : true,
    responseType   : '',
    overlayTemplate: '<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>',
    onLoadStart    : function () {
    },
    onLoadDone     : function (response) {
      return response;
    }
  };

  var Selector = {
    data: '[data-widget="box-refresh"]'
  };

  // BoxRefresh Class Definition
  // =========================
  var BoxRefresh = function (element, options) {
    this.element  = element;
    this.options  = options;
    this.$overlay = $(options.overlayTemplate);

    if (options.source === '') {
      throw new Error('Source url was not defined. Please specify a url in your BoxRefresh source option.');
    }

    this._setUpListeners();
    this.load();
  };

  BoxRefresh.prototype.load = function () {
    this._addOverlay();
    this.options.onLoadStart.call($(this));

    $.get(this.options.source, this.options.params, function (response) {
      if (this.options.loadInContent) {
        $(this.element).find(this.options.content).html(response);
      }
      this.options.onLoadDone.call($(this), response);
      this._removeOverlay();
    }.bind(this), this.options.responseType !== '' && this.options.responseType);
  };

  // Private

  BoxRefresh.prototype._setUpListeners = function () {
    $(this.element).on('click', this.options.trigger, function (event) {
      if (event) event.preventDefault();
      this.load();
    }.bind(this));
  };

  BoxRefresh.prototype._addOverlay = function () {
    $(this.element).append(this.$overlay);
  };

  BoxRefresh.prototype._removeOverlay = function () {
    $(this.$overlay).remove();
  };

  // Plugin Definition
  // =================
  function Plugin(option) {
    return this.each(function () {
      var $this = $(this);
      var data  = $this.data(DataKey);

      if (!data) {
        var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
        $this.data(DataKey, (data = new BoxRefresh($this, options)));
      }

      if (typeof data == 'string') {
        if (typeof data[option] == 'undefined') {
          throw new Error('No method named ' + option);
        }
        data[option]();
      }
    });
  }

  var old = $.fn.boxRefresh;

  $.fn.boxRefresh             = Plugin;
  $.fn.boxRefresh.Constructor = BoxRefresh;

  // No Conflict Mode
  // ================
  $.fn.boxRefresh.noConflict = function () {
    $.fn.boxRefresh = old;
    return this;
  };

  // BoxRefresh Data API
  // =================
  $(window).on('load', function () {
    $(Selector.data).each(function () {
      Plugin.call($(this));
    });
  });

}(jQuery);

/* BoxWidget()
 * ======
 * Adds box widget functions to boxes.
 *
 * @Usage: $('.my-box').boxWidget(options)
 *         This plugin auto activates on any element using the `.box` class
 *         Pass any option as data-option="value"
 */
+function ($) {
  'use strict';

  var DataKey = 'lte.boxwidget';

  var Default = {
    animationSpeed : 500,
    collapseTrigger: '[data-widget="collapse"]',
    removeTrigger  : '[data-widget="remove"]',
    collapseIcon   : 'fa-minus',
    expandIcon     : 'fa-plus',
    removeIcon     : 'fa-times'
  };

  var Selector = {
    data     : '.box',
    collapsed: '.collapsed-box',
    header   : '.box-header',
    body     : '.box-body',
    footer   : '.box-footer',
    tools    : '.box-tools'
  };

  var ClassName = {
    collapsed: 'collapsed-box'
  };

  var Event = {
        collapsing: 'collapsing.boxwidget',
        collapsed: 'collapsed.boxwidget',
        expanding: 'expanding.boxwidget',
        expanded: 'expanded.boxwidget',
        removing: 'removing.boxwidget',
        removed: 'removed.boxwidget'        
    };

  // BoxWidget Class Definition
  // =====================
  var BoxWidget = function (element, options) {
    this.element = element;
    this.options = options;

    this._setUpListeners();
  };

  BoxWidget.prototype.toggle = function () {
    var isOpen = !$(this.element).is(Selector.collapsed);

    if (isOpen) {
      this.collapse();
    } else {
      this.expand();
    }
  };

  BoxWidget.prototype.expand = function () {
    var expandedEvent = $.Event(Event.expanded);
    var expandingEvent = $.Event(Event.expanding);
    var collapseIcon  = this.options.collapseIcon;
    var expandIcon    = this.options.expandIcon;

    $(this.element).removeClass(ClassName.collapsed);

    $(this.element)
      .children(Selector.header + ', ' + Selector.body + ', ' + Selector.footer)
      .children(Selector.tools)
      .find('.' + expandIcon)
      .removeClass(expandIcon)
      .addClass(collapseIcon);

    $(this.element).children(Selector.body + ', ' + Selector.footer)
      .slideDown(this.options.animationSpeed, function () {
        $(this.element).trigger(expandedEvent);
      }.bind(this))
      .trigger(expandingEvent);
  };

  BoxWidget.prototype.collapse = function () {
    var collapsedEvent = $.Event(Event.collapsed);
    var collapsingEvent = $.Event(Event.collapsing);
    var collapseIcon   = this.options.collapseIcon;
    var expandIcon     = this.options.expandIcon;

    $(this.element)
      .children(Selector.header + ', ' + Selector.body + ', ' + Selector.footer)
      .children(Selector.tools)
      .find('.' + collapseIcon)
      .removeClass(collapseIcon)
      .addClass(expandIcon);

    $(this.element).children(Selector.body + ', ' + Selector.footer)
      .slideUp(this.options.animationSpeed, function () {
        $(this.element).addClass(ClassName.collapsed);
        $(this.element).trigger(collapsedEvent);
      }.bind(this))
      .trigger(collapsingEvent);
  };

  BoxWidget.prototype.remove = function () {
    var removedEvent = $.Event(Event.removed);
    var removingEvent = $.Event(Event.removing);

    $(this.element).slideUp(this.options.animationSpeed, function () {
      $(this.element).trigger(removedEvent);
      $(this.element).remove();
    }.bind(this))
    .trigger(removingEvent);
  };

  // Private

  BoxWidget.prototype._setUpListeners = function () {
    var that = this;

    $(this.element).on('click', this.options.collapseTrigger, function (event) {
      if (event) event.preventDefault();
      that.toggle($(this));
      return false;
    });

    $(this.element).on('click', this.options.removeTrigger, function (event) {
      if (event) event.preventDefault();
      that.remove($(this));
      return false;
    });
  };

  // Plugin Definition
  // =================
  function Plugin(option) {
    return this.each(function () {
      var $this = $(this);
      var data  = $this.data(DataKey);

      if (!data) {
        var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
        $this.data(DataKey, (data = new BoxWidget($this, options)));
      }

      if (typeof option == 'string') {
        if (typeof data[option] == 'undefined') {
          throw new Error('No method named ' + option);
        }
        data[option]();
      }
    });
  }

  var old = $.fn.boxWidget;

  $.fn.boxWidget             = Plugin;
  $.fn.boxWidget.Constructor = BoxWidget;

  // No Conflict Mode
  // ================
  $.fn.boxWidget.noConflict = function () {
    $.fn.boxWidget = old;
    return this;
  };

  // BoxWidget Data API
  // ==================
  $(window).on('load', function () {
    $(Selector.data).each(function () {
      Plugin.call($(this));
    });
  });
}(jQuery);

/* ControlSidebar()
 * ===============
 * Toggles the state of the control sidebar
 *
 * @Usage: $('#control-sidebar-trigger').controlSidebar(options)
 *         or add [data-toggle="control-sidebar"] to the trigger
 *         Pass any option as data-option="value"
 */
+function ($) {
  'use strict';

  var DataKey = 'lte.controlsidebar';

  var Default = {
    controlsidebarSlide: true
  };

  var Selector = {
    sidebar: '.control-sidebar',
    data   : '[data-toggle="control-sidebar"]',
    open   : '.control-sidebar-open',
    bg     : '.control-sidebar-bg',
    wrapper: '.wrapper',
    content: '.content-wrapper',
    boxed  : '.layout-boxed'
  };

  var ClassName = {
    open: 'control-sidebar-open',
    transition: 'control-sidebar-hold-transition',
    fixed: 'fixed'
  };

  var Event = {
    collapsed: 'collapsed.controlsidebar',
    expanded : 'expanded.controlsidebar'
  };

  // ControlSidebar Class Definition
  // ===============================
  var ControlSidebar = function (element, options) {
    this.element         = element;
    this.options         = options;
    this.hasBindedResize = false;

    this.init();
  };

  ControlSidebar.prototype.init = function () {
    // Add click listener if the element hasn't been
    // initialized using the data API
    if (!$(this.element).is(Selector.data)) {
      $(this).on('click', this.toggle);
    }

    this.fix();
    $(window).resize(function () {
      this.fix();
    }.bind(this));
  };

  ControlSidebar.prototype.toggle = function (event) {
    if (event) event.preventDefault();

    this.fix();

    if (!$(Selector.sidebar).is(Selector.open) && !$('body').is(Selector.open)) {
      this.expand();
    } else {
      this.collapse();
    }
  };

  ControlSidebar.prototype.expand = function () {
    $(Selector.sidebar).show();
    if (!this.options.controlsidebarSlide) {
      $('body').addClass(ClassName.transition).addClass(ClassName.open).delay(50).queue(function(){
        $('body').removeClass(ClassName.transition);
        $(this).dequeue()
      })
    } else {
      $(Selector.sidebar).addClass(ClassName.open);
    }


    $(this.element).trigger($.Event(Event.expanded));
  };

  ControlSidebar.prototype.collapse = function () {
    if (!this.options.controlsidebarSlide) {
      $('body').addClass(ClassName.transition).removeClass(ClassName.open).delay(50).queue(function(){
        $('body').removeClass(ClassName.transition);
        $(this).dequeue()
      })
    } else {
      $(Selector.sidebar).removeClass(ClassName.open);
    }
    $(Selector.sidebar).fadeOut();
    $(this.element).trigger($.Event(Event.collapsed));
  };

  ControlSidebar.prototype.fix = function () {
    if ($('body').is(Selector.boxed)) {
      this._fixForBoxed($(Selector.bg));
    }
  };

  // Private

  ControlSidebar.prototype._fixForBoxed = function (bg) {
    bg.css({
      position: 'absolute',
      height  : $(Selector.wrapper).height()
    });
  };

  // Plugin Definition
  // =================
  function Plugin(option) {
    return this.each(function () {
      var $this = $(this);
      var data  = $this.data(DataKey);

      if (!data) {
        var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
        $this.data(DataKey, (data = new ControlSidebar($this, options)));
      }

      if (typeof option == 'string') data.toggle();
    });
  }

  var old = $.fn.controlSidebar;

  $.fn.controlSidebar             = Plugin;
  $.fn.controlSidebar.Constructor = ControlSidebar;

  // No Conflict Mode
  // ================
  $.fn.controlSidebar.noConflict = function () {
    $.fn.controlSidebar = old;
    return this;
  };

  // ControlSidebar Data API
  // =======================
  $(document).on('click', Selector.data, function (event) {
    if (event) event.preventDefault();
    Plugin.call($(this), 'toggle');
  });

}(jQuery);

/* PushMenu()
 * ==========
 * Adds the push menu functionality to the sidebar.
 *
 * @usage: $('.btn').pushMenu(options)
 *          or add [data-toggle="push-menu"] to any button
 *          Pass any option as data-option="value"
 */
+function ($) {
  'use strict';

  var DataKey = 'lte.pushmenu';

  var Default = {
    collapseScreenSize   : 767,
    expandOnHover        : false,
    expandTransitionDelay: 200
  };

  var Selector = {
    collapsed     : '.sidebar-collapse',
    open          : '.sidebar-open',
    mainSidebar   : '.main-sidebar',
    contentWrapper: '.content-wrapper',
    searchInput   : '.sidebar-form .form-control',
    button        : '[data-toggle="push-menu"]',
    mini          : '.sidebar-mini',
    expanded      : '.sidebar-expanded-on-hover',
    layoutFixed   : '.fixed'
  };

  var ClassName = {
    collapsed    : 'sidebar-collapse',
    open         : 'sidebar-open',
    mini         : 'sidebar-mini',
    expanded     : 'sidebar-expanded-on-hover',
    expandFeature: 'sidebar-mini-expand-feature',
    layoutFixed  : 'fixed'
  };

  var Event = {
    expanded : 'expanded.pushMenu',
    collapsed: 'collapsed.pushMenu'
  };

  // PushMenu Class Definition
  // =========================
  var PushMenu = function (options) {
    this.options = options;
    this.init();
  };

  PushMenu.prototype.init = function () {
    if (this.options.expandOnHover
      || ($('body').is(Selector.mini + Selector.layoutFixed))) {
      this.expandOnHover();
      $('body').addClass(ClassName.expandFeature);
    }

    $(Selector.contentWrapper).click(function () {
      // Enable hide menu when clicking on the content-wrapper on small screens
      if ($(window).width() <= this.options.collapseScreenSize && $('body').hasClass(ClassName.open)) {
        this.close();
      }
    }.bind(this));

    // __Fix for android devices
    $(Selector.searchInput).click(function (e) {
      e.stopPropagation();
    });
  };

  PushMenu.prototype.toggle = function () {
    var windowWidth = $(window).width();
    var isOpen      = !$('body').hasClass(ClassName.collapsed);

    if (windowWidth <= this.options.collapseScreenSize) {
      isOpen = $('body').hasClass(ClassName.open);
    }

    if (!isOpen) {
      this.open();
    } else {
      this.close();
    }
  };

  PushMenu.prototype.open = function () {
    var windowWidth = $(window).width();

    if (windowWidth > this.options.collapseScreenSize) {
      $('body').removeClass(ClassName.collapsed)
        .trigger($.Event(Event.expanded));
    }
    else {
      $('body').addClass(ClassName.open)
        .trigger($.Event(Event.expanded));
    }
  };

  PushMenu.prototype.close = function () {
    var windowWidth = $(window).width();
    if (windowWidth > this.options.collapseScreenSize) {
      $('body').addClass(ClassName.collapsed)
        .trigger($.Event(Event.collapsed));
    } else {
      $('body').removeClass(ClassName.open + ' ' + ClassName.collapsed)
        .trigger($.Event(Event.collapsed));
    }
  };

  PushMenu.prototype.expandOnHover = function () {
    $(Selector.mainSidebar).hover(function () {
      if ($('body').is(Selector.mini + Selector.collapsed)
        && $(window).width() > this.options.collapseScreenSize) {
        this.expand();
      }
    }.bind(this), function () {
      if ($('body').is(Selector.expanded)) {
        this.collapse();
      }
    }.bind(this));
  };

  PushMenu.prototype.expand = function () {
    setTimeout(function () {
      $('body').removeClass(ClassName.collapsed)
        .addClass(ClassName.expanded);
    }, this.options.expandTransitionDelay);
  };

  PushMenu.prototype.collapse = function () {
    setTimeout(function () {
      $('body').removeClass(ClassName.expanded)
        .addClass(ClassName.collapsed);
    }, this.options.expandTransitionDelay);
  };

  // PushMenu Plugin Definition
  // ==========================
  function Plugin(option) {
    return this.each(function () {
      var $this = $(this);
      var data  = $this.data(DataKey);

      if (!data) {
        var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
        $this.data(DataKey, (data = new PushMenu(options)));
      }

      if (option === 'toggle') data.toggle();
    });
  }

  var old = $.fn.pushMenu;

  $.fn.pushMenu             = Plugin;
  $.fn.pushMenu.Constructor = PushMenu;

  // No Conflict Mode
  // ================
  $.fn.pushMenu.noConflict = function () {
    $.fn.pushMenu = old;
    return this;
  };

  // Data API
  // ========
  $(document).on('click', Selector.button, function (e) {
    e.preventDefault();
    Plugin.call($(this), 'toggle');
  });
  $(window).on('load', function () {
    Plugin.call($(Selector.button));
  });
}(jQuery);

/* Tree()
 * ======
 * Converts a nested list into a multilevel
 * tree view menu.
 *
 * @Usage: $('.my-menu').tree(options)
 *         or add [data-widget="tree"] to the ul element
 *         Pass any option as data-option="value"
 */
+function ($) {
  'use strict';

  var DataKey = 'lte.tree';

  var Default = {
    animationSpeed: 500,
    accordion     : true,
    followLink    : false,
    trigger       : '.treeview a'
  };

  var Selector = {
    tree        : '.tree',
    treeview    : '.treeview',
    treeviewMenu: '.treeview-menu',
    open        : '.menu-open, .active',
    li          : 'li',
    data        : '[data-widget="tree"]',
    active      : '.active'
  };

  var ClassName = {
    open: 'menu-open',
    tree: 'tree'
  };

  var Event = {
    collapsed: 'collapsed.tree',
    expanded : 'expanded.tree'
  };

  // Tree Class Definition
  // =====================
  var Tree = function (element, options) {
    this.element = element;
    this.options = options;

    $(this.element).addClass(ClassName.tree);

    $(Selector.treeview + Selector.active, this.element).addClass(ClassName.open);

    this._setUpListeners();
  };

  Tree.prototype.toggle = function (link, event) {
    var treeviewMenu = link.next(Selector.treeviewMenu);
    var parentLi     = link.parent();
    var isOpen       = parentLi.hasClass(ClassName.open);

    if (!parentLi.is(Selector.treeview)) {
      return;
    }

    if (!this.options.followLink || link.attr('href') === '#') {
      event.preventDefault();
    }

    if (isOpen) {
      this.collapse(treeviewMenu, parentLi);
    } else {
      this.expand(treeviewMenu, parentLi);
    }
  };

  Tree.prototype.expand = function (tree, parent) {
    var expandedEvent = $.Event(Event.expanded);

    if (this.options.accordion) {
      var openMenuLi = parent.siblings(Selector.open);
      var openTree   = openMenuLi.children(Selector.treeviewMenu);
      this.collapse(openTree, openMenuLi);
    }

    parent.addClass(ClassName.open);
    tree.stop().slideDown(this.options.animationSpeed, function () {
      $(this.element).trigger(expandedEvent);
      parent.height('auto');
    }.bind(this));
  };

  Tree.prototype.collapse = function (tree, parentLi) {
    var collapsedEvent = $.Event(Event.collapsed);

    //tree.find(Selector.open).removeClass(ClassName.open);
    parentLi.removeClass(ClassName.open);
    tree.stop().slideUp(this.options.animationSpeed, function () {
      //tree.find(Selector.open + ' > ' + Selector.treeview).slideUp();
      $(this.element).trigger(collapsedEvent);

      // Collapse child items
      parentLi.find(Selector.treeview).removeClass(ClassName.open).find(Selector.treeviewMenu).hide();
    }.bind(this));
  };

  // Private

  Tree.prototype._setUpListeners = function () {
    var that = this;

    $(this.element).on('click', this.options.trigger, function (event) {
      that.toggle($(this), event);
    });
  };

  // Plugin Definition
  // =================
  function Plugin(option) {
    return this.each(function () {
      var $this = $(this);
      var data  = $this.data(DataKey);

      if (!data) {
        var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
        $this.data(DataKey, new Tree($this, options));
      }
    });
  }

  var old = $.fn.tree;

  $.fn.tree             = Plugin;
  $.fn.tree.Constructor = Tree;

  // No Conflict Mode
  // ================
  $.fn.tree.noConflict = function () {
    $.fn.tree = old;
    return this;
  };

  // Tree Data API
  // =============
  $(window).on('load', function () {
    $(Selector.data).each(function () {
      Plugin.call($(this));
    });
  });

}(jQuery);

/* Layout()
 * ========
 * Implements AdminLTE layout.
 * Fixes the layout height in case min-height fails.
 *
 * @usage activated automatically upon window load.
 *        Configure any options by passing data-option="value"
 *        to the body tag.
 */
+function ($) {
  'use strict';

  var DataKey = 'lte.layout';

  var Default = {
    slimscroll : true,
    resetHeight: true
  };

  var Selector = {
    wrapper       : '.wrapper',
    contentWrapper: '.content-wrapper',
    layoutBoxed   : '.layout-boxed',
    mainFooter    : '.main-footer',
    mainHeader    : '.main-header',
    mainSidebar   : '.main-sidebar',
    slimScrollDiv : 'slimScrollDiv',
    sidebar       : '.sidebar',
    controlSidebar: '.control-sidebar',
    fixed         : '.fixed',
    sidebarMenu   : '.sidebar-menu',
    logo          : '.main-header .logo'
  };

  var ClassName = {
    fixed         : 'fixed',
    holdTransition: 'hold-transition'
  };

  var Layout = function (options) {
    this.options      = options;
    this.bindedResize = false;
    this.activate();
  };

  Layout.prototype.activate = function () {
    this.fix();
    this.fixSidebar();

    $('body').removeClass(ClassName.holdTransition);

    if (this.options.resetHeight) {
      $('body, html, ' + Selector.wrapper).css({
        'height'    : 'auto',
        'min-height': '100%'
      });
    }

    if (!this.bindedResize) {
      $(window).resize(function () {
        this.fix();
        this.fixSidebar();

        $(Selector.logo + ', ' + Selector.sidebar).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () {
          this.fix();
          this.fixSidebar();
        }.bind(this));
      }.bind(this));

      this.bindedResize = true;
    }

    $(Selector.sidebarMenu).on('expanded.tree', function () {
      this.fix();
      this.fixSidebar();
    }.bind(this));

    $(Selector.sidebarMenu).on('collapsed.tree', function () {
      this.fix();
      this.fixSidebar();
    }.bind(this));
  };

  Layout.prototype.fix = function () {
    // Remove overflow from .wrapper if layout-boxed exists
    $(Selector.layoutBoxed + ' > ' + Selector.wrapper).css('overflow', 'hidden');

    // Get window height and the wrapper height
    var footerHeight  = $(Selector.mainFooter).outerHeight() || 0;
    var headerHeight  = $(Selector.mainHeader).outerHeight() || 0;
    var neg           = headerHeight + footerHeight;
    var windowHeight  = $(window).height();
    var sidebarHeight = $(Selector.sidebar).outerHeight() || 0;

    // Set the min-height of the content and sidebar based on
    // the height of the document.
    if ($('body').hasClass(ClassName.fixed)) {
      $(Selector.contentWrapper).css('min-height', windowHeight - footerHeight);
    } else {
      var postSetHeight;

      if (windowHeight >= sidebarHeight + headerHeight) {
        $(Selector.contentWrapper).css('min-height', windowHeight - neg);
        postSetHeight = windowHeight - neg;
      } else {
        $(Selector.contentWrapper).css('min-height', sidebarHeight);
        postSetHeight = sidebarHeight;
      }

      // Fix for the control sidebar height
      var $controlSidebar = $(Selector.controlSidebar);
      if (typeof $controlSidebar !== 'undefined') {
        if ($controlSidebar.height() > postSetHeight)
          $(Selector.contentWrapper).css('min-height', $controlSidebar.height());
      }
    }
  };

  Layout.prototype.fixSidebar = function () {
    // Make sure the body tag has the .fixed class
    if (!$('body').hasClass(ClassName.fixed)) {
      if (typeof $.fn.slimScroll !== 'undefined') {
        $(Selector.sidebar).slimScroll({ destroy: true }).height('auto');
      }
      return;
    }

    // Enable slimscroll for fixed layout
    if (this.options.slimscroll) {
      if (typeof $.fn.slimScroll !== 'undefined') {
        // Destroy if it exists
        // $(Selector.sidebar).slimScroll({ destroy: true }).height('auto')

        // Add slimscroll
        if ($(Selector.mainSidebar).find(Selector.slimScrollDiv).length === 0) {
          $(Selector.sidebar).slimScroll({
            height: ($(window).height() - $(Selector.mainHeader).height()) + 'px'
          });
        }
      }
    }
  };

  // Plugin Definition
  // =================
  function Plugin(option) {
    return this.each(function () {
      var $this = $(this);
      var data  = $this.data(DataKey);

      if (!data) {
        var options = $.extend({}, Default, $this.data(), typeof option === 'object' && option);
        $this.data(DataKey, (data = new Layout(options)));
      }

      if (typeof option === 'string') {
        if (typeof data[option] === 'undefined') {
          throw new Error('No method named ' + option);
        }
        data[option]();
      }
    });
  }

  var old = $.fn.layout;

  $.fn.layout            = Plugin;
  $.fn.layout.Constuctor = Layout;

  // No conflict mode
  // ================
  $.fn.layout.noConflict = function () {
    $.fn.layout = old;
    return this;
  };

  // Layout DATA-API
  // ===============
  $(window).on('load', function () {
    Plugin.call($('body'));
  });
}(jQuery);

/*!
 * jQuery Validation Plugin v1.19.5
 *
 * https://jqueryvalidation.org/
 *
 * Copyright (c) 2022 Jörn Zaefferer
 * Released under the MIT license
 */
(function( factory ) {
	if ( typeof define === "function" && define.amd ) {
		define( ["jquery"], factory );
	} else if (typeof module === "object" && module.exports) {
		module.exports = factory( require( "jquery" ) );
	} else {
		factory( jQuery );
	}
}(function( $ ) {

$.extend( $.fn, {

	// https://jqueryvalidation.org/validate/
	validate: function( options ) {

		// If nothing is selected, return nothing; can't chain anyway
		if ( !this.length ) {
			if ( options && options.debug && window.console ) {
				console.warn( "Nothing selected, can't validate, returning nothing." );
			}
			return;
		}

		// Check if a validator for this form was already created
		var validator = $.data( this[ 0 ], "validator" );
		if ( validator ) {
			return validator;
		}

		// Add novalidate tag if HTML5.
		this.attr( "novalidate", "novalidate" );

		validator = new $.validator( options, this[ 0 ] );
		$.data( this[ 0 ], "validator", validator );

		if ( validator.settings.onsubmit ) {

			this.on( "click.validate", ":submit", function( event ) {

				// Track the used submit button to properly handle scripted
				// submits later.
				validator.submitButton = event.currentTarget;

				// Allow suppressing validation by adding a cancel class to the submit button
				if ( $( this ).hasClass( "cancel" ) ) {
					validator.cancelSubmit = true;
				}

				// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
				if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
					validator.cancelSubmit = true;
				}
			} );

			// Validate the form on submit
			this.on( "submit.validate", function( event ) {
				if ( validator.settings.debug ) {

					// Prevent form submit to be able to see console output
					event.preventDefault();
				}

				function handle() {
					var hidden, result;

					// Insert a hidden input as a replacement for the missing submit button
					// The hidden input is inserted in two cases:
					//   - A user defined a `submitHandler`
					//   - There was a pending request due to `remote` method and `stopRequest()`
					//     was called to submit the form in case it's valid
					if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {
						hidden = $( "<input type='hidden'/>" )
							.attr( "name", validator.submitButton.name )
							.val( $( validator.submitButton ).val() )
							.appendTo( validator.currentForm );
					}

					if ( validator.settings.submitHandler && !validator.settings.debug ) {
						result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
						if ( hidden ) {

							// And clean up afterwards; thanks to no-block-scope, hidden can be referenced
							hidden.remove();
						}
						if ( result !== undefined ) {
							return result;
						}
						return false;
					}
					return true;
				}

				// Prevent submit for invalid forms or custom submit handlers
				if ( validator.cancelSubmit ) {
					validator.cancelSubmit = false;
					return handle();
				}
				if ( validator.form() ) {
					if ( validator.pendingRequest ) {
						validator.formSubmitted = true;
						return false;
					}
					return handle();
				} else {
					validator.focusInvalid();
					return false;
				}
			} );
		}

		return validator;
	},

	// https://jqueryvalidation.org/valid/
	valid: function() {
		var valid, validator, errorList;

		if ( $( this[ 0 ] ).is( "form" ) ) {
			valid = this.validate().form();
		} else {
			errorList = [];
			valid = true;
			validator = $( this[ 0 ].form ).validate();
			this.each( function() {
				valid = validator.element( this ) && valid;
				if ( !valid ) {
					errorList = errorList.concat( validator.errorList );
				}
			} );
			validator.errorList = errorList;
		}
		return valid;
	},

	// https://jqueryvalidation.org/rules/
	rules: function( command, argument ) {
		var element = this[ 0 ],
			isContentEditable = typeof this.attr( "contenteditable" ) !== "undefined" && this.attr( "contenteditable" ) !== "false",
			settings, staticRules, existingRules, data, param, filtered;

		// If nothing is selected, return empty object; can't chain anyway
		if ( element == null ) {
			return;
		}

		if ( !element.form && isContentEditable ) {
			element.form = this.closest( "form" )[ 0 ];
			element.name = this.attr( "name" );
		}

		if ( element.form == null ) {
			return;
		}

		if ( command ) {
			settings = $.data( element.form, "validator" ).settings;
			staticRules = settings.rules;
			existingRules = $.validator.staticRules( element );
			switch ( command ) {
			case "add":
				$.extend( existingRules, $.validator.normalizeRule( argument ) );

				// Remove messages from rules, but allow them to be set separately
				delete existingRules.messages;
				staticRules[ element.name ] = existingRules;
				if ( argument.messages ) {
					settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
				}
				break;
			case "remove":
				if ( !argument ) {
					delete staticRules[ element.name ];
					return existingRules;
				}
				filtered = {};
				$.each( argument.split( /\s/ ), function( index, method ) {
					filtered[ method ] = existingRules[ method ];
					delete existingRules[ method ];
				} );
				return filtered;
			}
		}

		data = $.validator.normalizeRules(
		$.extend(
			{},
			$.validator.classRules( element ),
			$.validator.attributeRules( element ),
			$.validator.dataRules( element ),
			$.validator.staticRules( element )
		), element );

		// Make sure required is at front
		if ( data.required ) {
			param = data.required;
			delete data.required;
			data = $.extend( { required: param }, data );
		}

		// Make sure remote is at back
		if ( data.remote ) {
			param = data.remote;
			delete data.remote;
			data = $.extend( data, { remote: param } );
		}

		return data;
	}
} );

// JQuery trim is deprecated, provide a trim method based on String.prototype.trim
var trim = function( str ) {

	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill
	return str.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "" );
};

// Custom selectors
$.extend( $.expr.pseudos || $.expr[ ":" ], {		// '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support

	// https://jqueryvalidation.org/blank-selector/
	blank: function( a ) {
		return !trim( "" + $( a ).val() );
	},

	// https://jqueryvalidation.org/filled-selector/
	filled: function( a ) {
		var val = $( a ).val();
		return val !== null && !!trim( "" + val );
	},

	// https://jqueryvalidation.org/unchecked-selector/
	unchecked: function( a ) {
		return !$( a ).prop( "checked" );
	}
} );

// Constructor for validator
$.validator = function( options, form ) {
	this.settings = $.extend( true, {}, $.validator.defaults, options );
	this.currentForm = form;
	this.init();
};

// https://jqueryvalidation.org/jQuery.validator.format/
$.validator.format = function( source, params ) {
	if ( arguments.length === 1 ) {
		return function() {
			var args = $.makeArray( arguments );
			args.unshift( source );
			return $.validator.format.apply( this, args );
		};
	}
	if ( params === undefined ) {
		return source;
	}
	if ( arguments.length > 2 && params.constructor !== Array  ) {
		params = $.makeArray( arguments ).slice( 1 );
	}
	if ( params.constructor !== Array ) {
		params = [ params ];
	}
	$.each( params, function( i, n ) {
		source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
			return n;
		} );
	} );
	return source;
};

$.extend( $.validator, {

	defaults: {
		messages: {},
		groups: {},
		rules: {},
		errorClass: "error",
		pendingClass: "pending",
		validClass: "valid",
		errorElement: "label",
		focusCleanup: false,
		focusInvalid: true,
		errorContainer: $( [] ),
		errorLabelContainer: $( [] ),
		onsubmit: true,
		ignore: ":hidden",
		ignoreTitle: false,
		onfocusin: function( element ) {
			this.lastActive = element;

			// Hide error label and remove error class on focus if enabled
			if ( this.settings.focusCleanup ) {
				if ( this.settings.unhighlight ) {
					this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
				}
				this.hideThese( this.errorsFor( element ) );
			}
		},
		onfocusout: function( element ) {
			if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
				this.element( element );
			}
		},
		onkeyup: function( element, event ) {

			// Avoid revalidate the field when pressing one of the following keys
			// Shift       => 16
			// Ctrl        => 17
			// Alt         => 18
			// Caps lock   => 20
			// End         => 35
			// Home        => 36
			// Left arrow  => 37
			// Up arrow    => 38
			// Right arrow => 39
			// Down arrow  => 40
			// Insert      => 45
			// Num lock    => 144
			// AltGr key   => 225
			var excludedKeys = [
				16, 17, 18, 20, 35, 36, 37,
				38, 39, 40, 45, 144, 225
			];

			if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
				return;
			} else if ( element.name in this.submitted || element.name in this.invalid ) {
				this.element( element );
			}
		},
		onclick: function( element ) {

			// Click on selects, radiobuttons and checkboxes
			if ( element.name in this.submitted ) {
				this.element( element );

			// Or option elements, check parent select in that case
			} else if ( element.parentNode.name in this.submitted ) {
				this.element( element.parentNode );
			}
		},
		highlight: function( element, errorClass, validClass ) {
			if ( element.type === "radio" ) {
				this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
			} else {
				$( element ).addClass( errorClass ).removeClass( validClass );
			}
		},
		unhighlight: function( element, errorClass, validClass ) {
			if ( element.type === "radio" ) {
				this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
			} else {
				$( element ).removeClass( errorClass ).addClass( validClass );
			}
		}
	},

	// https://jqueryvalidation.org/jQuery.validator.setDefaults/
	setDefaults: function( settings ) {
		$.extend( $.validator.defaults, settings );
	},

	messages: {
		required: "This field is required.",
		remote: "Please fix this field.",
		email: "Please enter a valid email address.",
		url: "Please enter a valid URL.",
		date: "Please enter a valid date.",
		dateISO: "Please enter a valid date (ISO).",
		number: "Please enter a valid number.",
		digits: "Please enter only digits.",
		equalTo: "Please enter the same value again.",
		maxlength: $.validator.format( "Please enter no more than {0} characters." ),
		minlength: $.validator.format( "Please enter at least {0} characters." ),
		rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
		range: $.validator.format( "Please enter a value between {0} and {1}." ),
		max: $.validator.format( "Please enter a value less than or equal to {0}." ),
		min: $.validator.format( "Please enter a value greater than or equal to {0}." ),
		step: $.validator.format( "Please enter a multiple of {0}." )
	},

	autoCreateRanges: false,

	prototype: {

		init: function() {
			this.labelContainer = $( this.settings.errorLabelContainer );
			this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
			this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
			this.submitted = {};
			this.valueCache = {};
			this.pendingRequest = 0;
			this.pending = {};
			this.invalid = {};
			this.reset();

			var currentForm = this.currentForm,
				groups = ( this.groups = {} ),
				rules;
			$.each( this.settings.groups, function( key, value ) {
				if ( typeof value === "string" ) {
					value = value.split( /\s/ );
				}
				$.each( value, function( index, name ) {
					groups[ name ] = key;
				} );
			} );
			rules = this.settings.rules;
			$.each( rules, function( key, value ) {
				rules[ key ] = $.validator.normalizeRule( value );
			} );

			function delegate( event ) {
				var isContentEditable = typeof $( this ).attr( "contenteditable" ) !== "undefined" && $( this ).attr( "contenteditable" ) !== "false";

				// Set form expando on contenteditable
				if ( !this.form && isContentEditable ) {
					this.form = $( this ).closest( "form" )[ 0 ];
					this.name = $( this ).attr( "name" );
				}

				// Ignore the element if it belongs to another form. This will happen mainly
				// when setting the `form` attribute of an input to the id of another form.
				if ( currentForm !== this.form ) {
					return;
				}

				var validator = $.data( this.form, "validator" ),
					eventType = "on" + event.type.replace( /^validate/, "" ),
					settings = validator.settings;
				if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
					settings[ eventType ].call( validator, this, event );
				}
			}

			$( this.currentForm )
				.on( "focusin.validate focusout.validate keyup.validate",
					":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
					"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
					"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
					"[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )

				// Support: Chrome, oldIE
				// "select" is provided as event.target when clicking a option
				.on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );

			if ( this.settings.invalidHandler ) {
				$( this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
			}
		},

		// https://jqueryvalidation.org/Validator.form/
		form: function() {
			this.checkForm();
			$.extend( this.submitted, this.errorMap );
			this.invalid = $.extend( {}, this.errorMap );
			if ( !this.valid() ) {
				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
			}
			this.showErrors();
			return this.valid();
		},

		checkForm: function() {
			this.prepareForm();
			for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
				this.check( elements[ i ] );
			}
			return this.valid();
		},

		// https://jqueryvalidation.org/Validator.element/
		element: function( element ) {
			var cleanElement = this.clean( element ),
				checkElement = this.validationTargetFor( cleanElement ),
				v = this,
				result = true,
				rs, group;

			if ( checkElement === undefined ) {
				delete this.invalid[ cleanElement.name ];
			} else {
				this.prepareElement( checkElement );
				this.currentElements = $( checkElement );

				// If this element is grouped, then validate all group elements already
				// containing a value
				group = this.groups[ checkElement.name ];
				if ( group ) {
					$.each( this.groups, function( name, testgroup ) {
						if ( testgroup === group && name !== checkElement.name ) {
							cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
							if ( cleanElement && cleanElement.name in v.invalid ) {
								v.currentElements.push( cleanElement );
								result = v.check( cleanElement ) && result;
							}
						}
					} );
				}

				rs = this.check( checkElement ) !== false;
				result = result && rs;
				if ( rs ) {
					this.invalid[ checkElement.name ] = false;
				} else {
					this.invalid[ checkElement.name ] = true;
				}

				if ( !this.numberOfInvalids() ) {

					// Hide error containers on last error
					this.toHide = this.toHide.add( this.containers );
				}
				this.showErrors();

				// Add aria-invalid status for screen readers
				$( element ).attr( "aria-invalid", !rs );
			}

			return result;
		},

		// https://jqueryvalidation.org/Validator.showErrors/
		showErrors: function( errors ) {
			if ( errors ) {
				var validator = this;

				// Add items to error list and map
				$.extend( this.errorMap, errors );
				this.errorList = $.map( this.errorMap, function( message, name ) {
					return {
						message: message,
						element: validator.findByName( name )[ 0 ]
					};
				} );

				// Remove items from success list
				this.successList = $.grep( this.successList, function( element ) {
					return !( element.name in errors );
				} );
			}
			if ( this.settings.showErrors ) {
				this.settings.showErrors.call( this, this.errorMap, this.errorList );
			} else {
				this.defaultShowErrors();
			}
		},

		// https://jqueryvalidation.org/Validator.resetForm/
		resetForm: function() {
			if ( $.fn.resetForm ) {
				$( this.currentForm ).resetForm();
			}
			this.invalid = {};
			this.submitted = {};
			this.prepareForm();
			this.hideErrors();
			var elements = this.elements()
				.removeData( "previousValue" )
				.removeAttr( "aria-invalid" );

			this.resetElements( elements );
		},

		resetElements: function( elements ) {
			var i;

			if ( this.settings.unhighlight ) {
				for ( i = 0; elements[ i ]; i++ ) {
					this.settings.unhighlight.call( this, elements[ i ],
						this.settings.errorClass, "" );
					this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
				}
			} else {
				elements
					.removeClass( this.settings.errorClass )
					.removeClass( this.settings.validClass );
			}
		},

		numberOfInvalids: function() {
			return this.objectLength( this.invalid );
		},

		objectLength: function( obj ) {
			/* jshint unused: false */
			var count = 0,
				i;
			for ( i in obj ) {

				// This check allows counting elements with empty error
				// message as invalid elements
				if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {
					count++;
				}
			}
			return count;
		},

		hideErrors: function() {
			this.hideThese( this.toHide );
		},

		hideThese: function( errors ) {
			errors.not( this.containers ).text( "" );
			this.addWrapper( errors ).hide();
		},

		valid: function() {
			return this.size() === 0;
		},

		size: function() {
			return this.errorList.length;
		},

		focusInvalid: function() {
			if ( this.settings.focusInvalid ) {
				try {
					$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
					.filter( ":visible" )
					.trigger( "focus" )

					// Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
					.trigger( "focusin" );
				} catch ( e ) {

					// Ignore IE throwing errors when focusing hidden elements
				}
			}
		},

		findLastActive: function() {
			var lastActive = this.lastActive;
			return lastActive && $.grep( this.errorList, function( n ) {
				return n.element.name === lastActive.name;
			} ).length === 1 && lastActive;
		},

		elements: function() {
			var validator = this,
				rulesCache = {};

			// Select all valid inputs inside the form (no submit or reset buttons)
			return $( this.currentForm )
			.find( "input, select, textarea, [contenteditable]" )
			.not( ":submit, :reset, :image, :disabled" )
			.not( this.settings.ignore )
			.filter( function() {
				var name = this.name || $( this ).attr( "name" ); // For contenteditable
				var isContentEditable = typeof $( this ).attr( "contenteditable" ) !== "undefined" && $( this ).attr( "contenteditable" ) !== "false";

				if ( !name && validator.settings.debug && window.console ) {
					console.error( "%o has no name assigned", this );
				}

				// Set form expando on contenteditable
				if ( isContentEditable ) {
					this.form = $( this ).closest( "form" )[ 0 ];
					this.name = name;
				}

				// Ignore elements that belong to other/nested forms
				if ( this.form !== validator.currentForm ) {
					return false;
				}

				// Select only the first element for each name, and only those with rules specified
				if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
					return false;
				}

				rulesCache[ name ] = true;
				return true;
			} );
		},

		clean: function( selector ) {
			return $( selector )[ 0 ];
		},

		errors: function() {
			var errorClass = this.settings.errorClass.split( " " ).join( "." );
			return $( this.settings.errorElement + "." + errorClass, this.errorContext );
		},

		resetInternals: function() {
			this.successList = [];
			this.errorList = [];
			this.errorMap = {};
			this.toShow = $( [] );
			this.toHide = $( [] );
		},

		reset: function() {
			this.resetInternals();
			this.currentElements = $( [] );
		},

		prepareForm: function() {
			this.reset();
			this.toHide = this.errors().add( this.containers );
		},

		prepareElement: function( element ) {
			this.reset();
			this.toHide = this.errorsFor( element );
		},

		elementValue: function( element ) {
			var $element = $( element ),
				type = element.type,
				isContentEditable = typeof $element.attr( "contenteditable" ) !== "undefined" && $element.attr( "contenteditable" ) !== "false",
				val, idx;

			if ( type === "radio" || type === "checkbox" ) {
				return this.findByName( element.name ).filter( ":checked" ).val();
			} else if ( type === "number" && typeof element.validity !== "undefined" ) {
				return element.validity.badInput ? "NaN" : $element.val();
			}

			if ( isContentEditable ) {
				val = $element.text();
			} else {
				val = $element.val();
			}

			if ( type === "file" ) {

				// Modern browser (chrome & safari)
				if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
					return val.substr( 12 );
				}

				// Legacy browsers
				// Unix-based path
				idx = val.lastIndexOf( "/" );
				if ( idx >= 0 ) {
					return val.substr( idx + 1 );
				}

				// Windows-based path
				idx = val.lastIndexOf( "\\" );
				if ( idx >= 0 ) {
					return val.substr( idx + 1 );
				}

				// Just the file name
				return val;
			}

			if ( typeof val === "string" ) {
				return val.replace( /\r/g, "" );
			}
			return val;
		},

		check: function( element ) {
			element = this.validationTargetFor( this.clean( element ) );

			var rules = $( element ).rules(),
				rulesCount = $.map( rules, function( n, i ) {
					return i;
				} ).length,
				dependencyMismatch = false,
				val = this.elementValue( element ),
				result, method, rule, normalizer;

			// Prioritize the local normalizer defined for this element over the global one
			// if the former exists, otherwise user the global one in case it exists.
			if ( typeof rules.normalizer === "function" ) {
				normalizer = rules.normalizer;
			} else if (	typeof this.settings.normalizer === "function" ) {
				normalizer = this.settings.normalizer;
			}

			// If normalizer is defined, then call it to retreive the changed value instead
			// of using the real one.
			// Note that `this` in the normalizer is `element`.
			if ( normalizer ) {
				val = normalizer.call( element, val );

				// Delete the normalizer from rules to avoid treating it as a pre-defined method.
				delete rules.normalizer;
			}

			for ( method in rules ) {
				rule = { method: method, parameters: rules[ method ] };
				try {
					result = $.validator.methods[ method ].call( this, val, element, rule.parameters );

					// If a method indicates that the field is optional and therefore valid,
					// don't mark it as valid when there are no other rules
					if ( result === "dependency-mismatch" && rulesCount === 1 ) {
						dependencyMismatch = true;
						continue;
					}
					dependencyMismatch = false;

					if ( result === "pending" ) {
						this.toHide = this.toHide.not( this.errorsFor( element ) );
						return;
					}

					if ( !result ) {
						this.formatAndAdd( element, rule );
						return false;
					}
				} catch ( e ) {
					if ( this.settings.debug && window.console ) {
						console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
					}
					if ( e instanceof TypeError ) {
						e.message += ".  Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
					}

					throw e;
				}
			}
			if ( dependencyMismatch ) {
				return;
			}
			if ( this.objectLength( rules ) ) {
				this.successList.push( element );
			}
			return true;
		},

		// Return the custom message for the given element and validation method
		// specified in the element's HTML5 data attribute
		// return the generic message if present and no method specific message is present
		customDataMessage: function( element, method ) {
			return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
				method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
		},

		// Return the custom message for the given element name and validation method
		customMessage: function( name, method ) {
			var m = this.settings.messages[ name ];
			return m && ( m.constructor === String ? m : m[ method ] );
		},

		// Return the first defined argument, allowing empty strings
		findDefined: function() {
			for ( var i = 0; i < arguments.length; i++ ) {
				if ( arguments[ i ] !== undefined ) {
					return arguments[ i ];
				}
			}
			return undefined;
		},

		// The second parameter 'rule' used to be a string, and extended to an object literal
		// of the following form:
		// rule = {
		//     method: "method name",
		//     parameters: "the given method parameters"
		// }
		//
		// The old behavior still supported, kept to maintain backward compatibility with
		// old code, and will be removed in the next major release.
		defaultMessage: function( element, rule ) {
			if ( typeof rule === "string" ) {
				rule = { method: rule };
			}

			var message = this.findDefined(
					this.customMessage( element.name, rule.method ),
					this.customDataMessage( element, rule.method ),

					// 'title' is never undefined, so handle empty string as undefined
					!this.settings.ignoreTitle && element.title || undefined,
					$.validator.messages[ rule.method ],
					"<strong>Warning: No message defined for " + element.name + "</strong>"
				),
				theregex = /\$?\{(\d+)\}/g;
			if ( typeof message === "function" ) {
				message = message.call( this, rule.parameters, element );
			} else if ( theregex.test( message ) ) {
				message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
			}

			return message;
		},

		formatAndAdd: function( element, rule ) {
			var message = this.defaultMessage( element, rule );

			this.errorList.push( {
				message: message,
				element: element,
				method: rule.method
			} );

			this.errorMap[ element.name ] = message;
			this.submitted[ element.name ] = message;
		},

		addWrapper: function( toToggle ) {
			if ( this.settings.wrapper ) {
				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
			}
			return toToggle;
		},

		defaultShowErrors: function() {
			var i, elements, error;
			for ( i = 0; this.errorList[ i ]; i++ ) {
				error = this.errorList[ i ];
				if ( this.settings.highlight ) {
					this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
				}
				this.showLabel( error.element, error.message );
			}
			if ( this.errorList.length ) {
				this.toShow = this.toShow.add( this.containers );
			}
			if ( this.settings.success ) {
				for ( i = 0; this.successList[ i ]; i++ ) {
					this.showLabel( this.successList[ i ] );
				}
			}
			if ( this.settings.unhighlight ) {
				for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
					this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
				}
			}
			this.toHide = this.toHide.not( this.toShow );
			this.hideErrors();
			this.addWrapper( this.toShow ).show();
		},

		validElements: function() {
			return this.currentElements.not( this.invalidElements() );
		},

		invalidElements: function() {
			return $( this.errorList ).map( function() {
				return this.element;
			} );
		},

		showLabel: function( element, message ) {
			var place, group, errorID, v,
				error = this.errorsFor( element ),
				elementID = this.idOrName( element ),
				describedBy = $( element ).attr( "aria-describedby" );

			if ( error.length ) {

				// Refresh error/success class
				error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );

				// Replace message on existing label
				error.html( message );
			} else {

				// Create error element
				error = $( "<" + this.settings.errorElement + ">" )
					.attr( "id", elementID + "-error" )
					.addClass( this.settings.errorClass )
					.html( message || "" );

				// Maintain reference to the element to be placed into the DOM
				place = error;
				if ( this.settings.wrapper ) {

					// Make sure the element is visible, even in IE
					// actually showing the wrapped element is handled elsewhere
					place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
				}
				if ( this.labelContainer.length ) {
					this.labelContainer.append( place );
				} else if ( this.settings.errorPlacement ) {
					this.settings.errorPlacement.call( this, place, $( element ) );
				} else {
					place.insertAfter( element );
				}

				// Link error back to the element
				if ( error.is( "label" ) ) {

					// If the error is a label, then associate using 'for'
					error.attr( "for", elementID );

					// If the element is not a child of an associated label, then it's necessary
					// to explicitly apply aria-describedby
				} else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
					errorID = error.attr( "id" );

					// Respect existing non-error aria-describedby
					if ( !describedBy ) {
						describedBy = errorID;
					} else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {

						// Add to end of list if not already present
						describedBy += " " + errorID;
					}
					$( element ).attr( "aria-describedby", describedBy );

					// If this element is grouped, then assign to all elements in the same group
					group = this.groups[ element.name ];
					if ( group ) {
						v = this;
						$.each( v.groups, function( name, testgroup ) {
							if ( testgroup === group ) {
								$( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
									.attr( "aria-describedby", error.attr( "id" ) );
							}
						} );
					}
				}
			}
			if ( !message && this.settings.success ) {
				error.text( "" );
				if ( typeof this.settings.success === "string" ) {
					error.addClass( this.settings.success );
				} else {
					this.settings.success( error, element );
				}
			}
			this.toShow = this.toShow.add( error );
		},

		errorsFor: function( element ) {
			var name = this.escapeCssMeta( this.idOrName( element ) ),
				describer = $( element ).attr( "aria-describedby" ),
				selector = "label[for='" + name + "'], label[for='" + name + "'] *";

			// 'aria-describedby' should directly reference the error element
			if ( describer ) {
				selector = selector + ", #" + this.escapeCssMeta( describer )
					.replace( /\s+/g, ", #" );
			}

			return this
				.errors()
				.filter( selector );
		},

		// See https://api.jquery.com/category/selectors/, for CSS
		// meta-characters that should be escaped in order to be used with JQuery
		// as a literal part of a name/id or any selector.
		escapeCssMeta: function( string ) {
			if ( string === undefined ) {
				return "";
			}

			return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
		},

		idOrName: function( element ) {
			return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
		},

		validationTargetFor: function( element ) {

			// If radio/checkbox, validate first element in group instead
			if ( this.checkable( element ) ) {
				element = this.findByName( element.name );
			}

			// Always apply ignore filter
			return $( element ).not( this.settings.ignore )[ 0 ];
		},

		checkable: function( element ) {
			return ( /radio|checkbox/i ).test( element.type );
		},

		findByName: function( name ) {
			return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
		},

		getLength: function( value, element ) {
			switch ( element.nodeName.toLowerCase() ) {
			case "select":
				return $( "option:selected", element ).length;
			case "input":
				if ( this.checkable( element ) ) {
					return this.findByName( element.name ).filter( ":checked" ).length;
				}
			}
			return value.length;
		},

		depend: function( param, element ) {
			return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
		},

		dependTypes: {
			"boolean": function( param ) {
				return param;
			},
			"string": function( param, element ) {
				return !!$( param, element.form ).length;
			},
			"function": function( param, element ) {
				return param( element );
			}
		},

		optional: function( element ) {
			var val = this.elementValue( element );
			return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
		},

		startRequest: function( element ) {
			if ( !this.pending[ element.name ] ) {
				this.pendingRequest++;
				$( element ).addClass( this.settings.pendingClass );
				this.pending[ element.name ] = true;
			}
		},

		stopRequest: function( element, valid ) {
			this.pendingRequest--;

			// Sometimes synchronization fails, make sure pendingRequest is never < 0
			if ( this.pendingRequest < 0 ) {
				this.pendingRequest = 0;
			}
			delete this.pending[ element.name ];
			$( element ).removeClass( this.settings.pendingClass );
			if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() && this.pendingRequest === 0 ) {
				$( this.currentForm ).trigger( "submit" );

				// Remove the hidden input that was used as a replacement for the
				// missing submit button. The hidden input is added by `handle()`
				// to ensure that the value of the used submit button is passed on
				// for scripted submits triggered by this method
				if ( this.submitButton ) {
					$( "input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove();
				}

				this.formSubmitted = false;
			} else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
				this.formSubmitted = false;
			}
		},

		previousValue: function( element, method ) {
			method = typeof method === "string" && method || "remote";

			return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
				old: null,
				valid: true,
				message: this.defaultMessage( element, { method: method } )
			} );
		},

		// Cleans up all forms and elements, removes validator-specific events
		destroy: function() {
			this.resetForm();

			$( this.currentForm )
				.off( ".validate" )
				.removeData( "validator" )
				.find( ".validate-equalTo-blur" )
					.off( ".validate-equalTo" )
					.removeClass( "validate-equalTo-blur" )
				.find( ".validate-lessThan-blur" )
					.off( ".validate-lessThan" )
					.removeClass( "validate-lessThan-blur" )
				.find( ".validate-lessThanEqual-blur" )
					.off( ".validate-lessThanEqual" )
					.removeClass( "validate-lessThanEqual-blur" )
				.find( ".validate-greaterThanEqual-blur" )
					.off( ".validate-greaterThanEqual" )
					.removeClass( "validate-greaterThanEqual-blur" )
				.find( ".validate-greaterThan-blur" )
					.off( ".validate-greaterThan" )
					.removeClass( "validate-greaterThan-blur" );
		}

	},

	classRuleSettings: {
		required: { required: true },
		email: { email: true },
		url: { url: true },
		date: { date: true },
		dateISO: { dateISO: true },
		number: { number: true },
		digits: { digits: true },
		creditcard: { creditcard: true }
	},

	addClassRules: function( className, rules ) {
		if ( className.constructor === String ) {
			this.classRuleSettings[ className ] = rules;
		} else {
			$.extend( this.classRuleSettings, className );
		}
	},

	classRules: function( element ) {
		var rules = {},
			classes = $( element ).attr( "class" );

		if ( classes ) {
			$.each( classes.split( " " ), function() {
				if ( this in $.validator.classRuleSettings ) {
					$.extend( rules, $.validator.classRuleSettings[ this ] );
				}
			} );
		}
		return rules;
	},

	normalizeAttributeRule: function( rules, type, method, value ) {

		// Convert the value to a number for number inputs, and for text for backwards compability
		// allows type="date" and others to be compared as strings
		if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
			value = Number( value );

			// Support Opera Mini, which returns NaN for undefined minlength
			if ( isNaN( value ) ) {
				value = undefined;
			}
		}

		if ( value || value === 0 ) {
			rules[ method ] = value;
		} else if ( type === method && type !== "range" ) {

			// Exception: the jquery validate 'range' method
			// does not test for the html5 'range' type
			rules[ type === "date" ? "dateISO" : method ] = true;
		}
	},

	attributeRules: function( element ) {
		var rules = {},
			$element = $( element ),
			type = element.getAttribute( "type" ),
			method, value;

		for ( method in $.validator.methods ) {

			// Support for <input required> in both html5 and older browsers
			if ( method === "required" ) {
				value = element.getAttribute( method );

				// Some browsers return an empty string for the required attribute
				// and non-HTML5 browsers might have required="" markup
				if ( value === "" ) {
					value = true;
				}

				// Force non-HTML5 browsers to return bool
				value = !!value;
			} else {
				value = $element.attr( method );
			}

			this.normalizeAttributeRule( rules, type, method, value );
		}

		// 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
		if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
			delete rules.maxlength;
		}

		return rules;
	},

	dataRules: function( element ) {
		var rules = {},
			$element = $( element ),
			type = element.getAttribute( "type" ),
			method, value;

		for ( method in $.validator.methods ) {
			value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );

			// Cast empty attributes like `data-rule-required` to `true`
			if ( value === "" ) {
				value = true;
			}

			this.normalizeAttributeRule( rules, type, method, value );
		}
		return rules;
	},

	staticRules: function( element ) {
		var rules = {},
			validator = $.data( element.form, "validator" );

		if ( validator.settings.rules ) {
			rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
		}
		return rules;
	},

	normalizeRules: function( rules, element ) {

		// Handle dependency check
		$.each( rules, function( prop, val ) {

			// Ignore rule when param is explicitly false, eg. required:false
			if ( val === false ) {
				delete rules[ prop ];
				return;
			}
			if ( val.param || val.depends ) {
				var keepRule = true;
				switch ( typeof val.depends ) {
				case "string":
					keepRule = !!$( val.depends, element.form ).length;
					break;
				case "function":
					keepRule = val.depends.call( element, element );
					break;
				}
				if ( keepRule ) {
					rules[ prop ] = val.param !== undefined ? val.param : true;
				} else {
					$.data( element.form, "validator" ).resetElements( $( element ) );
					delete rules[ prop ];
				}
			}
		} );

		// Evaluate parameters
		$.each( rules, function( rule, parameter ) {
			rules[ rule ] = typeof parameter === "function" && rule !== "normalizer" ? parameter( element ) : parameter;
		} );

		// Clean number parameters
		$.each( [ "minlength", "maxlength" ], function() {
			if ( rules[ this ] ) {
				rules[ this ] = Number( rules[ this ] );
			}
		} );
		$.each( [ "rangelength", "range" ], function() {
			var parts;
			if ( rules[ this ] ) {
				if ( Array.isArray( rules[ this ] ) ) {
					rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
				} else if ( typeof rules[ this ] === "string" ) {
					parts = rules[ this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
					rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
				}
			}
		} );

		if ( $.validator.autoCreateRanges ) {

			// Auto-create ranges
			if ( rules.min != null && rules.max != null ) {
				rules.range = [ rules.min, rules.max ];
				delete rules.min;
				delete rules.max;
			}
			if ( rules.minlength != null && rules.maxlength != null ) {
				rules.rangelength = [ rules.minlength, rules.maxlength ];
				delete rules.minlength;
				delete rules.maxlength;
			}
		}

		return rules;
	},

	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
	normalizeRule: function( data ) {
		if ( typeof data === "string" ) {
			var transformed = {};
			$.each( data.split( /\s/ ), function() {
				transformed[ this ] = true;
			} );
			data = transformed;
		}
		return data;
	},

	// https://jqueryvalidation.org/jQuery.validator.addMethod/
	addMethod: function( name, method, message ) {
		$.validator.methods[ name ] = method;
		$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
		if ( method.length < 3 ) {
			$.validator.addClassRules( name, $.validator.normalizeRule( name ) );
		}
	},

	// https://jqueryvalidation.org/jQuery.validator.methods/
	methods: {

		// https://jqueryvalidation.org/required-method/
		required: function( value, element, param ) {

			// Check if dependency is met
			if ( !this.depend( param, element ) ) {
				return "dependency-mismatch";
			}
			if ( element.nodeName.toLowerCase() === "select" ) {

				// Could be an array for select-multiple or a string, both are fine this way
				var val = $( element ).val();
				return val && val.length > 0;
			}
			if ( this.checkable( element ) ) {
				return this.getLength( value, element ) > 0;
			}
			return value !== undefined && value !== null && value.length > 0;
		},

		// https://jqueryvalidation.org/email-method/
		email: function( value, element ) {

			// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
			// Retrieved 2014-01-14
			// If you have a problem with this implementation, report a bug against the above spec
			// Or use custom methods to implement your own email validation
			return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
		},

		// https://jqueryvalidation.org/url-method/
		url: function( value, element ) {

			// Copyright (c) 2010-2013 Diego Perini, MIT licensed
			// https://gist.github.com/dperini/729294
			// see also https://mathiasbynens.be/demo/url-regex
			// modified to allow protocol-relative URLs
			return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:(?:[^\]\[?\/<~#`!@$^&*()+=}|:";',>{ ]|%[0-9A-Fa-f]{2})+(?::(?:[^\]\[?\/<~#`!@$^&*()+=}|:";',>{ ]|%[0-9A-Fa-f]{2})*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( value );
		},

		// https://jqueryvalidation.org/date-method/
		date: ( function() {
			var called = false;

			return function( value, element ) {
				if ( !called ) {
					called = true;
					if ( this.settings.debug && window.console ) {
						console.warn(
							"The `date` method is deprecated and will be removed in version '2.0.0'.\n" +
							"Please don't use it, since it relies on the Date constructor, which\n" +
							"behaves very differently across browsers and locales. Use `dateISO`\n" +
							"instead or one of the locale specific methods in `localizations/`\n" +
							"and `additional-methods.js`."
						);
					}
				}

				return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
			};
		}() ),

		// https://jqueryvalidation.org/dateISO-method/
		dateISO: function( value, element ) {
			return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
		},

		// https://jqueryvalidation.org/number-method/
		number: function( value, element ) {
			return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
		},

		// https://jqueryvalidation.org/digits-method/
		digits: function( value, element ) {
			return this.optional( element ) || /^\d+$/.test( value );
		},

		// https://jqueryvalidation.org/minlength-method/
		minlength: function( value, element, param ) {
			var length = Array.isArray( value ) ? value.length : this.getLength( value, element );
			return this.optional( element ) || length >= param;
		},

		// https://jqueryvalidation.org/maxlength-method/
		maxlength: function( value, element, param ) {
			var length = Array.isArray( value ) ? value.length : this.getLength( value, element );
			return this.optional( element ) || length <= param;
		},

		// https://jqueryvalidation.org/rangelength-method/
		rangelength: function( value, element, param ) {
			var length = Array.isArray( value ) ? value.length : this.getLength( value, element );
			return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
		},

		// https://jqueryvalidation.org/min-method/
		min: function( value, element, param ) {
			return this.optional( element ) || value >= param;
		},

		// https://jqueryvalidation.org/max-method/
		max: function( value, element, param ) {
			return this.optional( element ) || value <= param;
		},

		// https://jqueryvalidation.org/range-method/
		range: function( value, element, param ) {
			return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
		},

		// https://jqueryvalidation.org/step-method/
		step: function( value, element, param ) {
			var type = $( element ).attr( "type" ),
				errorMessage = "Step attribute on input type " + type + " is not supported.",
				supportedTypes = [ "text", "number", "range" ],
				re = new RegExp( "\\b" + type + "\\b" ),
				notSupported = type && !re.test( supportedTypes.join() ),
				decimalPlaces = function( num ) {
					var match = ( "" + num ).match( /(?:\.(\d+))?$/ );
					if ( !match ) {
						return 0;
					}

					// Number of digits right of decimal point.
					return match[ 1 ] ? match[ 1 ].length : 0;
				},
				toInt = function( num ) {
					return Math.round( num * Math.pow( 10, decimals ) );
				},
				valid = true,
				decimals;

			// Works only for text, number and range input types
			// TODO find a way to support input types date, datetime, datetime-local, month, time and week
			if ( notSupported ) {
				throw new Error( errorMessage );
			}

			decimals = decimalPlaces( param );

			// Value can't have too many decimals
			if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {
				valid = false;
			}

			return this.optional( element ) || valid;
		},

		// https://jqueryvalidation.org/equalTo-method/
		equalTo: function( value, element, param ) {

			// Bind to the blur event of the target in order to revalidate whenever the target field is updated
			var target = $( param );
			if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
				target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
					$( element ).valid();
				} );
			}
			return value === target.val();
		},

		// https://jqueryvalidation.org/remote-method/
		remote: function( value, element, param, method ) {
			if ( this.optional( element ) ) {
				return "dependency-mismatch";
			}

			method = typeof method === "string" && method || "remote";

			var previous = this.previousValue( element, method ),
				validator, data, optionDataString;

			if ( !this.settings.messages[ element.name ] ) {
				this.settings.messages[ element.name ] = {};
			}
			previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];
			this.settings.messages[ element.name ][ method ] = previous.message;

			param = typeof param === "string" && { url: param } || param;
			optionDataString = $.param( $.extend( { data: value }, param.data ) );
			if ( previous.old === optionDataString ) {
				return previous.valid;
			}

			previous.old = optionDataString;
			validator = this;
			this.startRequest( element );
			data = {};
			data[ element.name ] = value;
			$.ajax( $.extend( true, {
				mode: "abort",
				port: "validate" + element.name,
				dataType: "json",
				data: data,
				context: validator.currentForm,
				success: function( response ) {
					var valid = response === true || response === "true",
						errors, message, submitted;

					validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
					if ( valid ) {
						submitted = validator.formSubmitted;
						validator.resetInternals();
						validator.toHide = validator.errorsFor( element );
						validator.formSubmitted = submitted;
						validator.successList.push( element );
						validator.invalid[ element.name ] = false;
						validator.showErrors();
					} else {
						errors = {};
						message = response || validator.defaultMessage( element, { method: method, parameters: value } );
						errors[ element.name ] = previous.message = message;
						validator.invalid[ element.name ] = true;
						validator.showErrors( errors );
					}
					previous.valid = valid;
					validator.stopRequest( element, valid );
				}
			}, param ) );
			return "pending";
		}
	}

} );

// Ajax mode: abort
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()

var pendingRequests = {},
	ajax;

// Use a prefilter if available (1.5+)
if ( $.ajaxPrefilter ) {
	$.ajaxPrefilter( function( settings, _, xhr ) {
		var port = settings.port;
		if ( settings.mode === "abort" ) {
			if ( pendingRequests[ port ] ) {
				pendingRequests[ port ].abort();
			}
			pendingRequests[ port ] = xhr;
		}
	} );
} else {

	// Proxy ajax
	ajax = $.ajax;
	$.ajax = function( settings ) {
		var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
			port = ( "port" in settings ? settings : $.ajaxSettings ).port;
		if ( mode === "abort" ) {
			if ( pendingRequests[ port ] ) {
				pendingRequests[ port ].abort();
			}
			pendingRequests[ port ] = ajax.apply( this, arguments );
			return pendingRequests[ port ];
		}
		return ajax.apply( this, arguments );
	};
}
return $;
}));
/*
* MultiSelect v0.9.12
* Copyright (c) 2012 Louis Cuny
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

!function ($) {

  "use strict";


 /* MULTISELECT CLASS DEFINITION
  * ====================== */

  var MultiSelect = function (element, options) {
    this.options = options;
    this.$element = $(element);
    this.$container = $('<div/>', { 'class': "ms-container" });
    this.$selectableContainer = $('<div/>', { 'class': 'ms-selectable' });
    this.$selectionContainer = $('<div/>', { 'class': 'ms-selection' });
    this.$selectableUl = $('<ul/>', { 'class': "ms-list", 'tabindex' : '-1' });
    this.$selectionUl = $('<ul/>', { 'class': "ms-list", 'tabindex' : '-1' });
    this.scrollTo = 0;
    this.elemsSelector = 'li:visible:not(.ms-optgroup-label,.ms-optgroup-container,.'+options.disabledClass+')';
  };

  MultiSelect.prototype = {
    constructor: MultiSelect,

    init: function(){
      var that = this,
          ms = this.$element;

      if (ms.next('.ms-container').length === 0){
        ms.css({ position: 'absolute', left: '-9999px' });
        ms.attr('id', ms.attr('id') ? ms.attr('id') : Math.ceil(Math.random()*1000)+'multiselect');
        this.$container.attr('id', 'ms-'+ms.attr('id'));
        this.$container.addClass(that.options.cssClass);
        ms.find('option').each(function(){
          that.generateLisFromOption(this);
        });

        this.$selectionUl.find('.ms-optgroup-label').hide();

        if (that.options.selectableHeader){
          that.$selectableContainer.append(that.options.selectableHeader);
        }
        that.$selectableContainer.append(that.$selectableUl);
        if (that.options.selectableFooter){
          that.$selectableContainer.append(that.options.selectableFooter);
        }

        if (that.options.selectionHeader){
          that.$selectionContainer.append(that.options.selectionHeader);
        }
        that.$selectionContainer.append(that.$selectionUl);
        if (that.options.selectionFooter){
          that.$selectionContainer.append(that.options.selectionFooter);
        }

        that.$container.append(that.$selectableContainer);
        that.$container.append(that.$selectionContainer);
        ms.after(that.$container);

        that.activeMouse(that.$selectableUl);
        that.activeKeyboard(that.$selectableUl);

        var action = that.options.dblClick ? 'dblclick' : 'click';

        that.$selectableUl.on(action, '.ms-elem-selectable', function(){
          that.select($(this).data('ms-value'));
        });
        that.$selectionUl.on(action, '.ms-elem-selection', function(){
          that.deselect($(this).data('ms-value'));
        });

        that.activeMouse(that.$selectionUl);
        that.activeKeyboard(that.$selectionUl);

        ms.on('focus', function(){
          that.$selectableUl.focus();
        })
      }

      var selectedValues = ms.find('option:selected').map(function(){ return $(this).val(); }).get();
      that.select(selectedValues, 'init');

      if (typeof that.options.afterInit === 'function') {
        that.options.afterInit.call(this, this.$container);
      }
    },

    'generateLisFromOption' : function(option, index, $container){
      var that = this,
          ms = that.$element,
          attributes = "",
          $option = $(option);

      for (var cpt = 0; cpt < option.attributes.length; cpt++){
        var attr = option.attributes[cpt];

        if(attr.name !== 'value' && attr.name !== 'disabled'){
          attributes += attr.name+'="'+attr.value+'" ';
        }
      }
      var selectableLi = $('<li '+attributes+'><span>'+that.escapeHTML($option.text())+'</span></li>'),
          selectedLi = selectableLi.clone(),
          value = $option.val(),
          elementId = that.sanitize(value);

      selectableLi
        .data('ms-value', value)
        .addClass('ms-elem-selectable')
        .attr('id', elementId+'-selectable');

      selectedLi
        .data('ms-value', value)
        .addClass('ms-elem-selection')
        .attr('id', elementId+'-selection')
        .hide();

      if ($option.prop('disabled') || ms.prop('disabled')){
        selectedLi.addClass(that.options.disabledClass);
        selectableLi.addClass(that.options.disabledClass);
      }

      var $optgroup = $option.parent('optgroup');

      if ($optgroup.length > 0){
        var optgroupLabel = $optgroup.attr('label'),
            optgroupId = that.sanitize(optgroupLabel),
            $selectableOptgroup = that.$selectableUl.find('#optgroup-selectable-'+optgroupId),
            $selectionOptgroup = that.$selectionUl.find('#optgroup-selection-'+optgroupId);

        if ($selectableOptgroup.length === 0){
          var optgroupContainerTpl = '<li class="ms-optgroup-container"></li>',
              optgroupTpl = '<ul class="ms-optgroup"><li class="ms-optgroup-label"><span>'+optgroupLabel+'</span></li></ul>';

          $selectableOptgroup = $(optgroupContainerTpl);
          $selectionOptgroup = $(optgroupContainerTpl);
          $selectableOptgroup.attr('id', 'optgroup-selectable-'+optgroupId);
          $selectionOptgroup.attr('id', 'optgroup-selection-'+optgroupId);
          $selectableOptgroup.append($(optgroupTpl));
          $selectionOptgroup.append($(optgroupTpl));
          if (that.options.selectableOptgroup){
            $selectableOptgroup.find('.ms-optgroup-label').on('click', function(){
              var values = $optgroup.children(':not(:selected, :disabled)').map(function(){ return $(this).val() }).get();
              that.select(values);
            });
            $selectionOptgroup.find('.ms-optgroup-label').on('click', function(){
              var values = $optgroup.children(':selected:not(:disabled)').map(function(){ return $(this).val() }).get();
              that.deselect(values);
            });
          }
          that.$selectableUl.append($selectableOptgroup);
          that.$selectionUl.append($selectionOptgroup);
        }
        index = index == undefined ? $selectableOptgroup.find('ul').children().length : index + 1;
        selectableLi.insertAt(index, $selectableOptgroup.children());
        selectedLi.insertAt(index, $selectionOptgroup.children());
      } else {
        index = index == undefined ? that.$selectableUl.children().length : index;

        selectableLi.insertAt(index, that.$selectableUl);
        selectedLi.insertAt(index, that.$selectionUl);
      }
    },

    'addOption' : function(options){
      var that = this;

      if (options.value !== undefined && options.value !== null){
        options = [options];
      } 
      $.each(options, function(index, option){
        if (option.value !== undefined && option.value !== null &&
            that.$element.find("option[value='"+option.value+"']").length === 0){
          var $option = $('<option value="'+option.value+'">'+option.text+'</option>'),
              index = parseInt((typeof option.index === 'undefined' ? that.$element.children().length : option.index)),
              $container = option.nested == undefined ? that.$element : $("optgroup[label='"+option.nested+"']")

          $option.insertAt(index, $container);
          that.generateLisFromOption($option.get(0), index, option.nested);
        }
      })
    },

    'escapeHTML' : function(text){
      return $("<div>").text(text).html();
    },

    'activeKeyboard' : function($list){
      var that = this;

      $list.on('focus', function(){
        $(this).addClass('ms-focus');
      })
      .on('blur', function(){
        $(this).removeClass('ms-focus');
      })
      .on('keydown', function(e){
        switch (e.which) {
          case 40:
          case 38:
            e.preventDefault();
            e.stopPropagation();
            that.moveHighlight($(this), (e.which === 38) ? -1 : 1);
            return;
          case 37:
          case 39:
            e.preventDefault();
            e.stopPropagation();
            that.switchList($list);
            return;
          case 9:
            if(that.$element.is('[tabindex]')){
              e.preventDefault();
              var tabindex = parseInt(that.$element.attr('tabindex'), 10);
              tabindex = (e.shiftKey) ? tabindex-1 : tabindex+1;
              $('[tabindex="'+(tabindex)+'"]').focus();
              return;
            }else{
              if(e.shiftKey){
                that.$element.trigger('focus');
              }
            }
        }
        if($.inArray(e.which, that.options.keySelect) > -1){
          e.preventDefault();
          e.stopPropagation();
          that.selectHighlighted($list);
          return;
        }
      });
    },

    'moveHighlight': function($list, direction){
      var $elems = $list.find(this.elemsSelector),
          $currElem = $elems.filter('.ms-hover'),
          $nextElem = null,
          elemHeight = $elems.first().outerHeight(),
          containerHeight = $list.height(),
          containerSelector = '#'+this.$container.prop('id');

      $elems.removeClass('ms-hover');
      if (direction === 1){ // DOWN

        $nextElem = $currElem.nextAll(this.elemsSelector).first();
        if ($nextElem.length === 0){
          var $optgroupUl = $currElem.parent();

          if ($optgroupUl.hasClass('ms-optgroup')){
            var $optgroupLi = $optgroupUl.parent(),
                $nextOptgroupLi = $optgroupLi.next(':visible');

            if ($nextOptgroupLi.length > 0){
              $nextElem = $nextOptgroupLi.find(this.elemsSelector).first();
            } else {
              $nextElem = $elems.first();
            }
          } else {
            $nextElem = $elems.first();
          }
        }
      } else if (direction === -1){ // UP

        $nextElem = $currElem.prevAll(this.elemsSelector).first();
        if ($nextElem.length === 0){
          var $optgroupUl = $currElem.parent();

          if ($optgroupUl.hasClass('ms-optgroup')){
            var $optgroupLi = $optgroupUl.parent(),
                $prevOptgroupLi = $optgroupLi.prev(':visible');

            if ($prevOptgroupLi.length > 0){
              $nextElem = $prevOptgroupLi.find(this.elemsSelector).last();
            } else {
              $nextElem = $elems.last();
            }
          } else {
            $nextElem = $elems.last();
          }
        }
      }
      if ($nextElem.length > 0){
        $nextElem.addClass('ms-hover');
        var scrollTo = $list.scrollTop() + $nextElem.position().top - 
                       containerHeight / 2 + elemHeight / 2;

        $list.scrollTop(scrollTo);
      }
    },

    'selectHighlighted' : function($list){
      var $elems = $list.find(this.elemsSelector),
          $highlightedElem = $elems.filter('.ms-hover').first();

      if ($highlightedElem.length > 0){
        if ($list.parent().hasClass('ms-selectable')){
          this.select($highlightedElem.data('ms-value'));
        } else {
          this.deselect($highlightedElem.data('ms-value'));
        }
        $elems.removeClass('ms-hover');
      }
    },

    'switchList' : function($list){
      $list.blur();
      this.$container.find(this.elemsSelector).removeClass('ms-hover');
      if ($list.parent().hasClass('ms-selectable')){
        this.$selectionUl.focus();
      } else {
        this.$selectableUl.focus();
      }
    },

    'activeMouse' : function($list){
      var that = this;

      this.$container.on('mouseenter', that.elemsSelector, function(){
        $(this).parents('.ms-container').find(that.elemsSelector).removeClass('ms-hover');
        $(this).addClass('ms-hover');
      });

      this.$container.on('mouseleave', that.elemsSelector, function () {
        $(this).parents('.ms-container').find(that.elemsSelector).removeClass('ms-hover');;
      });
    },

    'refresh' : function() {
      this.destroy();
      this.$element.multiSelect(this.options);
    },

    'destroy' : function(){
      $("#ms-"+this.$element.attr("id")).remove();
      this.$element.css('position', '').css('left', '')
      this.$element.removeData('multiselect');
    },

    'select' : function(value, method){
      if (typeof value === 'string'){ value = [value]; }

      var that = this,
          ms = this.$element,
          msIds = $.map(value, function(val){ return(that.sanitize(val)); }),
          selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable').filter(':not(.'+that.options.disabledClass+')'),
          selections = this.$selectionUl.find('#' + msIds.join('-selection, #') + '-selection').filter(':not(.'+that.options.disabledClass+')'),
          options = ms.find('option:not(:disabled)').filter(function(){ return($.inArray(this.value, value) > -1); });

      if (method === 'init'){
        selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable'),
        selections = this.$selectionUl.find('#' + msIds.join('-selection, #') + '-selection');
      }

      if (selectables.length > 0){
        selectables.addClass('ms-selected').hide();
        selections.addClass('ms-selected').show();

        options.prop('selected', true);

        that.$container.find(that.elemsSelector).removeClass('ms-hover');

        var selectableOptgroups = that.$selectableUl.children('.ms-optgroup-container');
        if (selectableOptgroups.length > 0){
          selectableOptgroups.each(function(){
            var selectablesLi = $(this).find('.ms-elem-selectable');
            if (selectablesLi.length === selectablesLi.filter('.ms-selected').length){
              $(this).find('.ms-optgroup-label').hide();
            }
          });

          var selectionOptgroups = that.$selectionUl.children('.ms-optgroup-container');
          selectionOptgroups.each(function(){
            var selectionsLi = $(this).find('.ms-elem-selection');
            if (selectionsLi.filter('.ms-selected').length > 0){
              $(this).find('.ms-optgroup-label').show();
            }
          });
        } else {
          if (that.options.keepOrder && method !== 'init'){
            var selectionLiLast = that.$selectionUl.find('.ms-selected');
            if((selectionLiLast.length > 1) && (selectionLiLast.last().get(0) != selections.get(0))) {
              selections.insertAfter(selectionLiLast.last());
            }
          }
        }
        if (method !== 'init'){
          ms.trigger('change');
          if (typeof that.options.afterSelect === 'function') {
            that.options.afterSelect.call(this, value);
          }
        }
      }
    },

    'deselect' : function(value){
      if (typeof value === 'string'){ value = [value]; }

      var that = this,
          ms = this.$element,
          msIds = $.map(value, function(val){ return(that.sanitize(val)); }),
          selectables = this.$selectableUl.find('#' + msIds.join('-selectable, #')+'-selectable'),
          selections = this.$selectionUl.find('#' + msIds.join('-selection, #')+'-selection').filter('.ms-selected').filter(':not(.'+that.options.disabledClass+')'),
          options = ms.find('option').filter(function(){ return($.inArray(this.value, value) > -1); });

      if (selections.length > 0){
        selectables.removeClass('ms-selected').show();
        selections.removeClass('ms-selected').hide();
        options.prop('selected', false);

        that.$container.find(that.elemsSelector).removeClass('ms-hover');

        var selectableOptgroups = that.$selectableUl.children('.ms-optgroup-container');
        if (selectableOptgroups.length > 0){
          selectableOptgroups.each(function(){
            var selectablesLi = $(this).find('.ms-elem-selectable');
            if (selectablesLi.filter(':not(.ms-selected)').length > 0){
              $(this).find('.ms-optgroup-label').show();
            }
          });

          var selectionOptgroups = that.$selectionUl.children('.ms-optgroup-container');
          selectionOptgroups.each(function(){
            var selectionsLi = $(this).find('.ms-elem-selection');
            if (selectionsLi.filter('.ms-selected').length === 0){
              $(this).find('.ms-optgroup-label').hide();
            }
          });
        }
        ms.trigger('change');
        if (typeof that.options.afterDeselect === 'function') {
          that.options.afterDeselect.call(this, value);
        }
      }
    },

    'select_all' : function(){
      var ms = this.$element,
          values = ms.val();

      ms.find('option:not(":disabled")').prop('selected', true);
      this.$selectableUl.find('.ms-elem-selectable').filter(':not(.'+this.options.disabledClass+')').addClass('ms-selected').hide();
      this.$selectionUl.find('.ms-optgroup-label').show();
      this.$selectableUl.find('.ms-optgroup-label').hide();
      this.$selectionUl.find('.ms-elem-selection').filter(':not(.'+this.options.disabledClass+')').addClass('ms-selected').show();
      this.$selectionUl.focus();
      ms.trigger('change');
      if (typeof this.options.afterSelect === 'function') {
        var selectedValues = $.grep(ms.val(), function(item){
          return $.inArray(item, values) < 0;
        });
        this.options.afterSelect.call(this, selectedValues);
      }
    },

    'deselect_all' : function(){
      var ms = this.$element,
          values = ms.val();

      ms.find('option').prop('selected', false);
      this.$selectableUl.find('.ms-elem-selectable').removeClass('ms-selected').show();
      this.$selectionUl.find('.ms-optgroup-label').hide();
      this.$selectableUl.find('.ms-optgroup-label').show();
      this.$selectionUl.find('.ms-elem-selection').removeClass('ms-selected').hide();
      this.$selectableUl.focus();
      ms.trigger('change');
      if (typeof this.options.afterDeselect === 'function') {
        this.options.afterDeselect.call(this, values);
      }
    },

    sanitize: function(value){
      var hash = 0, i, character;
      if (value.length == 0) return hash;
      var ls = 0;
      for (i = 0, ls = value.length; i < ls; i++) {
        character  = value.charCodeAt(i);
        hash  = ((hash<<5)-hash)+character;
        hash |= 0; // Convert to 32bit integer
      }
      return hash;
    }
  };

  /* MULTISELECT PLUGIN DEFINITION
   * ======================= */

  $.fn.multiSelect = function () {
    var option = arguments[0],
        args = arguments;

    return this.each(function () {
      var $this = $(this),
          data = $this.data('multiselect'),
          options = $.extend({}, $.fn.multiSelect.defaults, $this.data(), typeof option === 'object' && option);

      if (!data){ $this.data('multiselect', (data = new MultiSelect(this, options))); }

      if (typeof option === 'string'){
        data[option](args[1]);
      } else {
        data.init();
      }
    });
  };

  $.fn.multiSelect.defaults = {
    keySelect: [32],
    selectableOptgroup: false,
    disabledClass : 'disabled',
    dblClick : false,
    keepOrder: false,
    cssClass: ''
  };

  $.fn.multiSelect.Constructor = MultiSelect;

  $.fn.insertAt = function(index, $parent) {
    return this.each(function() {
      if (index === 0) {
        $parent.prepend(this);
      } else {
        $parent.children().eq(index - 1).after(this);
      }
    });
}

}(window.jQuery);

//! moment.js
//! version : 2.30.1
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com

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

    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 hasOwnProp(a, b) {
        return Object.prototype.hasOwnProperty.call(a, b);
    }

    function isObjectEmpty(obj) {
        if (Object.getOwnPropertyNames) {
            return Object.getOwnPropertyNames(obj).length === 0;
        } else {
            var k;
            for (k in obj) {
                if (hasOwnProp(obj, 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,
            arrLen = arr.length;
        for (i = 0; i < arrLen; ++i) {
            res.push(fn(arr[i], i));
        }
        return res;
    }

    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,
            invalidEra: null,
            invalidMonth: null,
            invalidFormat: false,
            userInvalidated: false,
            iso: false,
            parsedDateParts: [],
            era: null,
            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),
                len = t.length >>> 0,
                i;

            for (i = 0; i < len; i++) {
                if (i in t && fun.call(this, t[i], i, t)) {
                    return true;
                }
            }

            return false;
        };
    }

    function isValid(m) {
        var flags = null,
            parsedParts = false,
            isNowValid = m._d && !isNaN(m._d.getTime());
        if (isNowValid) {
            flags = getParsingFlags(m);
            parsedParts = some.call(flags.parsedDateParts, function (i) {
                return i != null;
            });
            isNowValid =
                flags.overflow < 0 &&
                !flags.empty &&
                !flags.invalidEra &&
                !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 = []),
        updateInProgress = false;

    function copyConfig(to, from) {
        var i,
            prop,
            val,
            momentPropertiesLen = momentProperties.length;

        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 (momentPropertiesLen > 0) {
            for (i = 0; i < momentPropertiesLen; i++) {
                prop = momentProperties[i];
                val = from[prop];
                if (!isUndefined(val)) {
                    to[prop] = val;
                }
            }
        }

        return to;
    }

    // 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 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 = [],
                    arg,
                    i,
                    key,
                    argLen = arguments.length;
                for (i = 0; i < argLen; i++) {
                    arg = '';
                    if (typeof arguments[i] === 'object') {
                        arg += '\n[' + i + '] ';
                        for (key in arguments[0]) {
                            if (hasOwnProp(arguments[0], key)) {
                                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 (
            (typeof Function !== 'undefined' && input instanceof Function) ||
            Object.prototype.toString.call(input) === '[object Function]'
        );
    }

    function set(config) {
        var prop, i;
        for (i in config) {
            if (hasOwnProp(config, i)) {
                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;
    }

    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?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,
        localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,
        formatFunctions = {},
        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 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
            .match(formattingTokens)
            .map(function (tok) {
                if (
                    tok === 'MMMM' ||
                    tok === 'MM' ||
                    tok === 'DD' ||
                    tok === 'dddd'
                ) {
                    return tok.slice(1);
                }
                return tok;
            })
            .join('');

        return this._longDateFormat[key];
    }

    var defaultInvalidDate = 'Invalid date';

    function invalidDate() {
        return this._invalidDate;
    }

    var defaultOrdinal = '%d',
        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',
        w: 'a week',
        ww: '%d weeks',
        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 = {
        D: 'date',
        dates: 'date',
        date: 'date',
        d: 'day',
        days: 'day',
        day: 'day',
        e: 'weekday',
        weekdays: 'weekday',
        weekday: 'weekday',
        E: 'isoWeekday',
        isoweekdays: 'isoWeekday',
        isoweekday: 'isoWeekday',
        DDD: 'dayOfYear',
        dayofyears: 'dayOfYear',
        dayofyear: 'dayOfYear',
        h: 'hour',
        hours: 'hour',
        hour: 'hour',
        ms: 'millisecond',
        milliseconds: 'millisecond',
        millisecond: 'millisecond',
        m: 'minute',
        minutes: 'minute',
        minute: 'minute',
        M: 'month',
        months: 'month',
        month: 'month',
        Q: 'quarter',
        quarters: 'quarter',
        quarter: 'quarter',
        s: 'second',
        seconds: 'second',
        second: 'second',
        gg: 'weekYear',
        weekyears: 'weekYear',
        weekyear: 'weekYear',
        GG: 'isoWeekYear',
        isoweekyears: 'isoWeekYear',
        isoweekyear: 'isoWeekYear',
        w: 'week',
        weeks: 'week',
        week: 'week',
        W: 'isoWeek',
        isoweeks: 'isoWeek',
        isoweek: 'isoWeek',
        y: 'year',
        years: 'year',
        year: 'year',
    };

    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 = {
        date: 9,
        day: 11,
        weekday: 11,
        isoWeekday: 11,
        dayOfYear: 4,
        hour: 13,
        millisecond: 16,
        minute: 14,
        month: 8,
        quarter: 7,
        second: 15,
        weekYear: 1,
        isoWeekYear: 1,
        week: 5,
        isoWeek: 5,
        year: 1,
    };

    function getPrioritizedUnits(unitsObj) {
        var units = [],
            u;
        for (u in unitsObj) {
            if (hasOwnProp(unitsObj, u)) {
                units.push({ unit: u, priority: priorities[u] });
            }
        }
        units.sort(function (a, b) {
            return a.priority - b.priority;
        });
        return units;
    }

    var match1 = /\d/, //       0 - 9
        match2 = /\d\d/, //      00 - 99
        match3 = /\d{3}/, //     000 - 999
        match4 = /\d{4}/, //    0000 - 9999
        match6 = /[+-]?\d{6}/, // -999999 - 999999
        match1to2 = /\d\d?/, //       0 - 99
        match3to4 = /\d\d\d\d?/, //     999 - 9999
        match5to6 = /\d\d\d\d\d\d?/, //   99999 - 999999
        match1to3 = /\d{1,3}/, //       0 - 999
        match1to4 = /\d{1,4}/, //       0 - 9999
        match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999
        matchUnsigned = /\d+/, //       0 - inf
        matchSigned = /[+-]?\d+/, //    -inf - inf
        matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
        matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z
        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
        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,
        match1to2NoLeadingZero = /^[1-9]\d?/, //         1-99
        match1to2HasZero = /^([1-9]\d|\d)/, //           0-99
        regexes;

    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, '\\$&');
    }

    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;
    }

    var tokens = {};

    function addParseToken(token, callback) {
        var i,
            func = callback,
            tokenLen;
        if (typeof token === 'string') {
            token = [token];
        }
        if (isNumber(callback)) {
            func = function (input, array) {
                array[callback] = toInt(input);
            };
        }
        tokenLen = token.length;
        for (i = 0; i < tokenLen; 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);
        }
    }

    function isLeapYear(year) {
        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
    }

    var YEAR = 0,
        MONTH = 1,
        DATE = 2,
        HOUR = 3,
        MINUTE = 4,
        SECOND = 5,
        MILLISECOND = 6,
        WEEK = 7,
        WEEKDAY = 8;

    // FORMATTING

    addFormatToken('Y', 0, 0, function () {
        var y = this.year();
        return y <= 9999 ? zeroFill(y, 4) : '+' + 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');

    // 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;
    }

    // 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) {
        if (!mom.isValid()) {
            return NaN;
        }

        var d = mom._d,
            isUTC = mom._isUTC;

        switch (unit) {
            case 'Milliseconds':
                return isUTC ? d.getUTCMilliseconds() : d.getMilliseconds();
            case 'Seconds':
                return isUTC ? d.getUTCSeconds() : d.getSeconds();
            case 'Minutes':
                return isUTC ? d.getUTCMinutes() : d.getMinutes();
            case 'Hours':
                return isUTC ? d.getUTCHours() : d.getHours();
            case 'Date':
                return isUTC ? d.getUTCDate() : d.getDate();
            case 'Day':
                return isUTC ? d.getUTCDay() : d.getDay();
            case 'Month':
                return isUTC ? d.getUTCMonth() : d.getMonth();
            case 'FullYear':
                return isUTC ? d.getUTCFullYear() : d.getFullYear();
            default:
                return NaN; // Just in case
        }
    }

    function set$1(mom, unit, value) {
        var d, isUTC, year, month, date;

        if (!mom.isValid() || isNaN(value)) {
            return;
        }

        d = mom._d;
        isUTC = mom._isUTC;

        switch (unit) {
            case 'Milliseconds':
                return void (isUTC
                    ? d.setUTCMilliseconds(value)
                    : d.setMilliseconds(value));
            case 'Seconds':
                return void (isUTC ? d.setUTCSeconds(value) : d.setSeconds(value));
            case 'Minutes':
                return void (isUTC ? d.setUTCMinutes(value) : d.setMinutes(value));
            case 'Hours':
                return void (isUTC ? d.setUTCHours(value) : d.setHours(value));
            case 'Date':
                return void (isUTC ? d.setUTCDate(value) : d.setDate(value));
            // case 'Day': // Not real
            //    return void (isUTC ? d.setUTCDay(value) : d.setDay(value));
            // case 'Month': // Not used because we need to pass two variables
            //     return void (isUTC ? d.setUTCMonth(value) : d.setMonth(value));
            case 'FullYear':
                break; // See below ...
            default:
                return; // Just in case
        }

        year = value;
        month = mom.month();
        date = mom.date();
        date = date === 29 && month === 1 && !isLeapYear(year) ? 28 : date;
        void (isUTC
            ? d.setUTCFullYear(year, month, date)
            : d.setFullYear(year, month, date));
    }

    // 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),
                i,
                prioritizedLen = prioritized.length;
            for (i = 0; i < prioritizedLen; 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);
    });

    // PARSING

    addRegexToken('M', match1to2, match1to2NoLeadingZero);
    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 defaultLocaleMonths =
            'January_February_March_April_May_June_July_August_September_October_November_December'.split(
                '_'
            ),
        defaultLocaleMonthsShort =
            'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),
        MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,
        defaultMonthsShortRegex = matchWord,
        defaultMonthsRegex = matchWord;

    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()];
    }

    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) {
        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;
                }
            }
        }

        var month = value,
            date = mom.date();

        date = date < 29 ? date : Math.min(date, daysInMonth(mom.year(), month));
        void (mom._isUTC
            ? mom._d.setUTCMonth(month, date)
            : mom._d.setMonth(month, date));
        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());
    }

    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;
        }
    }

    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,
            shortP,
            longP;
        for (i = 0; i < 12; i++) {
            // make the regex if we don't have it already
            mom = createUTC([2000, i]);
            shortP = regexEscape(this.monthsShort(mom, ''));
            longP = regexEscape(this.months(mom, ''));
            shortPieces.push(shortP);
            longPieces.push(longP);
            mixedPieces.push(longP);
            mixedPieces.push(shortP);
        }
        // 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);

        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;
        // the date constructor remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            // preserve leap years using a full 400 year cycle, then reset
            date = new Date(y + 400, m, d, h, M, s, ms);
            if (isFinite(date.getFullYear())) {
                date.setFullYear(y);
            }
        } else {
            date = new Date(y, m, d, h, M, s, ms);
        }

        return date;
    }

    function createUTCDate(y) {
        var date, args;
        // the Date.UTC function remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            args = Array.prototype.slice.call(arguments);
            // preserve leap years using a full 400 year cycle, then reset
            args[0] = y + 400;
            date = new Date(Date.UTC.apply(null, args));
            if (isFinite(date.getUTCFullYear())) {
                date.setUTCFullYear(y);
            }
        } else {
            date = new Date(Date.UTC.apply(null, arguments));
        }

        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');

    // PARSING

    addRegexToken('w', match1to2, match1to2NoLeadingZero);
    addRegexToken('ww', match1to2, match2);
    addRegexToken('W', match1to2, match1to2NoLeadingZero);
    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 6th 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');

    // 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
    function shiftWeekdays(ws, n) {
        return ws.slice(n, 7).concat(ws.slice(0, n));
    }

    var defaultLocaleWeekdays =
            'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
        defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
        defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
        defaultWeekdaysRegex = matchWord,
        defaultWeekdaysShortRegex = matchWord,
        defaultWeekdaysMinRegex = matchWord;

    function localeWeekdays(m, format) {
        var weekdays = isArray(this._weekdays)
            ? this._weekdays
            : this._weekdays[
                  m && m !== true && this._weekdays.isFormat.test(format)
                      ? 'format'
                      : 'standalone'
              ];
        return m === true
            ? shiftWeekdays(weekdays, this._week.dow)
            : m
              ? weekdays[m.day()]
              : weekdays;
    }

    function localeWeekdaysShort(m) {
        return m === true
            ? shiftWeekdays(this._weekdaysShort, this._week.dow)
            : m
              ? this._weekdaysShort[m.day()]
              : this._weekdaysShort;
    }

    function localeWeekdaysMin(m) {
        return m === true
            ? shiftWeekdays(this._weekdaysMin, this._week.dow)
            : 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 = get(this, 'Day');
        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;
        }
    }

    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;
        }
    }

    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;
        }
    }

    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 = regexEscape(this.weekdaysMin(mom, ''));
            shortp = regexEscape(this.weekdaysShort(mom, ''));
            longp = regexEscape(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);

        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);

    // PARSING

    function matchMeridiem(isStrict, locale) {
        return locale._meridiemParse;
    }

    addRegexToken('a', matchMeridiem);
    addRegexToken('A', matchMeridiem);
    addRegexToken('H', match1to2, match1to2HasZero);
    addRegexToken('h', match1to2, match1to2NoLeadingZero);
    addRegexToken('k', match1to2, match1to2NoLeadingZero);
    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,
            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,
            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,
        // 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.
        getSetHour = makeGetSet('Hours', true);

    function localeMeridiem(hours, minutes, isLower) {
        if (hours > 11) {
            return isLower ? 'pm' : 'PM';
        } else {
            return isLower ? 'am' : 'AM';
        }
    }

    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 = {},
        localeFamilies = {},
        globalLocale;

    function commonPrefix(arr1, arr2) {
        var i,
            minl = Math.min(arr1.length, arr2.length);
        for (i = 0; i < minl; i += 1) {
            if (arr1[i] !== arr2[i]) {
                return i;
            }
        }
        return minl;
    }

    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 &&
                    commonPrefix(split, next) >= j - 1
                ) {
                    //the next array item is better than a shallower substring of this one
                    break;
                }
                j--;
            }
            i++;
        }
        return globalLocale;
    }

    function isLocaleNameSane(name) {
        // Prevent names that look like filesystem paths, i.e contain '/' or '\'
        // Ensure name is available and function returns boolean
        return !!(name && name.match('^[^/\\\\]*$'));
    }

    function loadLocale(name) {
        var oldLocale = null,
            aliasedRequire;
        // TODO: Find a better way to register and load all the locales in Node
        if (
            locales[name] === undefined &&
            typeof module !== 'undefined' &&
            module &&
            module.exports &&
            isLocaleNameSane(name)
        ) {
            try {
                oldLocale = globalLocale._abbr;
                aliasedRequire = require;
                aliasedRequire('./locale/' + name);
                getSetGlobalLocale(oldLocale);
            } catch (e) {
                // mark as not found to avoid repeating expensive file require call causing high CPU
                // when trying to find en-US, en_US, en-us for every format call
                locales[name] = null; // null means not found
            }
        }
        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;

            if (locales[name] != null && locales[name].parentLocale != null) {
                // Update existing child locale in-place to avoid memory-leaks
                locales[name].set(mergeConfigs(locales[name]._config, config));
            } else {
                // MERGE
                tmpLocale = loadLocale(name);
                if (tmpLocale != null) {
                    parentConfig = tmpLocale._config;
                }
                config = mergeConfigs(parentConfig, config);
                if (tmpLocale == null) {
                    // updateLocale is called for creating a new locale
                    // Set abbr so it will have a name (getters return
                    // undefined otherwise).
                    config.abbr = name;
                }
                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;
                    if (name === getSetGlobalLocale()) {
                        getSetGlobalLocale(name);
                    }
                } 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,
            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;
    }

    // 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)?)?$/,
        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)?)?$/,
        tzRegex = /Z|[+-]\d\d(?::?\d\d)?/,
        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}/],
            ['GGGG[W]WWE', /\d{4}W\d{3}/],
            ['GGGG[W]WW', /\d{4}W\d{2}/, false],
            ['YYYYDDD', /\d{7}/],
            ['YYYYMM', /\d{6}/, false],
            ['YYYY', /\d{4}/, false],
        ],
        // iso time formats and regexes
        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/],
        ],
        aspNetJsonRegex = /^\/?Date\((-?\d+)/i,
        // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
        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}))$/,
        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,
        };

    // date from iso format
    function configFromISO(config) {
        var i,
            l,
            string = config._i,
            match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
            allowTime,
            dateFormat,
            timeFormat,
            tzFormat,
            isoDatesLen = isoDates.length,
            isoTimesLen = isoTimes.length;

        if (match) {
            getParsingFlags(config).iso = true;
            for (i = 0, l = isoDatesLen; 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 = isoTimesLen; 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;
        }
    }

    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 independent 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;
    }

    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),
                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)),
            parsedArray;
        if (match) {
            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 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict
    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;
        }

        if (config._strict) {
            config._isValid = false;
        } else {
            // 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. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.',
        function (config) {
            config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
        }
    );

    // 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, curWeek;

        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;

            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 beginning of week
                weekday = w.e + dow;
                if (w.e < 0 || w.e > 6) {
                    weekdayOverflow = true;
                }
            } else {
                // default to beginning 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;
        }
    }

    // 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,
            era,
            tokenLen;

        tokens =
            expandFormat(config._f, config._locale).match(formattingTokens) || [];
        tokenLen = tokens.length;
        for (i = 0; i < tokenLen; i++) {
            token = tokens[i];
            parsedInput = (string.match(getParseRegexForToken(token, config)) ||
                [])[0];
            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
        );

        // handle era
        era = getParsingFlags(config).era;
        if (era !== null) {
            config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]);
        }

        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,
            validFormatFound,
            bestFormatIsValid = false,
            configfLen = config._f.length;

        if (configfLen === 0) {
            getParsingFlags(config).invalidFormat = true;
            config._d = new Date(NaN);
            return;
        }

        for (i = 0; i < configfLen; i++) {
            currentScore = 0;
            validFormatFound = false;
            tempConfig = copyConfig({}, config);
            if (config._useUTC != null) {
                tempConfig._useUTC = config._useUTC;
            }
            tempConfig._f = config._f[i];
            configFromStringAndFormat(tempConfig);

            if (isValid(tempConfig)) {
                validFormatFound = true;
            }

            // 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 (!bestFormatIsValid) {
                if (
                    scoreToBeat == null ||
                    currentScore < scoreToBeat ||
                    validFormatFound
                ) {
                    scoreToBeat = currentScore;
                    bestMoment = tempConfig;
                    if (validFormatFound) {
                        bestFormatIsValid = true;
                    }
                }
            } else {
                if (currentScore < scoreToBeat) {
                    scoreToBeat = currentScore;
                    bestMoment = tempConfig;
                }
            }
        }

        extend(config, bestMoment || tempConfig);
    }

    function configFromObject(config) {
        if (config._d) {
            return;
        }

        var i = normalizeObjectUnits(config._i),
            dayOrDate = i.day === undefined ? i.date : i.day;
        config._a = map(
            [i.year, i.month, dayOrDate, 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 (format === true || format === false) {
            strict = format;
            format = undefined;
        }

        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();
                }
            }
        ),
        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) {
        var key,
            unitHasDecimal = false,
            i,
            orderLen = ordering.length;
        for (key in m) {
            if (
                hasOwnProp(m, key) &&
                !(
                    indexOf.call(ordering, key) !== -1 &&
                    (m[key] == null || !isNaN(m[key]))
                )
            ) {
                return false;
            }
        }

        for (i = 0; i < orderLen; ++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 || normalizedInput.isoWeek || 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);
        }
    }

    // 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;
    }

    // FORMATTING

    function offset(token, separator) {
        addFormatToken(token, 0, 0, function () {
            var offset = this.utcOffset(),
                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),
            chunk,
            parts,
            minutes;

        if (matches === null) {
            return null;
        }

        chunk = matches[matches.length - 1] || [];
        parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
        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());
    }

    // 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 = {},
            other;

        copyConfig(c, this);
        c = prepareConfig(c);

        if (c._a) {
            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
        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) || !isNaN(+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 : 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;
        }

        if (isDuration(input) && hasOwnProp(input, '_isValid')) {
            ret._isValid = input._isValid;
        }

        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 = {};

        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;
            }

            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'),
        subtract = createAdder(-1, 'subtract');

    function isString(input) {
        return typeof input === 'string' || input instanceof String;
    }

    // type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined
    function isMomentInput(input) {
        return (
            isMoment(input) ||
            isDate(input) ||
            isString(input) ||
            isNumber(input) ||
            isNumberOrStringArray(input) ||
            isMomentInputObject(input) ||
            input === null ||
            input === undefined
        );
    }

    function isMomentInputObject(input) {
        var objectTest = isObject(input) && !isObjectEmpty(input),
            propertyTest = false,
            properties = [
                'years',
                'year',
                'y',
                'months',
                'month',
                'M',
                'days',
                'day',
                'd',
                'dates',
                'date',
                'D',
                'hours',
                'hour',
                'h',
                'minutes',
                'minute',
                'm',
                'seconds',
                'second',
                's',
                'milliseconds',
                'millisecond',
                'ms',
            ],
            i,
            property,
            propertyLen = properties.length;

        for (i = 0; i < propertyLen; i += 1) {
            property = properties[i];
            propertyTest = propertyTest || hasOwnProp(input, property);
        }

        return objectTest && propertyTest;
    }

    function isNumberOrStringArray(input) {
        var arrayTest = isArray(input),
            dataTypeTest = false;
        if (arrayTest) {
            dataTypeTest =
                input.filter(function (item) {
                    return !isNumber(item) && isString(input);
                }).length === 0;
        }
        return arrayTest && dataTypeTest;
    }

    function isCalendarSpec(input) {
        var objectTest = isObject(input) && !isObjectEmpty(input),
            propertyTest = false,
            properties = [
                'sameDay',
                'nextDay',
                'lastDay',
                'nextWeek',
                'lastWeek',
                'sameElse',
            ],
            i,
            property;

        for (i = 0; i < properties.length; i += 1) {
            property = properties[i];
            propertyTest = propertyTest || hasOwnProp(input, property);
        }

        return objectTest && propertyTest;
    }

    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) {
        // Support for single parameter, formats only overload to the calendar function
        if (arguments.length === 1) {
            if (!arguments[0]) {
                time = undefined;
                formats = undefined;
            } else if (isMomentInput(arguments[0])) {
                time = arguments[0];
                formats = undefined;
            } else if (isCalendarSpec(arguments[0])) {
                formats = arguments[0];
                time = undefined;
            }
        }
        // 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',
            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(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(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) {
        var localFrom = isMoment(from) ? from : createLocal(from),
            localTo = isMoment(to) ? to : createLocal(to);
        if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
            return false;
        }
        inclusivity = inclusivity || '()';
        return (
            (inclusivity[0] === '('
                ? this.isAfter(localFrom, units)
                : !this.isBefore(localFrom, units)) &&
            (inclusivity[1] === ')'
                ? this.isBefore(localTo, units)
                : !this.isAfter(localTo, 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) {
        if (a.date() < b.date()) {
            // end-of-month calculations work correct when the start month has more
            // days than the end month.
            return -monthDiff(b, a);
        }
        // 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,
            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',
            zone = '',
            prefix,
            year,
            datetime,
            suffix;
        if (!this.isLocal()) {
            func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
            zone = 'Z';
        }
        prefix = '[' + func + '("]';
        year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
        datetime = '-MM-DD[T]HH:mm:ss.SSS';
        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;
    }

    var MS_PER_SECOND = 1000,
        MS_PER_MINUTE = 60 * MS_PER_SECOND,
        MS_PER_HOUR = 60 * MS_PER_MINUTE,
        MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR;

    // actual modulo - handles negative numbers (for dates before 1970):
    function mod$1(dividend, divisor) {
        return ((dividend % divisor) + divisor) % divisor;
    }

    function localStartOfDate(y, m, d) {
        // the date constructor remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            // preserve leap years using a full 400 year cycle, then reset
            return new Date(y + 400, m, d) - MS_PER_400_YEARS;
        } else {
            return new Date(y, m, d).valueOf();
        }
    }

    function utcStartOfDate(y, m, d) {
        // Date.UTC remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            // preserve leap years using a full 400 year cycle, then reset
            return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
        } else {
            return Date.UTC(y, m, d);
        }
    }

    function startOf(units) {
        var time, startOfDate;
        units = normalizeUnits(units);
        if (units === undefined || units === 'millisecond' || !this.isValid()) {
            return this;
        }

        startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;

        switch (units) {
            case 'year':
                time = startOfDate(this.year(), 0, 1);
                break;
            case 'quarter':
                time = startOfDate(
                    this.year(),
                    this.month() - (this.month() % 3),
                    1
                );
                break;
            case 'month':
                time = startOfDate(this.year(), this.month(), 1);
                break;
            case 'week':
                time = startOfDate(
                    this.year(),
                    this.month(),
                    this.date() - this.weekday()
                );
                break;
            case 'isoWeek':
                time = startOfDate(
                    this.year(),
                    this.month(),
                    this.date() - (this.isoWeekday() - 1)
                );
                break;
            case 'day':
            case 'date':
                time = startOfDate(this.year(), this.month(), this.date());
                break;
            case 'hour':
                time = this._d.valueOf();
                time -= mod$1(
                    time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
                    MS_PER_HOUR
                );
                break;
            case 'minute':
                time = this._d.valueOf();
                time -= mod$1(time, MS_PER_MINUTE);
                break;
            case 'second':
                time = this._d.valueOf();
                time -= mod$1(time, MS_PER_SECOND);
                break;
        }

        this._d.setTime(time);
        hooks.updateOffset(this, true);
        return this;
    }

    function endOf(units) {
        var time, startOfDate;
        units = normalizeUnits(units);
        if (units === undefined || units === 'millisecond' || !this.isValid()) {
            return this;
        }

        startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;

        switch (units) {
            case 'year':
                time = startOfDate(this.year() + 1, 0, 1) - 1;
                break;
            case 'quarter':
                time =
                    startOfDate(
                        this.year(),
                        this.month() - (this.month() % 3) + 3,
                        1
                    ) - 1;
                break;
            case 'month':
                time = startOfDate(this.year(), this.month() + 1, 1) - 1;
                break;
            case 'week':
                time =
                    startOfDate(
                        this.year(),
                        this.month(),
                        this.date() - this.weekday() + 7
                    ) - 1;
                break;
            case 'isoWeek':
                time =
                    startOfDate(
                        this.year(),
                        this.month(),
                        this.date() - (this.isoWeekday() - 1) + 7
                    ) - 1;
                break;
            case 'day':
            case 'date':
                time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
                break;
            case 'hour':
                time = this._d.valueOf();
                time +=
                    MS_PER_HOUR -
                    mod$1(
                        time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
                        MS_PER_HOUR
                    ) -
                    1;
                break;
            case 'minute':
                time = this._d.valueOf();
                time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
                break;
            case 'second':
                time = this._d.valueOf();
                time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
                break;
        }

        this._d.setTime(time);
        hooks.updateOffset(this, true);
        return this;
    }

    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,
        };
    }

    addFormatToken('N', 0, 0, 'eraAbbr');
    addFormatToken('NN', 0, 0, 'eraAbbr');
    addFormatToken('NNN', 0, 0, 'eraAbbr');
    addFormatToken('NNNN', 0, 0, 'eraName');
    addFormatToken('NNNNN', 0, 0, 'eraNarrow');

    addFormatToken('y', ['y', 1], 'yo', 'eraYear');
    addFormatToken('y', ['yy', 2], 0, 'eraYear');
    addFormatToken('y', ['yyy', 3], 0, 'eraYear');
    addFormatToken('y', ['yyyy', 4], 0, 'eraYear');

    addRegexToken('N', matchEraAbbr);
    addRegexToken('NN', matchEraAbbr);
    addRegexToken('NNN', matchEraAbbr);
    addRegexToken('NNNN', matchEraName);
    addRegexToken('NNNNN', matchEraNarrow);

    addParseToken(
        ['N', 'NN', 'NNN', 'NNNN', 'NNNNN'],
        function (input, array, config, token) {
            var era = config._locale.erasParse(input, token, config._strict);
            if (era) {
                getParsingFlags(config).era = era;
            } else {
                getParsingFlags(config).invalidEra = input;
            }
        }
    );

    addRegexToken('y', matchUnsigned);
    addRegexToken('yy', matchUnsigned);
    addRegexToken('yyy', matchUnsigned);
    addRegexToken('yyyy', matchUnsigned);
    addRegexToken('yo', matchEraYearOrdinal);

    addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR);
    addParseToken(['yo'], function (input, array, config, token) {
        var match;
        if (config._locale._eraYearOrdinalRegex) {
            match = input.match(config._locale._eraYearOrdinalRegex);
        }

        if (config._locale.eraYearOrdinalParse) {
            array[YEAR] = config._locale.eraYearOrdinalParse(input, match);
        } else {
            array[YEAR] = parseInt(input, 10);
        }
    });

    function localeEras(m, format) {
        var i,
            l,
            date,
            eras = this._eras || getLocale('en')._eras;
        for (i = 0, l = eras.length; i < l; ++i) {
            switch (typeof eras[i].since) {
                case 'string':
                    // truncate time
                    date = hooks(eras[i].since).startOf('day');
                    eras[i].since = date.valueOf();
                    break;
            }

            switch (typeof eras[i].until) {
                case 'undefined':
                    eras[i].until = +Infinity;
                    break;
                case 'string':
                    // truncate time
                    date = hooks(eras[i].until).startOf('day').valueOf();
                    eras[i].until = date.valueOf();
                    break;
            }
        }
        return eras;
    }

    function localeErasParse(eraName, format, strict) {
        var i,
            l,
            eras = this.eras(),
            name,
            abbr,
            narrow;
        eraName = eraName.toUpperCase();

        for (i = 0, l = eras.length; i < l; ++i) {
            name = eras[i].name.toUpperCase();
            abbr = eras[i].abbr.toUpperCase();
            narrow = eras[i].narrow.toUpperCase();

            if (strict) {
                switch (format) {
                    case 'N':
                    case 'NN':
                    case 'NNN':
                        if (abbr === eraName) {
                            return eras[i];
                        }
                        break;

                    case 'NNNN':
                        if (name === eraName) {
                            return eras[i];
                        }
                        break;

                    case 'NNNNN':
                        if (narrow === eraName) {
                            return eras[i];
                        }
                        break;
                }
            } else if ([name, abbr, narrow].indexOf(eraName) >= 0) {
                return eras[i];
            }
        }
    }

    function localeErasConvertYear(era, year) {
        var dir = era.since <= era.until ? +1 : -1;
        if (year === undefined) {
            return hooks(era.since).year();
        } else {
            return hooks(era.since).year() + (year - era.offset) * dir;
        }
    }

    function getEraName() {
        var i,
            l,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            // truncate time
            val = this.clone().startOf('day').valueOf();

            if (eras[i].since <= val && val <= eras[i].until) {
                return eras[i].name;
            }
            if (eras[i].until <= val && val <= eras[i].since) {
                return eras[i].name;
            }
        }

        return '';
    }

    function getEraNarrow() {
        var i,
            l,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            // truncate time
            val = this.clone().startOf('day').valueOf();

            if (eras[i].since <= val && val <= eras[i].until) {
                return eras[i].narrow;
            }
            if (eras[i].until <= val && val <= eras[i].since) {
                return eras[i].narrow;
            }
        }

        return '';
    }

    function getEraAbbr() {
        var i,
            l,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            // truncate time
            val = this.clone().startOf('day').valueOf();

            if (eras[i].since <= val && val <= eras[i].until) {
                return eras[i].abbr;
            }
            if (eras[i].until <= val && val <= eras[i].since) {
                return eras[i].abbr;
            }
        }

        return '';
    }

    function getEraYear() {
        var i,
            l,
            dir,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            dir = eras[i].since <= eras[i].until ? +1 : -1;

            // truncate time
            val = this.clone().startOf('day').valueOf();

            if (
                (eras[i].since <= val && val <= eras[i].until) ||
                (eras[i].until <= val && val <= eras[i].since)
            ) {
                return (
                    (this.year() - hooks(eras[i].since).year()) * dir +
                    eras[i].offset
                );
            }
        }

        return this.year();
    }

    function erasNameRegex(isStrict) {
        if (!hasOwnProp(this, '_erasNameRegex')) {
            computeErasParse.call(this);
        }
        return isStrict ? this._erasNameRegex : this._erasRegex;
    }

    function erasAbbrRegex(isStrict) {
        if (!hasOwnProp(this, '_erasAbbrRegex')) {
            computeErasParse.call(this);
        }
        return isStrict ? this._erasAbbrRegex : this._erasRegex;
    }

    function erasNarrowRegex(isStrict) {
        if (!hasOwnProp(this, '_erasNarrowRegex')) {
            computeErasParse.call(this);
        }
        return isStrict ? this._erasNarrowRegex : this._erasRegex;
    }

    function matchEraAbbr(isStrict, locale) {
        return locale.erasAbbrRegex(isStrict);
    }

    function matchEraName(isStrict, locale) {
        return locale.erasNameRegex(isStrict);
    }

    function matchEraNarrow(isStrict, locale) {
        return locale.erasNarrowRegex(isStrict);
    }

    function matchEraYearOrdinal(isStrict, locale) {
        return locale._eraYearOrdinalRegex || matchUnsigned;
    }

    function computeErasParse() {
        var abbrPieces = [],
            namePieces = [],
            narrowPieces = [],
            mixedPieces = [],
            i,
            l,
            erasName,
            erasAbbr,
            erasNarrow,
            eras = this.eras();

        for (i = 0, l = eras.length; i < l; ++i) {
            erasName = regexEscape(eras[i].name);
            erasAbbr = regexEscape(eras[i].abbr);
            erasNarrow = regexEscape(eras[i].narrow);

            namePieces.push(erasName);
            abbrPieces.push(erasAbbr);
            narrowPieces.push(erasNarrow);
            mixedPieces.push(erasName);
            mixedPieces.push(erasAbbr);
            mixedPieces.push(erasNarrow);
        }

        this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
        this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i');
        this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i');
        this._erasNarrowRegex = new RegExp(
            '^(' + narrowPieces.join('|') + ')',
            'i'
        );
    }

    // 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

    // 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.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 getISOWeeksInISOWeekYear() {
        return weeksInYear(this.isoWeekYear(), 1, 4);
    }

    function getWeeksInYear() {
        var weekInfo = this.localeData()._week;
        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
    }

    function getWeeksInWeekYear() {
        var weekInfo = this.localeData()._week;
        return weeksInYear(this.weekYear(), 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');

    // 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');

    // PARSING

    addRegexToken('D', match1to2, match1to2NoLeadingZero);
    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');

    // 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');

    // PARSING

    addRegexToken('m', match1to2, match1to2HasZero);
    addRegexToken('mm', match1to2, match2);
    addParseToken(['m', 'mm'], MINUTE);

    // MOMENTS

    var getSetMinute = makeGetSet('Minutes', false);

    // FORMATTING

    addFormatToken('s', ['ss', 2], 0, 'second');

    // PARSING

    addRegexToken('s', match1to2, match1to2HasZero);
    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;
    });

    // PARSING

    addRegexToken('S', match1to3, match1);
    addRegexToken('SS', match1to3, match2);
    addRegexToken('SSS', match1to3, match3);

    var token, getSetMillisecond;
    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);
    }

    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;
    if (typeof Symbol !== 'undefined' && Symbol.for != null) {
        proto[Symbol.for('nodejs.util.inspect.custom')] = function () {
            return 'Moment<' + this.format() + '>';
        };
    }
    proto.toJSON = toJSON;
    proto.toString = toString;
    proto.unix = unix;
    proto.valueOf = valueOf;
    proto.creationData = creationData;
    proto.eraName = getEraName;
    proto.eraNarrow = getEraNarrow;
    proto.eraAbbr = getEraAbbr;
    proto.eraYear = getEraYear;
    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.weeksInWeekYear = getWeeksInWeekYear;
    proto.isoWeeksInYear = getISOWeeksInYear;
    proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear;
    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.eras = localeEras;
    proto$1.erasParse = localeErasParse;
    proto$1.erasConvertYear = localeErasConvertYear;
    proto$1.erasAbbrRegex = erasAbbrRegex;
    proto$1.erasNameRegex = erasNameRegex;
    proto$1.erasNarrowRegex = erasNarrowRegex;

    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(),
            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,
            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,
            i,
            out = [];

        if (index != null) {
            return get$1(format, (index + shift) % 7, field, 'day');
        }

        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', {
        eras: [
            {
                since: '0001-01-01',
                until: +Infinity,
                offset: 1,
                name: 'Anno Domini',
                narrow: 'AD',
                abbr: 'AD',
            },
            {
                since: '0000-12-31',
                until: -Infinity,
                offset: 1,
                name: 'Before Christ',
                narrow: 'BC',
                abbr: 'BC',
            },
        ],
        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,
            days = this._days,
            months = this._months,
            data = this._data,
            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,
            months,
            milliseconds = this._milliseconds;

        units = normalizeUnits(units);

        if (units === 'month' || units === 'quarter' || units === 'year') {
            days = this._days + milliseconds / 864e5;
            months = this._months + daysToMonths(days);
            switch (units) {
                case 'month':
                    return months;
                case 'quarter':
                    return months / 3;
                case 'year':
                    return 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);
            }
        }
    }

    function makeAs(alias) {
        return function () {
            return this.as(alias);
        };
    }

    var asMilliseconds = makeAs('ms'),
        asSeconds = makeAs('s'),
        asMinutes = makeAs('m'),
        asHours = makeAs('h'),
        asDays = makeAs('d'),
        asWeeks = makeAs('w'),
        asMonths = makeAs('M'),
        asQuarters = makeAs('Q'),
        asYears = makeAs('y'),
        valueOf$1 = asMilliseconds;

    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'),
        seconds = makeGetter('seconds'),
        minutes = makeGetter('minutes'),
        hours = makeGetter('hours'),
        days = makeGetter('days'),
        months = makeGetter('months'),
        years = makeGetter('years');

    function weeks() {
        return absFloor(this.days() / 7);
    }

    var round = Math.round,
        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/week
            w: null, // weeks 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, thresholds, locale) {
        var duration = createDuration(posNegDuration).abs(),
            seconds = round(duration.as('s')),
            minutes = round(duration.as('m')),
            hours = round(duration.as('h')),
            days = round(duration.as('d')),
            months = round(duration.as('M')),
            weeks = round(duration.as('w')),
            years = round(duration.as('y')),
            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]);

        if (thresholds.w != null) {
            a =
                a ||
                (weeks <= 1 && ['w']) ||
                (weeks < thresholds.w && ['ww', weeks]);
        }
        a = a ||
            (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(argWithSuffix, argThresholds) {
        if (!this.isValid()) {
            return this.localeData().invalidDate();
        }

        var withSuffix = false,
            th = thresholds,
            locale,
            output;

        if (typeof argWithSuffix === 'object') {
            argThresholds = argWithSuffix;
            argWithSuffix = false;
        }
        if (typeof argWithSuffix === 'boolean') {
            withSuffix = argWithSuffix;
        }
        if (typeof argThresholds === 'object') {
            th = Object.assign({}, thresholds, argThresholds);
            if (argThresholds.s != null && argThresholds.ss == null) {
                th.ss = argThresholds.s - 1;
            }
        }

        locale = this.localeData();
        output = relativeTime$1(this, !withSuffix, th, 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,
            days = abs$1(this._days),
            months = abs$1(this._months),
            minutes,
            hours,
            years,
            s,
            total = this.asSeconds(),
            totalSign,
            ymSign,
            daysSign,
            hmsSign;

        if (!total) {
            // this is the same as C#'s (Noda) and python (isodate)...
            // but not other JS (goog.date)
            return 'P0D';
        }

        // 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
        s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';

        totalSign = total < 0 ? '-' : '';
        ymSign = sign(this._months) !== sign(total) ? '-' : '';
        daysSign = sign(this._days) !== sign(total) ? '-' : '';
        hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';

        return (
            totalSign +
            'P' +
            (years ? ymSign + years + 'Y' : '') +
            (months ? ymSign + months + 'M' : '') +
            (days ? daysSign + days + 'D' : '') +
            (hours || minutes || seconds ? 'T' : '') +
            (hours ? hmsSign + hours + 'H' : '') +
            (minutes ? hmsSign + minutes + 'M' : '') +
            (seconds ? 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.asQuarters = asQuarters;
    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;

    // 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) * 1000);
    });
    addParseToken('x', function (input, array, config) {
        config._d = new Date(toInt(input));
    });

    //! moment.js

    hooks.version = '2.30.1';

    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: 'GGGG-[W]WW', // <input type="week" />
        MONTH: 'YYYY-MM', // <input type="month" />
    };

    return hooks;

})));

!function(e){"use strict";if("function"==typeof define&&define.amd)define(["jquery","moment"],e);else if("object"==typeof exports)module.exports=e(require("jquery"),require("moment"));else{if("undefined"==typeof jQuery)throw"bootstrap-datetimepicker requires jQuery to be loaded first";if("undefined"==typeof moment)throw"bootstrap-datetimepicker requires Moment.js to be loaded first";e(jQuery,moment)}}(function($,_){"use strict";if(!_)throw new Error("bootstrap-datetimepicker requires Moment.js to be loaded first");function i(i,p){function a(){return void 0!==_.tz&&void 0!==p.timeZone&&null!==p.timeZone&&""!==p.timeZone}function c(e){var t;return t=null==e?_():_.isDate(e)||_.isMoment(e)?_(e):a()?_.tz(e,B,p.useStrict,p.timeZone):_(e,B,p.useStrict),a()&&t.tz(p.timeZone),t}function d(e){if("string"!=typeof e||1<e.length)throw new TypeError("isEnabled expects a single character string parameter");switch(e){case"y":return-1!==q.indexOf("Y");case"M":return-1!==q.indexOf("M");case"d":return-1!==q.toLowerCase().indexOf("d");case"h":case"H":return-1!==q.toLowerCase().indexOf("h");case"m":return-1!==q.indexOf("m");case"s":return-1!==q.indexOf("s");default:return!1}}function l(){return d("h")||d("m")||d("s")}function u(){return d("y")||d("M")||d("d")}function f(){var e,t,a,n=$("<div>").addClass("timepicker-hours").append($("<table>").addClass("table-condensed")),r=$("<div>").addClass("timepicker-minutes").append($("<table>").addClass("table-condensed")),i=$("<div>").addClass("timepicker-seconds").append($("<table>").addClass("table-condensed")),o=[(e=$("<tr>"),t=$("<tr>"),a=$("<tr>"),d("h")&&(e.append($("<td>").append($("<a>").attr({href:"#",tabindex:"-1",title:p.tooltips.incrementHour}).addClass("btn").attr("data-action","incrementHours").append($("<span>").addClass(p.icons.up)))),t.append($("<td>").append($("<span>").addClass("timepicker-hour").attr({"data-time-component":"hours",title:p.tooltips.pickHour}).attr("data-action","showHours"))),a.append($("<td>").append($("<a>").attr({href:"#",tabindex:"-1",title:p.tooltips.decrementHour}).addClass("btn").attr("data-action","decrementHours").append($("<span>").addClass(p.icons.down))))),d("m")&&(d("h")&&(e.append($("<td>").addClass("separator")),t.append($("<td>").addClass("separator").html(":")),a.append($("<td>").addClass("separator"))),e.append($("<td>").append($("<a>").attr({href:"#",tabindex:"-1",title:p.tooltips.incrementMinute}).addClass("btn").attr("data-action","incrementMinutes").append($("<span>").addClass(p.icons.up)))),t.append($("<td>").append($("<span>").addClass("timepicker-minute").attr({"data-time-component":"minutes",title:p.tooltips.pickMinute}).attr("data-action","showMinutes"))),a.append($("<td>").append($("<a>").attr({href:"#",tabindex:"-1",title:p.tooltips.decrementMinute}).addClass("btn").attr("data-action","decrementMinutes").append($("<span>").addClass(p.icons.down))))),d("s")&&(d("m")&&(e.append($("<td>").addClass("separator")),t.append($("<td>").addClass("separator").html(":")),a.append($("<td>").addClass("separator"))),e.append($("<td>").append($("<a>").attr({href:"#",tabindex:"-1",title:p.tooltips.incrementSecond}).addClass("btn").attr("data-action","incrementSeconds").append($("<span>").addClass(p.icons.up)))),t.append($("<td>").append($("<span>").addClass("timepicker-second").attr({"data-time-component":"seconds",title:p.tooltips.pickSecond}).attr("data-action","showSeconds"))),a.append($("<td>").append($("<a>").attr({href:"#",tabindex:"-1",title:p.tooltips.decrementSecond}).addClass("btn").attr("data-action","decrementSeconds").append($("<span>").addClass(p.icons.down))))),Y||(e.append($("<td>").addClass("separator")),t.append($("<td>").append($("<button>").addClass("btn btn-primary").attr({"data-action":"togglePeriod",tabindex:"-1",title:p.tooltips.togglePeriod}))),a.append($("<td>").addClass("separator"))),$("<div>").addClass("timepicker-picker").append($("<table>").addClass("table-condensed").append([e,t,a])))];return d("h")&&o.push(n),d("m")&&o.push(r),d("s")&&o.push(i),o}function t(){var e,t,a,n=$("<div>").addClass("bootstrap-datetimepicker-widget dropdown-menu"),r=$("<div>").addClass("datepicker").append((t=$("<thead>").append($("<tr>").append($("<th>").addClass("prev").attr("data-action","previous").append($("<span>").addClass(p.icons.previous))).append($("<th>").addClass("picker-switch").attr("data-action","pickerSwitch").attr("colspan",p.calendarWeeks?"6":"5")).append($("<th>").addClass("next").attr("data-action","next").append($("<span>").addClass(p.icons.next)))),a=$("<tbody>").append($("<tr>").append($("<td>").attr("colspan",p.calendarWeeks?"8":"7"))),[$("<div>").addClass("datepicker-days").append($("<table>").addClass("table-condensed").append(t).append($("<tbody>"))),$("<div>").addClass("datepicker-months").append($("<table>").addClass("table-condensed").append(t.clone()).append(a.clone())),$("<div>").addClass("datepicker-years").append($("<table>").addClass("table-condensed").append(t.clone()).append(a.clone())),$("<div>").addClass("datepicker-decades").append($("<table>").addClass("table-condensed").append(t.clone()).append(a.clone()))])),i=$("<div>").addClass("timepicker").append(f()),o=$("<ul>").addClass("list-unstyled"),s=$("<li>").addClass("picker-switch"+(p.collapse?" accordion-toggle":"")).append((e=[],p.showTodayButton&&e.push($("<td>").append($("<a>").attr({"data-action":"today",title:p.tooltips.today}).append($("<span>").addClass(p.icons.today)))),!p.sideBySide&&u()&&l()&&e.push($("<td>").append($("<a>").attr({"data-action":"togglePicker",title:p.tooltips.selectTime}).append($("<span>").addClass(p.icons.time)))),p.showClear&&e.push($("<td>").append($("<a>").attr({"data-action":"clear",title:p.tooltips.clear}).append($("<span>").addClass(p.icons.clear)))),p.showClose&&e.push($("<td>").append($("<a>").attr({"data-action":"close",title:p.tooltips.close}).append($("<span>").addClass(p.icons.close)))),$("<table>").addClass("table-condensed").append($("<tbody>").append($("<tr>").append(e)))));return p.inline&&n.removeClass("dropdown-menu"),Y&&n.addClass("usetwentyfour"),d("s")&&!Y&&n.addClass("wider"),p.sideBySide&&u()&&l()?(n.addClass("timepicker-sbs"),"top"===p.toolbarPlacement&&n.append(s),n.append($("<div>").addClass("row").append(r.addClass("col-md-6")).append(i.addClass("col-md-6"))),"bottom"===p.toolbarPlacement&&n.append(s),n):("top"===p.toolbarPlacement&&o.append(s),u()&&o.append($("<li>").addClass(p.collapse&&l()?"collapse in":"").append(r)),"default"===p.toolbarPlacement&&o.append(s),l()&&o.append($("<li>").addClass(p.collapse&&u()?"collapse":"").append(i)),"bottom"===p.toolbarPlacement&&o.append(s),n.append(o))}function n(){var e,t=(z||i).position(),a=(z||i).offset(),n=p.widgetPositioning.vertical,r=p.widgetPositioning.horizontal;if(p.widgetParent)e=p.widgetParent.append(N);else if(i.is("input"))e=i.after(N).parent();else{if(p.inline)return void(e=i.append(N));(e=i).children().first().after(N)}if("auto"===n&&(n=a.top+1.5*N.height()>=$(window).height()+$(window).scrollTop()&&N.height()+i.outerHeight()<a.top?"top":"bottom"),"auto"===r&&(r=e.width()<a.left+N.outerWidth()/2&&a.left+N.outerWidth()>$(window).width()?"right":"left"),"top"===n?N.addClass("top").removeClass("bottom"):N.addClass("bottom").removeClass("top"),"right"===r?N.addClass("pull-right"):N.removeClass("pull-right"),"static"===e.css("position")&&(e=e.parents().filter(function(){return"static"!==$(this).css("position")}).first()),0===e.length)throw new Error("datetimepicker component should be placed within a non-static positioned container");N.css({top:"top"===n?"auto":t.top+i.outerHeight(),bottom:"top"===n?e.outerHeight()-(e===i?0:t.top):"auto",left:"left"===r?e===i?0:t.left:"auto",right:"left"===r?"auto":e.outerWidth()-i.outerWidth()-(e===i?0:t.left)})}function h(e){"dp.change"===e.type&&(e.date&&e.date.isSame(e.oldDate)||!e.date&&!e.oldDate)||i.trigger(e)}function r(e){"y"===e&&(e="YYYY"),h({type:"dp.update",change:e,viewDate:H.clone()})}function o(e){N&&(e&&(j=Math.max(V,Math.min(3,j+e))),N.find(".datepicker > div").hide().filter(".datepicker-"+Z[j].clsName).show())}function m(e,t){var a,n,r,i;if(e.isValid()&&!(p.disabledDates&&"d"===t&&(a=e,!0===p.disabledDates[a.format("YYYY-MM-DD")])||p.enabledDates&&"d"===t&&(n=e,!0!==p.enabledDates[n.format("YYYY-MM-DD")])||p.minDate&&e.isBefore(p.minDate,t)||p.maxDate&&e.isAfter(p.maxDate,t)||p.daysOfWeekDisabled&&"d"===t&&-1!==p.daysOfWeekDisabled.indexOf(e.day())||p.disabledHours&&("h"===t||"m"===t||"s"===t)&&(r=e,!0===p.disabledHours[r.format("H")])||p.enabledHours&&("h"===t||"m"===t||"s"===t)&&(i=e,!0!==p.enabledHours[i.format("H")]))){if(p.disabledTimeIntervals&&("h"===t||"m"===t||"s"===t)){var o=!1;if($.each(p.disabledTimeIntervals,function(){if(e.isBetween(this[0],this[1]))return!(o=!0)}),o)return}return 1}}function s(){var e,t,a,n=N.find(".datepicker-days"),r=n.find("th"),i=[],o=[];if(u()){for(r.eq(0).find("span").attr("title",p.tooltips.prevMonth),r.eq(1).attr("title",p.tooltips.selectMonth),r.eq(2).find("span").attr("title",p.tooltips.nextMonth),n.find(".disabled").removeClass("disabled"),r.eq(1).text(H.format(p.dayViewHeaderFormat)),m(H.clone().subtract(1,"M"),"M")||r.eq(0).addClass("disabled"),m(H.clone().add(1,"M"),"M")||r.eq(2).addClass("disabled"),e=H.clone().startOf("M").startOf("w").startOf("d"),a=0;a<42;a++)0===e.weekday()&&(t=$("<tr>"),p.calendarWeeks&&t.append('<td class="cw">'+e.week()+"</td>"),i.push(t)),o=["day"],e.isBefore(H,"M")&&o.push("old"),e.isAfter(H,"M")&&o.push("new"),e.isSame(E,"d")&&!W&&o.push("active"),m(e,"d")||o.push("disabled"),e.isSame(c(),"d")&&o.push("today"),0!==e.day()&&6!==e.day()||o.push("weekend"),h({type:"dp.classify",date:e,classNames:o}),t.append('<td data-action="selectDay" data-day="'+e.format("L")+'" class="'+o.join(" ")+'">'+e.date()+"</td>"),e.add(1,"d");var s,d,l;n.find("tbody").empty().append(i),s=N.find(".datepicker-months"),d=s.find("th"),l=s.find("tbody").find("span"),d.eq(0).find("span").attr("title",p.tooltips.prevYear),d.eq(1).attr("title",p.tooltips.selectYear),d.eq(2).find("span").attr("title",p.tooltips.nextYear),s.find(".disabled").removeClass("disabled"),m(H.clone().subtract(1,"y"),"y")||d.eq(0).addClass("disabled"),d.eq(1).text(H.year()),m(H.clone().add(1,"y"),"y")||d.eq(2).addClass("disabled"),l.removeClass("active"),E.isSame(H,"y")&&!W&&l.eq(E.month()).addClass("active"),l.each(function(e){m(H.clone().month(e),"M")||$(this).addClass("disabled")}),function(){var e=N.find(".datepicker-years"),t=e.find("th"),a=H.clone().subtract(5,"y"),n=H.clone().add(6,"y"),r="";for(t.eq(0).find("span").attr("title",p.tooltips.prevDecade),t.eq(1).attr("title",p.tooltips.selectDecade),t.eq(2).find("span").attr("title",p.tooltips.nextDecade),e.find(".disabled").removeClass("disabled"),p.minDate&&p.minDate.isAfter(a,"y")&&t.eq(0).addClass("disabled"),t.eq(1).text(a.year()+"-"+n.year()),p.maxDate&&p.maxDate.isBefore(n,"y")&&t.eq(2).addClass("disabled");!a.isAfter(n,"y");)r+='<span data-action="selectYear" class="year'+(a.isSame(E,"y")&&!W?" active":"")+(m(a,"y")?"":" disabled")+'">'+a.year()+"</span>",a.add(1,"y");e.find("td").html(r)}(),function(){var e,t=N.find(".datepicker-decades"),a=t.find("th"),n=_({y:H.year()-H.year()%100-1}),r=n.clone().add(100,"y"),i=n.clone(),o=!1,s=!1,d="";for(a.eq(0).find("span").attr("title",p.tooltips.prevCentury),a.eq(2).find("span").attr("title",p.tooltips.nextCentury),t.find(".disabled").removeClass("disabled"),(n.isSame(_({y:1900}))||p.minDate&&p.minDate.isAfter(n,"y"))&&a.eq(0).addClass("disabled"),a.eq(1).text(n.year()+"-"+r.year()),(n.isSame(_({y:2e3}))||p.maxDate&&p.maxDate.isBefore(r,"y"))&&a.eq(2).addClass("disabled");!n.isAfter(r,"y");)e=n.year()+12,o=p.minDate&&p.minDate.isAfter(n,"y")&&p.minDate.year()<=e,s=p.maxDate&&p.maxDate.isAfter(n,"y")&&p.maxDate.year()<=e,d+='<span data-action="selectDecade" class="decade'+(E.isAfter(n)&&E.year()<=e?" active":"")+(m(n,"y")||o||s?"":" disabled")+'" data-selection="'+(n.year()+6)+'">'+(n.year()+1)+" - "+(n.year()+12)+"</span>",n.add(12,"y");d+="<span></span><span></span><span></span>",t.find("td").html(d),a.eq(1).text(i.year()+1+"-"+n.year())}()}}function e(){var e,t,a=N.find(".timepicker span[data-time-component]");Y||(e=N.find(".timepicker [data-action=togglePeriod]"),t=E.clone().add(12<=E.hours()?-12:12,"h"),e.text(E.format("A")),m(t,"h")?e.removeClass("disabled"):e.addClass("disabled")),a.filter("[data-time-component=hours]").text(E.format(Y?"HH":"hh")),a.filter("[data-time-component=minutes]").text(E.format("mm")),a.filter("[data-time-component=seconds]").text(E.format("ss")),function(){var e=N.find(".timepicker-hours table"),t=H.clone().startOf("d"),a=[],n=$("<tr>");for(11<H.hour()&&!Y&&t.hour(12);t.isSame(H,"d")&&(Y||H.hour()<12&&t.hour()<12||11<H.hour());)t.hour()%4==0&&(n=$("<tr>"),a.push(n)),n.append('<td data-action="selectHour" class="hour'+(m(t,"h")?"":" disabled")+'">'+t.format(Y?"HH":"hh")+"</td>"),t.add(1,"h");e.empty().append(a)}(),function(){for(var e=N.find(".timepicker-minutes table"),t=H.clone().startOf("h"),a=[],n=$("<tr>"),r=1===p.stepping?5:p.stepping;H.isSame(t,"h");)t.minute()%(4*r)==0&&(n=$("<tr>"),a.push(n)),n.append('<td data-action="selectMinute" class="minute'+(m(t,"m")?"":" disabled")+'">'+t.format("mm")+"</td>"),t.add(r,"m");e.empty().append(a)}(),function(){for(var e=N.find(".timepicker-seconds table"),t=H.clone().startOf("m"),a=[],n=$("<tr>");H.isSame(t,"m");)t.second()%20==0&&(n=$("<tr>"),a.push(n)),n.append('<td data-action="selectSecond" class="second'+(m(t,"s")?"":" disabled")+'">'+t.format("ss")+"</td>"),t.add(5,"s");e.empty().append(a)}()}function y(){N&&(s(),e())}function g(e){var t=W?null:E;if(!e)return W=!0,I.val(""),i.data("date",""),h({type:"dp.change",date:!1,oldDate:t}),void y();if(e=e.clone().locale(p.locale),a()&&e.tz(p.timeZone),1!==p.stepping)for(e.minutes(Math.round(e.minutes()/p.stepping)*p.stepping).seconds(0);p.minDate&&e.isBefore(p.minDate);)e.add(p.stepping,"minutes");m(e)?(H=(E=e).clone(),I.val(E.format(q)),i.data("date",E.format(q)),W=!1,y(),h({type:"dp.change",date:E.clone(),oldDate:t})):(p.keepInvalid?h({type:"dp.change",date:e,oldDate:t}):I.val(W?"":E.format(q)),h({type:"dp.error",date:e,oldDate:t}))}function b(){var t=!1;return N?(N.find(".collapse").each(function(){var e=$(this).data("collapse");return!e||!e.transitioning||!(t=!0)}),t||(z&&z.hasClass("btn")&&z.toggleClass("active"),N.hide(),$(window).off("resize",n),N.off("click","[data-action]"),N.off("mousedown",!1),N.remove(),N=!1,h({type:"dp.hide",date:E.clone()}),I.blur(),H=E.clone()),L):L}function w(){g(null)}function v(e){return void 0===p.parseInputDate?(!_.isMoment(e)||e instanceof Date)&&(e=c(e)):e=p.parseInputDate(e),e}function k(e){return $(e.currentTarget).is(".disabled")||X[$(e.currentTarget).data("action")].apply(L,arguments),!1}function D(){var e;return I.prop("disabled")||!p.ignoreReadonly&&I.prop("readonly")||N||(void 0!==I.val()&&0!==I.val().trim().length?g(v(I.val().trim())):W&&p.useCurrent&&(p.inline||I.is("input")&&0===I.val().trim().length)&&(e=c(),"string"==typeof p.useCurrent&&(e={year:function(e){return e.month(0).date(1).hours(0).seconds(0).minutes(0)},month:function(e){return e.date(1).hours(0).seconds(0).minutes(0)},day:function(e){return e.hours(0).seconds(0).minutes(0)},hour:function(e){return e.seconds(0).minutes(0)},minute:function(e){return e.seconds(0)}}[p.useCurrent](e)),g(e)),N=t(),function(){var e=$("<tr>"),t=H.clone().startOf("w").startOf("d");for(!0===p.calendarWeeks&&e.append($("<th>").addClass("cw").text("#"));t.isBefore(H.clone().endOf("w"));)e.append($("<th>").addClass("dow").text(t.format("dd"))),t.add(1,"d");N.find(".datepicker-days thead").append(e)}(),function(){for(var e=[],t=H.clone().startOf("y").startOf("d");t.isSame(H,"y");)e.push($("<span>").attr("data-action","selectMonth").addClass("month").text(t.format("MMM"))),t.add(1,"M");N.find(".datepicker-months td").empty().append(e)}(),N.find(".timepicker-hours").hide(),N.find(".timepicker-minutes").hide(),N.find(".timepicker-seconds").hide(),y(),o(),$(window).on("resize",n),N.on("click","[data-action]",k),N.on("mousedown",!1),z&&z.hasClass("btn")&&z.toggleClass("active"),n(),N.show(),p.focusOnShow&&!I.is(":focus")&&I.focus(),h({type:"dp.show"})),L}function C(){return(N?b:D)()}function x(e){var t,a,n,r,i=null,o=[],s={},d=e.which;for(t in K[d]="p",K)K.hasOwnProperty(t)&&"p"===K[t]&&(o.push(t),parseInt(t,10)!==d&&(s[t]=!0));for(t in p.keyBinds)if(p.keyBinds.hasOwnProperty(t)&&"function"==typeof p.keyBinds[t]&&(n=t.split(" ")).length===o.length&&J[d]===n[n.length-1]){for(r=!0,a=n.length-2;0<=a;a--)if(!(J[n[a]]in s)){r=!1;break}if(r){i=p.keyBinds[t];break}}i&&(i.call(L,N),e.stopPropagation(),e.preventDefault())}function T(e){K[e.which]="r",e.stopPropagation(),e.preventDefault()}function M(e){var t=$(e.target).val().trim(),a=t?v(t):null;return g(a),e.stopImmediatePropagation(),!1}function S(e){var t={};return $.each(e,function(){var e=v(this);e.isValid()&&(t[e.format("YYYY-MM-DD")]=!0)}),!!Object.keys(t).length&&t}function O(e){var t={};return $.each(e,function(){t[this]=!0}),!!Object.keys(t).length&&t}function P(){var e=p.format||"L LT";q=e.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(e){return(E.localeData().longDateFormat(e)||e).replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(e){return E.localeData().longDateFormat(e)||e})}),(B=p.extraFormats?p.extraFormats.slice():[]).indexOf(e)<0&&B.indexOf(q)<0&&B.push(q),Y=q.toLowerCase().indexOf("a")<1&&q.replace(/\[.*?\]/g,"").indexOf("h")<1,d("y")&&(V=2),d("M")&&(V=1),d("d")&&(V=0),j=Math.max(V,j),W||g(E)}var E,H,I,Y,q,B,j,A,F,L={},W=!0,z=!1,N=!1,V=0,Z=[{clsName:"days",navFnc:"M",navStep:1},{clsName:"months",navFnc:"y",navStep:1},{clsName:"years",navFnc:"y",navStep:10},{clsName:"decades",navFnc:"y",navStep:100}],R=["days","months","years","decades"],Q=["top","bottom","auto"],U=["left","right","auto"],G=["default","top","bottom"],J={up:38,38:"up",down:40,40:"down",left:37,37:"left",right:39,39:"right",tab:9,9:"tab",escape:27,27:"escape",enter:13,13:"enter",pageUp:33,33:"pageUp",pageDown:34,34:"pageDown",shift:16,16:"shift",control:17,17:"control",space:32,32:"space",t:84,84:"t",delete:46,46:"delete"},K={},X={next:function(){var e=Z[j].navFnc;H.add(Z[j].navStep,e),s(),r(e)},previous:function(){var e=Z[j].navFnc;H.subtract(Z[j].navStep,e),s(),r(e)},pickerSwitch:function(){o(1)},selectMonth:function(e){var t=$(e.target).closest("tbody").find("span").index($(e.target));H.month(t),j===V?(g(E.clone().year(H.year()).month(H.month())),p.inline||b()):(o(-1),s()),r("M")},selectYear:function(e){var t=parseInt($(e.target).text(),10)||0;H.year(t),j===V?(g(E.clone().year(H.year())),p.inline||b()):(o(-1),s()),r("YYYY")},selectDecade:function(e){var t=parseInt($(e.target).data("selection"),10)||0;H.year(t),j===V?(g(E.clone().year(H.year())),p.inline||b()):(o(-1),s()),r("YYYY")},selectDay:function(e){var t=H.clone();$(e.target).is(".old")&&t.subtract(1,"M"),$(e.target).is(".new")&&t.add(1,"M"),g(t.date(parseInt($(e.target).text(),10))),l()||p.keepOpen||p.inline||b()},incrementHours:function(){var e=E.clone().add(1,"h");m(e,"h")&&g(e)},incrementMinutes:function(){var e=E.clone().add(p.stepping,"m");m(e,"m")&&g(e)},incrementSeconds:function(){var e=E.clone().add(1,"s");m(e,"s")&&g(e)},decrementHours:function(){var e=E.clone().subtract(1,"h");m(e,"h")&&g(e)},decrementMinutes:function(){var e=E.clone().subtract(p.stepping,"m");m(e,"m")&&g(e)},decrementSeconds:function(){var e=E.clone().subtract(1,"s");m(e,"s")&&g(e)},togglePeriod:function(){g(E.clone().add(12<=E.hours()?-12:12,"h"))},togglePicker:function(e){var t,a=$(e.target),n=a.closest("ul"),r=n.find(".in"),i=n.find(".collapse:not(.in)");if(r&&r.length){if((t=r.data("collapse"))&&t.transitioning)return;r.collapse?(r.collapse("hide"),i.collapse("show")):(r.removeClass("in"),i.addClass("in")),a.is("span")?a.toggleClass(p.icons.time+" "+p.icons.date):a.find("span").toggleClass(p.icons.time+" "+p.icons.date)}},showPicker:function(){N.find(".timepicker > div:not(.timepicker-picker)").hide(),N.find(".timepicker .timepicker-picker").show()},showHours:function(){N.find(".timepicker .timepicker-picker").hide(),N.find(".timepicker .timepicker-hours").show()},showMinutes:function(){N.find(".timepicker .timepicker-picker").hide(),N.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){N.find(".timepicker .timepicker-picker").hide(),N.find(".timepicker .timepicker-seconds").show()},selectHour:function(e){var t=parseInt($(e.target).text(),10);Y||(12<=E.hours()?12!==t&&(t+=12):12===t&&(t=0)),g(E.clone().hours(t)),X.showPicker.call(L)},selectMinute:function(e){g(E.clone().minutes(parseInt($(e.target).text(),10))),X.showPicker.call(L)},selectSecond:function(e){g(E.clone().seconds(parseInt($(e.target).text(),10))),X.showPicker.call(L)},clear:w,today:function(){var e=c();m(e,"d")&&g(e)},close:b};if(L.destroy=function(){b(),I.off({change:M,blur:blur,keydown:x,keyup:T,focus:p.allowInputToggle?b:""}),i.is("input")?I.off({focus:D}):z&&(z.off("click",C),z.off("mousedown",!1)),i.removeData("DateTimePicker"),i.removeData("date")},L.toggle=C,L.show=D,L.hide=b,L.disable=function(){return b(),z&&z.hasClass("btn")&&z.addClass("disabled"),I.prop("disabled",!0),L},L.enable=function(){return z&&z.hasClass("btn")&&z.removeClass("disabled"),I.prop("disabled",!1),L},L.ignoreReadonly=function(e){if(0===arguments.length)return p.ignoreReadonly;if("boolean"!=typeof e)throw new TypeError("ignoreReadonly () expects a boolean parameter");return p.ignoreReadonly=e,L},L.options=function(e){if(0===arguments.length)return $.extend(!0,{},p);if(!(e instanceof Object))throw new TypeError("options() options parameter should be an object");return $.extend(!0,p,e),$.each(p,function(e,t){if(void 0===L[e])throw new TypeError("option "+e+" is not recognized!");L[e](t)}),L},L.date=function(e){if(0===arguments.length)return W?null:E.clone();if(!(null===e||"string"==typeof e||_.isMoment(e)||e instanceof Date))throw new TypeError("date() parameter must be one of [null, string, moment or Date]");return g(null===e?null:v(e)),L},L.format=function(e){if(0===arguments.length)return p.format;if("string"!=typeof e&&("boolean"!=typeof e||!1!==e))throw new TypeError("format() expects a string or boolean:false parameter "+e);return p.format=e,q&&P(),L},L.timeZone=function(e){if(0===arguments.length)return p.timeZone;if("string"!=typeof e)throw new TypeError("newZone() expects a string parameter");return p.timeZone=e,L},L.dayViewHeaderFormat=function(e){if(0===arguments.length)return p.dayViewHeaderFormat;if("string"!=typeof e)throw new TypeError("dayViewHeaderFormat() expects a string parameter");return p.dayViewHeaderFormat=e,L},L.extraFormats=function(e){if(0===arguments.length)return p.extraFormats;if(!1!==e&&!(e instanceof Array))throw new TypeError("extraFormats() expects an array or false parameter");return p.extraFormats=e,B&&P(),L},L.disabledDates=function(e){if(0===arguments.length)return p.disabledDates?$.extend({},p.disabledDates):p.disabledDates;if(!e)return p.disabledDates=!1,y(),L;if(!(e instanceof Array))throw new TypeError("disabledDates() expects an array parameter");return p.disabledDates=S(e),p.enabledDates=!1,y(),L},L.enabledDates=function(e){if(0===arguments.length)return p.enabledDates?$.extend({},p.enabledDates):p.enabledDates;if(!e)return p.enabledDates=!1,y(),L;if(!(e instanceof Array))throw new TypeError("enabledDates() expects an array parameter");return p.enabledDates=S(e),p.disabledDates=!1,y(),L},L.daysOfWeekDisabled=function(e){if(0===arguments.length)return p.daysOfWeekDisabled.splice(0);if("boolean"==typeof e&&!e)return p.daysOfWeekDisabled=!1,y(),L;if(!(e instanceof Array))throw new TypeError("daysOfWeekDisabled() expects an array parameter");if(p.daysOfWeekDisabled=e.reduce(function(e,t){return 6<(t=parseInt(t,10))||t<0||isNaN(t)||-1===e.indexOf(t)&&e.push(t),e},[]).sort(),p.useCurrent&&!p.keepInvalid){for(var t=0;!m(E,"d");){if(E.add(1,"d"),31===t)throw"Tried 31 times to find a valid date";t++}g(E)}return y(),L},L.maxDate=function(e){if(0===arguments.length)return p.maxDate?p.maxDate.clone():p.maxDate;if("boolean"==typeof e&&!1===e)return p.maxDate=!1,y(),L;"string"==typeof e&&("now"!==e&&"moment"!==e||(e=c()));var t=v(e);if(!t.isValid())throw new TypeError("maxDate() Could not parse date parameter: "+e);if(p.minDate&&t.isBefore(p.minDate))throw new TypeError("maxDate() date parameter is before options.minDate: "+t.format(q));return p.maxDate=t,p.useCurrent&&!p.keepInvalid&&E.isAfter(e)&&g(p.maxDate),H.isAfter(t)&&(H=t.clone().subtract(p.stepping,"m")),y(),L},L.minDate=function(e){if(0===arguments.length)return p.minDate?p.minDate.clone():p.minDate;if("boolean"==typeof e&&!1===e)return p.minDate=!1,y(),L;"string"==typeof e&&("now"!==e&&"moment"!==e||(e=c()));var t=v(e);if(!t.isValid())throw new TypeError("minDate() Could not parse date parameter: "+e);if(p.maxDate&&t.isAfter(p.maxDate))throw new TypeError("minDate() date parameter is after options.maxDate: "+t.format(q));return p.minDate=t,p.useCurrent&&!p.keepInvalid&&E.isBefore(e)&&g(p.minDate),H.isBefore(t)&&(H=t.clone().add(p.stepping,"m")),y(),L},L.defaultDate=function(e){if(0===arguments.length)return p.defaultDate?p.defaultDate.clone():p.defaultDate;if(!e)return p.defaultDate=!1,L;"string"==typeof e&&(e="now"===e||"moment"===e?c():c(e));var t=v(e);if(!t.isValid())throw new TypeError("defaultDate() Could not parse date parameter: "+e);if(!m(t))throw new TypeError("defaultDate() date passed is invalid according to component setup validations");return p.defaultDate=t,(p.defaultDate&&p.inline||""===I.val().trim())&&g(p.defaultDate),L},L.locale=function(e){if(0===arguments.length)return p.locale;if(!_.localeData(e))throw new TypeError("locale() locale "+e+" is not loaded from moment locales!");return p.locale=e,E.locale(p.locale),H.locale(p.locale),q&&P(),N&&(b(),D()),L},L.stepping=function(e){return 0===arguments.length?p.stepping:(e=parseInt(e,10),(isNaN(e)||e<1)&&(e=1),p.stepping=e,L)},L.useCurrent=function(e){var t=["year","month","day","hour","minute"];if(0===arguments.length)return p.useCurrent;if("boolean"!=typeof e&&"string"!=typeof e)throw new TypeError("useCurrent() expects a boolean or string parameter");if("string"==typeof e&&-1===t.indexOf(e.toLowerCase()))throw new TypeError("useCurrent() expects a string parameter of "+t.join(", "));return p.useCurrent=e,L},L.collapse=function(e){if(0===arguments.length)return p.collapse;if("boolean"!=typeof e)throw new TypeError("collapse() expects a boolean parameter");return p.collapse===e||(p.collapse=e,N&&(b(),D())),L},L.icons=function(e){if(0===arguments.length)return $.extend({},p.icons);if(!(e instanceof Object))throw new TypeError("icons() expects parameter to be an Object");return $.extend(p.icons,e),N&&(b(),D()),L},L.tooltips=function(e){if(0===arguments.length)return $.extend({},p.tooltips);if(!(e instanceof Object))throw new TypeError("tooltips() expects parameter to be an Object");return $.extend(p.tooltips,e),N&&(b(),D()),L},L.useStrict=function(e){if(0===arguments.length)return p.useStrict;if("boolean"!=typeof e)throw new TypeError("useStrict() expects a boolean parameter");return p.useStrict=e,L},L.sideBySide=function(e){if(0===arguments.length)return p.sideBySide;if("boolean"!=typeof e)throw new TypeError("sideBySide() expects a boolean parameter");return p.sideBySide=e,N&&(b(),D()),L},L.viewMode=function(e){if(0===arguments.length)return p.viewMode;if("string"!=typeof e)throw new TypeError("viewMode() expects a string parameter");if(-1===R.indexOf(e))throw new TypeError("viewMode() parameter must be one of ("+R.join(", ")+") value");return p.viewMode=e,j=Math.max(R.indexOf(e),V),o(),L},L.toolbarPlacement=function(e){if(0===arguments.length)return p.toolbarPlacement;if("string"!=typeof e)throw new TypeError("toolbarPlacement() expects a string parameter");if(-1===G.indexOf(e))throw new TypeError("toolbarPlacement() parameter must be one of ("+G.join(", ")+") value");return p.toolbarPlacement=e,N&&(b(),D()),L},L.widgetPositioning=function(e){if(0===arguments.length)return $.extend({},p.widgetPositioning);if("[object Object]"!=={}.toString.call(e))throw new TypeError("widgetPositioning() expects an object variable");if(e.horizontal){if("string"!=typeof e.horizontal)throw new TypeError("widgetPositioning() horizontal variable must be a string");if(e.horizontal=e.horizontal.toLowerCase(),-1===U.indexOf(e.horizontal))throw new TypeError("widgetPositioning() expects horizontal parameter to be one of ("+U.join(", ")+")");p.widgetPositioning.horizontal=e.horizontal}if(e.vertical){if("string"!=typeof e.vertical)throw new TypeError("widgetPositioning() vertical variable must be a string");if(e.vertical=e.vertical.toLowerCase(),-1===Q.indexOf(e.vertical))throw new TypeError("widgetPositioning() expects vertical parameter to be one of ("+Q.join(", ")+")");p.widgetPositioning.vertical=e.vertical}return y(),L},L.calendarWeeks=function(e){if(0===arguments.length)return p.calendarWeeks;if("boolean"!=typeof e)throw new TypeError("calendarWeeks() expects parameter to be a boolean value");return p.calendarWeeks=e,y(),L},L.showTodayButton=function(e){if(0===arguments.length)return p.showTodayButton;if("boolean"!=typeof e)throw new TypeError("showTodayButton() expects a boolean parameter");return p.showTodayButton=e,N&&(b(),D()),L},L.showClear=function(e){if(0===arguments.length)return p.showClear;if("boolean"!=typeof e)throw new TypeError("showClear() expects a boolean parameter");return p.showClear=e,N&&(b(),D()),L},L.widgetParent=function(e){if(0===arguments.length)return p.widgetParent;if("string"==typeof e&&(e=$(e)),null!==e&&"string"!=typeof e&&!(e instanceof $))throw new TypeError("widgetParent() expects a string or a jQuery object parameter");return p.widgetParent=e,N&&(b(),D()),L},L.keepOpen=function(e){if(0===arguments.length)return p.keepOpen;if("boolean"!=typeof e)throw new TypeError("keepOpen() expects a boolean parameter");return p.keepOpen=e,L},L.focusOnShow=function(e){if(0===arguments.length)return p.focusOnShow;if("boolean"!=typeof e)throw new TypeError("focusOnShow() expects a boolean parameter");return p.focusOnShow=e,L},L.inline=function(e){if(0===arguments.length)return p.inline;if("boolean"!=typeof e)throw new TypeError("inline() expects a boolean parameter");return p.inline=e,L},L.clear=function(){return w(),L},L.keyBinds=function(e){return 0===arguments.length?p.keyBinds:(p.keyBinds=e,L)},L.getMoment=function(e){return c(e)},L.debug=function(e){if("boolean"!=typeof e)throw new TypeError("debug() expects a boolean parameter");return p.debug=e,L},L.allowInputToggle=function(e){if(0===arguments.length)return p.allowInputToggle;if("boolean"!=typeof e)throw new TypeError("allowInputToggle() expects a boolean parameter");return p.allowInputToggle=e,L},L.showClose=function(e){if(0===arguments.length)return p.showClose;if("boolean"!=typeof e)throw new TypeError("showClose() expects a boolean parameter");return p.showClose=e,L},L.keepInvalid=function(e){if(0===arguments.length)return p.keepInvalid;if("boolean"!=typeof e)throw new TypeError("keepInvalid() expects a boolean parameter");return p.keepInvalid=e,L},L.datepickerInput=function(e){if(0===arguments.length)return p.datepickerInput;if("string"!=typeof e)throw new TypeError("datepickerInput() expects a string parameter");return p.datepickerInput=e,L},L.parseInputDate=function(e){if(0===arguments.length)return p.parseInputDate;if("function"!=typeof e)throw new TypeError("parseInputDate() sholud be as function");return p.parseInputDate=e,L},L.disabledTimeIntervals=function(e){if(0===arguments.length)return p.disabledTimeIntervals?$.extend({},p.disabledTimeIntervals):p.disabledTimeIntervals;if(!e)return p.disabledTimeIntervals=!1,y(),L;if(!(e instanceof Array))throw new TypeError("disabledTimeIntervals() expects an array parameter");return p.disabledTimeIntervals=e,y(),L},L.disabledHours=function(e){if(0===arguments.length)return p.disabledHours?$.extend({},p.disabledHours):p.disabledHours;if(!e)return p.disabledHours=!1,y(),L;if(!(e instanceof Array))throw new TypeError("disabledHours() expects an array parameter");if(p.disabledHours=O(e),p.enabledHours=!1,p.useCurrent&&!p.keepInvalid){for(var t=0;!m(E,"h");){if(E.add(1,"h"),24===t)throw"Tried 24 times to find a valid date";t++}g(E)}return y(),L},L.enabledHours=function(e){if(0===arguments.length)return p.enabledHours?$.extend({},p.enabledHours):p.enabledHours;if(!e)return p.enabledHours=!1,y(),L;if(!(e instanceof Array))throw new TypeError("enabledHours() expects an array parameter");if(p.enabledHours=O(e),p.disabledHours=!1,p.useCurrent&&!p.keepInvalid){for(var t=0;!m(E,"h");){if(E.add(1,"h"),24===t)throw"Tried 24 times to find a valid date";t++}g(E)}return y(),L},L.viewDate=function(e){if(0===arguments.length)return H.clone();if(!e)return H=E.clone(),L;if(!("string"==typeof e||_.isMoment(e)||e instanceof Date))throw new TypeError("viewDate() parameter must be one of [string, moment or Date]");return H=v(e),r(),L},i.is("input"))I=i;else if(0===(I=i.find(p.datepickerInput)).length)I=i.find("input");else if(!I.is("input"))throw new Error('CSS class "'+p.datepickerInput+'" cannot be applied to non input element');if(i.hasClass("input-group")&&(z=0===i.find(".datepickerbutton").length?i.find(".input-group-addon"):i.find(".datepickerbutton")),!p.inline&&!I.is("input"))throw new Error("Could not initialize DateTimePicker without an input element");return E=c(),H=E.clone(),$.extend(!0,p,(F={},(A=i.is("input")||p.inline?i.data():i.find("input").data()).dateOptions&&A.dateOptions instanceof Object&&(F=$.extend(!0,F,A.dateOptions)),$.each(p,function(e){var t="date"+e.charAt(0).toUpperCase()+e.slice(1);void 0!==A[t]&&(F[e]=A[t])}),F)),L.options(p),P(),I.on({change:M,blur:p.debug?"":b,keydown:x,keyup:T,focus:p.allowInputToggle?D:""}),i.is("input")?I.on({focus:D}):z&&(z.on("click",C),z.on("mousedown",!1)),I.prop("disabled")&&L.disable(),I.is("input")&&0!==I.val().trim().length?g(v(I.val().trim())):p.defaultDate&&void 0===I.attr("placeholder")&&g(p.defaultDate),p.inline&&D(),L}return $.fn.datetimepicker=function(a){a=a||{};var t,n=Array.prototype.slice.call(arguments,1),r=!0;if("object"==typeof a)return this.each(function(){var e,t=$(this);t.data("DateTimePicker")||(e=$.extend(!0,{},$.fn.datetimepicker.defaults,a),t.data("DateTimePicker",i(t,e)))});if("string"==typeof a)return this.each(function(){var e=$(this).data("DateTimePicker");if(!e)throw new Error('bootstrap-datetimepicker("'+a+'") method was called on an element that is not using DateTimePicker');t=e[a].apply(e,n),r=t===e}),r||-1<$.inArray(a,["destroy","hide","show","toggle"])?this:t;throw new TypeError("Invalid arguments for DateTimePicker: "+a)},$.fn.datetimepicker.defaults={timeZone:"",format:!1,dayViewHeaderFormat:"MMMM YYYY",extraFormats:!1,stepping:1,minDate:!1,maxDate:!1,useCurrent:!0,collapse:!0,locale:_.locale(),defaultDate:!1,disabledDates:!1,enabledDates:!1,icons:{time:"glyphicon glyphicon-time",date:"glyphicon glyphicon-calendar",up:"glyphicon glyphicon-chevron-up",down:"glyphicon glyphicon-chevron-down",previous:"glyphicon glyphicon-chevron-left",next:"glyphicon glyphicon-chevron-right",today:"glyphicon glyphicon-screenshot",clear:"glyphicon glyphicon-trash",close:"glyphicon glyphicon-remove"},tooltips:{today:"Go to today",clear:"Clear selection",close:"Close the picker",selectMonth:"Select Month",prevMonth:"Previous Month",nextMonth:"Next Month",selectYear:"Select Year",prevYear:"Previous Year",nextYear:"Next Year",selectDecade:"Select Decade",prevDecade:"Previous Decade",nextDecade:"Next Decade",prevCentury:"Previous Century",nextCentury:"Next Century",pickHour:"Pick Hour",incrementHour:"Increment Hour",decrementHour:"Decrement Hour",pickMinute:"Pick Minute",incrementMinute:"Increment Minute",decrementMinute:"Decrement Minute",pickSecond:"Pick Second",incrementSecond:"Increment Second",decrementSecond:"Decrement Second",togglePeriod:"Toggle Period",selectTime:"Select Time"},useStrict:!1,sideBySide:!1,daysOfWeekDisabled:!1,calendarWeeks:!1,viewMode:"days",toolbarPlacement:"default",showTodayButton:!1,showClear:!1,showClose:!1,widgetPositioning:{horizontal:"auto",vertical:"auto"},widgetParent:null,ignoreReadonly:!1,keepOpen:!1,focusOnShow:!0,inline:!1,keepInvalid:!1,datepickerInput:".datepickerinput",keyBinds:{up:function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")?this.date(t.clone().subtract(7,"d")):this.date(t.clone().add(this.stepping(),"m"))}},down:function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")?this.date(t.clone().add(7,"d")):this.date(t.clone().subtract(this.stepping(),"m"))}else this.show()},"control up":function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")?this.date(t.clone().subtract(1,"y")):this.date(t.clone().add(1,"h"))}},"control down":function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")?this.date(t.clone().add(1,"y")):this.date(t.clone().subtract(1,"h"))}},left:function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")&&this.date(t.clone().subtract(1,"d"))}},right:function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")&&this.date(t.clone().add(1,"d"))}},pageUp:function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")&&this.date(t.clone().subtract(1,"M"))}},pageDown:function(e){if(e){var t=this.date()||this.getMoment();e.find(".datepicker").is(":visible")&&this.date(t.clone().add(1,"M"))}},enter:function(){this.hide()},escape:function(){this.hide()},"control space":function(e){e&&e.find(".timepicker").is(":visible")&&e.find('.btn[data-action="togglePeriod"]').click()},t:function(){this.date(this.getMoment())},delete:function(){this.clear()}},debug:!1,allowInputToggle:!1,disabledTimeIntervals:!1,disabledHours:!1,enabledHours:!1,viewDate:!1},$.fn.datetimepicker});
/* =========================================================
 * bootstrap-datepicker.js
 * Repo: https://github.com/uxsolutions/bootstrap-datepicker/
 * Demo: https://uxsolutions.github.io/bootstrap-datepicker/
 * Docs: https://bootstrap-datepicker.readthedocs.org/
 * =========================================================
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ========================================================= */

(function(factory){
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        factory(require('jquery'));
    } else {
        factory(jQuery);
    }
}(function($, undefined){
	function UTCDate(){
		return new Date(Date.UTC.apply(Date, arguments));
	}
	function UTCToday(){
		var today = new Date();
		return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
	}
	function isUTCEquals(date1, date2) {
		return (
			date1.getUTCFullYear() === date2.getUTCFullYear() &&
			date1.getUTCMonth() === date2.getUTCMonth() &&
			date1.getUTCDate() === date2.getUTCDate()
		);
	}
	function alias(method, deprecationMsg){
		return function(){
			if (deprecationMsg !== undefined) {
				$.fn.datepicker.deprecated(deprecationMsg);
			}

			return this[method].apply(this, arguments);
		};
	}
	function isValidDate(d) {
		return d && !isNaN(d.getTime());
	}

	var DateArray = (function(){
		var extras = {
			get: function(i){
				return this.slice(i)[0];
			},
			contains: function(d){
				// Array.indexOf is not cross-browser;
				// $.inArray doesn't work with Dates
				var val = d && d.valueOf();
				for (var i=0, l=this.length; i < l; i++)
          // Use date arithmetic to allow dates with different times to match
          if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000*60*60*24)
						return i;
				return -1;
			},
			remove: function(i){
				this.splice(i,1);
			},
			replace: function(new_array){
				if (!new_array)
					return;
				if (!Array.isArray(new_array))
					new_array = [new_array];
				this.clear();
				this.push.apply(this, new_array);
			},
			clear: function(){
				this.length = 0;
			},
			copy: function(){
				var a = new DateArray();
				a.replace(this);
				return a;
			}
		};

		return function(){
			var a = [];
			a.push.apply(a, arguments);
			$.extend(a, extras);
			return a;
		};
	})();


	// Picker object

	var Datepicker = function(element, options){
		$.data(element, 'datepicker', this);

		this._events = [];
		this._secondaryEvents = [];

		this._process_options(options);

		this.dates = new DateArray();
		this.viewDate = this.o.defaultViewDate;
		this.focusDate = null;

		this.element = $(element);
		this.isInput = this.element.is('input');
		this.inputField = this.isInput ? this.element : this.element.find('input');
		this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .input-group-append, .input-group-prepend, .btn') : false;
		if (this.component && this.component.length === 0){
			this.component = false;
    }

		if (this.o.isInline === null){
			this.isInline = !this.component && !this.isInput;
		} else {
			this.isInline = this.o.isInline;
		}

		this.picker = $(DPGlobal.template);

		// Checking templates and inserting
		if (this._check_template(this.o.templates.leftArrow)) {
			this.picker.find('.prev').html(this.o.templates.leftArrow);
		}

		if (this._check_template(this.o.templates.rightArrow)) {
			this.picker.find('.next').html(this.o.templates.rightArrow);
		}

		this._buildEvents();
		this._attachEvents();

		if (this.isInline){
			this.picker.addClass('datepicker-inline').appendTo(this.element);
		}
		else {
			this.picker.addClass('datepicker-dropdown dropdown-menu');
		}

		if (this.o.rtl){
			this.picker.addClass('datepicker-rtl');
		}

		if (this.o.calendarWeeks) {
			this.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear')
				.attr('colspan', function(i, val){
					return Number(val) + 1;
				});
		}

		this._process_options({
			startDate: this._o.startDate,
			endDate: this._o.endDate,
			daysOfWeekDisabled: this.o.daysOfWeekDisabled,
			daysOfWeekHighlighted: this.o.daysOfWeekHighlighted,
			datesDisabled: this.o.datesDisabled
		});

		this._allow_update = false;
		this.setViewMode(this.o.startView);
		this._allow_update = true;

		this.fillDow();
		this.fillMonths();

		this.update();

		if (this.isInline){
			this.show();
		}
	};

	Datepicker.prototype = {
		constructor: Datepicker,

		_resolveViewName: function(view){
			$.each(DPGlobal.viewModes, function(i, viewMode){
				if (view === i || $.inArray(view, viewMode.names) !== -1){
					view = i;
					return false;
				}
			});

			return view;
		},

		_resolveDaysOfWeek: function(daysOfWeek){
			if (!Array.isArray(daysOfWeek))
				daysOfWeek = daysOfWeek.split(/[,\s]*/);
			return $.map(daysOfWeek, Number);
		},

		_check_template: function(tmp){
			try {
				// If empty
				if (tmp === undefined || tmp === "") {
					return false;
				}
				// If no html, everything ok
				if ((tmp.match(/[<>]/g) || []).length <= 0) {
					return true;
				}
				// Checking if html is fine
				var jDom = $(tmp);
				return jDom.length > 0;
			}
			catch (ex) {
				return false;
			}
		},

		_process_options: function(opts){
			// Store raw options for reference
			this._o = $.extend({}, this._o, opts);
			// Processed options
			var o = this.o = $.extend({}, this._o);

			// Check if "de-DE" style date is available, if not language should
			// fallback to 2 letter code eg "de"
			var lang = o.language;
			if (!dates[lang]){
				lang = lang.split('-')[0];
				if (!dates[lang])
					lang = defaults.language;
			}
			o.language = lang;

			// Retrieve view index from any aliases
			o.startView = this._resolveViewName(o.startView);
			o.minViewMode = this._resolveViewName(o.minViewMode);
			o.maxViewMode = this._resolveViewName(o.maxViewMode);

			// Check view is between min and max
			o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));

			// true, false, or Number > 0
			if (o.multidate !== true){
				o.multidate = Number(o.multidate) || false;
				if (o.multidate !== false)
					o.multidate = Math.max(0, o.multidate);
			}
			o.multidateSeparator = String(o.multidateSeparator);

			o.weekStart %= 7;
			o.weekEnd = (o.weekStart + 6) % 7;

			var format = DPGlobal.parseFormat(o.format);
			if (o.startDate !== -Infinity){
				if (!!o.startDate){
					if (o.startDate instanceof Date)
						o.startDate = this._local_to_utc(this._zero_time(o.startDate));
					else
						o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
				}
				else {
					o.startDate = -Infinity;
				}
			}
			if (o.endDate !== Infinity){
				if (!!o.endDate){
					if (o.endDate instanceof Date)
						o.endDate = this._local_to_utc(this._zero_time(o.endDate));
					else
						o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
				}
				else {
					o.endDate = Infinity;
				}
			}

			o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled||[]);
			o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted||[]);

			o.datesDisabled = o.datesDisabled||[];
			if (!Array.isArray(o.datesDisabled)) {
				o.datesDisabled = o.datesDisabled.split(',');
			}
			o.datesDisabled = $.map(o.datesDisabled, function(d){
				return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
			});

			var plc = String(o.orientation).toLowerCase().split(/\s+/g),
				_plc = o.orientation.toLowerCase();
			plc = $.grep(plc, function(word){
				return /^auto|left|right|top|bottom$/.test(word);
			});
			o.orientation = {x: 'auto', y: 'auto'};
			if (!_plc || _plc === 'auto')
				; // no action
			else if (plc.length === 1){
				switch (plc[0]){
					case 'top':
					case 'bottom':
						o.orientation.y = plc[0];
						break;
					case 'left':
					case 'right':
						o.orientation.x = plc[0];
						break;
				}
			}
			else {
				_plc = $.grep(plc, function(word){
					return /^left|right$/.test(word);
				});
				o.orientation.x = _plc[0] || 'auto';

				_plc = $.grep(plc, function(word){
					return /^top|bottom$/.test(word);
				});
				o.orientation.y = _plc[0] || 'auto';
			}
			if (o.defaultViewDate instanceof Date || typeof o.defaultViewDate === 'string') {
				o.defaultViewDate = DPGlobal.parseDate(o.defaultViewDate, format, o.language, o.assumeNearbyYear);
			} else if (o.defaultViewDate) {
				var year = o.defaultViewDate.year || new Date().getFullYear();
				var month = o.defaultViewDate.month || 0;
				var day = o.defaultViewDate.day || 1;
				o.defaultViewDate = UTCDate(year, month, day);
			} else {
				o.defaultViewDate = UTCToday();
			}
		},
		_applyEvents: function(evs){
			for (var i=0, el, ch, ev; i < evs.length; i++){
				el = evs[i][0];
				if (evs[i].length === 2){
					ch = undefined;
					ev = evs[i][1];
				} else if (evs[i].length === 3){
					ch = evs[i][1];
					ev = evs[i][2];
				}
				el.on(ev, ch);
			}
		},
		_unapplyEvents: function(evs){
			for (var i=0, el, ev, ch; i < evs.length; i++){
				el = evs[i][0];
				if (evs[i].length === 2){
					ch = undefined;
					ev = evs[i][1];
				} else if (evs[i].length === 3){
					ch = evs[i][1];
					ev = evs[i][2];
				}
				el.off(ev, ch);
			}
		},
		_buildEvents: function(){
            var events = {
                keyup: $.proxy(function(e){
                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
                        this.update();
                }, this),
                keydown: $.proxy(this.keydown, this),
                paste: $.proxy(this.paste, this)
            };

            if (this.o.showOnFocus === true) {
                events.focus = $.proxy(this.show, this);
            }

            if (this.isInput) { // single input
                this._events = [
                    [this.element, events]
                ];
            }
            // component: input + button
            else if (this.component && this.inputField.length) {
                this._events = [
                    // For components that are not readonly, allow keyboard nav
                    [this.inputField, events],
                    [this.component, {
                        click: $.proxy(this.show, this)
                    }]
                ];
            }
			else {
				this._events = [
					[this.element, {
						click: $.proxy(this.show, this),
						keydown: $.proxy(this.keydown, this)
					}]
				];
			}
			this._events.push(
				// Component: listen for blur on element descendants
				[this.element, '*', {
					blur: $.proxy(function(e){
						this._focused_from = e.target;
					}, this)
				}],
				// Input: listen for blur on element
				[this.element, {
					blur: $.proxy(function(e){
						this._focused_from = e.target;
					}, this)
				}]
			);

			if (this.o.immediateUpdates) {
				// Trigger input updates immediately on changed year/month
				this._events.push([this.element, {
					'changeYear changeMonth': $.proxy(function(e){
						this.update(e.date);
					}, this)
				}]);
			}

			this._secondaryEvents = [
				[this.picker, {
					click: $.proxy(this.click, this)
				}],
				[this.picker, '.prev, .next', {
					click: $.proxy(this.navArrowsClick, this)
				}],
				[this.picker, '.day:not(.disabled)', {
					click: $.proxy(this.dayCellClick, this)
				}],
				[$(window), {
					resize: $.proxy(this.place, this)
				}],
				[$(document), {
					'mousedown touchstart': $.proxy(function(e){
						// Clicked outside the datepicker, hide it
						if (!(
							this.element.is(e.target) ||
							this.element.find(e.target).length ||
							this.picker.is(e.target) ||
							this.picker.find(e.target).length ||
							this.isInline
						)){
							this.hide();
						}
					}, this)
				}]
			];
		},
		_attachEvents: function(){
			this._detachEvents();
			this._applyEvents(this._events);
		},
		_detachEvents: function(){
			this._unapplyEvents(this._events);
		},
		_attachSecondaryEvents: function(){
			this._detachSecondaryEvents();
			this._applyEvents(this._secondaryEvents);
		},
		_detachSecondaryEvents: function(){
			this._unapplyEvents(this._secondaryEvents);
		},
		_trigger: function(event, altdate){
			var date = altdate || this.dates.get(-1),
				local_date = this._utc_to_local(date);

			this.element.trigger({
				type: event,
				date: local_date,
				viewMode: this.viewMode,
				dates: $.map(this.dates, this._utc_to_local),
				format: $.proxy(function(ix, format){
					if (arguments.length === 0){
						ix = this.dates.length - 1;
						format = this.o.format;
					} else if (typeof ix === 'string'){
						format = ix;
						ix = this.dates.length - 1;
					}
					format = format || this.o.format;
					var date = this.dates.get(ix);
					return DPGlobal.formatDate(date, format, this.o.language);
				}, this)
			});
		},

		show: function(){
			if (this.inputField.is(':disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))
				return;
			if (!this.isInline)
				this.picker.appendTo(this.o.container);
			this.place();
			this.picker.show();
			this._attachSecondaryEvents();
			this._trigger('show');
			if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
				$(this.element).blur();
			}
			return this;
		},

		hide: function(){
			if (this.isInline || !this.picker.is(':visible'))
				return this;
			this.focusDate = null;
			this.picker.hide().detach();
			this._detachSecondaryEvents();
			this.setViewMode(this.o.startView);

			if (this.o.forceParse && this.inputField.val())
				this.setValue();
			this._trigger('hide');
			return this;
		},

		destroy: function(){
			this.hide();
			this._detachEvents();
			this._detachSecondaryEvents();
			this.picker.remove();
			delete this.element.data().datepicker;
			if (!this.isInput){
				delete this.element.data().date;
			}
			return this;
		},

		paste: function(e){
			var dateString;
			if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types
				&& $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {
				dateString = e.originalEvent.clipboardData.getData('text/plain');
			} else if (window.clipboardData) {
				dateString = window.clipboardData.getData('Text');
			} else {
				return;
			}
			this.setDate(dateString);
			this.update();
			e.preventDefault();
		},

		_utc_to_local: function(utc){
			if (!utc) {
				return utc;
			}

			var local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));

			if (local.getTimezoneOffset() !== utc.getTimezoneOffset()) {
				local = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000));
			}

			return local;
		},
		_local_to_utc: function(local){
			return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
		},
		_zero_time: function(local){
			return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
		},
		_zero_utc_time: function(utc){
			return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
		},

		getDates: function(){
			return $.map(this.dates, this._utc_to_local);
		},

		getUTCDates: function(){
			return $.map(this.dates, function(d){
				return new Date(d);
			});
		},

		getDate: function(){
			return this._utc_to_local(this.getUTCDate());
		},

		getUTCDate: function(){
			var selected_date = this.dates.get(-1);
			if (selected_date !== undefined) {
				return new Date(selected_date);
			} else {
				return null;
			}
		},

		clearDates: function(){
			this.inputField.val('');
			this._trigger('changeDate');
			this.update();
			if (this.o.autoclose) {
				this.hide();
			}
		},

		setDates: function(){
			var args = Array.isArray(arguments[0]) ? arguments[0] : arguments;
			this.update.apply(this, args);
			this._trigger('changeDate');
			this.setValue();
			return this;
		},

		setUTCDates: function(){
			var args = Array.isArray(arguments[0]) ? arguments[0] : arguments;
			this.setDates.apply(this, $.map(args, this._utc_to_local));
			return this;
		},

		setDate: alias('setDates'),
		setUTCDate: alias('setUTCDates'),
		remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead'),

		setValue: function(){
			var formatted = this.getFormattedDate();
			this.inputField.val(formatted);
			return this;
		},

		getFormattedDate: function(format){
			if (format === undefined)
				format = this.o.format;

			var lang = this.o.language;
			return $.map(this.dates, function(d){
				return DPGlobal.formatDate(d, format, lang);
			}).join(this.o.multidateSeparator);
		},

		getStartDate: function(){
			return this.o.startDate;
		},

		setStartDate: function(startDate){
			this._process_options({startDate: startDate});
			this.update();
			this.updateNavArrows();
			return this;
		},

		getEndDate: function(){
			return this.o.endDate;
		},

		setEndDate: function(endDate){
			this._process_options({endDate: endDate});
			this.update();
			this.updateNavArrows();
			return this;
		},

		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
			this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
			this.update();
			return this;
		},

		setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
			this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
			this.update();
			return this;
		},

		setDatesDisabled: function(datesDisabled){
			this._process_options({datesDisabled: datesDisabled});
			this.update();
			return this;
		},

		place: function(){
			if (this.isInline)
				return this;
			var calendarWidth = this.picker.outerWidth(),
				calendarHeight = this.picker.outerHeight(),
				visualPadding = 10,
				container = $(this.o.container),
				windowWidth = container.width(),
				scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
				appendOffset = container.offset();

			var parentsZindex = [0];
			this.element.parents().each(function(){
				var itemZIndex = $(this).css('z-index');
				if (itemZIndex !== 'auto' && Number(itemZIndex) !== 0) parentsZindex.push(Number(itemZIndex));
			});
			var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
			var offset = this.component ? this.component.parent().offset() : this.element.offset();
			var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
			var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
			var left = offset.left - appendOffset.left;
			var top = offset.top - appendOffset.top;

			if (this.o.container !== 'body') {
				top += scrollTop;
			}

			this.picker.removeClass(
				'datepicker-orient-top datepicker-orient-bottom '+
				'datepicker-orient-right datepicker-orient-left'
			);

			if (this.o.orientation.x !== 'auto'){
				this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
				if (this.o.orientation.x === 'right')
					left -= calendarWidth - width;
			}
			// auto x orientation is best-placement: if it crosses a window
			// edge, fudge it sideways
			else {
				if (offset.left < 0) {
					// component is outside the window on the left side. Move it into visible range
					this.picker.addClass('datepicker-orient-left');
					left -= offset.left - visualPadding;
				} else if (left + calendarWidth > windowWidth) {
					// the calendar passes the widow right edge. Align it to component right side
					this.picker.addClass('datepicker-orient-right');
					left += width - calendarWidth;
				} else {
					if (this.o.rtl) {
						// Default to right
						this.picker.addClass('datepicker-orient-right');
					} else {
						// Default to left
						this.picker.addClass('datepicker-orient-left');
					}
				}
			}

			// auto y orientation is best-situation: top or bottom, no fudging,
			// decision based on which shows more of the calendar
			var yorient = this.o.orientation.y,
				top_overflow;
			if (yorient === 'auto'){
				top_overflow = -scrollTop + top - calendarHeight;
				yorient = top_overflow < 0 ? 'bottom' : 'top';
			}

			this.picker.addClass('datepicker-orient-' + yorient);
			if (yorient === 'top')
				top -= calendarHeight + parseInt(this.picker.css('padding-top'));
			else
				top += height;

			if (this.o.rtl) {
				var right = windowWidth - (left + width);
				this.picker.css({
					top: top,
					right: right,
					zIndex: zIndex
				});
			} else {
				this.picker.css({
					top: top,
					left: left,
					zIndex: zIndex
				});
			}
			return this;
		},

		_allow_update: true,
		update: function(){
			if (!this._allow_update)
				return this;

			var oldDates = this.dates.copy(),
				dates = [],
				fromArgs = false;
			if (arguments.length){
				$.each(arguments, $.proxy(function(i, date){
					if (date instanceof Date)
						date = this._local_to_utc(date);
					dates.push(date);
				}, this));
				fromArgs = true;
			} else {
				dates = this.isInput
						? this.element.val()
						: this.element.data('date') || this.inputField.val();
				if (dates && this.o.multidate)
					dates = dates.split(this.o.multidateSeparator);
				else
					dates = [dates];
				delete this.element.data().date;
			}

			dates = $.map(dates, $.proxy(function(date){
				return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
			}, this));
			dates = $.grep(dates, $.proxy(function(date){
				return (
					!this.dateWithinRange(date) ||
					!date
				);
			}, this), true);
			this.dates.replace(dates);

			if (this.o.updateViewDate) {
				if (this.dates.length)
					this.viewDate = new Date(this.dates.get(-1));
				else if (this.viewDate < this.o.startDate)
					this.viewDate = new Date(this.o.startDate);
				else if (this.viewDate > this.o.endDate)
					this.viewDate = new Date(this.o.endDate);
				else
					this.viewDate = this.o.defaultViewDate;
			}

			if (fromArgs){
				// setting date by clicking
				this.setValue();
				this.element.change();
			}
			else if (this.dates.length){
				// setting date by typing
				if (String(oldDates) !== String(this.dates) && fromArgs) {
					this._trigger('changeDate');
					this.element.change();
				}
			}
			if (!this.dates.length && oldDates.length) {
				this._trigger('clearDate');
				this.element.change();
			}

			this.fill();
			return this;
		},

		fillDow: function(){
      if (this.o.showWeekDays) {
			var dowCnt = this.o.weekStart,
				html = '<tr>';
			if (this.o.calendarWeeks){
				html += '<th class="cw">&#160;</th>';
			}
			while (dowCnt < this.o.weekStart + 7){
				html += '<th class="dow';
        if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) !== -1)
          html += ' disabled';
        html += '">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
			}
			html += '</tr>';
			this.picker.find('.datepicker-days thead').append(html);
      }
		},

		fillMonths: function(){
      var localDate = this._utc_to_local(this.viewDate);
			var html = '';
			var focused;
			for (var i = 0; i < 12; i++){
				focused = localDate && localDate.getMonth() === i ? ' focused' : '';
				html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i] + '</span>';
			}
			this.picker.find('.datepicker-months td').html(html);
		},

		setRange: function(range){
			if (!range || !range.length)
				delete this.range;
			else
				this.range = $.map(range, function(d){
					return d.valueOf();
				});
			this.fill();
		},

		getClassNames: function(date){
			var cls = [],
				year = this.viewDate.getUTCFullYear(),
				month = this.viewDate.getUTCMonth(),
				today = UTCToday();
			if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
				cls.push('old');
			} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
				cls.push('new');
			}
			if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
				cls.push('focused');
			// Compare internal UTC date with UTC today, not local today
			if (this.o.todayHighlight && isUTCEquals(date, today)) {
				cls.push('today');
			}
			if (this.dates.contains(date) !== -1)
				cls.push('active');
			if (!this.dateWithinRange(date)){
				cls.push('disabled');
			}
			if (this.dateIsDisabled(date)){
				cls.push('disabled', 'disabled-date');
			}
			if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
				cls.push('highlighted');
			}

			if (this.range){
				if (date > this.range[0] && date < this.range[this.range.length-1]){
					cls.push('range');
				}
				if ($.inArray(date.valueOf(), this.range) !== -1){
					cls.push('selected');
				}
				if (date.valueOf() === this.range[0]){
          cls.push('range-start');
        }
        if (date.valueOf() === this.range[this.range.length-1]){
          cls.push('range-end');
        }
			}
			return cls;
		},

		_fill_yearsView: function(selector, cssClass, factor, year, startYear, endYear, beforeFn){
			var html = '';
			var step = factor / 10;
			var view = this.picker.find(selector);
			var startVal = Math.floor(year / factor) * factor;
			var endVal = startVal + step * 9;
			var focusedVal = Math.floor(this.viewDate.getFullYear() / step) * step;
			var selected = $.map(this.dates, function(d){
				return Math.floor(d.getUTCFullYear() / step) * step;
			});

			var classes, tooltip, before;
			for (var currVal = startVal - step; currVal <= endVal + step; currVal += step) {
				classes = [cssClass];
				tooltip = null;

				if (currVal === startVal - step) {
					classes.push('old');
				} else if (currVal === endVal + step) {
					classes.push('new');
				}
				if ($.inArray(currVal, selected) !== -1) {
					classes.push('active');
				}
				if (currVal < startYear || currVal > endYear) {
					classes.push('disabled');
				}
				if (currVal === focusedVal) {
				  classes.push('focused');
        }

				if (beforeFn !== $.noop) {
					before = beforeFn(new Date(currVal, 0, 1));
					if (before === undefined) {
						before = {};
					} else if (typeof before === 'boolean') {
						before = {enabled: before};
					} else if (typeof before === 'string') {
						before = {classes: before};
					}
					if (before.enabled === false) {
						classes.push('disabled');
					}
					if (before.classes) {
						classes = classes.concat(before.classes.split(/\s+/));
					}
					if (before.tooltip) {
						tooltip = before.tooltip;
					}
				}

				html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + currVal + '</span>';
			}

			view.find('.datepicker-switch').text(startVal + '-' + endVal);
			view.find('td').html(html);
		},

		fill: function(){
			var d = new Date(this.viewDate),
				year = d.getUTCFullYear(),
				month = d.getUTCMonth(),
				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
				todaytxt = dates[this.o.language].today || dates['en'].today || '',
				cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
        titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
        todayDate = UTCToday(),
        titleBtnVisible = (this.o.todayBtn === true || this.o.todayBtn === 'linked') && todayDate >= this.o.startDate && todayDate <= this.o.endDate && !this.weekOfDateIsDisabled(todayDate),
				tooltip,
				before;
			if (isNaN(year) || isNaN(month))
				return;
			this.picker.find('.datepicker-days .datepicker-switch')
						.text(DPGlobal.formatDate(d, titleFormat, this.o.language));
			this.picker.find('tfoot .today')
						.text(todaytxt)
            .css('display', titleBtnVisible ? 'table-cell' : 'none');
			this.picker.find('tfoot .clear')
						.text(cleartxt)
						.css('display', this.o.clearBtn === true ? 'table-cell' : 'none');
			this.picker.find('thead .datepicker-title')
						.text(this.o.title)
						.css('display', typeof this.o.title === 'string' && this.o.title !== '' ? 'table-cell' : 'none');
			this.updateNavArrows();
			this.fillMonths();
			var prevMonth = UTCDate(year, month, 0),
				day = prevMonth.getUTCDate();
			prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
			var nextMonth = new Date(prevMonth);
			if (prevMonth.getUTCFullYear() < 100){
        nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
      }
			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
			nextMonth = nextMonth.valueOf();
			var html = [];
			var weekDay, clsName;
			while (prevMonth.valueOf() < nextMonth){
				weekDay = prevMonth.getUTCDay();
				if (weekDay === this.o.weekStart){
					html.push('<tr>');
					if (this.o.calendarWeeks){
						// ISO 8601: First week contains first thursday.
						// ISO also states week starts on Monday, but we can be more abstract here.
						var
							// Start of current week: based on weekstart/current date
							ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),
							// Thursday of this week
							th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
							// First Thursday of year, year from thursday
							yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
							// Calendar week: ms between thursdays, div ms per day, div 7 days
							calWeek = (th - yth) / 864e5 / 7 + 1;
						html.push('<td class="cw">'+ calWeek +'</td>');
					}
				}
				clsName = this.getClassNames(prevMonth);
				clsName.push('day');

				var content = prevMonth.getUTCDate();

				if (this.o.beforeShowDay !== $.noop){
					before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
					if (before === undefined)
						before = {};
					else if (typeof before === 'boolean')
						before = {enabled: before};
					else if (typeof before === 'string')
						before = {classes: before};
					if (before.enabled === false)
						clsName.push('disabled');
					if (before.classes)
						clsName = clsName.concat(before.classes.split(/\s+/));
					if (before.tooltip)
						tooltip = before.tooltip;
					if (before.content)
						content = before.content;
				}

				//Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2)
				//Fallback to unique function for older jquery versions
				if (typeof $.uniqueSort === "function") {
					clsName = $.uniqueSort(clsName);
				} else {
					clsName = $.unique(clsName);
				}

				html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + ' data-date="' + prevMonth.getTime().toString() + '">' + content + '</td>');
				tooltip = null;
				if (weekDay === this.o.weekEnd){
					html.push('</tr>');
				}
				prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
			}
			this.picker.find('.datepicker-days tbody').html(html.join(''));

			var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
			var months = this.picker.find('.datepicker-months')
						.find('.datepicker-switch')
							.text(this.o.maxViewMode < 2 ? monthsTitle : year)
							.end()
						.find('tbody span').removeClass('active');

			$.each(this.dates, function(i, d){
				if (d.getUTCFullYear() === year)
					months.eq(d.getUTCMonth()).addClass('active');
			});

			if (year < startYear || year > endYear){
				months.addClass('disabled');
			}
			if (year === startYear){
				months.slice(0, startMonth).addClass('disabled');
			}
			if (year === endYear){
				months.slice(endMonth+1).addClass('disabled');
			}

			if (this.o.beforeShowMonth !== $.noop){
				var that = this;
				$.each(months, function(i, month){
          var moDate = new Date(year, i, 1);
          var before = that.o.beforeShowMonth(moDate);
					if (before === undefined)
						before = {};
					else if (typeof before === 'boolean')
						before = {enabled: before};
					else if (typeof before === 'string')
						before = {classes: before};
					if (before.enabled === false && !$(month).hasClass('disabled'))
					    $(month).addClass('disabled');
					if (before.classes)
					    $(month).addClass(before.classes);
					if (before.tooltip)
					    $(month).prop('title', before.tooltip);
				});
			}

			// Generating decade/years picker
			this._fill_yearsView(
				'.datepicker-years',
				'year',
				10,
				year,
				startYear,
				endYear,
				this.o.beforeShowYear
			);

			// Generating century/decades picker
			this._fill_yearsView(
				'.datepicker-decades',
				'decade',
				100,
				year,
				startYear,
				endYear,
				this.o.beforeShowDecade
			);

			// Generating millennium/centuries picker
			this._fill_yearsView(
				'.datepicker-centuries',
				'century',
				1000,
				year,
				startYear,
				endYear,
				this.o.beforeShowCentury
			);
		},

		updateNavArrows: function(){
			if (!this._allow_update)
				return;

			var d = new Date(this.viewDate),
				year = d.getUTCFullYear(),
				month = d.getUTCMonth(),
				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
				prevIsDisabled,
				nextIsDisabled,
				factor = 1;
			switch (this.viewMode){
				case 4:
					factor *= 10;
					/* falls through */
				case 3:
					factor *= 10;
					/* falls through */
				case 2:
					factor *= 10;
					/* falls through */
				case 1:
					prevIsDisabled = Math.floor(year / factor) * factor <= startYear;
					nextIsDisabled = Math.floor(year / factor) * factor + factor > endYear;
					break;
				case 0:
					prevIsDisabled = year <= startYear && month <= startMonth;
					nextIsDisabled = year >= endYear && month >= endMonth;
					break;
			}

			this.picker.find('.prev').toggleClass('disabled', prevIsDisabled);
			this.picker.find('.next').toggleClass('disabled', nextIsDisabled);
		},

		click: function(e){
			e.preventDefault();
			e.stopPropagation();

			var target, dir, day, year, month;
			target = $(e.target);

			// Clicked on the switch
			if (target.hasClass('datepicker-switch') && this.viewMode !== this.o.maxViewMode){
				this.setViewMode(this.viewMode + 1);
			}

			// Clicked on today button
			if (target.hasClass('today') && !target.hasClass('day')){
				this.setViewMode(0);
				this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
			}

			// Clicked on clear button
			if (target.hasClass('clear')){
				this.clearDates();
			}

			if (!target.hasClass('disabled')){
				// Clicked on a month, year, decade, century
				if (target.hasClass('month')
						|| target.hasClass('year')
						|| target.hasClass('decade')
						|| target.hasClass('century')) {
					this.viewDate.setUTCDate(1);

					day = 1;
					if (this.viewMode === 1){
						month = target.parent().find('span').index(target);
						year = this.viewDate.getUTCFullYear();
						this.viewDate.setUTCMonth(month);
					} else {
						month = 0;
						year = Number(target.text());
						this.viewDate.setUTCFullYear(year);
					}

					this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);

					if (this.viewMode === this.o.minViewMode){
						this._setDate(UTCDate(year, month, day));
					} else {
						this.setViewMode(this.viewMode - 1);
						this.fill();
					}
				}
			}

			if (this.picker.is(':visible') && this._focused_from){
				this._focused_from.focus();
			}
			delete this._focused_from;
		},

		dayCellClick: function(e){
			var $target = $(e.currentTarget);
			var timestamp = $target.data('date');
			var date = new Date(timestamp);

			if (this.o.updateViewDate) {
				if (date.getUTCFullYear() !== this.viewDate.getUTCFullYear()) {
					this._trigger('changeYear', this.viewDate);
				}

				if (date.getUTCMonth() !== this.viewDate.getUTCMonth()) {
					this._trigger('changeMonth', this.viewDate);
				}
			}
			this._setDate(date);
		},

		// Clicked on prev or next
		navArrowsClick: function(e){
			var $target = $(e.currentTarget);
			var dir = $target.hasClass('prev') ? -1 : 1;
			if (this.viewMode !== 0){
				dir *= DPGlobal.viewModes[this.viewMode].navStep * 12;
			}
			this.viewDate = this.moveMonth(this.viewDate, dir);
			this._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate);
			this.fill();
		},

		_toggle_multidate: function(date){
			var ix = this.dates.contains(date);
			if (!date){
				this.dates.clear();
			}

			if (ix !== -1){
				if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){
					this.dates.remove(ix);
				}
			} else if (this.o.multidate === false) {
				this.dates.clear();
				this.dates.push(date);
			}
			else {
				this.dates.push(date);
			}

			if (typeof this.o.multidate === 'number')
				while (this.dates.length > this.o.multidate)
					this.dates.remove(0);
		},

		_setDate: function(date, which){
			if (!which || which === 'date')
				this._toggle_multidate(date && new Date(date));
			if ((!which && this.o.updateViewDate) || which === 'view')
				this.viewDate = date && new Date(date);

			this.fill();
			this.setValue();
			if (!which || which !== 'view') {
				this._trigger('changeDate');
			}
			this.inputField.trigger('change');
			if (this.o.autoclose && (!which || which === 'date')){
				this.hide();
			}
		},

		moveDay: function(date, dir){
			var newDate = new Date(date);
			newDate.setUTCDate(date.getUTCDate() + dir);

			return newDate;
		},

		moveWeek: function(date, dir){
			return this.moveDay(date, dir * 7);
		},

		moveMonth: function(date, dir){
			if (!isValidDate(date))
				return this.o.defaultViewDate;
			if (!dir)
				return date;
			var new_date = new Date(date.valueOf()),
				day = new_date.getUTCDate(),
				month = new_date.getUTCMonth(),
				mag = Math.abs(dir),
				new_month, test;
			dir = dir > 0 ? 1 : -1;
			if (mag === 1){
				test = dir === -1
					// If going back one month, make sure month is not current month
					// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
					? function(){
						return new_date.getUTCMonth() === month;
					}
					// If going forward one month, make sure month is as expected
					// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
					: function(){
						return new_date.getUTCMonth() !== new_month;
					};
				new_month = month + dir;
				new_date.setUTCMonth(new_month);
				// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
				new_month = (new_month + 12) % 12;
			}
			else {
				// For magnitudes >1, move one month at a time...
				for (var i=0; i < mag; i++)
					// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
					new_date = this.moveMonth(new_date, dir);
				// ...then reset the day, keeping it in the new month
				new_month = new_date.getUTCMonth();
				new_date.setUTCDate(day);
				test = function(){
					return new_month !== new_date.getUTCMonth();
				};
			}
			// Common date-resetting loop -- if date is beyond end of month, make it
			// end of month
			while (test()){
				new_date.setUTCDate(--day);
				new_date.setUTCMonth(new_month);
			}
			return new_date;
		},

		moveYear: function(date, dir){
			return this.moveMonth(date, dir*12);
		},

		moveAvailableDate: function(date, dir, fn){
			do {
				date = this[fn](date, dir);

				if (!this.dateWithinRange(date))
					return false;

				fn = 'moveDay';
			}
			while (this.dateIsDisabled(date));

			return date;
		},

		weekOfDateIsDisabled: function(date){
			return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;
		},

		dateIsDisabled: function(date){
			return (
				this.weekOfDateIsDisabled(date) ||
				$.grep(this.o.datesDisabled, function(d){
					return isUTCEquals(date, d);
				}).length > 0
			);
		},

		dateWithinRange: function(date){
			return date >= this.o.startDate && date <= this.o.endDate;
		},

		keydown: function(e){
			if (!this.picker.is(':visible')){
				if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
					this.show();
					e.stopPropagation();
        }
				return;
			}
			var dateChanged = false,
				dir, newViewDate,
				focusDate = this.focusDate || this.viewDate;
			switch (e.keyCode){
				case 27: // escape
					if (this.focusDate){
						this.focusDate = null;
						this.viewDate = this.dates.get(-1) || this.viewDate;
						this.fill();
					}
					else
						this.hide();
					e.preventDefault();
					e.stopPropagation();
					break;
				case 37: // left
				case 38: // up
				case 39: // right
				case 40: // down
					if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)
						break;
					dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;
          if (this.viewMode === 0) {
  					if (e.ctrlKey){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');

  						if (newViewDate)
  							this._trigger('changeYear', this.viewDate);
  					} else if (e.shiftKey){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');

  						if (newViewDate)
  							this._trigger('changeMonth', this.viewDate);
  					} else if (e.keyCode === 37 || e.keyCode === 39){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');
  					} else if (!this.weekOfDateIsDisabled(focusDate)){
  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');
  					}
          } else if (this.viewMode === 1) {
            if (e.keyCode === 38 || e.keyCode === 40) {
              dir = dir * 4;
            }
            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
          } else if (this.viewMode === 2) {
            if (e.keyCode === 38 || e.keyCode === 40) {
              dir = dir * 4;
            }
            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
          }
					if (newViewDate){
						this.focusDate = this.viewDate = newViewDate;
						this.setValue();
						this.fill();
						e.preventDefault();
					}
					break;
				case 13: // enter
					if (!this.o.forceParse)
						break;
					focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
					if (this.o.keyboardNavigation) {
						this._toggle_multidate(focusDate);
						dateChanged = true;
					}
					this.focusDate = null;
					this.viewDate = this.dates.get(-1) || this.viewDate;
					this.setValue();
					this.fill();
					if (this.picker.is(':visible')){
						e.preventDefault();
						e.stopPropagation();
						if (this.o.autoclose)
							this.hide();
					}
					break;
				case 9: // tab
					this.focusDate = null;
					this.viewDate = this.dates.get(-1) || this.viewDate;
					this.fill();
					this.hide();
					break;
			}
			if (dateChanged){
				if (this.dates.length)
					this._trigger('changeDate');
				else
					this._trigger('clearDate');
				this.inputField.trigger('change');
			}
		},

		setViewMode: function(viewMode){
			this.viewMode = viewMode;
			this.picker
				.children('div')
				.hide()
				.filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName)
					.show();
			this.updateNavArrows();
      this._trigger('changeViewMode', new Date(this.viewDate));
		}
	};

	var DateRangePicker = function(element, options){
		$.data(element, 'datepicker', this);
		this.element = $(element);
		this.inputs = $.map(options.inputs, function(i){
			return i.jquery ? i[0] : i;
		});
		delete options.inputs;

		this.keepEmptyValues = options.keepEmptyValues;
		delete options.keepEmptyValues;

		datepickerPlugin.call($(this.inputs), options)
			.on('changeDate', $.proxy(this.dateUpdated, this));

		this.pickers = $.map(this.inputs, function(i){
			return $.data(i, 'datepicker');
		});
		this.updateDates();
	};
	DateRangePicker.prototype = {
		updateDates: function(){
			this.dates = $.map(this.pickers, function(i){
				return i.getUTCDate();
			});
			this.updateRanges();
		},
		updateRanges: function(){
			var range = $.map(this.dates, function(d){
				return d.valueOf();
			});
			$.each(this.pickers, function(i, p){
				p.setRange(range);
			});
		},
		clearDates: function(){
			$.each(this.pickers, function(i, p){
				p.clearDates();
			});
		},
		dateUpdated: function(e){
			// `this.updating` is a workaround for preventing infinite recursion
			// between `changeDate` triggering and `setUTCDate` calling.  Until
			// there is a better mechanism.
			if (this.updating)
				return;
			this.updating = true;

			var dp = $.data(e.target, 'datepicker');

			if (dp === undefined) {
				return;
			}

			var new_date = dp.getUTCDate(),
				keep_empty_values = this.keepEmptyValues,
				i = $.inArray(e.target, this.inputs),
				j = i - 1,
				k = i + 1,
				l = this.inputs.length;
			if (i === -1)
				return;

			$.each(this.pickers, function(i, p){
				if (!p.getUTCDate() && (p === dp || !keep_empty_values))
					p.setUTCDate(new_date);
			});

			if (new_date < this.dates[j]){
				// Date being moved earlier/left
				while (j >= 0 && new_date < this.dates[j] && (this.pickers[j].element.val() || "").length > 0) {
					this.pickers[j--].setUTCDate(new_date);
				}
			} else if (new_date > this.dates[k]){
				// Date being moved later/right
				while (k < l && new_date > this.dates[k] && (this.pickers[k].element.val() || "").length > 0) {
					this.pickers[k++].setUTCDate(new_date);
				}
			}
			this.updateDates();

			delete this.updating;
		},
		destroy: function(){
			$.map(this.pickers, function(p){ p.destroy(); });
			$(this.inputs).off('changeDate', this.dateUpdated);
			delete this.element.data().datepicker;
		},
		remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead')
	};

	function opts_from_el(el, prefix){
		// Derive options from element data-attrs
		var data = $(el).data(),
			out = {}, inkey,
			replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
		prefix = new RegExp('^' + prefix.toLowerCase());
		function re_lower(_,a){
			return a.toLowerCase();
		}
		for (var key in data)
			if (prefix.test(key)){
				inkey = key.replace(replace, re_lower);
				out[inkey] = data[key];
			}
		return out;
	}

	function opts_from_locale(lang){
		// Derive options from locale plugins
		var out = {};
		// Check if "de-DE" style date is available, if not language should
		// fallback to 2 letter code eg "de"
		if (!dates[lang]){
			lang = lang.split('-')[0];
			if (!dates[lang])
				return;
		}
		var d = dates[lang];
		$.each(locale_opts, function(i,k){
			if (k in d)
				out[k] = d[k];
		});
		return out;
	}

	var old = $.fn.datepicker;
	var datepickerPlugin = function(option){
		var args = Array.apply(null, arguments);
		args.shift();
		var internal_return;
		this.each(function(){
			var $this = $(this),
				data = $this.data('datepicker'),
				options = typeof option === 'object' && option;
			if (!data){
				var elopts = opts_from_el(this, 'date'),
					// Preliminary otions
					xopts = $.extend({}, defaults, elopts, options),
					locopts = opts_from_locale(xopts.language),
					// Options priority: js args, data-attrs, locales, defaults
					opts = $.extend({}, defaults, locopts, elopts, options);
				if ($this.hasClass('input-daterange') || opts.inputs){
					$.extend(opts, {
						inputs: opts.inputs || $this.find('input').toArray()
					});
					data = new DateRangePicker(this, opts);
				}
				else {
					data = new Datepicker(this, opts);
				}
				$this.data('datepicker', data);
			}
			if (typeof option === 'string' && typeof data[option] === 'function'){
				internal_return = data[option].apply(data, args);
			}
		});

		if (
			internal_return === undefined ||
			internal_return instanceof Datepicker ||
			internal_return instanceof DateRangePicker
		)
			return this;

		if (this.length > 1)
			throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
		else
			return internal_return;
	};
	$.fn.datepicker = datepickerPlugin;

	var defaults = $.fn.datepicker.defaults = {
		assumeNearbyYear: false,
		autoclose: false,
		beforeShowDay: $.noop,
		beforeShowMonth: $.noop,
		beforeShowYear: $.noop,
		beforeShowDecade: $.noop,
		beforeShowCentury: $.noop,
		calendarWeeks: false,
		clearBtn: false,
		toggleActive: false,
		daysOfWeekDisabled: [],
		daysOfWeekHighlighted: [],
		datesDisabled: [],
		endDate: Infinity,
		forceParse: true,
		format: 'mm/dd/yyyy',
		isInline: null,
		keepEmptyValues: false,
		keyboardNavigation: true,
		language: 'en',
		minViewMode: 0,
		maxViewMode: 4,
		multidate: false,
		multidateSeparator: ',',
		orientation: "auto",
		rtl: false,
		startDate: -Infinity,
		startView: 0,
		todayBtn: false,
		todayHighlight: false,
		updateViewDate: true,
		weekStart: 0,
		disableTouchKeyboard: false,
		enableOnReadonly: true,
		showOnFocus: true,
		zIndexOffset: 10,
		container: 'body',
		immediateUpdates: false,
		title: '',
		templates: {
			leftArrow: '&#x00AB;',
			rightArrow: '&#x00BB;'
		},
    showWeekDays: true
	};
	var locale_opts = $.fn.datepicker.locale_opts = [
		'format',
		'rtl',
		'weekStart'
	];
	$.fn.datepicker.Constructor = Datepicker;
	var dates = $.fn.datepicker.dates = {
		en: {
			days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
			daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
			daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
			months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
			today: "Today",
			clear: "Clear",
			titleFormat: "MM yyyy"
		}
	};

	var DPGlobal = {
		viewModes: [
			{
				names: ['days', 'month'],
				clsName: 'days',
				e: 'changeMonth'
			},
			{
				names: ['months', 'year'],
				clsName: 'months',
				e: 'changeYear',
				navStep: 1
			},
			{
				names: ['years', 'decade'],
				clsName: 'years',
				e: 'changeDecade',
				navStep: 10
			},
			{
				names: ['decades', 'century'],
				clsName: 'decades',
				e: 'changeCentury',
				navStep: 100
			},
			{
				names: ['centuries', 'millennium'],
				clsName: 'centuries',
				e: 'changeMillennium',
				navStep: 1000
			}
		],
		validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
		nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g,
		parseFormat: function(format){
			if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
                return format;
            // IE treats \0 as a string end in inputs (truncating the value),
			// so it's a bad format delimiter, anyway
			var separators = format.replace(this.validParts, '\0').split('\0'),
				parts = format.match(this.validParts);
			if (!separators || !separators.length || !parts || parts.length === 0){
				throw new Error("Invalid date format.");
			}
			return {separators: separators, parts: parts};
		},
		parseDate: function(date, format, language, assumeNearby){
			if (!date)
				return undefined;
			if (date instanceof Date)
				return date;
			if (typeof format === 'string')
				format = DPGlobal.parseFormat(format);
			if (format.toValue)
				return format.toValue(date, format, language);
			var fn_map = {
					d: 'moveDay',
					m: 'moveMonth',
					w: 'moveWeek',
					y: 'moveYear'
				},
				dateAliases = {
					yesterday: '-1d',
					today: '+0d',
					tomorrow: '+1d'
				},
				parts, part, dir, i, fn;
			if (date in dateAliases){
				date = dateAliases[date];
			}
			if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/i.test(date)){
				parts = date.match(/([\-+]\d+)([dmwy])/gi);
				date = new Date();
				for (i=0; i < parts.length; i++){
					part = parts[i].match(/([\-+]\d+)([dmwy])/i);
					dir = Number(part[1]);
					fn = fn_map[part[2].toLowerCase()];
					date = Datepicker.prototype[fn](date, dir);
				}
				return Datepicker.prototype._zero_utc_time(date);
			}

			parts = date && date.match(this.nonpunctuation) || [];

			function applyNearbyYear(year, threshold){
				if (threshold === true)
					threshold = 10;

				// if year is 2 digits or less, than the user most likely is trying to get a recent century
				if (year < 100){
					year += 2000;
					// if the new year is more than threshold years in advance, use last century
					if (year > ((new Date()).getFullYear()+threshold)){
						year -= 100;
					}
				}

				return year;
			}

			var parsed = {},
				setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
				setters_map = {
					yyyy: function(d,v){
						return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
					},
					m: function(d,v){
						if (isNaN(d))
							return d;
						v -= 1;
						while (v < 0) v += 12;
						v %= 12;
						d.setUTCMonth(v);
						while (d.getUTCMonth() !== v)
							d.setUTCDate(d.getUTCDate()-1);
						return d;
					},
					d: function(d,v){
						return d.setUTCDate(v);
					}
				},
				val, filtered;
			setters_map['yy'] = setters_map['yyyy'];
			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
			setters_map['dd'] = setters_map['d'];
			date = UTCToday();
			var fparts = format.parts.slice();
			// Remove noop parts
			if (parts.length !== fparts.length){
				fparts = $(fparts).filter(function(i,p){
					return $.inArray(p, setters_order) !== -1;
				}).toArray();
			}
			// Process remainder
			function match_part(){
				var m = this.slice(0, parts[i].length),
					p = parts[i].slice(0, m.length);
				return m.toLowerCase() === p.toLowerCase();
			}
			if (parts.length === fparts.length){
				var cnt;
				for (i=0, cnt = fparts.length; i < cnt; i++){
					val = parseInt(parts[i], 10);
					part = fparts[i];
					if (isNaN(val)){
						switch (part){
							case 'MM':
								filtered = $(dates[language].months).filter(match_part);
								val = $.inArray(filtered[0], dates[language].months) + 1;
								break;
							case 'M':
								filtered = $(dates[language].monthsShort).filter(match_part);
								val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
								break;
						}
					}
					parsed[part] = val;
				}
				var _date, s;
				for (i=0; i < setters_order.length; i++){
					s = setters_order[i];
					if (s in parsed && !isNaN(parsed[s])){
						_date = new Date(date);
						setters_map[s](_date, parsed[s]);
						if (!isNaN(_date))
							date = _date;
					}
				}
			}
			return date;
		},
		formatDate: function(date, format, language){
			if (!date)
				return '';
			if (typeof format === 'string')
				format = DPGlobal.parseFormat(format);
			if (format.toDisplay)
                return format.toDisplay(date, format, language);
            var val = {
				d: date.getUTCDate(),
				D: dates[language].daysShort[date.getUTCDay()],
				DD: dates[language].days[date.getUTCDay()],
				m: date.getUTCMonth() + 1,
				M: dates[language].monthsShort[date.getUTCMonth()],
				MM: dates[language].months[date.getUTCMonth()],
				yy: date.getUTCFullYear().toString().substring(2),
				yyyy: date.getUTCFullYear()
			};
			val.dd = (val.d < 10 ? '0' : '') + val.d;
			val.mm = (val.m < 10 ? '0' : '') + val.m;
			date = [];
			var seps = $.extend([], format.separators);
			for (var i=0, cnt = format.parts.length; i <= cnt; i++){
				if (seps.length)
					date.push(seps.shift());
				date.push(val[format.parts[i]]);
			}
			return date.join('');
		},
		headTemplate: '<thead>'+
			              '<tr>'+
			                '<th colspan="7" class="datepicker-title"></th>'+
			              '</tr>'+
							'<tr>'+
								'<th class="prev">'+defaults.templates.leftArrow+'</th>'+
								'<th colspan="5" class="datepicker-switch"></th>'+
								'<th class="next">'+defaults.templates.rightArrow+'</th>'+
							'</tr>'+
						'</thead>',
		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
		footTemplate: '<tfoot>'+
							'<tr>'+
								'<th colspan="7" class="today"></th>'+
							'</tr>'+
							'<tr>'+
								'<th colspan="7" class="clear"></th>'+
							'</tr>'+
						'</tfoot>'
	};
	DPGlobal.template = '<div class="datepicker">'+
							'<div class="datepicker-days">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									'<tbody></tbody>'+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-months">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-years">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-decades">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
							'<div class="datepicker-centuries">'+
								'<table class="table-condensed">'+
									DPGlobal.headTemplate+
									DPGlobal.contTemplate+
									DPGlobal.footTemplate+
								'</table>'+
							'</div>'+
						'</div>';

	$.fn.datepicker.DPGlobal = DPGlobal;


	/* DATEPICKER NO CONFLICT
	* =================== */

	$.fn.datepicker.noConflict = function(){
		$.fn.datepicker = old;
		return this;
	};

	/* DATEPICKER VERSION
	 * =================== */
	$.fn.datepicker.version = '1.10.0';

	$.fn.datepicker.deprecated = function(msg){
		var console = window.console;
		if (console && console.warn) {
			console.warn('DEPRECATED: ' + msg);
		}
	};


	/* DATEPICKER DATA-API
	* ================== */

	$(document).on(
		'focus.datepicker.data-api click.datepicker.data-api',
		'[data-provide="datepicker"]',
		function(e){
			var $this = $(this);
			if ($this.data('datepicker'))
				return;
			e.preventDefault();
			// component click requires us to explicitly show it
			datepickerPlugin.call($this, 'show');
		}
	);
	$(function(){
		datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
	});

}));

/*
 * bootstrap-filestyle
 * doc: http://markusslima.github.io/bootstrap-filestyle/
 * github: https://github.com/markusslima/bootstrap-filestyle
 *
 * Copyright (c) 2014 Markus Vinicius da Silva Lima
 * Version 1.2.1
 * Licensed under the MIT license.
 */
(function($) {"use strict";

    var nextId = 0;

	var Filestyle = function(element, options) {
		this.options = options;
		this.$elementFilestyle = [];
		this.$element = $(element);
	};

	Filestyle.prototype = {
		clear : function() {
			this.$element.val('');
			this.$elementFilestyle.find(':text').val('');
			this.$elementFilestyle.find('.badge').remove();
		},

		destroy : function() {
			this.$element.removeAttr('style').removeData('filestyle');
			this.$elementFilestyle.remove();
		},

		disabled : function(value) {
			if (value === true) {
				if (!this.options.disabled) {
					this.$element.attr('disabled', 'true');
					this.$elementFilestyle.find('label').attr('disabled', 'true');
					this.options.disabled = true;
				}
			} else if (value === false) {
				if (this.options.disabled) {
					this.$element.removeAttr('disabled');
					this.$elementFilestyle.find('label').removeAttr('disabled');
					this.options.disabled = false;
				}
			} else {
				return this.options.disabled;
			}
		},

		buttonBefore : function(value) {
			if (value === true) {
				if (!this.options.buttonBefore) {
					this.options.buttonBefore = true;
					if (this.options.input) {
						this.$elementFilestyle.remove();
						this.constructor();
						this.pushNameFiles();
					}
				}
			} else if (value === false) {
				if (this.options.buttonBefore) {
					this.options.buttonBefore = false;
					if (this.options.input) {
						this.$elementFilestyle.remove();
						this.constructor();
						this.pushNameFiles();
					}
				}
			} else {
				return this.options.buttonBefore;
			}
		},

		icon : function(value) {
			if (value === true) {
				if (!this.options.icon) {
					this.options.icon = true;
					this.$elementFilestyle.find('label').prepend(this.htmlIcon());
				}
			} else if (value === false) {
				if (this.options.icon) {
					this.options.icon = false;
					this.$elementFilestyle.find('.icon-span-filestyle').remove();
				}
			} else {
				return this.options.icon;
			}
		},
		
		input : function(value) {
			if (value === true) {
				if (!this.options.input) {
					this.options.input = true;

					if (this.options.buttonBefore) {
						this.$elementFilestyle.append(this.htmlInput());
					} else {
						this.$elementFilestyle.prepend(this.htmlInput());
					}

					this.$elementFilestyle.find('.badge').remove();

					this.pushNameFiles();

					this.$elementFilestyle.find('.group-span-filestyle').addClass('input-group-btn');
				}
			} else if (value === false) {
				if (this.options.input) {
					this.options.input = false;
					this.$elementFilestyle.find(':text').remove();
					var files = this.pushNameFiles();
					if (files.length > 0 && this.options.badge) {
						this.$elementFilestyle.find('label').append(' <span class="badge">' + files.length + '</span>');
					}
					this.$elementFilestyle.find('.group-span-filestyle').removeClass('input-group-btn');
				}
			} else {
				return this.options.input;
			}
		},

		size : function(value) {
			if (value !== undefined) {
				var btn = this.$elementFilestyle.find('label'), input = this.$elementFilestyle.find('input');

				btn.removeClass('btn-lg btn-sm');
				input.removeClass('input-lg input-sm');
				if (value != 'nr') {
					btn.addClass('btn-' + value);
					input.addClass('input-' + value);
				}
			} else {
				return this.options.size;
			}
		},
		
		placeholder : function(value) {
			if (value !== undefined) {
				this.options.placeholder = value;
				this.$elementFilestyle.find('input').attr('placeholder', value);
			} else {
				return this.options.placeholder;
			}
		},		

		buttonText : function(value) {
			if (value !== undefined) {
				this.options.buttonText = value;
				this.$elementFilestyle.find('label .buttonText').html(this.options.buttonText);
			} else {
				return this.options.buttonText;
			}
		},
		
		buttonName : function(value) {
			if (value !== undefined) {
				this.options.buttonName = value;
				this.$elementFilestyle.find('label').attr({
					'class' : 'btn ' + this.options.buttonName
				});
			} else {
				return this.options.buttonName;
			}
		},

		iconName : function(value) {
			if (value !== undefined) {
				this.$elementFilestyle.find('.icon-span-filestyle').attr({
					'class' : 'icon-span-filestyle ' + this.options.iconName
				});
			} else {
				return this.options.iconName;
			}
		},

		htmlIcon : function() {
			if (this.options.icon) {
				return '<span class="icon-span-filestyle ' + this.options.iconName + '"></span> ';
			} else {
				return '';
			}
		},

		htmlInput : function() {
			if (this.options.input) {
				return '<input type="text" class="form-control ' + (this.options.size == 'nr' ? '' : 'input-' + this.options.size) + '" placeholder="'+ this.options.placeholder +'" disabled> ';
			} else {
				return '';
			}
		},

		// puts the name of the input files
		// return files
		pushNameFiles : function() {
			var content = '', files = [];
			if (this.$element[0].files === undefined) {
				files[0] = {
					'name' : this.$element[0] && this.$element[0].value
				};
			} else {
				files = this.$element[0].files;
			}

			for (var i = 0; i < files.length; i++) {
				content += files[i].name.split("\\").pop() + ', ';
			}

			if (content !== '') {
				this.$elementFilestyle.find(':text').val(content.replace(/\, $/g, ''));
			} else {
				this.$elementFilestyle.find(':text').val('');
			}
			
			return files;
		},

		constructor : function() {
			var _self = this, 
				html = '', 
				id = _self.$element.attr('id'), 
				files = [], 
				btn = '', 
				$label;

			if (id === '' || !id) {
				id = 'filestyle-' + nextId;
				_self.$element.attr({
					'id' : id
				});
                nextId++;
			}

			btn = '<span class="group-span-filestyle ' + (_self.options.input ? 'input-group-btn' : '') + '">' + 
			  '<label for="' + id + '" class="btn ' + _self.options.buttonName + ' ' + 
			(_self.options.size == 'nr' ? '' : 'btn-' + _self.options.size) + '" ' + 
			(_self.options.disabled ? 'disabled="true"' : '') + '>' + 
			_self.htmlIcon() + '<span class="buttonText">' + _self.options.buttonText + '</span>' + 
			  '</label>' + 
			  '</span>';
			
			html = _self.options.buttonBefore ? btn + _self.htmlInput() : _self.htmlInput() + btn;
			
			_self.$elementFilestyle = $('<div class="bootstrap-filestyle input-group">' + html + '</div>');
			_self.$elementFilestyle.find('.group-span-filestyle').attr('tabindex', "0").keypress(function(e) {
			if (e.keyCode === 13 || e.charCode === 32) {
				_self.$elementFilestyle.find('label').click();
					return false;
				}
			});

			// hidding input file and add filestyle
			_self.$element.css({
				'position' : 'absolute',
				'clip' : 'rect(0px 0px 0px 0px)' // using 0px for work in IE8
			}).attr('tabindex', "-1").after(_self.$elementFilestyle);

			if (_self.options.disabled) {
				_self.$element.attr('disabled', 'true');
			}

			// Getting input file value
			_self.$element.change(function() {
				var files = _self.pushNameFiles();

				if (_self.options.input == false && _self.options.badge) {
					if (_self.$elementFilestyle.find('.badge').length == 0) {
						_self.$elementFilestyle.find('label').append(' <span class="badge">' + files.length + '</span>');
					} else if (files.length == 0) {
						_self.$elementFilestyle.find('.badge').remove();
					} else {
						_self.$elementFilestyle.find('.badge').html(files.length);
					}
				} else {
					_self.$elementFilestyle.find('.badge').remove();
				}
			});

			// Check if browser is Firefox
			if (window.navigator.userAgent.search(/firefox/i) > -1) {
				// Simulating choose file for firefox
				_self.$elementFilestyle.find('label').click(function() {
					_self.$element.click();
					return false;
				});
			}
		}
	};

	var old = $.fn.filestyle;

	$.fn.filestyle = function(option, value) {
		var get = '', element = this.each(function() {
			if ($(this).attr('type') === 'file') {
				var $this = $(this), data = $this.data('filestyle'), options = $.extend({}, $.fn.filestyle.defaults, option, typeof option === 'object' && option);

				if (!data) {
					$this.data('filestyle', ( data = new Filestyle(this, options)));
					data.constructor();
				}

				if ( typeof option === 'string') {
					get = data[option](value);
				}
			}
		});

		if ( typeof get !== undefined) {
			return get;
		} else {
			return element;
		}
	};

	$.fn.filestyle.defaults = {
		'buttonText' : 'Choose file',
		'iconName' : 'glyphicon glyphicon-folder-open',
		'buttonName' : 'btn-default',
		'size' : 'nr',
		'input' : true,
		'badge' : true,
		'icon' : true,
		'buttonBefore' : false,
		'disabled' : false,
		'placeholder': ''
	};

	$.fn.filestyle.noConflict = function() {
		$.fn.filestyle = old;
		return this;
	};

	$(function() {
		$('.filestyle').each(function() {
			var $this = $(this), options = {

				'input' : $this.attr('data-input') === 'false' ? false : true,
				'icon' : $this.attr('data-icon') === 'false' ? false : true,
				'buttonBefore' : $this.attr('data-buttonBefore') === 'true' ? true : false,
				'disabled' : $this.attr('data-disabled') === 'true' ? true : false,
				'size' : $this.attr('data-size'),
				'buttonText' : $this.attr('data-buttonText'),
				'buttonName' : $this.attr('data-buttonName'),
				'iconName' : $this.attr('data-iconName'),
				'badge' : $this.attr('data-badge') === 'false' ? false : true,
				'placeholder': $this.attr('data-placeholder')
			};

			$this.filestyle(options);
		});
	});
})(window.jQuery);

/**
* @version: 3.0.5
* @author: Dan Grossman http://www.dangrossman.info/
* @copyright: Copyright (c) 2012-2019 Dan Grossman. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
* @website: http://www.daterangepicker.com/
*/
// Following the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Make globaly available as well
        define(['moment', 'jquery'], function (moment, jquery) {
            if (!jquery.fn) jquery.fn = {}; // webpack server rendering
            if (typeof moment !== 'function' && moment.default) moment = moment.default
            return factory(moment, jquery);
        });
    } else if (typeof module === 'object' && module.exports) {
        // Node / Browserify
        //isomorphic issue
        var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined;
        if (!jQuery) {
            jQuery = require('jquery');
            if (!jQuery.fn) jQuery.fn = {};
        }
        var moment = (typeof window != 'undefined' && typeof window.moment != 'undefined') ? window.moment : require('moment');
        module.exports = factory(moment, jQuery);
    } else {
        // Browser globals
        root.daterangepicker = factory(root.moment, root.jQuery);
    }
}(this, function(moment, $) {
    var DateRangePicker = function(element, options, cb) {

        //default settings for options
        this.parentEl = 'body';
        this.element = $(element);
        this.startDate = moment().startOf('day');
        this.endDate = moment().endOf('day');
        this.minDate = false;
        this.maxDate = false;
        this.maxSpan = false;
        this.autoApply = false;
        this.singleDatePicker = false;
        this.showDropdowns = false;
        this.minYear = moment().subtract(100, 'year').format('YYYY');
        this.maxYear = moment().add(100, 'year').format('YYYY');
        this.showWeekNumbers = false;
        this.showISOWeekNumbers = false;
        this.showCustomRangeLabel = true;
        this.timePicker = false;
        this.timePicker24Hour = false;
        this.timePickerIncrement = 1;
        this.timePickerSeconds = false;
        this.linkedCalendars = true;
        this.autoUpdateInput = true;
        this.alwaysShowCalendars = false;
        this.ranges = {};

        this.opens = 'right';
        if (this.element.hasClass('pull-right'))
            this.opens = 'left';

        this.drops = 'down';
        if (this.element.hasClass('dropup'))
            this.drops = 'up';

        this.buttonClasses = 'btn btn-sm';
        this.applyButtonClasses = 'btn-primary';
        this.cancelButtonClasses = 'btn-default';

        this.locale = {
            direction: 'ltr',
            format: moment.localeData().longDateFormat('L'),
            separator: ' - ',
            applyLabel: 'Apply',
            cancelLabel: 'Cancel',
            weekLabel: 'W',
            customRangeLabel: 'Custom Range',
            daysOfWeek: moment.weekdaysMin(),
            monthNames: moment.monthsShort(),
            firstDay: moment.localeData().firstDayOfWeek()
        };

        this.callback = function() { };

        //some state information
        this.isShowing = false;
        this.leftCalendar = {};
        this.rightCalendar = {};

        //custom options from user
        if (typeof options !== 'object' || options === null)
            options = {};

        //allow setting options with data attributes
        //data-api options will be overwritten with custom javascript options
        options = $.extend(this.element.data(), options);

        //html template for the picker UI
        if (typeof options.template !== 'string' && !(options.template instanceof $))
            options.template =
            '<div class="daterangepicker">' +
                '<div class="ranges"></div>' +
                '<div class="drp-calendar left">' +
                    '<div class="calendar-table"></div>' +
                    '<div class="calendar-time"></div>' +
                '</div>' +
                '<div class="drp-calendar right">' +
                    '<div class="calendar-table"></div>' +
                    '<div class="calendar-time"></div>' +
                '</div>' +
                '<div class="drp-buttons">' +
                    '<span class="drp-selected"></span>' +
                    '<button class="cancelBtn" type="button"></button>' +
                    '<button class="applyBtn" disabled="disabled" type="button"></button> ' +
                '</div>' +
            '</div>';

        this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
        this.container = $(options.template).appendTo(this.parentEl);

        //
        // handle all the possible options overriding defaults
        //

        if (typeof options.locale === 'object') {

            if (typeof options.locale.direction === 'string')
                this.locale.direction = options.locale.direction;

            if (typeof options.locale.format === 'string')
                this.locale.format = options.locale.format;

            if (typeof options.locale.separator === 'string')
                this.locale.separator = options.locale.separator;

            if (typeof options.locale.daysOfWeek === 'object')
                this.locale.daysOfWeek = options.locale.daysOfWeek.slice();

            if (typeof options.locale.monthNames === 'object')
              this.locale.monthNames = options.locale.monthNames.slice();

            if (typeof options.locale.firstDay === 'number')
              this.locale.firstDay = options.locale.firstDay;

            if (typeof options.locale.applyLabel === 'string')
              this.locale.applyLabel = options.locale.applyLabel;

            if (typeof options.locale.cancelLabel === 'string')
              this.locale.cancelLabel = options.locale.cancelLabel;

            if (typeof options.locale.weekLabel === 'string')
              this.locale.weekLabel = options.locale.weekLabel;

            if (typeof options.locale.customRangeLabel === 'string'){
                //Support unicode chars in the custom range name.
                var elem = document.createElement('textarea');
                elem.innerHTML = options.locale.customRangeLabel;
                var rangeHtml = elem.value;
                this.locale.customRangeLabel = rangeHtml;
            }
        }
        this.container.addClass(this.locale.direction);

        if (typeof options.startDate === 'string')
            this.startDate = moment(options.startDate, this.locale.format);

        if (typeof options.endDate === 'string')
            this.endDate = moment(options.endDate, this.locale.format);

        if (typeof options.minDate === 'string')
            this.minDate = moment(options.minDate, this.locale.format);

        if (typeof options.maxDate === 'string')
            this.maxDate = moment(options.maxDate, this.locale.format);

        if (typeof options.startDate === 'object')
            this.startDate = moment(options.startDate);

        if (typeof options.endDate === 'object')
            this.endDate = moment(options.endDate);

        if (typeof options.minDate === 'object')
            this.minDate = moment(options.minDate);

        if (typeof options.maxDate === 'object')
            this.maxDate = moment(options.maxDate);

        // sanity check for bad options
        if (this.minDate && this.startDate.isBefore(this.minDate))
            this.startDate = this.minDate.clone();

        // sanity check for bad options
        if (this.maxDate && this.endDate.isAfter(this.maxDate))
            this.endDate = this.maxDate.clone();

        if (typeof options.applyButtonClasses === 'string')
            this.applyButtonClasses = options.applyButtonClasses;

        if (typeof options.applyClass === 'string') //backwards compat
            this.applyButtonClasses = options.applyClass;

        if (typeof options.cancelButtonClasses === 'string')
            this.cancelButtonClasses = options.cancelButtonClasses;

        if (typeof options.cancelClass === 'string') //backwards compat
            this.cancelButtonClasses = options.cancelClass;

        if (typeof options.maxSpan === 'object')
            this.maxSpan = options.maxSpan;

        if (typeof options.dateLimit === 'object') //backwards compat
            this.maxSpan = options.dateLimit;

        if (typeof options.opens === 'string')
            this.opens = options.opens;

        if (typeof options.drops === 'string')
            this.drops = options.drops;

        if (typeof options.showWeekNumbers === 'boolean')
            this.showWeekNumbers = options.showWeekNumbers;

        if (typeof options.showISOWeekNumbers === 'boolean')
            this.showISOWeekNumbers = options.showISOWeekNumbers;

        if (typeof options.buttonClasses === 'string')
            this.buttonClasses = options.buttonClasses;

        if (typeof options.buttonClasses === 'object')
            this.buttonClasses = options.buttonClasses.join(' ');

        if (typeof options.showDropdowns === 'boolean')
            this.showDropdowns = options.showDropdowns;

        if (typeof options.minYear === 'number')
            this.minYear = options.minYear;

        if (typeof options.maxYear === 'number')
            this.maxYear = options.maxYear;

        if (typeof options.showCustomRangeLabel === 'boolean')
            this.showCustomRangeLabel = options.showCustomRangeLabel;

        if (typeof options.singleDatePicker === 'boolean') {
            this.singleDatePicker = options.singleDatePicker;
            if (this.singleDatePicker)
                this.endDate = this.startDate.clone();
        }

        if (typeof options.timePicker === 'boolean')
            this.timePicker = options.timePicker;

        if (typeof options.timePickerSeconds === 'boolean')
            this.timePickerSeconds = options.timePickerSeconds;

        if (typeof options.timePickerIncrement === 'number')
            this.timePickerIncrement = options.timePickerIncrement;

        if (typeof options.timePicker24Hour === 'boolean')
            this.timePicker24Hour = options.timePicker24Hour;

        if (typeof options.autoApply === 'boolean')
            this.autoApply = options.autoApply;

        if (typeof options.autoUpdateInput === 'boolean')
            this.autoUpdateInput = options.autoUpdateInput;

        if (typeof options.linkedCalendars === 'boolean')
            this.linkedCalendars = options.linkedCalendars;

        if (typeof options.isInvalidDate === 'function')
            this.isInvalidDate = options.isInvalidDate;

        if (typeof options.isCustomDate === 'function')
            this.isCustomDate = options.isCustomDate;

        if (typeof options.alwaysShowCalendars === 'boolean')
            this.alwaysShowCalendars = options.alwaysShowCalendars;

        // update day names order to firstDay
        if (this.locale.firstDay != 0) {
            var iterator = this.locale.firstDay;
            while (iterator > 0) {
                this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
                iterator--;
            }
        }

        var start, end, range;

        //if no start/end dates set, check if an input element contains initial values
        if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
            if ($(this.element).is(':text')) {
                var val = $(this.element).val(),
                    split = val.split(this.locale.separator);

                start = end = null;

                if (split.length == 2) {
                    start = moment(split[0], this.locale.format);
                    end = moment(split[1], this.locale.format);
                } else if (this.singleDatePicker && val !== "") {
                    start = moment(val, this.locale.format);
                    end = moment(val, this.locale.format);
                }
                if (start !== null && end !== null) {
                    this.setStartDate(start);
                    this.setEndDate(end);
                }
            }
        }

        if (typeof options.ranges === 'object') {
            for (range in options.ranges) {

                if (typeof options.ranges[range][0] === 'string')
                    start = moment(options.ranges[range][0], this.locale.format);
                else
                    start = moment(options.ranges[range][0]);

                if (typeof options.ranges[range][1] === 'string')
                    end = moment(options.ranges[range][1], this.locale.format);
                else
                    end = moment(options.ranges[range][1]);

                // If the start or end date exceed those allowed by the minDate or maxSpan
                // options, shorten the range to the allowable period.
                if (this.minDate && start.isBefore(this.minDate))
                    start = this.minDate.clone();

                var maxDate = this.maxDate;
                if (this.maxSpan && maxDate && start.clone().add(this.maxSpan).isAfter(maxDate))
                    maxDate = start.clone().add(this.maxSpan);
                if (maxDate && end.isAfter(maxDate))
                    end = maxDate.clone();

                // If the end of the range is before the minimum or the start of the range is
                // after the maximum, don't display this range option at all.
                if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day'))
                  || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))
                    continue;

                //Support unicode chars in the range names.
                var elem = document.createElement('textarea');
                elem.innerHTML = range;
                var rangeHtml = elem.value;

                this.ranges[rangeHtml] = [start, end];
            }

            var list = '<ul>';
            for (range in this.ranges) {
                list += '<li data-range-key="' + range + '">' + range + '</li>';
            }
            if (this.showCustomRangeLabel) {
                list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + '</li>';
            }
            list += '</ul>';
            this.container.find('.ranges').prepend(list);
        }

        if (typeof cb === 'function') {
            this.callback = cb;
        }

        if (!this.timePicker) {
            this.startDate = this.startDate.startOf('day');
            this.endDate = this.endDate.endOf('day');
            this.container.find('.calendar-time').hide();
        }

        //can't be used together for now
        if (this.timePicker && this.autoApply)
            this.autoApply = false;

        if (this.autoApply) {
            this.container.addClass('auto-apply');
        }

        if (typeof options.ranges === 'object')
            this.container.addClass('show-ranges');

        if (this.singleDatePicker) {
            this.container.addClass('single');
            this.container.find('.drp-calendar.left').addClass('single');
            this.container.find('.drp-calendar.left').show();
            this.container.find('.drp-calendar.right').hide();
            if (!this.timePicker) {
                this.container.addClass('auto-apply');
            }
        }

        if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) {
            this.container.addClass('show-calendar');
        }

        this.container.addClass('opens' + this.opens);

        //apply CSS classes and labels to buttons
        this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses);
        if (this.applyButtonClasses.length)
            this.container.find('.applyBtn').addClass(this.applyButtonClasses);
        if (this.cancelButtonClasses.length)
            this.container.find('.cancelBtn').addClass(this.cancelButtonClasses);
        this.container.find('.applyBtn').html(this.locale.applyLabel);
        this.container.find('.cancelBtn').html(this.locale.cancelLabel);

        //
        // event listeners
        //

        this.container.find('.drp-calendar')
            .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
            .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
            .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
            .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
            .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
            .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
            .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))

        this.container.find('.ranges')
            .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))

        this.container.find('.drp-buttons')
            .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
            .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))

        if (this.element.is('input') || this.element.is('button')) {
            this.element.on({
                'click.daterangepicker': $.proxy(this.show, this),
                'focus.daterangepicker': $.proxy(this.show, this),
                'keyup.daterangepicker': $.proxy(this.elementChanged, this),
                'keydown.daterangepicker': $.proxy(this.keydown, this) //IE 11 compatibility
            });
        } else {
            this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
            this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this));
        }

        //
        // if attached to a text input, set the initial value
        //

        this.updateElement();

    };

    DateRangePicker.prototype = {

        constructor: DateRangePicker,

        setStartDate: function(startDate) {
            if (typeof startDate === 'string')
                this.startDate = moment(startDate, this.locale.format);

            if (typeof startDate === 'object')
                this.startDate = moment(startDate);

            if (!this.timePicker)
                this.startDate = this.startDate.startOf('day');

            if (this.timePicker && this.timePickerIncrement)
                this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);

            if (this.minDate && this.startDate.isBefore(this.minDate)) {
                this.startDate = this.minDate.clone();
                if (this.timePicker && this.timePickerIncrement)
                    this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
            }

            if (this.maxDate && this.startDate.isAfter(this.maxDate)) {
                this.startDate = this.maxDate.clone();
                if (this.timePicker && this.timePickerIncrement)
                    this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
            }

            if (!this.isShowing)
                this.updateElement();

            this.updateMonthsInView();
        },

        setEndDate: function(endDate) {
            if (typeof endDate === 'string')
                this.endDate = moment(endDate, this.locale.format);

            if (typeof endDate === 'object')
                this.endDate = moment(endDate);

            if (!this.timePicker)
                this.endDate = this.endDate.endOf('day');

            if (this.timePicker && this.timePickerIncrement)
                this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);

            if (this.endDate.isBefore(this.startDate))
                this.endDate = this.startDate.clone();

            if (this.maxDate && this.endDate.isAfter(this.maxDate))
                this.endDate = this.maxDate.clone();

            if (this.maxSpan && this.startDate.clone().add(this.maxSpan).isBefore(this.endDate))
                this.endDate = this.startDate.clone().add(this.maxSpan);

            this.previousRightTime = this.endDate.clone();

            this.container.find('.drp-selected').html(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));

            if (!this.isShowing)
                this.updateElement();

            this.updateMonthsInView();
        },

        isInvalidDate: function() {
            return false;
        },

        isCustomDate: function() {
            return false;
        },

        updateView: function() {
            if (this.timePicker) {
                this.renderTimePicker('left');
                this.renderTimePicker('right');
                if (!this.endDate) {
                    this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');
                } else {
                    this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');
                }
            }
            if (this.endDate)
                this.container.find('.drp-selected').html(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
            this.updateMonthsInView();
            this.updateCalendars();
            this.updateFormInputs();
        },

        updateMonthsInView: function() {
            if (this.endDate) {

                //if both dates are visible already, do nothing
                if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&
                    (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
                    &&
                    (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
                    ) {
                    return;
                }

                this.leftCalendar.month = this.startDate.clone().date(2);
                if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) {
                    this.rightCalendar.month = this.endDate.clone().date(2);
                } else {
                    this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
                }

            } else {
                if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) {
                    this.leftCalendar.month = this.startDate.clone().date(2);
                    this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
                }
            }
            if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) {
              this.rightCalendar.month = this.maxDate.clone().date(2);
              this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month');
            }
        },

        updateCalendars: function() {

            if (this.timePicker) {
                var hour, minute, second;
                if (this.endDate) {
                    hour = parseInt(this.container.find('.left .hourselect').val(), 10);
                    minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
                    if (isNaN(minute)) {
                        minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10);
                    }
                    second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.left .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                } else {
                    hour = parseInt(this.container.find('.right .hourselect').val(), 10);
                    minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
                    if (isNaN(minute)) {
                        minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10);
                    }
                    second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.right .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                }
                this.leftCalendar.month.hour(hour).minute(minute).second(second);
                this.rightCalendar.month.hour(hour).minute(minute).second(second);
            }

            this.renderCalendar('left');
            this.renderCalendar('right');

            //highlight any predefined range matching the current start and end dates
            this.container.find('.ranges li').removeClass('active');
            if (this.endDate == null) return;

            this.calculateChosenLabel();
        },

        renderCalendar: function(side) {

            //
            // Build the matrix of dates that will populate the calendar
            //

            var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar;
            var month = calendar.month.month();
            var year = calendar.month.year();
            var hour = calendar.month.hour();
            var minute = calendar.month.minute();
            var second = calendar.month.second();
            var daysInMonth = moment([year, month]).daysInMonth();
            var firstDay = moment([year, month, 1]);
            var lastDay = moment([year, month, daysInMonth]);
            var lastMonth = moment(firstDay).subtract(1, 'month').month();
            var lastYear = moment(firstDay).subtract(1, 'month').year();
            var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
            var dayOfWeek = firstDay.day();

            //initialize a 6 rows x 7 columns array for the calendar
            var calendar = [];
            calendar.firstDay = firstDay;
            calendar.lastDay = lastDay;

            for (var i = 0; i < 6; i++) {
                calendar[i] = [];
            }

            //populate the calendar with date objects
            var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;
            if (startDay > daysInLastMonth)
                startDay -= 7;

            if (dayOfWeek == this.locale.firstDay)
                startDay = daysInLastMonth - 6;

            var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]);

            var col, row;
            for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {
                if (i > 0 && col % 7 === 0) {
                    col = 0;
                    row++;
                }
                calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);
                curDate.hour(12);

                if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {
                    calendar[row][col] = this.minDate.clone();
                }

                if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {
                    calendar[row][col] = this.maxDate.clone();
                }

            }

            //make the calendar object available to hoverDate/clickDate
            if (side == 'left') {
                this.leftCalendar.calendar = calendar;
            } else {
                this.rightCalendar.calendar = calendar;
            }

            //
            // Display the calendar
            //

            var minDate = side == 'left' ? this.minDate : this.startDate;
            var maxDate = this.maxDate;
            var selected = side == 'left' ? this.startDate : this.endDate;
            var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'};

            var html = '<table class="table-condensed">';
            html += '<thead>';
            html += '<tr>';

            // add empty cell for week number
            if (this.showWeekNumbers || this.showISOWeekNumbers)
                html += '<th></th>';

            if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) {
                html += '<th class="prev available"><span></span></th>';
            } else {
                html += '<th></th>';
            }

            var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");

            if (this.showDropdowns) {
                var currentMonth = calendar[1][1].month();
                var currentYear = calendar[1][1].year();
                var maxYear = (maxDate && maxDate.year()) || (this.maxYear);
                var minYear = (minDate && minDate.year()) || (this.minYear);
                var inMinYear = currentYear == minYear;
                var inMaxYear = currentYear == maxYear;

                var monthHtml = '<select class="monthselect">';
                for (var m = 0; m < 12; m++) {
                    if ((!inMinYear || (minDate && m >= minDate.month())) && (!inMaxYear || (maxDate && m <= maxDate.month()))) {
                        monthHtml += "<option value='" + m + "'" +
                            (m === currentMonth ? " selected='selected'" : "") +
                            ">" + this.locale.monthNames[m] + "</option>";
                    } else {
                        monthHtml += "<option value='" + m + "'" +
                            (m === currentMonth ? " selected='selected'" : "") +
                            " disabled='disabled'>" + this.locale.monthNames[m] + "</option>";
                    }
                }
                monthHtml += "</select>";

                var yearHtml = '<select class="yearselect">';
                for (var y = minYear; y <= maxYear; y++) {
                    yearHtml += '<option value="' + y + '"' +
                        (y === currentYear ? ' selected="selected"' : '') +
                        '>' + y + '</option>';
                }
                yearHtml += '</select>';

                dateHtml = monthHtml + yearHtml;
            }

            html += '<th colspan="5" class="month">' + dateHtml + '</th>';
            if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) {
                html += '<th class="next available"><span></span></th>';
            } else {
                html += '<th></th>';
            }

            html += '</tr>';
            html += '<tr>';

            // add week number label
            if (this.showWeekNumbers || this.showISOWeekNumbers)
                html += '<th class="week">' + this.locale.weekLabel + '</th>';

            $.each(this.locale.daysOfWeek, function(index, dayOfWeek) {
                html += '<th>' + dayOfWeek + '</th>';
            });

            html += '</tr>';
            html += '</thead>';
            html += '<tbody>';

            //adjust maxDate to reflect the maxSpan setting in order to
            //grey out end dates beyond the maxSpan
            if (this.endDate == null && this.maxSpan) {
                var maxLimit = this.startDate.clone().add(this.maxSpan).endOf('day');
                if (!maxDate || maxLimit.isBefore(maxDate)) {
                    maxDate = maxLimit;
                }
            }

            for (var row = 0; row < 6; row++) {
                html += '<tr>';

                // add week number
                if (this.showWeekNumbers)
                    html += '<td class="week">' + calendar[row][0].week() + '</td>';
                else if (this.showISOWeekNumbers)
                    html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>';

                for (var col = 0; col < 7; col++) {

                    var classes = [];

                    //highlight today's date
                    if (calendar[row][col].isSame(new Date(), "day"))
                        classes.push('today');

                    //highlight weekends
                    if (calendar[row][col].isoWeekday() > 5)
                        classes.push('weekend');

                    //grey out the dates in other months displayed at beginning and end of this calendar
                    if (calendar[row][col].month() != calendar[1][1].month())
                        classes.push('off', 'ends');

                    //don't allow selection of dates before the minimum date
                    if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))
                        classes.push('off', 'disabled');

                    //don't allow selection of dates after the maximum date
                    if (maxDate && calendar[row][col].isAfter(maxDate, 'day'))
                        classes.push('off', 'disabled');

                    //don't allow selection of date if a custom function decides it's invalid
                    if (this.isInvalidDate(calendar[row][col]))
                        classes.push('off', 'disabled');

                    //highlight the currently selected start date
                    if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD'))
                        classes.push('active', 'start-date');

                    //highlight the currently selected end date
                    if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD'))
                        classes.push('active', 'end-date');

                    //highlight dates in-between the selected dates
                    if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)
                        classes.push('in-range');

                    //apply custom classes for this date
                    var isCustom = this.isCustomDate(calendar[row][col]);
                    if (isCustom !== false) {
                        if (typeof isCustom === 'string')
                            classes.push(isCustom);
                        else
                            Array.prototype.push.apply(classes, isCustom);
                    }

                    var cname = '', disabled = false;
                    for (var i = 0; i < classes.length; i++) {
                        cname += classes[i] + ' ';
                        if (classes[i] == 'disabled')
                            disabled = true;
                    }
                    if (!disabled)
                        cname += 'available';

                    html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '">' + calendar[row][col].date() + '</td>';

                }
                html += '</tr>';
            }

            html += '</tbody>';
            html += '</table>';

            this.container.find('.drp-calendar.' + side + ' .calendar-table').html(html);

        },

        renderTimePicker: function(side) {

            // Don't bother updating the time picker if it's currently disabled
            // because an end date hasn't been clicked yet
            if (side == 'right' && !this.endDate) return;

            var html, selected, minDate, maxDate = this.maxDate;

            if (this.maxSpan && (!this.maxDate || this.startDate.clone().add(this.maxSpan).isBefore(this.maxDate)))
                maxDate = this.startDate.clone().add(this.maxSpan);

            if (side == 'left') {
                selected = this.startDate.clone();
                minDate = this.minDate;
            } else if (side == 'right') {
                selected = this.endDate.clone();
                minDate = this.startDate;

                //Preserve the time already selected
                var timeSelector = this.container.find('.drp-calendar.right .calendar-time');
                if (timeSelector.html() != '') {

                    selected.hour(!isNaN(selected.hour()) ? selected.hour() : timeSelector.find('.hourselect option:selected').val());
                    selected.minute(!isNaN(selected.minute()) ? selected.minute() : timeSelector.find('.minuteselect option:selected').val());
                    selected.second(!isNaN(selected.second()) ? selected.second() : timeSelector.find('.secondselect option:selected').val());

                    if (!this.timePicker24Hour) {
                        var ampm = timeSelector.find('.ampmselect option:selected').val();
                        if (ampm === 'PM' && selected.hour() < 12)
                            selected.hour(selected.hour() + 12);
                        if (ampm === 'AM' && selected.hour() === 12)
                            selected.hour(0);
                    }

                }

                if (selected.isBefore(this.startDate))
                    selected = this.startDate.clone();

                if (maxDate && selected.isAfter(maxDate))
                    selected = maxDate.clone();

            }

            //
            // hours
            //

            html = '<select class="hourselect">';

            var start = this.timePicker24Hour ? 0 : 1;
            var end = this.timePicker24Hour ? 23 : 12;

            for (var i = start; i <= end; i++) {
                var i_in_24 = i;
                if (!this.timePicker24Hour)
                    i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i);

                var time = selected.clone().hour(i_in_24);
                var disabled = false;
                if (minDate && time.minute(59).isBefore(minDate))
                    disabled = true;
                if (maxDate && time.minute(0).isAfter(maxDate))
                    disabled = true;

                if (i_in_24 == selected.hour() && !disabled) {
                    html += '<option value="' + i + '" selected="selected">' + i + '</option>';
                } else if (disabled) {
                    html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>';
                } else {
                    html += '<option value="' + i + '">' + i + '</option>';
                }
            }

            html += '</select> ';

            //
            // minutes
            //

            html += ': <select class="minuteselect">';

            for (var i = 0; i < 60; i += this.timePickerIncrement) {
                var padded = i < 10 ? '0' + i : i;
                var time = selected.clone().minute(i);

                var disabled = false;
                if (minDate && time.second(59).isBefore(minDate))
                    disabled = true;
                if (maxDate && time.second(0).isAfter(maxDate))
                    disabled = true;

                if (selected.minute() == i && !disabled) {
                    html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
                } else if (disabled) {
                    html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
                } else {
                    html += '<option value="' + i + '">' + padded + '</option>';
                }
            }

            html += '</select> ';

            //
            // seconds
            //

            if (this.timePickerSeconds) {
                html += ': <select class="secondselect">';

                for (var i = 0; i < 60; i++) {
                    var padded = i < 10 ? '0' + i : i;
                    var time = selected.clone().second(i);

                    var disabled = false;
                    if (minDate && time.isBefore(minDate))
                        disabled = true;
                    if (maxDate && time.isAfter(maxDate))
                        disabled = true;

                    if (selected.second() == i && !disabled) {
                        html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
                    } else if (disabled) {
                        html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
                    } else {
                        html += '<option value="' + i + '">' + padded + '</option>';
                    }
                }

                html += '</select> ';
            }

            //
            // AM/PM
            //

            if (!this.timePicker24Hour) {
                html += '<select class="ampmselect">';

                var am_html = '';
                var pm_html = '';

                if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate))
                    am_html = ' disabled="disabled" class="disabled"';

                if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate))
                    pm_html = ' disabled="disabled" class="disabled"';

                if (selected.hour() >= 12) {
                    html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>';
                } else {
                    html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>';
                }

                html += '</select>';
            }

            this.container.find('.drp-calendar.' + side + ' .calendar-time').html(html);

        },

        updateFormInputs: function() {

            if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {
                this.container.find('button.applyBtn').removeAttr('disabled');
            } else {
                this.container.find('button.applyBtn').attr('disabled', 'disabled');
            }

        },

        move: function() {
            var parentOffset = { top: 0, left: 0 },
                containerTop;
            var parentRightEdge = $(window).width();
            if (!this.parentEl.is('body')) {
                parentOffset = {
                    top: this.parentEl.offset().top - this.parentEl.scrollTop(),
                    left: this.parentEl.offset().left - this.parentEl.scrollLeft()
                };
                parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;
            }

            if (this.drops == 'up')
                containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
            else
                containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;

            // Force the container to it's actual width
            this.container.css({
              top: 0,
              left: 0,
              right: 'auto'
            });
            var containerWidth = this.container.outerWidth();

            this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('drop-up');

            if (this.opens == 'left') {
                var containerRight = parentRightEdge - this.element.offset().left - this.element.outerWidth();
                if (containerWidth + containerRight > $(window).width()) {
                    this.container.css({
                        top: containerTop,
                        right: 'auto',
                        left: 9
                    });
                } else {
                    this.container.css({
                        top: containerTop,
                        right: containerRight,
                        left: 'auto'
                    });
                }
            } else if (this.opens == 'center') {
                var containerLeft = this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2
                                        - containerWidth / 2;
                if (containerLeft < 0) {
                    this.container.css({
                        top: containerTop,
                        right: 'auto',
                        left: 9
                    });
                } else if (containerLeft + containerWidth > $(window).width()) {
                    this.container.css({
                        top: containerTop,
                        left: 'auto',
                        right: 0
                    });
                } else {
                    this.container.css({
                        top: containerTop,
                        left: containerLeft,
                        right: 'auto'
                    });
                }
            } else {
                var containerLeft = this.element.offset().left - parentOffset.left;
                if (containerLeft + containerWidth > $(window).width()) {
                    this.container.css({
                        top: containerTop,
                        left: 'auto',
                        right: 0
                    });
                } else {
                    this.container.css({
                        top: containerTop,
                        left: containerLeft,
                        right: 'auto'
                    });
                }
            }
        },

        show: function(e) {
            if (this.isShowing) return;

            // Create a click proxy that is private to this instance of datepicker, for unbinding
            this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this);

            // Bind global datepicker mousedown for hiding and
            $(document)
              .on('mousedown.daterangepicker', this._outsideClickProxy)
              // also support mobile devices
              .on('touchend.daterangepicker', this._outsideClickProxy)
              // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
              .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
              // and also close when focus changes to outside the picker (eg. tabbing between controls)
              .on('focusin.daterangepicker', this._outsideClickProxy);

            // Reposition the picker if the window is resized while it's open
            $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this));

            this.oldStartDate = this.startDate.clone();
            this.oldEndDate = this.endDate.clone();
            this.previousRightTime = this.endDate.clone();

            this.updateView();
            this.container.show();
            this.move();
            this.element.trigger('show.daterangepicker', this);
            this.isShowing = true;
        },

        hide: function(e) {
            if (!this.isShowing) return;

            //incomplete date selection, revert to last values
            if (!this.endDate) {
                this.startDate = this.oldStartDate.clone();
                this.endDate = this.oldEndDate.clone();
            }

            //if a new date range was selected, invoke the user callback function
            if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
                this.callback(this.startDate.clone(), this.endDate.clone(), this.chosenLabel);

            //if picker is attached to a text input, update it
            this.updateElement();

            $(document).off('.daterangepicker');
            $(window).off('.daterangepicker');
            this.container.hide();
            this.element.trigger('hide.daterangepicker', this);
            this.isShowing = false;
        },

        toggle: function(e) {
            if (this.isShowing) {
                this.hide();
            } else {
                this.show();
            }
        },

        outsideClick: function(e) {
            var target = $(e.target);
            // if the page is clicked anywhere except within the daterangerpicker/button
            // itself then call this.hide()
            if (
                // ie modal dialog fix
                e.type == "focusin" ||
                target.closest(this.element).length ||
                target.closest(this.container).length ||
                target.closest('.calendar-table').length
                ) return;
            this.hide();
            this.element.trigger('outsideClick.daterangepicker', this);
        },

        showCalendars: function() {
            this.container.addClass('show-calendar');
            this.move();
            this.element.trigger('showCalendar.daterangepicker', this);
        },

        hideCalendars: function() {
            this.container.removeClass('show-calendar');
            this.element.trigger('hideCalendar.daterangepicker', this);
        },

        clickRange: function(e) {
            var label = e.target.getAttribute('data-range-key');
            this.chosenLabel = label;
            if (label == this.locale.customRangeLabel) {
                this.showCalendars();
            } else {
                var dates = this.ranges[label];
                this.startDate = dates[0];
                this.endDate = dates[1];

                if (!this.timePicker) {
                    this.startDate.startOf('day');
                    this.endDate.endOf('day');
                }

                if (!this.alwaysShowCalendars)
                    this.hideCalendars();
                this.clickApply();
            }
        },

        clickPrev: function(e) {
            var cal = $(e.target).parents('.drp-calendar');
            if (cal.hasClass('left')) {
                this.leftCalendar.month.subtract(1, 'month');
                if (this.linkedCalendars)
                    this.rightCalendar.month.subtract(1, 'month');
            } else {
                this.rightCalendar.month.subtract(1, 'month');
            }
            this.updateCalendars();
        },

        clickNext: function(e) {
            var cal = $(e.target).parents('.drp-calendar');
            if (cal.hasClass('left')) {
                this.leftCalendar.month.add(1, 'month');
            } else {
                this.rightCalendar.month.add(1, 'month');
                if (this.linkedCalendars)
                    this.leftCalendar.month.add(1, 'month');
            }
            this.updateCalendars();
        },

        hoverDate: function(e) {

            //ignore dates that can't be selected
            if (!$(e.target).hasClass('available')) return;

            var title = $(e.target).attr('data-title');
            var row = title.substr(1, 1);
            var col = title.substr(3, 1);
            var cal = $(e.target).parents('.drp-calendar');
            var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];

            //highlight the dates between the start date and the date being hovered as a potential end date
            var leftCalendar = this.leftCalendar;
            var rightCalendar = this.rightCalendar;
            var startDate = this.startDate;
            if (!this.endDate) {
                this.container.find('.drp-calendar tbody td').each(function(index, el) {

                    //skip week numbers, only look at dates
                    if ($(el).hasClass('week')) return;

                    var title = $(el).attr('data-title');
                    var row = title.substr(1, 1);
                    var col = title.substr(3, 1);
                    var cal = $(el).parents('.drp-calendar');
                    var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];

                    if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {
                        $(el).addClass('in-range');
                    } else {
                        $(el).removeClass('in-range');
                    }

                });
            }

        },

        clickDate: function(e) {

            if (!$(e.target).hasClass('available')) return;

            var title = $(e.target).attr('data-title');
            var row = title.substr(1, 1);
            var col = title.substr(3, 1);
            var cal = $(e.target).parents('.drp-calendar');
            var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];

            //
            // this function needs to do a few things:
            // * alternate between selecting a start and end date for the range,
            // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date
            // * if autoapply is enabled, and an end date was chosen, apply the selection
            // * if single date picker mode, and time picker isn't enabled, apply the selection immediately
            // * if one of the inputs above the calendars was focused, cancel that manual input
            //

            if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start
                if (this.timePicker) {
                    var hour = parseInt(this.container.find('.left .hourselect').val(), 10);
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.left .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                    var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
                    if (isNaN(minute)) {
                        minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10);
                    }
                    var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
                    date = date.clone().hour(hour).minute(minute).second(second);
                }
                this.endDate = null;
                this.setStartDate(date.clone());
            } else if (!this.endDate && date.isBefore(this.startDate)) {
                //special case: clicking the same date for start/end,
                //but the time of the end date is before the start date
                this.setEndDate(this.startDate.clone());
            } else { // picking end
                if (this.timePicker) {
                    var hour = parseInt(this.container.find('.right .hourselect').val(), 10);
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.right .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                    var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
                    if (isNaN(minute)) {
                        minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10);
                    }
                    var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
                    date = date.clone().hour(hour).minute(minute).second(second);
                }
                this.setEndDate(date.clone());
                if (this.autoApply) {
                  this.calculateChosenLabel();
                  this.clickApply();
                }
            }

            if (this.singleDatePicker) {
                this.setEndDate(this.startDate);
                if (!this.timePicker)
                    this.clickApply();
            }

            this.updateView();

            //This is to cancel the blur event handler if the mouse was in one of the inputs
            e.stopPropagation();

        },

        calculateChosenLabel: function () {
            var customRange = true;
            var i = 0;
            for (var range in this.ranges) {
              if (this.timePicker) {
                    var format = this.timePickerSeconds ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD HH:mm";
                    //ignore times when comparing dates if time picker seconds is not enabled
                    if (this.startDate.format(format) == this.ranges[range][0].format(format) && this.endDate.format(format) == this.ranges[range][1].format(format)) {
                        customRange = false;
                        this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').attr('data-range-key');
                        break;
                    }
                } else {
                    //ignore times when comparing dates if time picker is not enabled
                    if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) {
                        customRange = false;
                        this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').attr('data-range-key');
                        break;
                    }
                }
                i++;
            }
            if (customRange) {
                if (this.showCustomRangeLabel) {
                    this.chosenLabel = this.container.find('.ranges li:last').addClass('active').attr('data-range-key');
                } else {
                    this.chosenLabel = null;
                }
                this.showCalendars();
            }
        },

        clickApply: function(e) {
            this.hide();
            this.element.trigger('apply.daterangepicker', this);
        },

        clickCancel: function(e) {
            this.startDate = this.oldStartDate;
            this.endDate = this.oldEndDate;
            this.hide();
            this.element.trigger('cancel.daterangepicker', this);
        },

        monthOrYearChanged: function(e) {
            var isLeft = $(e.target).closest('.drp-calendar').hasClass('left'),
                leftOrRight = isLeft ? 'left' : 'right',
                cal = this.container.find('.drp-calendar.'+leftOrRight);

            // Month must be Number for new moment versions
            var month = parseInt(cal.find('.monthselect').val(), 10);
            var year = cal.find('.yearselect').val();

            if (!isLeft) {
                if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {
                    month = this.startDate.month();
                    year = this.startDate.year();
                }
            }

            if (this.minDate) {
                if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {
                    month = this.minDate.month();
                    year = this.minDate.year();
                }
            }

            if (this.maxDate) {
                if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {
                    month = this.maxDate.month();
                    year = this.maxDate.year();
                }
            }

            if (isLeft) {
                this.leftCalendar.month.month(month).year(year);
                if (this.linkedCalendars)
                    this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month');
            } else {
                this.rightCalendar.month.month(month).year(year);
                if (this.linkedCalendars)
                    this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month');
            }
            this.updateCalendars();
        },

        timeChanged: function(e) {

            var cal = $(e.target).closest('.drp-calendar'),
                isLeft = cal.hasClass('left');

            var hour = parseInt(cal.find('.hourselect').val(), 10);
            var minute = parseInt(cal.find('.minuteselect').val(), 10);
            if (isNaN(minute)) {
                minute = parseInt(cal.find('.minuteselect option:last').val(), 10);
            }
            var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;

            if (!this.timePicker24Hour) {
                var ampm = cal.find('.ampmselect').val();
                if (ampm === 'PM' && hour < 12)
                    hour += 12;
                if (ampm === 'AM' && hour === 12)
                    hour = 0;
            }

            if (isLeft) {
                var start = this.startDate.clone();
                start.hour(hour);
                start.minute(minute);
                start.second(second);
                this.setStartDate(start);
                if (this.singleDatePicker) {
                    this.endDate = this.startDate.clone();
                } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) {
                    this.setEndDate(start.clone());
                }
            } else if (this.endDate) {
                var end = this.endDate.clone();
                end.hour(hour);
                end.minute(minute);
                end.second(second);
                this.setEndDate(end);
            }

            //update the calendars so all clickable dates reflect the new time component
            this.updateCalendars();

            //update the form inputs above the calendars with the new time
            this.updateFormInputs();

            //re-render the time pickers because changing one selection can affect what's enabled in another
            this.renderTimePicker('left');
            this.renderTimePicker('right');

        },

        elementChanged: function() {
            if (!this.element.is('input')) return;
            if (!this.element.val().length) return;

            var dateString = this.element.val().split(this.locale.separator),
                start = null,
                end = null;

            if (dateString.length === 2) {
                start = moment(dateString[0], this.locale.format);
                end = moment(dateString[1], this.locale.format);
            }

            if (this.singleDatePicker || start === null || end === null) {
                start = moment(this.element.val(), this.locale.format);
                end = start;
            }

            if (!start.isValid() || !end.isValid()) return;

            this.setStartDate(start);
            this.setEndDate(end);
            this.updateView();
        },

        keydown: function(e) {
            //hide on tab or enter
            if ((e.keyCode === 9) || (e.keyCode === 13)) {
                this.hide();
            }

            //hide on esc and prevent propagation
            if (e.keyCode === 27) {
                e.preventDefault();
                e.stopPropagation();

                this.hide();
            }
        },

        updateElement: function() {
            if (this.element.is('input') && this.autoUpdateInput) {
                var newValue = this.startDate.format(this.locale.format);
                if (!this.singleDatePicker) {
                    newValue += this.locale.separator + this.endDate.format(this.locale.format);
                }
                if (newValue !== this.element.val()) {
                    this.element.val(newValue).trigger('change');
                }
            }
        },

        remove: function() {
            this.container.remove();
            this.element.off('.daterangepicker');
            this.element.removeData();
        }

    };

    $.fn.daterangepicker = function(options, callback) {
        var implementOptions = $.extend(true, {}, $.fn.daterangepicker.defaultOptions, options);
        this.each(function() {
            var el = $(this);
            if (el.data('daterangepicker'))
                el.data('daterangepicker').remove();
            el.data('daterangepicker', new DateRangePicker(el, implementOptions, callback));
        });
        return this;
    };

    return DateRangePicker;

}));

/*! rangeslider.js - v2.3.2 | (c) 2018 @andreruffert | MIT license | https://github.com/andreruffert/rangeslider.js */
(function(factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function($) {
    'use strict';

    // Polyfill Number.isNaN(value)
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
    Number.isNaN = Number.isNaN || function(value) {
        return typeof value === 'number' && value !== value;
    };

    /**
     * Range feature detection
     * @return {Boolean}
     */
    function supportsRange() {
        var input = document.createElement('input');
        input.setAttribute('type', 'range');
        return input.type !== 'text';
    }

    var pluginName = 'rangeslider',
        pluginIdentifier = 0,
        hasInputRangeSupport = supportsRange(),
        defaults = {
            polyfill: true,
            orientation: 'horizontal',
            rangeClass: 'rangeslider',
            disabledClass: 'rangeslider--disabled',
            activeClass: 'rangeslider--active',
            horizontalClass: 'rangeslider--horizontal',
            verticalClass: 'rangeslider--vertical',
            fillClass: 'rangeslider__fill',
            handleClass: 'rangeslider__handle',
            startEvent: ['mousedown', 'touchstart', 'pointerdown'],
            moveEvent: ['mousemove', 'touchmove', 'pointermove'],
            endEvent: ['mouseup', 'touchend', 'pointerup']
        },
        constants = {
            orientation: {
                horizontal: {
                    dimension: 'width',
                    direction: 'left',
                    directionStyle: 'left',
                    coordinate: 'x'
                },
                vertical: {
                    dimension: 'height',
                    direction: 'top',
                    directionStyle: 'bottom',
                    coordinate: 'y'
                }
            }
        };

    /**
     * Delays a function for the given number of milliseconds, and then calls
     * it with the arguments supplied.
     *
     * @param  {Function} fn   [description]
     * @param  {Number}   wait [description]
     * @return {Function}
     */
    function delay(fn, wait) {
        var args = Array.prototype.slice.call(arguments, 2);
        return setTimeout(function(){ return fn.apply(null, args); }, wait);
    }

    /**
     * Returns a debounced function that will make sure the given
     * function is not triggered too much.
     *
     * @param  {Function} fn Function to debounce.
     * @param  {Number}   debounceDuration OPTIONAL. The amount of time in milliseconds for which we will debounce the function. (defaults to 100ms)
     * @return {Function}
     */
    function debounce(fn, debounceDuration) {
        debounceDuration = debounceDuration || 100;
        return function() {
            if (!fn.debouncing) {
                var args = Array.prototype.slice.apply(arguments);
                fn.lastReturnVal = fn.apply(window, args);
                fn.debouncing = true;
            }
            clearTimeout(fn.debounceTimeout);
            fn.debounceTimeout = setTimeout(function(){
                fn.debouncing = false;
            }, debounceDuration);
            return fn.lastReturnVal;
        };
    }

    /**
     * Check if a `element` is visible in the DOM
     *
     * @param  {Element}  element
     * @return {Boolean}
     */
    function isHidden(element) {
        return (
            element && (
                element.offsetWidth === 0 ||
                element.offsetHeight === 0 ||
                // Also Consider native `<details>` elements.
                element.open === false
            )
        );
    }

    /**
     * Get hidden parentNodes of an `element`
     *
     * @param  {Element} element
     * @return {[type]}
     */
    function getHiddenParentNodes(element) {
        var parents = [],
            node    = element.parentNode;

        while (isHidden(node)) {
            parents.push(node);
            node = node.parentNode;
        }
        return parents;
    }

    /**
     * Returns dimensions for an element even if it is not visible in the DOM.
     *
     * @param  {Element} element
     * @param  {String}  key     (e.g. offsetWidth …)
     * @return {Number}
     */
    function getDimension(element, key) {
        var hiddenParentNodes       = getHiddenParentNodes(element),
            hiddenParentNodesLength = hiddenParentNodes.length,
            inlineStyle             = [],
            dimension               = element[key];

        // Used for native `<details>` elements
        function toggleOpenProperty(element) {
            if (typeof element.open !== 'undefined') {
                element.open = (element.open) ? false : true;
            }
        }

        if (hiddenParentNodesLength) {
            for (var i = 0; i < hiddenParentNodesLength; i++) {

                // Cache style attribute to restore it later.
                inlineStyle[i] = hiddenParentNodes[i].style.cssText;

                // visually hide
                if (hiddenParentNodes[i].style.setProperty) {
                    hiddenParentNodes[i].style.setProperty('display', 'block', 'important');
                } else {
                    hiddenParentNodes[i].style.cssText += ';display: block !important';
                }
                hiddenParentNodes[i].style.height = '0';
                hiddenParentNodes[i].style.overflow = 'hidden';
                hiddenParentNodes[i].style.visibility = 'hidden';
                toggleOpenProperty(hiddenParentNodes[i]);
            }

            // Update dimension
            dimension = element[key];

            for (var j = 0; j < hiddenParentNodesLength; j++) {

                // Restore the style attribute
                hiddenParentNodes[j].style.cssText = inlineStyle[j];
                toggleOpenProperty(hiddenParentNodes[j]);
            }
        }
        return dimension;
    }

    /**
     * Returns the parsed float or the default if it failed.
     *
     * @param  {String}  str
     * @param  {Number}  defaultValue
     * @return {Number}
     */
    function tryParseFloat(str, defaultValue) {
        var value = parseFloat(str);
        return Number.isNaN(value) ? defaultValue : value;
    }

    /**
     * Capitalize the first letter of string
     *
     * @param  {String} str
     * @return {String}
     */
    function ucfirst(str) {
        return str.charAt(0).toUpperCase() + str.substr(1);
    }

    /**
     * Plugin
     * @param {String} element
     * @param {Object} options
     */
    function Plugin(element, options) {
        this.$window            = $(window);
        this.$document          = $(document);
        this.$element           = $(element);
        this.options            = $.extend( {}, defaults, options );
        this.polyfill           = this.options.polyfill;
        this.orientation        = this.$element[0].getAttribute('data-orientation') || this.options.orientation;
        this.onInit             = this.options.onInit;
        this.onSlide            = this.options.onSlide;
        this.onSlideEnd         = this.options.onSlideEnd;
        this.DIMENSION          = constants.orientation[this.orientation].dimension;
        this.DIRECTION          = constants.orientation[this.orientation].direction;
        this.DIRECTION_STYLE    = constants.orientation[this.orientation].directionStyle;
        this.COORDINATE         = constants.orientation[this.orientation].coordinate;

        // Plugin should only be used as a polyfill
        if (this.polyfill) {
            // Input range support?
            if (hasInputRangeSupport) { return false; }
        }

        this.identifier = 'js-' + pluginName + '-' +(pluginIdentifier++);
        this.startEvent = this.options.startEvent.join('.' + this.identifier + ' ') + '.' + this.identifier;
        this.moveEvent  = this.options.moveEvent.join('.' + this.identifier + ' ') + '.' + this.identifier;
        this.endEvent   = this.options.endEvent.join('.' + this.identifier + ' ') + '.' + this.identifier;
        this.toFixed    = (this.step + '').replace('.', '').length - 1;
        this.$fill      = $('<div class="' + this.options.fillClass + '" />');
        this.$handle    = $('<div class="' + this.options.handleClass + '" />');
        this.$range     = $('<div class="' + this.options.rangeClass + ' ' + this.options[this.orientation + 'Class'] + '" id="' + this.identifier + '" />').insertAfter(this.$element).prepend(this.$fill, this.$handle);

        // visually hide the input
        this.$element.css({
            'position': 'absolute',
            'width': '1px',
            'height': '1px',
            'overflow': 'hidden',
            'opacity': '0'
        });

        // Store context
        this.handleDown = $.proxy(this.handleDown, this);
        this.handleMove = $.proxy(this.handleMove, this);
        this.handleEnd  = $.proxy(this.handleEnd, this);

        this.init();

        // Attach Events
        var _this = this;
        this.$window.on('resize.' + this.identifier, debounce(function() {
            // Simulate resizeEnd event.
            delay(function() { _this.update(false, false); }, 300);
        }, 20));

        this.$document.on(this.startEvent, '#' + this.identifier + ':not(.' + this.options.disabledClass + ')', this.handleDown);

        // Listen to programmatic value changes
        this.$element.on('change.' + this.identifier, function(e, data) {
            if (data && data.origin === _this.identifier) {
                return;
            }

            var value = e.target.value,
                pos = _this.getPositionFromValue(value);
            _this.setPosition(pos);
        });
    }

    Plugin.prototype.init = function() {
        this.update(true, false);

        if (this.onInit && typeof this.onInit === 'function') {
            this.onInit();
        }
    };

    Plugin.prototype.update = function(updateAttributes, triggerSlide) {
        updateAttributes = updateAttributes || false;

        if (updateAttributes) {
            this.min    = tryParseFloat(this.$element[0].getAttribute('min'), 0);
            this.max    = tryParseFloat(this.$element[0].getAttribute('max'), 100);
            this.value  = tryParseFloat(this.$element[0].value, Math.round(this.min + (this.max-this.min)/2));
            this.step   = tryParseFloat(this.$element[0].getAttribute('step'), 1);
        }

        this.handleDimension    = getDimension(this.$handle[0], 'offset' + ucfirst(this.DIMENSION));
        this.rangeDimension     = getDimension(this.$range[0], 'offset' + ucfirst(this.DIMENSION));
        this.maxHandlePos       = this.rangeDimension - this.handleDimension;
        this.grabPos            = this.handleDimension / 2;
        this.position           = this.getPositionFromValue(this.value);

        // Consider disabled state
        if (this.$element[0].disabled) {
            this.$range.addClass(this.options.disabledClass);
        } else {
            this.$range.removeClass(this.options.disabledClass);
        }

        this.setPosition(this.position, triggerSlide);
    };

    Plugin.prototype.handleDown = function(e) {
        e.preventDefault();

        // Only respond to mouse main button clicks (usually the left button)
        if (e.button && e.button !== 0) { return; }

        this.$document.on(this.moveEvent, this.handleMove);
        this.$document.on(this.endEvent, this.handleEnd);

        // add active class because Firefox is ignoring
        // the handle:active pseudo selector because of `e.preventDefault();`
        this.$range.addClass(this.options.activeClass);

        // If we click on the handle don't set the new position
        if ((' ' + e.target.className + ' ').replace(/[\n\t]/g, ' ').indexOf(this.options.handleClass) > -1) {
            return;
        }

        var pos         = this.getRelativePosition(e),
            rangePos    = this.$range[0].getBoundingClientRect()[this.DIRECTION],
            handlePos   = this.getPositionFromNode(this.$handle[0]) - rangePos,
            setPos      = (this.orientation === 'vertical') ? (this.maxHandlePos - (pos - this.grabPos)) : (pos - this.grabPos);

        this.setPosition(setPos);

        if (pos >= handlePos && pos < handlePos + this.handleDimension) {
            this.grabPos = pos - handlePos;
        }
    };

    Plugin.prototype.handleMove = function(e) {
        e.preventDefault();
        var pos = this.getRelativePosition(e);
        var setPos = (this.orientation === 'vertical') ? (this.maxHandlePos - (pos - this.grabPos)) : (pos - this.grabPos);
        this.setPosition(setPos);
    };

    Plugin.prototype.handleEnd = function(e) {
        e.preventDefault();
        this.$document.off(this.moveEvent, this.handleMove);
        this.$document.off(this.endEvent, this.handleEnd);

        this.$range.removeClass(this.options.activeClass);

        // Ok we're done fire the change event
        this.$element.trigger('change', { origin: this.identifier });

        if (this.onSlideEnd && typeof this.onSlideEnd === 'function') {
            this.onSlideEnd(this.position, this.value);
        }
    };

    Plugin.prototype.cap = function(pos, min, max) {
        if (pos < min) { return min; }
        if (pos > max) { return max; }
        return pos;
    };

    Plugin.prototype.setPosition = function(pos, triggerSlide) {
        var value, newPos;

        if (triggerSlide === undefined) {
            triggerSlide = true;
        }

        // Snapping steps
        value = this.getValueFromPosition(this.cap(pos, 0, this.maxHandlePos));
        newPos = this.getPositionFromValue(value);

        // Update ui
        this.$fill[0].style[this.DIMENSION] = (newPos + this.grabPos) + 'px';
        this.$handle[0].style[this.DIRECTION_STYLE] = newPos + 'px';
        this.setValue(value);

        // Update globals
        this.position = newPos;
        this.value = value;

        if (triggerSlide && this.onSlide && typeof this.onSlide === 'function') {
            this.onSlide(newPos, value);
        }
    };

    // Returns element position relative to the parent
    Plugin.prototype.getPositionFromNode = function(node) {
        var i = 0;
        while (node !== null) {
            i += node.offsetLeft;
            node = node.offsetParent;
        }
        return i;
    };

    Plugin.prototype.getRelativePosition = function(e) {
        // Get the offset DIRECTION relative to the viewport
        var ucCoordinate = ucfirst(this.COORDINATE),
            rangePos = this.$range[0].getBoundingClientRect()[this.DIRECTION],
            pageCoordinate = 0;

        if (typeof e.originalEvent['client' + ucCoordinate] !== 'undefined') {
            pageCoordinate = e.originalEvent['client' + ucCoordinate];
        }
        else if (
          e.originalEvent.touches &&
          e.originalEvent.touches[0] &&
          typeof e.originalEvent.touches[0]['client' + ucCoordinate] !== 'undefined'
        ) {
            pageCoordinate = e.originalEvent.touches[0]['client' + ucCoordinate];
        }
        else if(e.currentPoint && typeof e.currentPoint[this.COORDINATE] !== 'undefined') {
            pageCoordinate = e.currentPoint[this.COORDINATE];
        }

        return pageCoordinate - rangePos;
    };

    Plugin.prototype.getPositionFromValue = function(value) {
        var percentage, pos;
        percentage = (value - this.min)/(this.max - this.min);
        pos = (!Number.isNaN(percentage)) ? percentage * this.maxHandlePos : 0;
        return pos;
    };

    Plugin.prototype.getValueFromPosition = function(pos) {
        var percentage, value;
        percentage = ((pos) / (this.maxHandlePos || 1));
        value = this.step * Math.round(percentage * (this.max - this.min) / this.step) + this.min;
        return Number((value).toFixed(this.toFixed));
    };

    Plugin.prototype.setValue = function(value) {
        if (value === this.value && this.$element[0].value !== '') {
            return;
        }

        // Set the new value and fire the `input` event
        this.$element
            .val(value)
            .trigger('input', { origin: this.identifier });
    };

    Plugin.prototype.destroy = function() {
        this.$document.off('.' + this.identifier);
        this.$window.off('.' + this.identifier);

        this.$element
            .off('.' + this.identifier)
            .removeAttr('style')
            .removeData('plugin_' + pluginName);

        // Remove the generated markup
        if (this.$range && this.$range.length) {
            this.$range[0].parentNode.removeChild(this.$range[0]);
        }
    };

    // A really lightweight plugin wrapper around the constructor,
    // preventing against multiple instantiations
    $.fn[pluginName] = function(options) {
        var args = Array.prototype.slice.call(arguments, 1);

        return this.each(function() {
            var $this = $(this),
                data  = $this.data('plugin_' + pluginName);

            // Create a new instance.
            if (!data) {
                $this.data('plugin_' + pluginName, (data = new Plugin(this, options)));
            }

            // Make it possible to access methods from public.
            // e.g `$element.rangeslider('method');`
            if (typeof options === 'string') {
                data[options].apply(data, args);
            }
        });
    };

    return 'rangeslider.js is available in jQuery context e.g $(selector).rangeslider(options);';

}));

/**!
 * Sortable 1.15.6
 * @author	RubaXa   <trash@rubaxa.org>
 * @author	owenm    <owen23355@gmail.com>
 * @license MIT
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.Sortable = factory());
}(this, (function () { 'use strict';

  function ownKeys(object, enumerableOnly) {
    var keys = Object.keys(object);
    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      if (enumerableOnly) {
        symbols = symbols.filter(function (sym) {
          return Object.getOwnPropertyDescriptor(object, sym).enumerable;
        });
      }
      keys.push.apply(keys, symbols);
    }
    return keys;
  }
  function _objectSpread2(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};
      if (i % 2) {
        ownKeys(Object(source), true).forEach(function (key) {
          _defineProperty(target, key, source[key]);
        });
      } else if (Object.getOwnPropertyDescriptors) {
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
      } else {
        ownKeys(Object(source)).forEach(function (key) {
          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
        });
      }
    }
    return target;
  }
  function _typeof(obj) {
    "@babel/helpers - typeof";

    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
      _typeof = function (obj) {
        return typeof obj;
      };
    } else {
      _typeof = function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
      };
    }
    return _typeof(obj);
  }
  function _defineProperty(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;
  }
  function _extends() {
    _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;
    };
    return _extends.apply(this, arguments);
  }
  function _objectWithoutPropertiesLoose(source, excluded) {
    if (source == null) return {};
    var target = {};
    var sourceKeys = Object.keys(source);
    var key, i;
    for (i = 0; i < sourceKeys.length; i++) {
      key = sourceKeys[i];
      if (excluded.indexOf(key) >= 0) continue;
      target[key] = source[key];
    }
    return target;
  }
  function _objectWithoutProperties(source, excluded) {
    if (source == null) return {};
    var target = _objectWithoutPropertiesLoose(source, excluded);
    var key, i;
    if (Object.getOwnPropertySymbols) {
      var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
      for (i = 0; i < sourceSymbolKeys.length; i++) {
        key = sourceSymbolKeys[i];
        if (excluded.indexOf(key) >= 0) continue;
        if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
        target[key] = source[key];
      }
    }
    return target;
  }
  function _toConsumableArray(arr) {
    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
  }
  function _arrayWithoutHoles(arr) {
    if (Array.isArray(arr)) return _arrayLikeToArray(arr);
  }
  function _iterableToArray(iter) {
    if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
  }
  function _unsupportedIterableToArray(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _arrayLikeToArray(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(o);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
  }
  function _arrayLikeToArray(arr, len) {
    if (len == null || len > arr.length) len = arr.length;
    for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
    return arr2;
  }
  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }

  var version = "1.15.6";

  function userAgent(pattern) {
    if (typeof window !== 'undefined' && window.navigator) {
      return !! /*@__PURE__*/navigator.userAgent.match(pattern);
    }
  }
  var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
  var Edge = userAgent(/Edge/i);
  var FireFox = userAgent(/firefox/i);
  var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
  var IOS = userAgent(/iP(ad|od|hone)/i);
  var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);

  var captureMode = {
    capture: false,
    passive: false
  };
  function on(el, event, fn) {
    el.addEventListener(event, fn, !IE11OrLess && captureMode);
  }
  function off(el, event, fn) {
    el.removeEventListener(event, fn, !IE11OrLess && captureMode);
  }
  function matches( /**HTMLElement*/el, /**String*/selector) {
    if (!selector) return;
    selector[0] === '>' && (selector = selector.substring(1));
    if (el) {
      try {
        if (el.matches) {
          return el.matches(selector);
        } else if (el.msMatchesSelector) {
          return el.msMatchesSelector(selector);
        } else if (el.webkitMatchesSelector) {
          return el.webkitMatchesSelector(selector);
        }
      } catch (_) {
        return false;
      }
    }
    return false;
  }
  function getParentOrHost(el) {
    return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
  }
  function closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {
    if (el) {
      ctx = ctx || document;
      do {
        if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
          return el;
        }
        if (el === ctx) break;
        /* jshint boss:true */
      } while (el = getParentOrHost(el));
    }
    return null;
  }
  var R_SPACE = /\s+/g;
  function toggleClass(el, name, state) {
    if (el && name) {
      if (el.classList) {
        el.classList[state ? 'add' : 'remove'](name);
      } else {
        var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
        el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
      }
    }
  }
  function css(el, prop, val) {
    var style = el && el.style;
    if (style) {
      if (val === void 0) {
        if (document.defaultView && document.defaultView.getComputedStyle) {
          val = document.defaultView.getComputedStyle(el, '');
        } else if (el.currentStyle) {
          val = el.currentStyle;
        }
        return prop === void 0 ? val : val[prop];
      } else {
        if (!(prop in style) && prop.indexOf('webkit') === -1) {
          prop = '-webkit-' + prop;
        }
        style[prop] = val + (typeof val === 'string' ? '' : 'px');
      }
    }
  }
  function matrix(el, selfOnly) {
    var appliedTransforms = '';
    if (typeof el === 'string') {
      appliedTransforms = el;
    } else {
      do {
        var transform = css(el, 'transform');
        if (transform && transform !== 'none') {
          appliedTransforms = transform + ' ' + appliedTransforms;
        }
        /* jshint boss:true */
      } while (!selfOnly && (el = el.parentNode));
    }
    var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
    /*jshint -W056 */
    return matrixFn && new matrixFn(appliedTransforms);
  }
  function find(ctx, tagName, iterator) {
    if (ctx) {
      var list = ctx.getElementsByTagName(tagName),
        i = 0,
        n = list.length;
      if (iterator) {
        for (; i < n; i++) {
          iterator(list[i], i);
        }
      }
      return list;
    }
    return [];
  }
  function getWindowScrollingElement() {
    var scrollingElement = document.scrollingElement;
    if (scrollingElement) {
      return scrollingElement;
    } else {
      return document.documentElement;
    }
  }

  /**
   * Returns the "bounding client rect" of given element
   * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
   * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
   * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
   * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
   * @param  {[HTMLElement]} container              The parent the element will be placed in
   * @return {Object}                               The boundingClientRect of el, with specified adjustments
   */
  function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
    if (!el.getBoundingClientRect && el !== window) return;
    var elRect, top, left, bottom, right, height, width;
    if (el !== window && el.parentNode && el !== getWindowScrollingElement()) {
      elRect = el.getBoundingClientRect();
      top = elRect.top;
      left = elRect.left;
      bottom = elRect.bottom;
      right = elRect.right;
      height = elRect.height;
      width = elRect.width;
    } else {
      top = 0;
      left = 0;
      bottom = window.innerHeight;
      right = window.innerWidth;
      height = window.innerHeight;
      width = window.innerWidth;
    }
    if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
      // Adjust for translate()
      container = container || el.parentNode;

      // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
      // Not needed on <= IE11
      if (!IE11OrLess) {
        do {
          if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
            var containerRect = container.getBoundingClientRect();

            // Set relative to edges of padding box of container
            top -= containerRect.top + parseInt(css(container, 'border-top-width'));
            left -= containerRect.left + parseInt(css(container, 'border-left-width'));
            bottom = top + elRect.height;
            right = left + elRect.width;
            break;
          }
          /* jshint boss:true */
        } while (container = container.parentNode);
      }
    }
    if (undoScale && el !== window) {
      // Adjust for scale()
      var elMatrix = matrix(container || el),
        scaleX = elMatrix && elMatrix.a,
        scaleY = elMatrix && elMatrix.d;
      if (elMatrix) {
        top /= scaleY;
        left /= scaleX;
        width /= scaleX;
        height /= scaleY;
        bottom = top + height;
        right = left + width;
      }
    }
    return {
      top: top,
      left: left,
      bottom: bottom,
      right: right,
      width: width,
      height: height
    };
  }

  /**
   * Checks if a side of an element is scrolled past a side of its parents
   * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
   * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
   * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
   * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
   */
  function isScrolledPast(el, elSide, parentSide) {
    var parent = getParentAutoScrollElement(el, true),
      elSideVal = getRect(el)[elSide];

    /* jshint boss:true */
    while (parent) {
      var parentSideVal = getRect(parent)[parentSide],
        visible = void 0;
      if (parentSide === 'top' || parentSide === 'left') {
        visible = elSideVal >= parentSideVal;
      } else {
        visible = elSideVal <= parentSideVal;
      }
      if (!visible) return parent;
      if (parent === getWindowScrollingElement()) break;
      parent = getParentAutoScrollElement(parent, false);
    }
    return false;
  }

  /**
   * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
   * and non-draggable elements
   * @param  {HTMLElement} el       The parent element
   * @param  {Number} childNum      The index of the child
   * @param  {Object} options       Parent Sortable's options
   * @return {HTMLElement}          The child at index childNum, or null if not found
   */
  function getChild(el, childNum, options, includeDragEl) {
    var currentChild = 0,
      i = 0,
      children = el.children;
    while (i < children.length) {
      if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) {
        if (currentChild === childNum) {
          return children[i];
        }
        currentChild++;
      }
      i++;
    }
    return null;
  }

  /**
   * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
   * @param  {HTMLElement} el       Parent element
   * @param  {selector} selector    Any other elements that should be ignored
   * @return {HTMLElement}          The last child, ignoring ghostEl
   */
  function lastChild(el, selector) {
    var last = el.lastElementChild;
    while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
      last = last.previousElementSibling;
    }
    return last || null;
  }

  /**
   * Returns the index of an element within its parent for a selected set of
   * elements
   * @param  {HTMLElement} el
   * @param  {selector} selector
   * @return {number}
   */
  function index(el, selector) {
    var index = 0;
    if (!el || !el.parentNode) {
      return -1;
    }

    /* jshint boss:true */
    while (el = el.previousElementSibling) {
      if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
        index++;
      }
    }
    return index;
  }

  /**
   * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
   * The value is returned in real pixels.
   * @param  {HTMLElement} el
   * @return {Array}             Offsets in the format of [left, top]
   */
  function getRelativeScrollOffset(el) {
    var offsetLeft = 0,
      offsetTop = 0,
      winScroller = getWindowScrollingElement();
    if (el) {
      do {
        var elMatrix = matrix(el),
          scaleX = elMatrix.a,
          scaleY = elMatrix.d;
        offsetLeft += el.scrollLeft * scaleX;
        offsetTop += el.scrollTop * scaleY;
      } while (el !== winScroller && (el = el.parentNode));
    }
    return [offsetLeft, offsetTop];
  }

  /**
   * Returns the index of the object within the given array
   * @param  {Array} arr   Array that may or may not hold the object
   * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
   * @return {Number}      The index of the object in the array, or -1
   */
  function indexOfObject(arr, obj) {
    for (var i in arr) {
      if (!arr.hasOwnProperty(i)) continue;
      for (var key in obj) {
        if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
      }
    }
    return -1;
  }
  function getParentAutoScrollElement(el, includeSelf) {
    // skip to window
    if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
    var elem = el;
    var gotSelf = false;
    do {
      // we don't need to get elem css if it isn't even overflowing in the first place (performance)
      if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
        var elemCSS = css(elem);
        if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
          if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
          if (gotSelf || includeSelf) return elem;
          gotSelf = true;
        }
      }
      /* jshint boss:true */
    } while (elem = elem.parentNode);
    return getWindowScrollingElement();
  }
  function extend(dst, src) {
    if (dst && src) {
      for (var key in src) {
        if (src.hasOwnProperty(key)) {
          dst[key] = src[key];
        }
      }
    }
    return dst;
  }
  function isRectEqual(rect1, rect2) {
    return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
  }
  var _throttleTimeout;
  function throttle(callback, ms) {
    return function () {
      if (!_throttleTimeout) {
        var args = arguments,
          _this = this;
        if (args.length === 1) {
          callback.call(_this, args[0]);
        } else {
          callback.apply(_this, args);
        }
        _throttleTimeout = setTimeout(function () {
          _throttleTimeout = void 0;
        }, ms);
      }
    };
  }
  function cancelThrottle() {
    clearTimeout(_throttleTimeout);
    _throttleTimeout = void 0;
  }
  function scrollBy(el, x, y) {
    el.scrollLeft += x;
    el.scrollTop += y;
  }
  function clone(el) {
    var Polymer = window.Polymer;
    var $ = window.jQuery || window.Zepto;
    if (Polymer && Polymer.dom) {
      return Polymer.dom(el).cloneNode(true);
    } else if ($) {
      return $(el).clone(true)[0];
    } else {
      return el.cloneNode(true);
    }
  }
  function setRect(el, rect) {
    css(el, 'position', 'absolute');
    css(el, 'top', rect.top);
    css(el, 'left', rect.left);
    css(el, 'width', rect.width);
    css(el, 'height', rect.height);
  }
  function unsetRect(el) {
    css(el, 'position', '');
    css(el, 'top', '');
    css(el, 'left', '');
    css(el, 'width', '');
    css(el, 'height', '');
  }
  function getChildContainingRectFromElement(container, options, ghostEl) {
    var rect = {};
    Array.from(container.children).forEach(function (child) {
      var _rect$left, _rect$top, _rect$right, _rect$bottom;
      if (!closest(child, options.draggable, container, false) || child.animated || child === ghostEl) return;
      var childRect = getRect(child);
      rect.left = Math.min((_rect$left = rect.left) !== null && _rect$left !== void 0 ? _rect$left : Infinity, childRect.left);
      rect.top = Math.min((_rect$top = rect.top) !== null && _rect$top !== void 0 ? _rect$top : Infinity, childRect.top);
      rect.right = Math.max((_rect$right = rect.right) !== null && _rect$right !== void 0 ? _rect$right : -Infinity, childRect.right);
      rect.bottom = Math.max((_rect$bottom = rect.bottom) !== null && _rect$bottom !== void 0 ? _rect$bottom : -Infinity, childRect.bottom);
    });
    rect.width = rect.right - rect.left;
    rect.height = rect.bottom - rect.top;
    rect.x = rect.left;
    rect.y = rect.top;
    return rect;
  }
  var expando = 'Sortable' + new Date().getTime();

  function AnimationStateManager() {
    var animationStates = [],
      animationCallbackId;
    return {
      captureAnimationState: function captureAnimationState() {
        animationStates = [];
        if (!this.options.animation) return;
        var children = [].slice.call(this.el.children);
        children.forEach(function (child) {
          if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
          animationStates.push({
            target: child,
            rect: getRect(child)
          });
          var fromRect = _objectSpread2({}, animationStates[animationStates.length - 1].rect);

          // If animating: compensate for current animation
          if (child.thisAnimationDuration) {
            var childMatrix = matrix(child, true);
            if (childMatrix) {
              fromRect.top -= childMatrix.f;
              fromRect.left -= childMatrix.e;
            }
          }
          child.fromRect = fromRect;
        });
      },
      addAnimationState: function addAnimationState(state) {
        animationStates.push(state);
      },
      removeAnimationState: function removeAnimationState(target) {
        animationStates.splice(indexOfObject(animationStates, {
          target: target
        }), 1);
      },
      animateAll: function animateAll(callback) {
        var _this = this;
        if (!this.options.animation) {
          clearTimeout(animationCallbackId);
          if (typeof callback === 'function') callback();
          return;
        }
        var animating = false,
          animationTime = 0;
        animationStates.forEach(function (state) {
          var time = 0,
            target = state.target,
            fromRect = target.fromRect,
            toRect = getRect(target),
            prevFromRect = target.prevFromRect,
            prevToRect = target.prevToRect,
            animatingRect = state.rect,
            targetMatrix = matrix(target, true);
          if (targetMatrix) {
            // Compensate for current animation
            toRect.top -= targetMatrix.f;
            toRect.left -= targetMatrix.e;
          }
          target.toRect = toRect;
          if (target.thisAnimationDuration) {
            // Could also check if animatingRect is between fromRect and toRect
            if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) &&
            // Make sure animatingRect is on line between toRect & fromRect
            (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
              // If returning to same place as started from animation and on same axis
              time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
            }
          }

          // if fromRect != toRect: animate
          if (!isRectEqual(toRect, fromRect)) {
            target.prevFromRect = fromRect;
            target.prevToRect = toRect;
            if (!time) {
              time = _this.options.animation;
            }
            _this.animate(target, animatingRect, toRect, time);
          }
          if (time) {
            animating = true;
            animationTime = Math.max(animationTime, time);
            clearTimeout(target.animationResetTimer);
            target.animationResetTimer = setTimeout(function () {
              target.animationTime = 0;
              target.prevFromRect = null;
              target.fromRect = null;
              target.prevToRect = null;
              target.thisAnimationDuration = null;
            }, time);
            target.thisAnimationDuration = time;
          }
        });
        clearTimeout(animationCallbackId);
        if (!animating) {
          if (typeof callback === 'function') callback();
        } else {
          animationCallbackId = setTimeout(function () {
            if (typeof callback === 'function') callback();
          }, animationTime);
        }
        animationStates = [];
      },
      animate: function animate(target, currentRect, toRect, duration) {
        if (duration) {
          css(target, 'transition', '');
          css(target, 'transform', '');
          var elMatrix = matrix(this.el),
            scaleX = elMatrix && elMatrix.a,
            scaleY = elMatrix && elMatrix.d,
            translateX = (currentRect.left - toRect.left) / (scaleX || 1),
            translateY = (currentRect.top - toRect.top) / (scaleY || 1);
          target.animatingX = !!translateX;
          target.animatingY = !!translateY;
          css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
          this.forRepaintDummy = repaint(target); // repaint

          css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
          css(target, 'transform', 'translate3d(0,0,0)');
          typeof target.animated === 'number' && clearTimeout(target.animated);
          target.animated = setTimeout(function () {
            css(target, 'transition', '');
            css(target, 'transform', '');
            target.animated = false;
            target.animatingX = false;
            target.animatingY = false;
          }, duration);
        }
      }
    };
  }
  function repaint(target) {
    return target.offsetWidth;
  }
  function calculateRealTime(animatingRect, fromRect, toRect, options) {
    return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
  }

  var plugins = [];
  var defaults = {
    initializeByDefault: true
  };
  var PluginManager = {
    mount: function mount(plugin) {
      // Set default static properties
      for (var option in defaults) {
        if (defaults.hasOwnProperty(option) && !(option in plugin)) {
          plugin[option] = defaults[option];
        }
      }
      plugins.forEach(function (p) {
        if (p.pluginName === plugin.pluginName) {
          throw "Sortable: Cannot mount plugin ".concat(plugin.pluginName, " more than once");
        }
      });
      plugins.push(plugin);
    },
    pluginEvent: function pluginEvent(eventName, sortable, evt) {
      var _this = this;
      this.eventCanceled = false;
      evt.cancel = function () {
        _this.eventCanceled = true;
      };
      var eventNameGlobal = eventName + 'Global';
      plugins.forEach(function (plugin) {
        if (!sortable[plugin.pluginName]) return;
        // Fire global events if it exists in this sortable
        if (sortable[plugin.pluginName][eventNameGlobal]) {
          sortable[plugin.pluginName][eventNameGlobal](_objectSpread2({
            sortable: sortable
          }, evt));
        }

        // Only fire plugin event if plugin is enabled in this sortable,
        // and plugin has event defined
        if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
          sortable[plugin.pluginName][eventName](_objectSpread2({
            sortable: sortable
          }, evt));
        }
      });
    },
    initializePlugins: function initializePlugins(sortable, el, defaults, options) {
      plugins.forEach(function (plugin) {
        var pluginName = plugin.pluginName;
        if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
        var initialized = new plugin(sortable, el, sortable.options);
        initialized.sortable = sortable;
        initialized.options = sortable.options;
        sortable[pluginName] = initialized;

        // Add default options from plugin
        _extends(defaults, initialized.defaults);
      });
      for (var option in sortable.options) {
        if (!sortable.options.hasOwnProperty(option)) continue;
        var modified = this.modifyOption(sortable, option, sortable.options[option]);
        if (typeof modified !== 'undefined') {
          sortable.options[option] = modified;
        }
      }
    },
    getEventProperties: function getEventProperties(name, sortable) {
      var eventProperties = {};
      plugins.forEach(function (plugin) {
        if (typeof plugin.eventProperties !== 'function') return;
        _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
      });
      return eventProperties;
    },
    modifyOption: function modifyOption(sortable, name, value) {
      var modifiedValue;
      plugins.forEach(function (plugin) {
        // Plugin must exist on the Sortable
        if (!sortable[plugin.pluginName]) return;

        // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
        if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
          modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
        }
      });
      return modifiedValue;
    }
  };

  function dispatchEvent(_ref) {
    var sortable = _ref.sortable,
      rootEl = _ref.rootEl,
      name = _ref.name,
      targetEl = _ref.targetEl,
      cloneEl = _ref.cloneEl,
      toEl = _ref.toEl,
      fromEl = _ref.fromEl,
      oldIndex = _ref.oldIndex,
      newIndex = _ref.newIndex,
      oldDraggableIndex = _ref.oldDraggableIndex,
      newDraggableIndex = _ref.newDraggableIndex,
      originalEvent = _ref.originalEvent,
      putSortable = _ref.putSortable,
      extraEventProperties = _ref.extraEventProperties;
    sortable = sortable || rootEl && rootEl[expando];
    if (!sortable) return;
    var evt,
      options = sortable.options,
      onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
    // Support for new CustomEvent feature
    if (window.CustomEvent && !IE11OrLess && !Edge) {
      evt = new CustomEvent(name, {
        bubbles: true,
        cancelable: true
      });
    } else {
      evt = document.createEvent('Event');
      evt.initEvent(name, true, true);
    }
    evt.to = toEl || rootEl;
    evt.from = fromEl || rootEl;
    evt.item = targetEl || rootEl;
    evt.clone = cloneEl;
    evt.oldIndex = oldIndex;
    evt.newIndex = newIndex;
    evt.oldDraggableIndex = oldDraggableIndex;
    evt.newDraggableIndex = newDraggableIndex;
    evt.originalEvent = originalEvent;
    evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
    var allEventProperties = _objectSpread2(_objectSpread2({}, extraEventProperties), PluginManager.getEventProperties(name, sortable));
    for (var option in allEventProperties) {
      evt[option] = allEventProperties[option];
    }
    if (rootEl) {
      rootEl.dispatchEvent(evt);
    }
    if (options[onName]) {
      options[onName].call(sortable, evt);
    }
  }

  var _excluded = ["evt"];
  var pluginEvent = function pluginEvent(eventName, sortable) {
    var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
      originalEvent = _ref.evt,
      data = _objectWithoutProperties(_ref, _excluded);
    PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread2({
      dragEl: dragEl,
      parentEl: parentEl,
      ghostEl: ghostEl,
      rootEl: rootEl,
      nextEl: nextEl,
      lastDownEl: lastDownEl,
      cloneEl: cloneEl,
      cloneHidden: cloneHidden,
      dragStarted: moved,
      putSortable: putSortable,
      activeSortable: Sortable.active,
      originalEvent: originalEvent,
      oldIndex: oldIndex,
      oldDraggableIndex: oldDraggableIndex,
      newIndex: newIndex,
      newDraggableIndex: newDraggableIndex,
      hideGhostForTarget: _hideGhostForTarget,
      unhideGhostForTarget: _unhideGhostForTarget,
      cloneNowHidden: function cloneNowHidden() {
        cloneHidden = true;
      },
      cloneNowShown: function cloneNowShown() {
        cloneHidden = false;
      },
      dispatchSortableEvent: function dispatchSortableEvent(name) {
        _dispatchEvent({
          sortable: sortable,
          name: name,
          originalEvent: originalEvent
        });
      }
    }, data));
  };
  function _dispatchEvent(info) {
    dispatchEvent(_objectSpread2({
      putSortable: putSortable,
      cloneEl: cloneEl,
      targetEl: dragEl,
      rootEl: rootEl,
      oldIndex: oldIndex,
      oldDraggableIndex: oldDraggableIndex,
      newIndex: newIndex,
      newDraggableIndex: newDraggableIndex
    }, info));
  }
  var dragEl,
    parentEl,
    ghostEl,
    rootEl,
    nextEl,
    lastDownEl,
    cloneEl,
    cloneHidden,
    oldIndex,
    newIndex,
    oldDraggableIndex,
    newDraggableIndex,
    activeGroup,
    putSortable,
    awaitingDragStarted = false,
    ignoreNextClick = false,
    sortables = [],
    tapEvt,
    touchEvt,
    lastDx,
    lastDy,
    tapDistanceLeft,
    tapDistanceTop,
    moved,
    lastTarget,
    lastDirection,
    pastFirstInvertThresh = false,
    isCircumstantialInvert = false,
    targetMoveDistance,
    // For positioning ghost absolutely
    ghostRelativeParent,
    ghostRelativeParentInitialScroll = [],
    // (left, top)

    _silent = false,
    savedInputChecked = [];

  /** @const */
  var documentExists = typeof document !== 'undefined',
    PositionGhostAbsolutely = IOS,
    CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
    // This will not pass for IE9, because IE9 DnD only works on anchors
    supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
    supportCssPointerEvents = function () {
      if (!documentExists) return;
      // false when <= IE11
      if (IE11OrLess) {
        return false;
      }
      var el = document.createElement('x');
      el.style.cssText = 'pointer-events:auto';
      return el.style.pointerEvents === 'auto';
    }(),
    _detectDirection = function _detectDirection(el, options) {
      var elCSS = css(el),
        elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
        child1 = getChild(el, 0, options),
        child2 = getChild(el, 1, options),
        firstChildCSS = child1 && css(child1),
        secondChildCSS = child2 && css(child2),
        firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
        secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
      if (elCSS.display === 'flex') {
        return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
      }
      if (elCSS.display === 'grid') {
        return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
      }
      if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
        var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
        return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
      }
      return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
    },
    _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
      var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
        dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
        dragElOppLength = vertical ? dragRect.width : dragRect.height,
        targetS1Opp = vertical ? targetRect.left : targetRect.top,
        targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
        targetOppLength = vertical ? targetRect.width : targetRect.height;
      return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
    },
    /**
     * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
     * @param  {Number} x      X position
     * @param  {Number} y      Y position
     * @return {HTMLElement}   Element of the first found nearest Sortable
     */
    _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
      var ret;
      sortables.some(function (sortable) {
        var threshold = sortable[expando].options.emptyInsertThreshold;
        if (!threshold || lastChild(sortable)) return;
        var rect = getRect(sortable),
          insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
          insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
        if (insideHorizontally && insideVertically) {
          return ret = sortable;
        }
      });
      return ret;
    },
    _prepareGroup = function _prepareGroup(options) {
      function toFn(value, pull) {
        return function (to, from, dragEl, evt) {
          var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
          if (value == null && (pull || sameGroup)) {
            // Default pull value
            // Default pull and put value if same group
            return true;
          } else if (value == null || value === false) {
            return false;
          } else if (pull && value === 'clone') {
            return value;
          } else if (typeof value === 'function') {
            return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
          } else {
            var otherGroup = (pull ? to : from).options.group.name;
            return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
          }
        };
      }
      var group = {};
      var originalGroup = options.group;
      if (!originalGroup || _typeof(originalGroup) != 'object') {
        originalGroup = {
          name: originalGroup
        };
      }
      group.name = originalGroup.name;
      group.checkPull = toFn(originalGroup.pull, true);
      group.checkPut = toFn(originalGroup.put);
      group.revertClone = originalGroup.revertClone;
      options.group = group;
    },
    _hideGhostForTarget = function _hideGhostForTarget() {
      if (!supportCssPointerEvents && ghostEl) {
        css(ghostEl, 'display', 'none');
      }
    },
    _unhideGhostForTarget = function _unhideGhostForTarget() {
      if (!supportCssPointerEvents && ghostEl) {
        css(ghostEl, 'display', '');
      }
    };

  // #1184 fix - Prevent click event on fallback if dragged but item not changed position
  if (documentExists && !ChromeForAndroid) {
    document.addEventListener('click', function (evt) {
      if (ignoreNextClick) {
        evt.preventDefault();
        evt.stopPropagation && evt.stopPropagation();
        evt.stopImmediatePropagation && evt.stopImmediatePropagation();
        ignoreNextClick = false;
        return false;
      }
    }, true);
  }
  var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
    if (dragEl) {
      evt = evt.touches ? evt.touches[0] : evt;
      var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
      if (nearest) {
        // Create imitation event
        var event = {};
        for (var i in evt) {
          if (evt.hasOwnProperty(i)) {
            event[i] = evt[i];
          }
        }
        event.target = event.rootEl = nearest;
        event.preventDefault = void 0;
        event.stopPropagation = void 0;
        nearest[expando]._onDragOver(event);
      }
    }
  };
  var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
    if (dragEl) {
      dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
    }
  };

  /**
   * @class  Sortable
   * @param  {HTMLElement}  el
   * @param  {Object}       [options]
   */
  function Sortable(el, options) {
    if (!(el && el.nodeType && el.nodeType === 1)) {
      throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
    }
    this.el = el; // root element
    this.options = options = _extends({}, options);

    // Export instance
    el[expando] = this;
    var defaults = {
      group: null,
      sort: true,
      disabled: false,
      store: null,
      handle: null,
      draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
      swapThreshold: 1,
      // percentage; 0 <= x <= 1
      invertSwap: false,
      // invert always
      invertedSwapThreshold: null,
      // will be set to same as swapThreshold if default
      removeCloneOnHide: true,
      direction: function direction() {
        return _detectDirection(el, this.options);
      },
      ghostClass: 'sortable-ghost',
      chosenClass: 'sortable-chosen',
      dragClass: 'sortable-drag',
      ignore: 'a, img',
      filter: null,
      preventOnFilter: true,
      animation: 0,
      easing: null,
      setData: function setData(dataTransfer, dragEl) {
        dataTransfer.setData('Text', dragEl.textContent);
      },
      dropBubble: false,
      dragoverBubble: false,
      dataIdAttr: 'data-id',
      delay: 0,
      delayOnTouchOnly: false,
      touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
      forceFallback: false,
      fallbackClass: 'sortable-fallback',
      fallbackOnBody: false,
      fallbackTolerance: 0,
      fallbackOffset: {
        x: 0,
        y: 0
      },
      // Disabled on Safari: #1571; Enabled on Safari IOS: #2244
      supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && (!Safari || IOS),
      emptyInsertThreshold: 5
    };
    PluginManager.initializePlugins(this, el, defaults);

    // Set default options
    for (var name in defaults) {
      !(name in options) && (options[name] = defaults[name]);
    }
    _prepareGroup(options);

    // Bind all private methods
    for (var fn in this) {
      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
        this[fn] = this[fn].bind(this);
      }
    }

    // Setup drag mode
    this.nativeDraggable = options.forceFallback ? false : supportDraggable;
    if (this.nativeDraggable) {
      // Touch start threshold cannot be greater than the native dragstart threshold
      this.options.touchStartThreshold = 1;
    }

    // Bind events
    if (options.supportPointer) {
      on(el, 'pointerdown', this._onTapStart);
    } else {
      on(el, 'mousedown', this._onTapStart);
      on(el, 'touchstart', this._onTapStart);
    }
    if (this.nativeDraggable) {
      on(el, 'dragover', this);
      on(el, 'dragenter', this);
    }
    sortables.push(this.el);

    // Restore sorting
    options.store && options.store.get && this.sort(options.store.get(this) || []);

    // Add animation state manager
    _extends(this, AnimationStateManager());
  }
  Sortable.prototype = /** @lends Sortable.prototype */{
    constructor: Sortable,
    _isOutsideThisEl: function _isOutsideThisEl(target) {
      if (!this.el.contains(target) && target !== this.el) {
        lastTarget = null;
      }
    },
    _getDirection: function _getDirection(evt, target) {
      return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
    },
    _onTapStart: function _onTapStart( /** Event|TouchEvent */evt) {
      if (!evt.cancelable) return;
      var _this = this,
        el = this.el,
        options = this.options,
        preventOnFilter = options.preventOnFilter,
        type = evt.type,
        touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
        target = (touch || evt).target,
        originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
        filter = options.filter;
      _saveInputCheckedState(el);

      // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
      if (dragEl) {
        return;
      }
      if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
        return; // only left button and enabled
      }

      // cancel dnd if original target is content editable
      if (originalTarget.isContentEditable) {
        return;
      }

      // Safari ignores further event handling after mousedown
      if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') {
        return;
      }
      target = closest(target, options.draggable, el, false);
      if (target && target.animated) {
        return;
      }
      if (lastDownEl === target) {
        // Ignoring duplicate `down`
        return;
      }

      // Get the index of the dragged element within its parent
      oldIndex = index(target);
      oldDraggableIndex = index(target, options.draggable);

      // Check filter
      if (typeof filter === 'function') {
        if (filter.call(this, evt, target, this)) {
          _dispatchEvent({
            sortable: _this,
            rootEl: originalTarget,
            name: 'filter',
            targetEl: target,
            toEl: el,
            fromEl: el
          });
          pluginEvent('filter', _this, {
            evt: evt
          });
          preventOnFilter && evt.preventDefault();
          return; // cancel dnd
        }
      } else if (filter) {
        filter = filter.split(',').some(function (criteria) {
          criteria = closest(originalTarget, criteria.trim(), el, false);
          if (criteria) {
            _dispatchEvent({
              sortable: _this,
              rootEl: criteria,
              name: 'filter',
              targetEl: target,
              fromEl: el,
              toEl: el
            });
            pluginEvent('filter', _this, {
              evt: evt
            });
            return true;
          }
        });
        if (filter) {
          preventOnFilter && evt.preventDefault();
          return; // cancel dnd
        }
      }
      if (options.handle && !closest(originalTarget, options.handle, el, false)) {
        return;
      }

      // Prepare `dragstart`
      this._prepareDragStart(evt, touch, target);
    },
    _prepareDragStart: function _prepareDragStart( /** Event */evt, /** Touch */touch, /** HTMLElement */target) {
      var _this = this,
        el = _this.el,
        options = _this.options,
        ownerDocument = el.ownerDocument,
        dragStartFn;
      if (target && !dragEl && target.parentNode === el) {
        var dragRect = getRect(target);
        rootEl = el;
        dragEl = target;
        parentEl = dragEl.parentNode;
        nextEl = dragEl.nextSibling;
        lastDownEl = target;
        activeGroup = options.group;
        Sortable.dragged = dragEl;
        tapEvt = {
          target: dragEl,
          clientX: (touch || evt).clientX,
          clientY: (touch || evt).clientY
        };
        tapDistanceLeft = tapEvt.clientX - dragRect.left;
        tapDistanceTop = tapEvt.clientY - dragRect.top;
        this._lastX = (touch || evt).clientX;
        this._lastY = (touch || evt).clientY;
        dragEl.style['will-change'] = 'all';
        dragStartFn = function dragStartFn() {
          pluginEvent('delayEnded', _this, {
            evt: evt
          });
          if (Sortable.eventCanceled) {
            _this._onDrop();
            return;
          }
          // Delayed drag has been triggered
          // we can re-enable the events: touchmove/mousemove
          _this._disableDelayedDragEvents();
          if (!FireFox && _this.nativeDraggable) {
            dragEl.draggable = true;
          }

          // Bind the events: dragstart/dragend
          _this._triggerDragStart(evt, touch);

          // Drag start event
          _dispatchEvent({
            sortable: _this,
            name: 'choose',
            originalEvent: evt
          });

          // Chosen item
          toggleClass(dragEl, options.chosenClass, true);
        };

        // Disable "draggable"
        options.ignore.split(',').forEach(function (criteria) {
          find(dragEl, criteria.trim(), _disableDraggable);
        });
        on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
        on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
        on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
        if (options.supportPointer) {
          on(ownerDocument, 'pointerup', _this._onDrop);
          // Native D&D triggers pointercancel
          !this.nativeDraggable && on(ownerDocument, 'pointercancel', _this._onDrop);
        } else {
          on(ownerDocument, 'mouseup', _this._onDrop);
          on(ownerDocument, 'touchend', _this._onDrop);
          on(ownerDocument, 'touchcancel', _this._onDrop);
        }

        // Make dragEl draggable (must be before delay for FireFox)
        if (FireFox && this.nativeDraggable) {
          this.options.touchStartThreshold = 4;
          dragEl.draggable = true;
        }
        pluginEvent('delayStart', this, {
          evt: evt
        });

        // Delay is impossible for native DnD in Edge or IE
        if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
          if (Sortable.eventCanceled) {
            this._onDrop();
            return;
          }
          // If the user moves the pointer or let go the click or touch
          // before the delay has been reached:
          // disable the delayed drag
          if (options.supportPointer) {
            on(ownerDocument, 'pointerup', _this._disableDelayedDrag);
            on(ownerDocument, 'pointercancel', _this._disableDelayedDrag);
          } else {
            on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
            on(ownerDocument, 'touchend', _this._disableDelayedDrag);
            on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
          }
          on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
          on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
          options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
          _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
        } else {
          dragStartFn();
        }
      }
    },
    _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( /** TouchEvent|PointerEvent **/e) {
      var touch = e.touches ? e.touches[0] : e;
      if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
        this._disableDelayedDrag();
      }
    },
    _disableDelayedDrag: function _disableDelayedDrag() {
      dragEl && _disableDraggable(dragEl);
      clearTimeout(this._dragStartTimer);
      this._disableDelayedDragEvents();
    },
    _disableDelayedDragEvents: function _disableDelayedDragEvents() {
      var ownerDocument = this.el.ownerDocument;
      off(ownerDocument, 'mouseup', this._disableDelayedDrag);
      off(ownerDocument, 'touchend', this._disableDelayedDrag);
      off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
      off(ownerDocument, 'pointerup', this._disableDelayedDrag);
      off(ownerDocument, 'pointercancel', this._disableDelayedDrag);
      off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
      off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
      off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
    },
    _triggerDragStart: function _triggerDragStart( /** Event */evt, /** Touch */touch) {
      touch = touch || evt.pointerType == 'touch' && evt;
      if (!this.nativeDraggable || touch) {
        if (this.options.supportPointer) {
          on(document, 'pointermove', this._onTouchMove);
        } else if (touch) {
          on(document, 'touchmove', this._onTouchMove);
        } else {
          on(document, 'mousemove', this._onTouchMove);
        }
      } else {
        on(dragEl, 'dragend', this);
        on(rootEl, 'dragstart', this._onDragStart);
      }
      try {
        if (document.selection) {
          _nextTick(function () {
            document.selection.empty();
          });
        } else {
          window.getSelection().removeAllRanges();
        }
      } catch (err) {}
    },
    _dragStarted: function _dragStarted(fallback, evt) {
      awaitingDragStarted = false;
      if (rootEl && dragEl) {
        pluginEvent('dragStarted', this, {
          evt: evt
        });
        if (this.nativeDraggable) {
          on(document, 'dragover', _checkOutsideTargetEl);
        }
        var options = this.options;

        // Apply effect
        !fallback && toggleClass(dragEl, options.dragClass, false);
        toggleClass(dragEl, options.ghostClass, true);
        Sortable.active = this;
        fallback && this._appendGhost();

        // Drag start event
        _dispatchEvent({
          sortable: this,
          name: 'start',
          originalEvent: evt
        });
      } else {
        this._nulling();
      }
    },
    _emulateDragOver: function _emulateDragOver() {
      if (touchEvt) {
        this._lastX = touchEvt.clientX;
        this._lastY = touchEvt.clientY;
        _hideGhostForTarget();
        var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
        var parent = target;
        while (target && target.shadowRoot) {
          target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
          if (target === parent) break;
          parent = target;
        }
        dragEl.parentNode[expando]._isOutsideThisEl(target);
        if (parent) {
          do {
            if (parent[expando]) {
              var inserted = void 0;
              inserted = parent[expando]._onDragOver({
                clientX: touchEvt.clientX,
                clientY: touchEvt.clientY,
                target: target,
                rootEl: parent
              });
              if (inserted && !this.options.dragoverBubble) {
                break;
              }
            }
            target = parent; // store last element
          }
          /* jshint boss:true */ while (parent = getParentOrHost(parent));
        }
        _unhideGhostForTarget();
      }
    },
    _onTouchMove: function _onTouchMove( /**TouchEvent*/evt) {
      if (tapEvt) {
        var options = this.options,
          fallbackTolerance = options.fallbackTolerance,
          fallbackOffset = options.fallbackOffset,
          touch = evt.touches ? evt.touches[0] : evt,
          ghostMatrix = ghostEl && matrix(ghostEl, true),
          scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
          scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
          relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
          dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
          dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1);

        // only set the status to dragging, when we are actually dragging
        if (!Sortable.active && !awaitingDragStarted) {
          if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
            return;
          }
          this._onDragStart(evt, true);
        }
        if (ghostEl) {
          if (ghostMatrix) {
            ghostMatrix.e += dx - (lastDx || 0);
            ghostMatrix.f += dy - (lastDy || 0);
          } else {
            ghostMatrix = {
              a: 1,
              b: 0,
              c: 0,
              d: 1,
              e: dx,
              f: dy
            };
          }
          var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
          css(ghostEl, 'webkitTransform', cssMatrix);
          css(ghostEl, 'mozTransform', cssMatrix);
          css(ghostEl, 'msTransform', cssMatrix);
          css(ghostEl, 'transform', cssMatrix);
          lastDx = dx;
          lastDy = dy;
          touchEvt = touch;
        }
        evt.cancelable && evt.preventDefault();
      }
    },
    _appendGhost: function _appendGhost() {
      // Bug if using scale(): https://stackoverflow.com/questions/2637058
      // Not being adjusted for
      if (!ghostEl) {
        var container = this.options.fallbackOnBody ? document.body : rootEl,
          rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
          options = this.options;

        // Position absolutely
        if (PositionGhostAbsolutely) {
          // Get relatively positioned parent
          ghostRelativeParent = container;
          while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
            ghostRelativeParent = ghostRelativeParent.parentNode;
          }
          if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
            if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
            rect.top += ghostRelativeParent.scrollTop;
            rect.left += ghostRelativeParent.scrollLeft;
          } else {
            ghostRelativeParent = getWindowScrollingElement();
          }
          ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
        }
        ghostEl = dragEl.cloneNode(true);
        toggleClass(ghostEl, options.ghostClass, false);
        toggleClass(ghostEl, options.fallbackClass, true);
        toggleClass(ghostEl, options.dragClass, true);
        css(ghostEl, 'transition', '');
        css(ghostEl, 'transform', '');
        css(ghostEl, 'box-sizing', 'border-box');
        css(ghostEl, 'margin', 0);
        css(ghostEl, 'top', rect.top);
        css(ghostEl, 'left', rect.left);
        css(ghostEl, 'width', rect.width);
        css(ghostEl, 'height', rect.height);
        css(ghostEl, 'opacity', '0.8');
        css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
        css(ghostEl, 'zIndex', '100000');
        css(ghostEl, 'pointerEvents', 'none');
        Sortable.ghost = ghostEl;
        container.appendChild(ghostEl);

        // Set transform-origin
        css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
      }
    },
    _onDragStart: function _onDragStart( /**Event*/evt, /**boolean*/fallback) {
      var _this = this;
      var dataTransfer = evt.dataTransfer;
      var options = _this.options;
      pluginEvent('dragStart', this, {
        evt: evt
      });
      if (Sortable.eventCanceled) {
        this._onDrop();
        return;
      }
      pluginEvent('setupClone', this);
      if (!Sortable.eventCanceled) {
        cloneEl = clone(dragEl);
        cloneEl.removeAttribute("id");
        cloneEl.draggable = false;
        cloneEl.style['will-change'] = '';
        this._hideClone();
        toggleClass(cloneEl, this.options.chosenClass, false);
        Sortable.clone = cloneEl;
      }

      // #1143: IFrame support workaround
      _this.cloneId = _nextTick(function () {
        pluginEvent('clone', _this);
        if (Sortable.eventCanceled) return;
        if (!_this.options.removeCloneOnHide) {
          rootEl.insertBefore(cloneEl, dragEl);
        }
        _this._hideClone();
        _dispatchEvent({
          sortable: _this,
          name: 'clone'
        });
      });
      !fallback && toggleClass(dragEl, options.dragClass, true);

      // Set proper drop events
      if (fallback) {
        ignoreNextClick = true;
        _this._loopId = setInterval(_this._emulateDragOver, 50);
      } else {
        // Undo what was set in _prepareDragStart before drag started
        off(document, 'mouseup', _this._onDrop);
        off(document, 'touchend', _this._onDrop);
        off(document, 'touchcancel', _this._onDrop);
        if (dataTransfer) {
          dataTransfer.effectAllowed = 'move';
          options.setData && options.setData.call(_this, dataTransfer, dragEl);
        }
        on(document, 'drop', _this);

        // #1276 fix:
        css(dragEl, 'transform', 'translateZ(0)');
      }
      awaitingDragStarted = true;
      _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
      on(document, 'selectstart', _this);
      moved = true;
      window.getSelection().removeAllRanges();
      if (Safari) {
        css(document.body, 'user-select', 'none');
      }
    },
    // Returns true - if no further action is needed (either inserted or another condition)
    _onDragOver: function _onDragOver( /**Event*/evt) {
      var el = this.el,
        target = evt.target,
        dragRect,
        targetRect,
        revert,
        options = this.options,
        group = options.group,
        activeSortable = Sortable.active,
        isOwner = activeGroup === group,
        canSort = options.sort,
        fromSortable = putSortable || activeSortable,
        vertical,
        _this = this,
        completedFired = false;
      if (_silent) return;
      function dragOverEvent(name, extra) {
        pluginEvent(name, _this, _objectSpread2({
          evt: evt,
          isOwner: isOwner,
          axis: vertical ? 'vertical' : 'horizontal',
          revert: revert,
          dragRect: dragRect,
          targetRect: targetRect,
          canSort: canSort,
          fromSortable: fromSortable,
          target: target,
          completed: completed,
          onMove: function onMove(target, after) {
            return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
          },
          changed: changed
        }, extra));
      }

      // Capture animation state
      function capture() {
        dragOverEvent('dragOverAnimationCapture');
        _this.captureAnimationState();
        if (_this !== fromSortable) {
          fromSortable.captureAnimationState();
        }
      }

      // Return invocation when dragEl is inserted (or completed)
      function completed(insertion) {
        dragOverEvent('dragOverCompleted', {
          insertion: insertion
        });
        if (insertion) {
          // Clones must be hidden before folding animation to capture dragRectAbsolute properly
          if (isOwner) {
            activeSortable._hideClone();
          } else {
            activeSortable._showClone(_this);
          }
          if (_this !== fromSortable) {
            // Set ghost class to new sortable's ghost class
            toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
            toggleClass(dragEl, options.ghostClass, true);
          }
          if (putSortable !== _this && _this !== Sortable.active) {
            putSortable = _this;
          } else if (_this === Sortable.active && putSortable) {
            putSortable = null;
          }

          // Animation
          if (fromSortable === _this) {
            _this._ignoreWhileAnimating = target;
          }
          _this.animateAll(function () {
            dragOverEvent('dragOverAnimationComplete');
            _this._ignoreWhileAnimating = null;
          });
          if (_this !== fromSortable) {
            fromSortable.animateAll();
            fromSortable._ignoreWhileAnimating = null;
          }
        }

        // Null lastTarget if it is not inside a previously swapped element
        if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
          lastTarget = null;
        }

        // no bubbling and not fallback
        if (!options.dragoverBubble && !evt.rootEl && target !== document) {
          dragEl.parentNode[expando]._isOutsideThisEl(evt.target);

          // Do not detect for empty insert if already inserted
          !insertion && nearestEmptyInsertDetectEvent(evt);
        }
        !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
        return completedFired = true;
      }

      // Call when dragEl has been inserted
      function changed() {
        newIndex = index(dragEl);
        newDraggableIndex = index(dragEl, options.draggable);
        _dispatchEvent({
          sortable: _this,
          name: 'change',
          toEl: el,
          newIndex: newIndex,
          newDraggableIndex: newDraggableIndex,
          originalEvent: evt
        });
      }
      if (evt.preventDefault !== void 0) {
        evt.cancelable && evt.preventDefault();
      }
      target = closest(target, options.draggable, el, true);
      dragOverEvent('dragOver');
      if (Sortable.eventCanceled) return completedFired;
      if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
        return completed(false);
      }
      ignoreNextClick = false;
      if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = parentEl !== rootEl) // Reverting item into the original list
      : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
        vertical = this._getDirection(evt, target) === 'vertical';
        dragRect = getRect(dragEl);
        dragOverEvent('dragOverValid');
        if (Sortable.eventCanceled) return completedFired;
        if (revert) {
          parentEl = rootEl; // actualization
          capture();
          this._hideClone();
          dragOverEvent('revert');
          if (!Sortable.eventCanceled) {
            if (nextEl) {
              rootEl.insertBefore(dragEl, nextEl);
            } else {
              rootEl.appendChild(dragEl);
            }
          }
          return completed(true);
        }
        var elLastChild = lastChild(el, options.draggable);
        if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
          // Insert to end of list

          // If already at end of list: Do not insert
          if (elLastChild === dragEl) {
            return completed(false);
          }

          // if there is a last element, it is the target
          if (elLastChild && el === evt.target) {
            target = elLastChild;
          }
          if (target) {
            targetRect = getRect(target);
          }
          if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
            capture();
            if (elLastChild && elLastChild.nextSibling) {
              // the last draggable element is not the last node
              el.insertBefore(dragEl, elLastChild.nextSibling);
            } else {
              el.appendChild(dragEl);
            }
            parentEl = el; // actualization

            changed();
            return completed(true);
          }
        } else if (elLastChild && _ghostIsFirst(evt, vertical, this)) {
          // Insert to start of list
          var firstChild = getChild(el, 0, options, true);
          if (firstChild === dragEl) {
            return completed(false);
          }
          target = firstChild;
          targetRect = getRect(target);
          if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) {
            capture();
            el.insertBefore(dragEl, firstChild);
            parentEl = el; // actualization

            changed();
            return completed(true);
          }
        } else if (target.parentNode === el) {
          targetRect = getRect(target);
          var direction = 0,
            targetBeforeFirstSwap,
            differentLevel = dragEl.parentNode !== el,
            differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
            side1 = vertical ? 'top' : 'left',
            scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
            scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
          if (lastTarget !== target) {
            targetBeforeFirstSwap = targetRect[side1];
            pastFirstInvertThresh = false;
            isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
          }
          direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
          var sibling;
          if (direction !== 0) {
            // Check if target is beside dragEl in respective direction (ignoring hidden elements)
            var dragIndex = index(dragEl);
            do {
              dragIndex -= direction;
              sibling = parentEl.children[dragIndex];
            } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
          }
          // If dragEl is already beside target: Do not insert
          if (direction === 0 || sibling === target) {
            return completed(false);
          }
          lastTarget = target;
          lastDirection = direction;
          var nextSibling = target.nextElementSibling,
            after = false;
          after = direction === 1;
          var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
          if (moveVector !== false) {
            if (moveVector === 1 || moveVector === -1) {
              after = moveVector === 1;
            }
            _silent = true;
            setTimeout(_unsilent, 30);
            capture();
            if (after && !nextSibling) {
              el.appendChild(dragEl);
            } else {
              target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
            }

            // Undo chrome's scroll adjustment (has no effect on other browsers)
            if (scrolledPastTop) {
              scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
            }
            parentEl = dragEl.parentNode; // actualization

            // must be done before animation
            if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
              targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
            }
            changed();
            return completed(true);
          }
        }
        if (el.contains(dragEl)) {
          return completed(false);
        }
      }
      return false;
    },
    _ignoreWhileAnimating: null,
    _offMoveEvents: function _offMoveEvents() {
      off(document, 'mousemove', this._onTouchMove);
      off(document, 'touchmove', this._onTouchMove);
      off(document, 'pointermove', this._onTouchMove);
      off(document, 'dragover', nearestEmptyInsertDetectEvent);
      off(document, 'mousemove', nearestEmptyInsertDetectEvent);
      off(document, 'touchmove', nearestEmptyInsertDetectEvent);
    },
    _offUpEvents: function _offUpEvents() {
      var ownerDocument = this.el.ownerDocument;
      off(ownerDocument, 'mouseup', this._onDrop);
      off(ownerDocument, 'touchend', this._onDrop);
      off(ownerDocument, 'pointerup', this._onDrop);
      off(ownerDocument, 'pointercancel', this._onDrop);
      off(ownerDocument, 'touchcancel', this._onDrop);
      off(document, 'selectstart', this);
    },
    _onDrop: function _onDrop( /**Event*/evt) {
      var el = this.el,
        options = this.options;

      // Get the index of the dragged element within its parent
      newIndex = index(dragEl);
      newDraggableIndex = index(dragEl, options.draggable);
      pluginEvent('drop', this, {
        evt: evt
      });
      parentEl = dragEl && dragEl.parentNode;

      // Get again after plugin event
      newIndex = index(dragEl);
      newDraggableIndex = index(dragEl, options.draggable);
      if (Sortable.eventCanceled) {
        this._nulling();
        return;
      }
      awaitingDragStarted = false;
      isCircumstantialInvert = false;
      pastFirstInvertThresh = false;
      clearInterval(this._loopId);
      clearTimeout(this._dragStartTimer);
      _cancelNextTick(this.cloneId);
      _cancelNextTick(this._dragStartId);

      // Unbind events
      if (this.nativeDraggable) {
        off(document, 'drop', this);
        off(el, 'dragstart', this._onDragStart);
      }
      this._offMoveEvents();
      this._offUpEvents();
      if (Safari) {
        css(document.body, 'user-select', '');
      }
      css(dragEl, 'transform', '');
      if (evt) {
        if (moved) {
          evt.cancelable && evt.preventDefault();
          !options.dropBubble && evt.stopPropagation();
        }
        ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
        if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
          // Remove clone(s)
          cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
        }
        if (dragEl) {
          if (this.nativeDraggable) {
            off(dragEl, 'dragend', this);
          }
          _disableDraggable(dragEl);
          dragEl.style['will-change'] = '';

          // Remove classes
          // ghostClass is added in dragStarted
          if (moved && !awaitingDragStarted) {
            toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
          }
          toggleClass(dragEl, this.options.chosenClass, false);

          // Drag stop event
          _dispatchEvent({
            sortable: this,
            name: 'unchoose',
            toEl: parentEl,
            newIndex: null,
            newDraggableIndex: null,
            originalEvent: evt
          });
          if (rootEl !== parentEl) {
            if (newIndex >= 0) {
              // Add event
              _dispatchEvent({
                rootEl: parentEl,
                name: 'add',
                toEl: parentEl,
                fromEl: rootEl,
                originalEvent: evt
              });

              // Remove event
              _dispatchEvent({
                sortable: this,
                name: 'remove',
                toEl: parentEl,
                originalEvent: evt
              });

              // drag from one list and drop into another
              _dispatchEvent({
                rootEl: parentEl,
                name: 'sort',
                toEl: parentEl,
                fromEl: rootEl,
                originalEvent: evt
              });
              _dispatchEvent({
                sortable: this,
                name: 'sort',
                toEl: parentEl,
                originalEvent: evt
              });
            }
            putSortable && putSortable.save();
          } else {
            if (newIndex !== oldIndex) {
              if (newIndex >= 0) {
                // drag & drop within the same list
                _dispatchEvent({
                  sortable: this,
                  name: 'update',
                  toEl: parentEl,
                  originalEvent: evt
                });
                _dispatchEvent({
                  sortable: this,
                  name: 'sort',
                  toEl: parentEl,
                  originalEvent: evt
                });
              }
            }
          }
          if (Sortable.active) {
            /* jshint eqnull:true */
            if (newIndex == null || newIndex === -1) {
              newIndex = oldIndex;
              newDraggableIndex = oldDraggableIndex;
            }
            _dispatchEvent({
              sortable: this,
              name: 'end',
              toEl: parentEl,
              originalEvent: evt
            });

            // Save sorting
            this.save();
          }
        }
      }
      this._nulling();
    },
    _nulling: function _nulling() {
      pluginEvent('nulling', this);
      rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
      savedInputChecked.forEach(function (el) {
        el.checked = true;
      });
      savedInputChecked.length = lastDx = lastDy = 0;
    },
    handleEvent: function handleEvent( /**Event*/evt) {
      switch (evt.type) {
        case 'drop':
        case 'dragend':
          this._onDrop(evt);
          break;
        case 'dragenter':
        case 'dragover':
          if (dragEl) {
            this._onDragOver(evt);
            _globalDragOver(evt);
          }
          break;
        case 'selectstart':
          evt.preventDefault();
          break;
      }
    },
    /**
     * Serializes the item into an array of string.
     * @returns {String[]}
     */
    toArray: function toArray() {
      var order = [],
        el,
        children = this.el.children,
        i = 0,
        n = children.length,
        options = this.options;
      for (; i < n; i++) {
        el = children[i];
        if (closest(el, options.draggable, this.el, false)) {
          order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
        }
      }
      return order;
    },
    /**
     * Sorts the elements according to the array.
     * @param  {String[]}  order  order of the items
     */
    sort: function sort(order, useAnimation) {
      var items = {},
        rootEl = this.el;
      this.toArray().forEach(function (id, i) {
        var el = rootEl.children[i];
        if (closest(el, this.options.draggable, rootEl, false)) {
          items[id] = el;
        }
      }, this);
      useAnimation && this.captureAnimationState();
      order.forEach(function (id) {
        if (items[id]) {
          rootEl.removeChild(items[id]);
          rootEl.appendChild(items[id]);
        }
      });
      useAnimation && this.animateAll();
    },
    /**
     * Save the current sorting
     */
    save: function save() {
      var store = this.options.store;
      store && store.set && store.set(this);
    },
    /**
     * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
     * @param   {HTMLElement}  el
     * @param   {String}       [selector]  default: `options.draggable`
     * @returns {HTMLElement|null}
     */
    closest: function closest$1(el, selector) {
      return closest(el, selector || this.options.draggable, this.el, false);
    },
    /**
     * Set/get option
     * @param   {string} name
     * @param   {*}      [value]
     * @returns {*}
     */
    option: function option(name, value) {
      var options = this.options;
      if (value === void 0) {
        return options[name];
      } else {
        var modifiedValue = PluginManager.modifyOption(this, name, value);
        if (typeof modifiedValue !== 'undefined') {
          options[name] = modifiedValue;
        } else {
          options[name] = value;
        }
        if (name === 'group') {
          _prepareGroup(options);
        }
      }
    },
    /**
     * Destroy
     */
    destroy: function destroy() {
      pluginEvent('destroy', this);
      var el = this.el;
      el[expando] = null;
      off(el, 'mousedown', this._onTapStart);
      off(el, 'touchstart', this._onTapStart);
      off(el, 'pointerdown', this._onTapStart);
      if (this.nativeDraggable) {
        off(el, 'dragover', this);
        off(el, 'dragenter', this);
      }
      // Remove draggable attributes
      Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
        el.removeAttribute('draggable');
      });
      this._onDrop();
      this._disableDelayedDragEvents();
      sortables.splice(sortables.indexOf(this.el), 1);
      this.el = el = null;
    },
    _hideClone: function _hideClone() {
      if (!cloneHidden) {
        pluginEvent('hideClone', this);
        if (Sortable.eventCanceled) return;
        css(cloneEl, 'display', 'none');
        if (this.options.removeCloneOnHide && cloneEl.parentNode) {
          cloneEl.parentNode.removeChild(cloneEl);
        }
        cloneHidden = true;
      }
    },
    _showClone: function _showClone(putSortable) {
      if (putSortable.lastPutMode !== 'clone') {
        this._hideClone();
        return;
      }
      if (cloneHidden) {
        pluginEvent('showClone', this);
        if (Sortable.eventCanceled) return;

        // show clone at dragEl or original position
        if (dragEl.parentNode == rootEl && !this.options.group.revertClone) {
          rootEl.insertBefore(cloneEl, dragEl);
        } else if (nextEl) {
          rootEl.insertBefore(cloneEl, nextEl);
        } else {
          rootEl.appendChild(cloneEl);
        }
        if (this.options.group.revertClone) {
          this.animate(dragEl, cloneEl);
        }
        css(cloneEl, 'display', '');
        cloneHidden = false;
      }
    }
  };
  function _globalDragOver( /**Event*/evt) {
    if (evt.dataTransfer) {
      evt.dataTransfer.dropEffect = 'move';
    }
    evt.cancelable && evt.preventDefault();
  }
  function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
    var evt,
      sortable = fromEl[expando],
      onMoveFn = sortable.options.onMove,
      retVal;
    // Support for new CustomEvent feature
    if (window.CustomEvent && !IE11OrLess && !Edge) {
      evt = new CustomEvent('move', {
        bubbles: true,
        cancelable: true
      });
    } else {
      evt = document.createEvent('Event');
      evt.initEvent('move', true, true);
    }
    evt.to = toEl;
    evt.from = fromEl;
    evt.dragged = dragEl;
    evt.draggedRect = dragRect;
    evt.related = targetEl || toEl;
    evt.relatedRect = targetRect || getRect(toEl);
    evt.willInsertAfter = willInsertAfter;
    evt.originalEvent = originalEvent;
    fromEl.dispatchEvent(evt);
    if (onMoveFn) {
      retVal = onMoveFn.call(sortable, evt, originalEvent);
    }
    return retVal;
  }
  function _disableDraggable(el) {
    el.draggable = false;
  }
  function _unsilent() {
    _silent = false;
  }
  function _ghostIsFirst(evt, vertical, sortable) {
    var firstElRect = getRect(getChild(sortable.el, 0, sortable.options, true));
    var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);
    var spacer = 10;
    return vertical ? evt.clientX < childContainingRect.left - spacer || evt.clientY < firstElRect.top && evt.clientX < firstElRect.right : evt.clientY < childContainingRect.top - spacer || evt.clientY < firstElRect.bottom && evt.clientX < firstElRect.left;
  }
  function _ghostIsLast(evt, vertical, sortable) {
    var lastElRect = getRect(lastChild(sortable.el, sortable.options.draggable));
    var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);
    var spacer = 10;
    return vertical ? evt.clientX > childContainingRect.right + spacer || evt.clientY > lastElRect.bottom && evt.clientX > lastElRect.left : evt.clientY > childContainingRect.bottom + spacer || evt.clientX > lastElRect.right && evt.clientY > lastElRect.top;
  }
  function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
    var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
      targetLength = vertical ? targetRect.height : targetRect.width,
      targetS1 = vertical ? targetRect.top : targetRect.left,
      targetS2 = vertical ? targetRect.bottom : targetRect.right,
      invert = false;
    if (!invertSwap) {
      // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
      if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
        // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
        // check if past first invert threshold on side opposite of lastDirection
        if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
          // past first invert threshold, do not restrict inverted threshold to dragEl shadow
          pastFirstInvertThresh = true;
        }
        if (!pastFirstInvertThresh) {
          // dragEl shadow (target move distance shadow)
          if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
          : mouseOnAxis > targetS2 - targetMoveDistance) {
            return -lastDirection;
          }
        } else {
          invert = true;
        }
      } else {
        // Regular
        if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
          return _getInsertDirection(target);
        }
      }
    }
    invert = invert || invertSwap;
    if (invert) {
      // Invert of regular
      if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
        return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
      }
    }
    return 0;
  }

  /**
   * Gets the direction dragEl must be swapped relative to target in order to make it
   * seem that dragEl has been "inserted" into that element's position
   * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
   * @return {Number}                   Direction dragEl must be swapped
   */
  function _getInsertDirection(target) {
    if (index(dragEl) < index(target)) {
      return 1;
    } else {
      return -1;
    }
  }

  /**
   * Generate id
   * @param   {HTMLElement} el
   * @returns {String}
   * @private
   */
  function _generateId(el) {
    var str = el.tagName + el.className + el.src + el.href + el.textContent,
      i = str.length,
      sum = 0;
    while (i--) {
      sum += str.charCodeAt(i);
    }
    return sum.toString(36);
  }
  function _saveInputCheckedState(root) {
    savedInputChecked.length = 0;
    var inputs = root.getElementsByTagName('input');
    var idx = inputs.length;
    while (idx--) {
      var el = inputs[idx];
      el.checked && savedInputChecked.push(el);
    }
  }
  function _nextTick(fn) {
    return setTimeout(fn, 0);
  }
  function _cancelNextTick(id) {
    return clearTimeout(id);
  }

  // Fixed #973:
  if (documentExists) {
    on(document, 'touchmove', function (evt) {
      if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
        evt.preventDefault();
      }
    });
  }

  // Export utils
  Sortable.utils = {
    on: on,
    off: off,
    css: css,
    find: find,
    is: function is(el, selector) {
      return !!closest(el, selector, el, false);
    },
    extend: extend,
    throttle: throttle,
    closest: closest,
    toggleClass: toggleClass,
    clone: clone,
    index: index,
    nextTick: _nextTick,
    cancelNextTick: _cancelNextTick,
    detectDirection: _detectDirection,
    getChild: getChild,
    expando: expando
  };

  /**
   * Get the Sortable instance of an element
   * @param  {HTMLElement} element The element
   * @return {Sortable|undefined}         The instance of Sortable
   */
  Sortable.get = function (element) {
    return element[expando];
  };

  /**
   * Mount a plugin to Sortable
   * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
   */
  Sortable.mount = function () {
    for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
      plugins[_key] = arguments[_key];
    }
    if (plugins[0].constructor === Array) plugins = plugins[0];
    plugins.forEach(function (plugin) {
      if (!plugin.prototype || !plugin.prototype.constructor) {
        throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
      }
      if (plugin.utils) Sortable.utils = _objectSpread2(_objectSpread2({}, Sortable.utils), plugin.utils);
      PluginManager.mount(plugin);
    });
  };

  /**
   * Create sortable instance
   * @param {HTMLElement}  el
   * @param {Object}      [options]
   */
  Sortable.create = function (el, options) {
    return new Sortable(el, options);
  };

  // Export
  Sortable.version = version;

  var autoScrolls = [],
    scrollEl,
    scrollRootEl,
    scrolling = false,
    lastAutoScrollX,
    lastAutoScrollY,
    touchEvt$1,
    pointerElemChangedInterval;
  function AutoScrollPlugin() {
    function AutoScroll() {
      this.defaults = {
        scroll: true,
        forceAutoScrollFallback: false,
        scrollSensitivity: 30,
        scrollSpeed: 10,
        bubbleScroll: true
      };

      // Bind all private methods
      for (var fn in this) {
        if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
          this[fn] = this[fn].bind(this);
        }
      }
    }
    AutoScroll.prototype = {
      dragStarted: function dragStarted(_ref) {
        var originalEvent = _ref.originalEvent;
        if (this.sortable.nativeDraggable) {
          on(document, 'dragover', this._handleAutoScroll);
        } else {
          if (this.options.supportPointer) {
            on(document, 'pointermove', this._handleFallbackAutoScroll);
          } else if (originalEvent.touches) {
            on(document, 'touchmove', this._handleFallbackAutoScroll);
          } else {
            on(document, 'mousemove', this._handleFallbackAutoScroll);
          }
        }
      },
      dragOverCompleted: function dragOverCompleted(_ref2) {
        var originalEvent = _ref2.originalEvent;
        // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
        if (!this.options.dragOverBubble && !originalEvent.rootEl) {
          this._handleAutoScroll(originalEvent);
        }
      },
      drop: function drop() {
        if (this.sortable.nativeDraggable) {
          off(document, 'dragover', this._handleAutoScroll);
        } else {
          off(document, 'pointermove', this._handleFallbackAutoScroll);
          off(document, 'touchmove', this._handleFallbackAutoScroll);
          off(document, 'mousemove', this._handleFallbackAutoScroll);
        }
        clearPointerElemChangedInterval();
        clearAutoScrolls();
        cancelThrottle();
      },
      nulling: function nulling() {
        touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
        autoScrolls.length = 0;
      },
      _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
        this._handleAutoScroll(evt, true);
      },
      _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
        var _this = this;
        var x = (evt.touches ? evt.touches[0] : evt).clientX,
          y = (evt.touches ? evt.touches[0] : evt).clientY,
          elem = document.elementFromPoint(x, y);
        touchEvt$1 = evt;

        // IE does not seem to have native autoscroll,
        // Edge's autoscroll seems too conditional,
        // MACOS Safari does not have autoscroll,
        // Firefox and Chrome are good
        if (fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari) {
          autoScroll(evt, this.options, elem, fallback);

          // Listener for pointer element change
          var ogElemScroller = getParentAutoScrollElement(elem, true);
          if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
            pointerElemChangedInterval && clearPointerElemChangedInterval();
            // Detect for pointer elem change, emulating native DnD behaviour
            pointerElemChangedInterval = setInterval(function () {
              var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
              if (newElem !== ogElemScroller) {
                ogElemScroller = newElem;
                clearAutoScrolls();
              }
              autoScroll(evt, _this.options, newElem, fallback);
            }, 10);
            lastAutoScrollX = x;
            lastAutoScrollY = y;
          }
        } else {
          // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
          if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
            clearAutoScrolls();
            return;
          }
          autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
        }
      }
    };
    return _extends(AutoScroll, {
      pluginName: 'scroll',
      initializeByDefault: true
    });
  }
  function clearAutoScrolls() {
    autoScrolls.forEach(function (autoScroll) {
      clearInterval(autoScroll.pid);
    });
    autoScrolls = [];
  }
  function clearPointerElemChangedInterval() {
    clearInterval(pointerElemChangedInterval);
  }
  var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
    // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
    if (!options.scroll) return;
    var x = (evt.touches ? evt.touches[0] : evt).clientX,
      y = (evt.touches ? evt.touches[0] : evt).clientY,
      sens = options.scrollSensitivity,
      speed = options.scrollSpeed,
      winScroller = getWindowScrollingElement();
    var scrollThisInstance = false,
      scrollCustomFn;

    // New scroll root, set scrollEl
    if (scrollRootEl !== rootEl) {
      scrollRootEl = rootEl;
      clearAutoScrolls();
      scrollEl = options.scroll;
      scrollCustomFn = options.scrollFn;
      if (scrollEl === true) {
        scrollEl = getParentAutoScrollElement(rootEl, true);
      }
    }
    var layersOut = 0;
    var currentParent = scrollEl;
    do {
      var el = currentParent,
        rect = getRect(el),
        top = rect.top,
        bottom = rect.bottom,
        left = rect.left,
        right = rect.right,
        width = rect.width,
        height = rect.height,
        canScrollX = void 0,
        canScrollY = void 0,
        scrollWidth = el.scrollWidth,
        scrollHeight = el.scrollHeight,
        elCSS = css(el),
        scrollPosX = el.scrollLeft,
        scrollPosY = el.scrollTop;
      if (el === winScroller) {
        canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
        canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
      } else {
        canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
        canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
      }
      var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
      var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
      if (!autoScrolls[layersOut]) {
        for (var i = 0; i <= layersOut; i++) {
          if (!autoScrolls[i]) {
            autoScrolls[i] = {};
          }
        }
      }
      if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
        autoScrolls[layersOut].el = el;
        autoScrolls[layersOut].vx = vx;
        autoScrolls[layersOut].vy = vy;
        clearInterval(autoScrolls[layersOut].pid);
        if (vx != 0 || vy != 0) {
          scrollThisInstance = true;
          /* jshint loopfunc:true */
          autoScrolls[layersOut].pid = setInterval(function () {
            // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
            if (isFallback && this.layer === 0) {
              Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
            }
            var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
            var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
            if (typeof scrollCustomFn === 'function') {
              if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
                return;
              }
            }
            scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
          }.bind({
            layer: layersOut
          }), 24);
        }
      }
      layersOut++;
    } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
    scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
  }, 30);

  var drop = function drop(_ref) {
    var originalEvent = _ref.originalEvent,
      putSortable = _ref.putSortable,
      dragEl = _ref.dragEl,
      activeSortable = _ref.activeSortable,
      dispatchSortableEvent = _ref.dispatchSortableEvent,
      hideGhostForTarget = _ref.hideGhostForTarget,
      unhideGhostForTarget = _ref.unhideGhostForTarget;
    if (!originalEvent) return;
    var toSortable = putSortable || activeSortable;
    hideGhostForTarget();
    var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
    var target = document.elementFromPoint(touch.clientX, touch.clientY);
    unhideGhostForTarget();
    if (toSortable && !toSortable.el.contains(target)) {
      dispatchSortableEvent('spill');
      this.onSpill({
        dragEl: dragEl,
        putSortable: putSortable
      });
    }
  };
  function Revert() {}
  Revert.prototype = {
    startIndex: null,
    dragStart: function dragStart(_ref2) {
      var oldDraggableIndex = _ref2.oldDraggableIndex;
      this.startIndex = oldDraggableIndex;
    },
    onSpill: function onSpill(_ref3) {
      var dragEl = _ref3.dragEl,
        putSortable = _ref3.putSortable;
      this.sortable.captureAnimationState();
      if (putSortable) {
        putSortable.captureAnimationState();
      }
      var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
      if (nextSibling) {
        this.sortable.el.insertBefore(dragEl, nextSibling);
      } else {
        this.sortable.el.appendChild(dragEl);
      }
      this.sortable.animateAll();
      if (putSortable) {
        putSortable.animateAll();
      }
    },
    drop: drop
  };
  _extends(Revert, {
    pluginName: 'revertOnSpill'
  });
  function Remove() {}
  Remove.prototype = {
    onSpill: function onSpill(_ref4) {
      var dragEl = _ref4.dragEl,
        putSortable = _ref4.putSortable;
      var parentSortable = putSortable || this.sortable;
      parentSortable.captureAnimationState();
      dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
      parentSortable.animateAll();
    },
    drop: drop
  };
  _extends(Remove, {
    pluginName: 'removeOnSpill'
  });

  var lastSwapEl;
  function SwapPlugin() {
    function Swap() {
      this.defaults = {
        swapClass: 'sortable-swap-highlight'
      };
    }
    Swap.prototype = {
      dragStart: function dragStart(_ref) {
        var dragEl = _ref.dragEl;
        lastSwapEl = dragEl;
      },
      dragOverValid: function dragOverValid(_ref2) {
        var completed = _ref2.completed,
          target = _ref2.target,
          onMove = _ref2.onMove,
          activeSortable = _ref2.activeSortable,
          changed = _ref2.changed,
          cancel = _ref2.cancel;
        if (!activeSortable.options.swap) return;
        var el = this.sortable.el,
          options = this.options;
        if (target && target !== el) {
          var prevSwapEl = lastSwapEl;
          if (onMove(target) !== false) {
            toggleClass(target, options.swapClass, true);
            lastSwapEl = target;
          } else {
            lastSwapEl = null;
          }
          if (prevSwapEl && prevSwapEl !== lastSwapEl) {
            toggleClass(prevSwapEl, options.swapClass, false);
          }
        }
        changed();
        completed(true);
        cancel();
      },
      drop: function drop(_ref3) {
        var activeSortable = _ref3.activeSortable,
          putSortable = _ref3.putSortable,
          dragEl = _ref3.dragEl;
        var toSortable = putSortable || this.sortable;
        var options = this.options;
        lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
        if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
          if (dragEl !== lastSwapEl) {
            toSortable.captureAnimationState();
            if (toSortable !== activeSortable) activeSortable.captureAnimationState();
            swapNodes(dragEl, lastSwapEl);
            toSortable.animateAll();
            if (toSortable !== activeSortable) activeSortable.animateAll();
          }
        }
      },
      nulling: function nulling() {
        lastSwapEl = null;
      }
    };
    return _extends(Swap, {
      pluginName: 'swap',
      eventProperties: function eventProperties() {
        return {
          swapItem: lastSwapEl
        };
      }
    });
  }
  function swapNodes(n1, n2) {
    var p1 = n1.parentNode,
      p2 = n2.parentNode,
      i1,
      i2;
    if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
    i1 = index(n1);
    i2 = index(n2);
    if (p1.isEqualNode(p2) && i1 < i2) {
      i2++;
    }
    p1.insertBefore(n2, p1.children[i1]);
    p2.insertBefore(n1, p2.children[i2]);
  }

  var multiDragElements = [],
    multiDragClones = [],
    lastMultiDragSelect,
    // for selection with modifier key down (SHIFT)
    multiDragSortable,
    initialFolding = false,
    // Initial multi-drag fold when drag started
    folding = false,
    // Folding any other time
    dragStarted = false,
    dragEl$1,
    clonesFromRect,
    clonesHidden;
  function MultiDragPlugin() {
    function MultiDrag(sortable) {
      // Bind all private methods
      for (var fn in this) {
        if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
          this[fn] = this[fn].bind(this);
        }
      }
      if (!sortable.options.avoidImplicitDeselect) {
        if (sortable.options.supportPointer) {
          on(document, 'pointerup', this._deselectMultiDrag);
        } else {
          on(document, 'mouseup', this._deselectMultiDrag);
          on(document, 'touchend', this._deselectMultiDrag);
        }
      }
      on(document, 'keydown', this._checkKeyDown);
      on(document, 'keyup', this._checkKeyUp);
      this.defaults = {
        selectedClass: 'sortable-selected',
        multiDragKey: null,
        avoidImplicitDeselect: false,
        setData: function setData(dataTransfer, dragEl) {
          var data = '';
          if (multiDragElements.length && multiDragSortable === sortable) {
            multiDragElements.forEach(function (multiDragElement, i) {
              data += (!i ? '' : ', ') + multiDragElement.textContent;
            });
          } else {
            data = dragEl.textContent;
          }
          dataTransfer.setData('Text', data);
        }
      };
    }
    MultiDrag.prototype = {
      multiDragKeyDown: false,
      isMultiDrag: false,
      delayStartGlobal: function delayStartGlobal(_ref) {
        var dragged = _ref.dragEl;
        dragEl$1 = dragged;
      },
      delayEnded: function delayEnded() {
        this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
      },
      setupClone: function setupClone(_ref2) {
        var sortable = _ref2.sortable,
          cancel = _ref2.cancel;
        if (!this.isMultiDrag) return;
        for (var i = 0; i < multiDragElements.length; i++) {
          multiDragClones.push(clone(multiDragElements[i]));
          multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
          multiDragClones[i].draggable = false;
          multiDragClones[i].style['will-change'] = '';
          toggleClass(multiDragClones[i], this.options.selectedClass, false);
          multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
        }
        sortable._hideClone();
        cancel();
      },
      clone: function clone(_ref3) {
        var sortable = _ref3.sortable,
          rootEl = _ref3.rootEl,
          dispatchSortableEvent = _ref3.dispatchSortableEvent,
          cancel = _ref3.cancel;
        if (!this.isMultiDrag) return;
        if (!this.options.removeCloneOnHide) {
          if (multiDragElements.length && multiDragSortable === sortable) {
            insertMultiDragClones(true, rootEl);
            dispatchSortableEvent('clone');
            cancel();
          }
        }
      },
      showClone: function showClone(_ref4) {
        var cloneNowShown = _ref4.cloneNowShown,
          rootEl = _ref4.rootEl,
          cancel = _ref4.cancel;
        if (!this.isMultiDrag) return;
        insertMultiDragClones(false, rootEl);
        multiDragClones.forEach(function (clone) {
          css(clone, 'display', '');
        });
        cloneNowShown();
        clonesHidden = false;
        cancel();
      },
      hideClone: function hideClone(_ref5) {
        var _this = this;
        var sortable = _ref5.sortable,
          cloneNowHidden = _ref5.cloneNowHidden,
          cancel = _ref5.cancel;
        if (!this.isMultiDrag) return;
        multiDragClones.forEach(function (clone) {
          css(clone, 'display', 'none');
          if (_this.options.removeCloneOnHide && clone.parentNode) {
            clone.parentNode.removeChild(clone);
          }
        });
        cloneNowHidden();
        clonesHidden = true;
        cancel();
      },
      dragStartGlobal: function dragStartGlobal(_ref6) {
        var sortable = _ref6.sortable;
        if (!this.isMultiDrag && multiDragSortable) {
          multiDragSortable.multiDrag._deselectMultiDrag();
        }
        multiDragElements.forEach(function (multiDragElement) {
          multiDragElement.sortableIndex = index(multiDragElement);
        });

        // Sort multi-drag elements
        multiDragElements = multiDragElements.sort(function (a, b) {
          return a.sortableIndex - b.sortableIndex;
        });
        dragStarted = true;
      },
      dragStarted: function dragStarted(_ref7) {
        var _this2 = this;
        var sortable = _ref7.sortable;
        if (!this.isMultiDrag) return;
        if (this.options.sort) {
          // Capture rects,
          // hide multi drag elements (by positioning them absolute),
          // set multi drag elements rects to dragRect,
          // show multi drag elements,
          // animate to rects,
          // unset rects & remove from DOM

          sortable.captureAnimationState();
          if (this.options.animation) {
            multiDragElements.forEach(function (multiDragElement) {
              if (multiDragElement === dragEl$1) return;
              css(multiDragElement, 'position', 'absolute');
            });
            var dragRect = getRect(dragEl$1, false, true, true);
            multiDragElements.forEach(function (multiDragElement) {
              if (multiDragElement === dragEl$1) return;
              setRect(multiDragElement, dragRect);
            });
            folding = true;
            initialFolding = true;
          }
        }
        sortable.animateAll(function () {
          folding = false;
          initialFolding = false;
          if (_this2.options.animation) {
            multiDragElements.forEach(function (multiDragElement) {
              unsetRect(multiDragElement);
            });
          }

          // Remove all auxiliary multidrag items from el, if sorting enabled
          if (_this2.options.sort) {
            removeMultiDragElements();
          }
        });
      },
      dragOver: function dragOver(_ref8) {
        var target = _ref8.target,
          completed = _ref8.completed,
          cancel = _ref8.cancel;
        if (folding && ~multiDragElements.indexOf(target)) {
          completed(false);
          cancel();
        }
      },
      revert: function revert(_ref9) {
        var fromSortable = _ref9.fromSortable,
          rootEl = _ref9.rootEl,
          sortable = _ref9.sortable,
          dragRect = _ref9.dragRect;
        if (multiDragElements.length > 1) {
          // Setup unfold animation
          multiDragElements.forEach(function (multiDragElement) {
            sortable.addAnimationState({
              target: multiDragElement,
              rect: folding ? getRect(multiDragElement) : dragRect
            });
            unsetRect(multiDragElement);
            multiDragElement.fromRect = dragRect;
            fromSortable.removeAnimationState(multiDragElement);
          });
          folding = false;
          insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
        }
      },
      dragOverCompleted: function dragOverCompleted(_ref10) {
        var sortable = _ref10.sortable,
          isOwner = _ref10.isOwner,
          insertion = _ref10.insertion,
          activeSortable = _ref10.activeSortable,
          parentEl = _ref10.parentEl,
          putSortable = _ref10.putSortable;
        var options = this.options;
        if (insertion) {
          // Clones must be hidden before folding animation to capture dragRectAbsolute properly
          if (isOwner) {
            activeSortable._hideClone();
          }
          initialFolding = false;
          // If leaving sort:false root, or already folding - Fold to new location
          if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
            // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
            var dragRectAbsolute = getRect(dragEl$1, false, true, true);
            multiDragElements.forEach(function (multiDragElement) {
              if (multiDragElement === dragEl$1) return;
              setRect(multiDragElement, dragRectAbsolute);

              // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
              // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
              parentEl.appendChild(multiDragElement);
            });
            folding = true;
          }

          // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
          if (!isOwner) {
            // Only remove if not folding (folding will remove them anyways)
            if (!folding) {
              removeMultiDragElements();
            }
            if (multiDragElements.length > 1) {
              var clonesHiddenBefore = clonesHidden;
              activeSortable._showClone(sortable);

              // Unfold animation for clones if showing from hidden
              if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
                multiDragClones.forEach(function (clone) {
                  activeSortable.addAnimationState({
                    target: clone,
                    rect: clonesFromRect
                  });
                  clone.fromRect = clonesFromRect;
                  clone.thisAnimationDuration = null;
                });
              }
            } else {
              activeSortable._showClone(sortable);
            }
          }
        }
      },
      dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
        var dragRect = _ref11.dragRect,
          isOwner = _ref11.isOwner,
          activeSortable = _ref11.activeSortable;
        multiDragElements.forEach(function (multiDragElement) {
          multiDragElement.thisAnimationDuration = null;
        });
        if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
          clonesFromRect = _extends({}, dragRect);
          var dragMatrix = matrix(dragEl$1, true);
          clonesFromRect.top -= dragMatrix.f;
          clonesFromRect.left -= dragMatrix.e;
        }
      },
      dragOverAnimationComplete: function dragOverAnimationComplete() {
        if (folding) {
          folding = false;
          removeMultiDragElements();
        }
      },
      drop: function drop(_ref12) {
        var evt = _ref12.originalEvent,
          rootEl = _ref12.rootEl,
          parentEl = _ref12.parentEl,
          sortable = _ref12.sortable,
          dispatchSortableEvent = _ref12.dispatchSortableEvent,
          oldIndex = _ref12.oldIndex,
          putSortable = _ref12.putSortable;
        var toSortable = putSortable || this.sortable;
        if (!evt) return;
        var options = this.options,
          children = parentEl.children;

        // Multi-drag selection
        if (!dragStarted) {
          if (options.multiDragKey && !this.multiDragKeyDown) {
            this._deselectMultiDrag();
          }
          toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
          if (!~multiDragElements.indexOf(dragEl$1)) {
            multiDragElements.push(dragEl$1);
            dispatchEvent({
              sortable: sortable,
              rootEl: rootEl,
              name: 'select',
              targetEl: dragEl$1,
              originalEvent: evt
            });

            // Modifier activated, select from last to dragEl
            if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
              var lastIndex = index(lastMultiDragSelect),
                currentIndex = index(dragEl$1);
              if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
                (function () {
                  // Must include lastMultiDragSelect (select it), in case modified selection from no selection
                  // (but previous selection existed)
                  var n, i;
                  if (currentIndex > lastIndex) {
                    i = lastIndex;
                    n = currentIndex;
                  } else {
                    i = currentIndex;
                    n = lastIndex + 1;
                  }
                  var filter = options.filter;
                  for (; i < n; i++) {
                    if (~multiDragElements.indexOf(children[i])) continue;
                    // Check if element is draggable
                    if (!closest(children[i], options.draggable, parentEl, false)) continue;
                    // Check if element is filtered
                    var filtered = filter && (typeof filter === 'function' ? filter.call(sortable, evt, children[i], sortable) : filter.split(',').some(function (criteria) {
                      return closest(children[i], criteria.trim(), parentEl, false);
                    }));
                    if (filtered) continue;
                    toggleClass(children[i], options.selectedClass, true);
                    multiDragElements.push(children[i]);
                    dispatchEvent({
                      sortable: sortable,
                      rootEl: rootEl,
                      name: 'select',
                      targetEl: children[i],
                      originalEvent: evt
                    });
                  }
                })();
              }
            } else {
              lastMultiDragSelect = dragEl$1;
            }
            multiDragSortable = toSortable;
          } else {
            multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
            lastMultiDragSelect = null;
            dispatchEvent({
              sortable: sortable,
              rootEl: rootEl,
              name: 'deselect',
              targetEl: dragEl$1,
              originalEvent: evt
            });
          }
        }

        // Multi-drag drop
        if (dragStarted && this.isMultiDrag) {
          folding = false;
          // Do not "unfold" after around dragEl if reverted
          if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
            var dragRect = getRect(dragEl$1),
              multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
            if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
            toSortable.captureAnimationState();
            if (!initialFolding) {
              if (options.animation) {
                dragEl$1.fromRect = dragRect;
                multiDragElements.forEach(function (multiDragElement) {
                  multiDragElement.thisAnimationDuration = null;
                  if (multiDragElement !== dragEl$1) {
                    var rect = folding ? getRect(multiDragElement) : dragRect;
                    multiDragElement.fromRect = rect;

                    // Prepare unfold animation
                    toSortable.addAnimationState({
                      target: multiDragElement,
                      rect: rect
                    });
                  }
                });
              }

              // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
              // properly they must all be removed
              removeMultiDragElements();
              multiDragElements.forEach(function (multiDragElement) {
                if (children[multiDragIndex]) {
                  parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
                } else {
                  parentEl.appendChild(multiDragElement);
                }
                multiDragIndex++;
              });

              // If initial folding is done, the elements may have changed position because they are now
              // unfolding around dragEl, even though dragEl may not have his index changed, so update event
              // must be fired here as Sortable will not.
              if (oldIndex === index(dragEl$1)) {
                var update = false;
                multiDragElements.forEach(function (multiDragElement) {
                  if (multiDragElement.sortableIndex !== index(multiDragElement)) {
                    update = true;
                    return;
                  }
                });
                if (update) {
                  dispatchSortableEvent('update');
                  dispatchSortableEvent('sort');
                }
              }
            }

            // Must be done after capturing individual rects (scroll bar)
            multiDragElements.forEach(function (multiDragElement) {
              unsetRect(multiDragElement);
            });
            toSortable.animateAll();
          }
          multiDragSortable = toSortable;
        }

        // Remove clones if necessary
        if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
          multiDragClones.forEach(function (clone) {
            clone.parentNode && clone.parentNode.removeChild(clone);
          });
        }
      },
      nullingGlobal: function nullingGlobal() {
        this.isMultiDrag = dragStarted = false;
        multiDragClones.length = 0;
      },
      destroyGlobal: function destroyGlobal() {
        this._deselectMultiDrag();
        off(document, 'pointerup', this._deselectMultiDrag);
        off(document, 'mouseup', this._deselectMultiDrag);
        off(document, 'touchend', this._deselectMultiDrag);
        off(document, 'keydown', this._checkKeyDown);
        off(document, 'keyup', this._checkKeyUp);
      },
      _deselectMultiDrag: function _deselectMultiDrag(evt) {
        if (typeof dragStarted !== "undefined" && dragStarted) return;

        // Only deselect if selection is in this sortable
        if (multiDragSortable !== this.sortable) return;

        // Only deselect if target is not item in this sortable
        if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return;

        // Only deselect if left click
        if (evt && evt.button !== 0) return;
        while (multiDragElements.length) {
          var el = multiDragElements[0];
          toggleClass(el, this.options.selectedClass, false);
          multiDragElements.shift();
          dispatchEvent({
            sortable: this.sortable,
            rootEl: this.sortable.el,
            name: 'deselect',
            targetEl: el,
            originalEvent: evt
          });
        }
      },
      _checkKeyDown: function _checkKeyDown(evt) {
        if (evt.key === this.options.multiDragKey) {
          this.multiDragKeyDown = true;
        }
      },
      _checkKeyUp: function _checkKeyUp(evt) {
        if (evt.key === this.options.multiDragKey) {
          this.multiDragKeyDown = false;
        }
      }
    };
    return _extends(MultiDrag, {
      // Static methods & properties
      pluginName: 'multiDrag',
      utils: {
        /**
         * Selects the provided multi-drag item
         * @param  {HTMLElement} el    The element to be selected
         */
        select: function select(el) {
          var sortable = el.parentNode[expando];
          if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
          if (multiDragSortable && multiDragSortable !== sortable) {
            multiDragSortable.multiDrag._deselectMultiDrag();
            multiDragSortable = sortable;
          }
          toggleClass(el, sortable.options.selectedClass, true);
          multiDragElements.push(el);
        },
        /**
         * Deselects the provided multi-drag item
         * @param  {HTMLElement} el    The element to be deselected
         */
        deselect: function deselect(el) {
          var sortable = el.parentNode[expando],
            index = multiDragElements.indexOf(el);
          if (!sortable || !sortable.options.multiDrag || !~index) return;
          toggleClass(el, sortable.options.selectedClass, false);
          multiDragElements.splice(index, 1);
        }
      },
      eventProperties: function eventProperties() {
        var _this3 = this;
        var oldIndicies = [],
          newIndicies = [];
        multiDragElements.forEach(function (multiDragElement) {
          oldIndicies.push({
            multiDragElement: multiDragElement,
            index: multiDragElement.sortableIndex
          });

          // multiDragElements will already be sorted if folding
          var newIndex;
          if (folding && multiDragElement !== dragEl$1) {
            newIndex = -1;
          } else if (folding) {
            newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');
          } else {
            newIndex = index(multiDragElement);
          }
          newIndicies.push({
            multiDragElement: multiDragElement,
            index: newIndex
          });
        });
        return {
          items: _toConsumableArray(multiDragElements),
          clones: [].concat(multiDragClones),
          oldIndicies: oldIndicies,
          newIndicies: newIndicies
        };
      },
      optionListeners: {
        multiDragKey: function multiDragKey(key) {
          key = key.toLowerCase();
          if (key === 'ctrl') {
            key = 'Control';
          } else if (key.length > 1) {
            key = key.charAt(0).toUpperCase() + key.substr(1);
          }
          return key;
        }
      }
    });
  }
  function insertMultiDragElements(clonesInserted, rootEl) {
    multiDragElements.forEach(function (multiDragElement, i) {
      var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
      if (target) {
        rootEl.insertBefore(multiDragElement, target);
      } else {
        rootEl.appendChild(multiDragElement);
      }
    });
  }

  /**
   * Insert multi-drag clones
   * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
   * @param  {HTMLElement} rootEl
   */
  function insertMultiDragClones(elementsInserted, rootEl) {
    multiDragClones.forEach(function (clone, i) {
      var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
      if (target) {
        rootEl.insertBefore(clone, target);
      } else {
        rootEl.appendChild(clone);
      }
    });
  }
  function removeMultiDragElements() {
    multiDragElements.forEach(function (multiDragElement) {
      if (multiDragElement === dragEl$1) return;
      multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
    });
  }

  Sortable.mount(new AutoScrollPlugin());
  Sortable.mount(Remove, Revert);

  Sortable.mount(new SwapPlugin());
  Sortable.mount(new MultiDragPlugin());

  return Sortable;

})));

(function (factory) {
  typeof define === 'function' && define.amd ? define(factory) :
  factory();
}((function () { 'use strict';

  (function() {

    var select = HTMLSelectElement.prototype;
    if (select.hasOwnProperty("selectedOptions")) return

    Object.defineProperty(select, "selectedOptions", {
      get: function() {
        return this.querySelectorAll(":checked")
      },
      enumerable: true,
      configurable: true,
    });
  })();

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

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

  (function(){function n(){function v(){return null}function l(a){return a?"object"===typeof a||"function"===typeof a:!1}function p(a){if(null!==a&&!l(a))throw new TypeError("Object prototype may only be an Object or null: "+a);}var q=null,e=Object,w=!!e.create||!({__proto__:null}instanceof e),A=e.create||(w?function(a){p(a);return {__proto__:a}}:function(a){function c(){}p(a);if(null===a)throw new SyntaxError("Native Object.create is required to create objects with null prototype");c.prototype=a;return new c}),
  B=e.getPrototypeOf||([].__proto__===Array.prototype?function(a){a=a.__proto__;return l(a)?a:null}:v);var m=function(a,c){function k(){}if(void 0===(this&&this instanceof m?this.constructor:void 0))throw new TypeError("Constructor Proxy requires 'new'");if(!l(a)||!l(c))throw new TypeError("Cannot create proxy with a non-object as target or handler");q=function(){a=null;k=function(b){throw new TypeError("Cannot perform '"+b+"' on a proxy that has been revoked");};};setTimeout(function(){q=null;},0);var g=
  c;c={get:null,set:null,apply:null,construct:null};for(var h in g){if(!(h in c))throw new TypeError("Proxy polyfill does not support trap '"+h+"'");c[h]=g[h];}"function"===typeof g&&(c.apply=g.apply.bind(g));g=B(a);var r=!1,t=!1;if("function"===typeof a){var f=function(){var b=this&&this.constructor===f,d=Array.prototype.slice.call(arguments);k(b?"construct":"apply");return b&&c.construct?c.construct.call(this,a,d):!b&&c.apply?c.apply(a,this,d):b?(d.unshift(a),new (a.bind.apply(a,d))):a.apply(this,
  d)};r=!0;}else a instanceof Array?(f=[],t=!0):f=w||null!==g?A(g):{};var x=c.get?function(b){k("get");return c.get(this,b,f)}:function(b){k("get");return this[b]},C=c.set?function(b,d){k("set");c.set(this,b,d,f);}:function(b,d){k("set");this[b]=d;},y={};e.getOwnPropertyNames(a).forEach(function(b){if(!((r||t)&&b in f)){var d=e.getOwnPropertyDescriptor(a,b);e.defineProperty(f,b,{enumerable:!!d.enumerable,get:x.bind(a,b),set:C.bind(a,b)});y[b]=!0;}});h=!0;if(r||t){var D=e.setPrototypeOf||([].__proto__===
  Array.prototype?function(b,d){p(d);b.__proto__=d;return b}:v);g&&D(f,g)||(h=!1);}if(c.get||!h)for(var u in a)y[u]||e.defineProperty(f,u,{get:x.bind(a,u)});e.seal(a);e.seal(f);return f};m.revocable=function(a,c){return {proxy:new m(a,c),revoke:q}};return m}var z="undefined"!==typeof process&&"[object process]"==={}.toString.call(process)||"undefined"!==typeof navigator&&"ReactNative"===navigator.product?commonjsGlobal:self;z.Proxy||(z.Proxy=n(),z.Proxy.revocable=z.Proxy.revocable);})();

  !function(e){var t=e.Element.prototype;"function"!=typeof t.matches&&(t.matches=t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||function(e){for(var t=(this.document||this.ownerDocument).querySelectorAll(e),o=0;t[o]&&t[o]!==this;)++o;return Boolean(t[o])}),"function"!=typeof t.closest&&(t.closest=function(e){for(var t=this;t&&1===t.nodeType;){if(t.matches(e))return t;t=t.parentNode;}return null});}(window);

  (function (arr) {
    arr.forEach(function (item) {
      if (item.hasOwnProperty('remove')) {
        return;
      }
      Object.defineProperty(item, 'remove', {
        configurable: true,
        enumerable: true,
        writable: true,
        value: function remove() {
          this.parentNode && this.parentNode.removeChild(this);
        }
      });
    });
  })([Element.prototype, CharacterData.prototype, DocumentType.prototype].filter(Boolean));

  /*
   * classList.js: Cross-browser full element.classList implementation.
   * 1.1.20170427
   *
   * By Eli Grey, http://eligrey.com
   * License: Dedicated to the public domain.
   *   See https://github.com/eligrey/classList.js/blob/master/LICENSE.md
   */

  /*global self, document, DOMException */

  /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */

  if ("document" in window.self) {

  // Full polyfill for browsers with no classList support
  // Including IE < Edge missing SVGElement.classList
  if (!("classList" in document.createElement("_")) 
  	|| document.createElementNS && !("classList" in document.createElementNS("http://www.w3.org/2000/svg","g"))) {

  (function (view) {

  if (!('Element' in view)) return;

  var
  	  classListProp = "classList"
  	, protoProp = "prototype"
  	, elemCtrProto = view.Element[protoProp]
  	, objCtr = Object
  	, strTrim = String[protoProp].trim || function () {
  		return this.replace(/^\s+|\s+$/g, "");
  	}
  	, arrIndexOf = Array[protoProp].indexOf || function (item) {
  		var
  			  i = 0
  			, len = this.length
  		;
  		for (; i < len; i++) {
  			if (i in this && this[i] === item) {
  				return i;
  			}
  		}
  		return -1;
  	}
  	// Vendors: please allow content code to instantiate DOMExceptions
  	, DOMEx = function (type, message) {
  		this.name = type;
  		this.code = DOMException[type];
  		this.message = message;
  	}
  	, checkTokenAndGetIndex = function (classList, token) {
  		if (token === "") {
  			throw new DOMEx(
  				  "SYNTAX_ERR"
  				, "An invalid or illegal string was specified"
  			);
  		}
  		if (/\s/.test(token)) {
  			throw new DOMEx(
  				  "INVALID_CHARACTER_ERR"
  				, "String contains an invalid character"
  			);
  		}
  		return arrIndexOf.call(classList, token);
  	}
  	, ClassList = function (elem) {
  		var
  			  trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
  			, classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
  			, i = 0
  			, len = classes.length
  		;
  		for (; i < len; i++) {
  			this.push(classes[i]);
  		}
  		this._updateClassName = function () {
  			elem.setAttribute("class", this.toString());
  		};
  	}
  	, classListProto = ClassList[protoProp] = []
  	, classListGetter = function () {
  		return new ClassList(this);
  	}
  ;
  // Most DOMException implementations don't allow calling DOMException's toString()
  // on non-DOMExceptions. Error's toString() is sufficient here.
  DOMEx[protoProp] = Error[protoProp];
  classListProto.item = function (i) {
  	return this[i] || null;
  };
  classListProto.contains = function (token) {
  	token += "";
  	return checkTokenAndGetIndex(this, token) !== -1;
  };
  classListProto.add = function () {
  	var
  		  tokens = arguments
  		, i = 0
  		, l = tokens.length
  		, token
  		, updated = false
  	;
  	do {
  		token = tokens[i] + "";
  		if (checkTokenAndGetIndex(this, token) === -1) {
  			this.push(token);
  			updated = true;
  		}
  	}
  	while (++i < l);

  	if (updated) {
  		this._updateClassName();
  	}
  };
  classListProto.remove = function () {
  	var
  		  tokens = arguments
  		, i = 0
  		, l = tokens.length
  		, token
  		, updated = false
  		, index
  	;
  	do {
  		token = tokens[i] + "";
  		index = checkTokenAndGetIndex(this, token);
  		while (index !== -1) {
  			this.splice(index, 1);
  			updated = true;
  			index = checkTokenAndGetIndex(this, token);
  		}
  	}
  	while (++i < l);

  	if (updated) {
  		this._updateClassName();
  	}
  };
  classListProto.toggle = function (token, force) {
  	token += "";

  	var
  		  result = this.contains(token)
  		, method = result ?
  			force !== true && "remove"
  		:
  			force !== false && "add"
  	;

  	if (method) {
  		this[method](token);
  	}

  	if (force === true || force === false) {
  		return force;
  	} else {
  		return !result;
  	}
  };
  classListProto.toString = function () {
  	return this.join(" ");
  };

  if (objCtr.defineProperty) {
  	var classListPropDesc = {
  		  get: classListGetter
  		, enumerable: true
  		, configurable: true
  	};
  	try {
  		objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
  	} catch (ex) { // IE 8 doesn't support enumerable:true
  		// adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
  		// modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
  		if (ex.number === undefined || ex.number === -0x7FF5EC54) {
  			classListPropDesc.enumerable = false;
  			objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
  		}
  	}
  } else if (objCtr[protoProp].__defineGetter__) {
  	elemCtrProto.__defineGetter__(classListProp, classListGetter);
  }

  }(window.self));

  }

  // There is full or partial native classList support, so just check if we need
  // to normalize the add/remove and toggle APIs.

  (function () {

  	var testElement = document.createElement("_");

  	testElement.classList.add("c1", "c2");

  	// Polyfill for IE 10/11 and Firefox <26, where classList.add and
  	// classList.remove exist but support only one argument at a time.
  	if (!testElement.classList.contains("c2")) {
  		var createMethod = function(method) {
  			var original = DOMTokenList.prototype[method];

  			DOMTokenList.prototype[method] = function(token) {
  				var i, len = arguments.length;

  				for (i = 0; i < len; i++) {
  					token = arguments[i];
  					original.call(this, token);
  				}
  			};
  		};
  		createMethod('add');
  		createMethod('remove');
  	}

  	testElement.classList.toggle("c3", false);

  	// Polyfill for IE 10 and Firefox <24, where classList.toggle does not
  	// support the second argument.
  	if (testElement.classList.contains("c3")) {
  		var _toggle = DOMTokenList.prototype.toggle;

  		DOMTokenList.prototype.toggle = function(token, force) {
  			if (1 in arguments && !this.contains(token) === !force) {
  				return force;
  			} else {
  				return _toggle.call(this, token);
  			}
  		};

  	}

  	testElement = null;
  }());

  }

  /**
   * @license
   * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
   * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
   * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
   * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
   * Code distributed by Google as part of the polymer project is also
   * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
   */

  // minimal template polyfill
  (function() {

    var needsTemplate = (typeof HTMLTemplateElement === 'undefined');
    var brokenDocFragment = !(document.createDocumentFragment().cloneNode() instanceof DocumentFragment);
    var needsDocFrag = false;

    // NOTE: Replace DocumentFragment to work around IE11 bug that
    // causes children of a document fragment modified while
    // there is a mutation observer to not have a parentNode, or
    // have a broken parentNode (!?!)
    if (/Trident/.test(navigator.userAgent)) {
      (function() {

        needsDocFrag = true;

        var origCloneNode = Node.prototype.cloneNode;
        Node.prototype.cloneNode = function cloneNode(deep) {
          var newDom = origCloneNode.call(this, deep);
          if (this instanceof DocumentFragment) {
            newDom.__proto__ = DocumentFragment.prototype;
          }
          return newDom;
        };

        // IE's DocumentFragment querySelector code doesn't work when
        // called on an element instance
        DocumentFragment.prototype.querySelectorAll = HTMLElement.prototype.querySelectorAll;
        DocumentFragment.prototype.querySelector = HTMLElement.prototype.querySelector;

        Object.defineProperties(DocumentFragment.prototype, {
          'nodeType': {
            get: function () {
              return Node.DOCUMENT_FRAGMENT_NODE;
            },
            configurable: true
          },

          'localName': {
            get: function () {
              return undefined;
            },
            configurable: true
          },

          'nodeName': {
            get: function () {
              return '#document-fragment';
            },
            configurable: true
          }
        });

        var origInsertBefore = Node.prototype.insertBefore;
        function insertBefore(newNode, refNode) {
          if (newNode instanceof DocumentFragment) {
            var child;
            while ((child = newNode.firstChild)) {
              origInsertBefore.call(this, child, refNode);
            }
          } else {
            origInsertBefore.call(this, newNode, refNode);
          }
          return newNode;
        }
        Node.prototype.insertBefore = insertBefore;

        var origAppendChild = Node.prototype.appendChild;
        Node.prototype.appendChild = function appendChild(child) {
          if (child instanceof DocumentFragment) {
            insertBefore.call(this, child, null);
          } else {
            origAppendChild.call(this, child);
          }
          return child;
        };

        var origRemoveChild = Node.prototype.removeChild;
        var origReplaceChild = Node.prototype.replaceChild;
        Node.prototype.replaceChild = function replaceChild(newChild, oldChild) {
          if (newChild instanceof DocumentFragment) {
            insertBefore.call(this, newChild, oldChild);
            origRemoveChild.call(this, oldChild);
          } else {
            origReplaceChild.call(this, newChild, oldChild);
          }
          return oldChild;
        };

        Document.prototype.createDocumentFragment = function createDocumentFragment() {
          var frag = this.createElement('df');
          frag.__proto__ = DocumentFragment.prototype;
          return frag;
        };

        var origImportNode = Document.prototype.importNode;
        Document.prototype.importNode = function importNode(impNode, deep) {
          deep = deep || false;
          var newNode = origImportNode.call(this, impNode, deep);
          if (impNode instanceof DocumentFragment) {
            newNode.__proto__ = DocumentFragment.prototype;
          }
          return newNode;
        };
      })();
    }

    // NOTE: we rely on this cloneNode not causing element upgrade.
    // This means this polyfill must load before the CE polyfill and
    // this would need to be re-worked if a browser supports native CE
    // but not <template>.
    var capturedCloneNode = Node.prototype.cloneNode;
    var capturedCreateElement = Document.prototype.createElement;
    var capturedImportNode = Document.prototype.importNode;
    var capturedRemoveChild = Node.prototype.removeChild;
    var capturedAppendChild = Node.prototype.appendChild;
    var capturedReplaceChild = Node.prototype.replaceChild;
    var capturedParseFromString = DOMParser.prototype.parseFromString;
    var capturedHTMLElementInnerHTML = Object.getOwnPropertyDescriptor(window.HTMLElement.prototype, 'innerHTML') || {
      /**
       * @this {!HTMLElement}
       * @return {string}
       */
      get: function() {
        return this.innerHTML;
      },
      /**
       * @this {!HTMLElement}
       * @param {string}
       */
      set: function(text) {
        this.innerHTML = text;
      }
    };
    var capturedChildNodes = Object.getOwnPropertyDescriptor(window.Node.prototype, 'childNodes') || {
      /**
       * @this {!Node}
       * @return {!NodeList}
       */
      get: function() {
        return this.childNodes;
      }
    };

    var elementQuerySelectorAll = Element.prototype.querySelectorAll;
    var docQuerySelectorAll = Document.prototype.querySelectorAll;
    var fragQuerySelectorAll = DocumentFragment.prototype.querySelectorAll;

    var scriptSelector = 'script:not([type]),script[type="application/javascript"],script[type="text/javascript"]';

    function QSA(node, selector) {
      // IE 11 throws a SyntaxError with `scriptSelector` if the node has no children due to the `:not([type])` syntax
      if (!node.childNodes.length) {
        return [];
      }
      switch (node.nodeType) {
        case Node.DOCUMENT_NODE:
          return docQuerySelectorAll.call(node, selector);
        case Node.DOCUMENT_FRAGMENT_NODE:
          return fragQuerySelectorAll.call(node, selector);
        default:
          return elementQuerySelectorAll.call(node, selector);
      }
    }

    // returns true if nested templates cannot be cloned (they cannot be on
    // some impl's like Safari 8 and Edge)
    // OR if cloning a document fragment does not result in a document fragment
    var needsCloning = (function() {
      if (!needsTemplate) {
        var t = document.createElement('template');
        var t2 = document.createElement('template');
        t2.content.appendChild(document.createElement('div'));
        t.content.appendChild(t2);
        var clone = t.cloneNode(true);
        return (clone.content.childNodes.length === 0 || clone.content.firstChild.content.childNodes.length === 0
          || brokenDocFragment);
      }
    })();

    var TEMPLATE_TAG = 'template';
    var PolyfilledHTMLTemplateElement = function() {};

    if (needsTemplate) {

      var contentDoc = document.implementation.createHTMLDocument('template');
      var canDecorate = true;

      var templateStyle = document.createElement('style');
      templateStyle.textContent = TEMPLATE_TAG + '{display:none;}';

      var head = document.head;
      head.insertBefore(templateStyle, head.firstElementChild);

      /**
        Provides a minimal shim for the <template> element.
      */
      PolyfilledHTMLTemplateElement.prototype = Object.create(HTMLElement.prototype);


      // if elements do not have `innerHTML` on instances, then
      // templates can be patched by swizzling their prototypes.
      var canProtoPatch =
        !(document.createElement('div').hasOwnProperty('innerHTML'));

      /**
        The `decorate` method moves element children to the template's `content`.
        NOTE: there is no support for dynamically adding elements to templates.
      */
      PolyfilledHTMLTemplateElement.decorate = function(template) {
        // if the template is decorated or not in HTML namespace, return fast
        if (template.content ||
            template.namespaceURI !== document.documentElement.namespaceURI) {
          return;
        }
        template.content = contentDoc.createDocumentFragment();
        var child;
        while ((child = template.firstChild)) {
          capturedAppendChild.call(template.content, child);
        }
        // NOTE: prefer prototype patching for performance and
        // because on some browsers (IE11), re-defining `innerHTML`
        // can result in intermittent errors.
        if (canProtoPatch) {
          template.__proto__ = PolyfilledHTMLTemplateElement.prototype;
        } else {
          template.cloneNode = function(deep) {
            return PolyfilledHTMLTemplateElement._cloneNode(this, deep);
          };
          // add innerHTML to template, if possible
          // Note: this throws on Safari 7
          if (canDecorate) {
            try {
              defineInnerHTML(template);
              defineOuterHTML(template);
            } catch (err) {
              canDecorate = false;
            }
          }
        }
        // bootstrap recursively
        PolyfilledHTMLTemplateElement.bootstrap(template.content);
      };

      // Taken from https://github.com/jquery/jquery/blob/73d7e6259c63ac45f42c6593da8c2796c6ce9281/src/manipulation/wrapMap.js
      var topLevelWrappingMap = {
        'option': ['select'],
        'thead': ['table'],
        'col': ['colgroup', 'table'],
        'tr': ['tbody', 'table'],
        'th': ['tr', 'tbody', 'table'],
        'td': ['tr', 'tbody', 'table']
      };

      var getTagName = function(text) {
        // Taken from https://github.com/jquery/jquery/blob/73d7e6259c63ac45f42c6593da8c2796c6ce9281/src/manipulation/var/rtagName.js
        return ( /<([a-z][^/\0>\x20\t\r\n\f]+)/i.exec(text) || ['', ''])[1].toLowerCase();
      };

      var defineInnerHTML = function defineInnerHTML(obj) {
        Object.defineProperty(obj, 'innerHTML', {
          get: function() {
            return getInnerHTML(this);
          },
          set: function(text) {
            // For IE11, wrap the text in the correct (table) context
            var wrap = topLevelWrappingMap[getTagName(text)];
            if (wrap) {
              for (var i = 0; i < wrap.length; i++) {
                text = '<' + wrap[i] + '>' + text + '</' + wrap[i] + '>';
              }
            }
            contentDoc.body.innerHTML = text;
            PolyfilledHTMLTemplateElement.bootstrap(contentDoc);
            while (this.content.firstChild) {
              capturedRemoveChild.call(this.content, this.content.firstChild);
            }
            var body = contentDoc.body;
            // If we had wrapped, get back to the original node
            if (wrap) {
              for (var j = 0; j < wrap.length; j++) {
                body = body.lastChild;
              }
            }
            while (body.firstChild) {
              capturedAppendChild.call(this.content, body.firstChild);
            }
          },
          configurable: true
        });
      };

      var defineOuterHTML = function defineOuterHTML(obj) {
        Object.defineProperty(obj, 'outerHTML', {
          get: function() {
            return '<' + TEMPLATE_TAG + '>' + this.innerHTML + '</' + TEMPLATE_TAG + '>';
          },
          set: function(innerHTML) {
            if (this.parentNode) {
              contentDoc.body.innerHTML = innerHTML;
              var docFrag = this.ownerDocument.createDocumentFragment();
              while (contentDoc.body.firstChild) {
                capturedAppendChild.call(docFrag, contentDoc.body.firstChild);
              }
              capturedReplaceChild.call(this.parentNode, docFrag, this);
            } else {
              throw new Error("Failed to set the 'outerHTML' property on 'Element': This element has no parent node.");
            }
          },
          configurable: true
        });
      };

      defineInnerHTML(PolyfilledHTMLTemplateElement.prototype);
      defineOuterHTML(PolyfilledHTMLTemplateElement.prototype);

      /**
        The `bootstrap` method is called automatically and "fixes" all
        <template> elements in the document referenced by the `doc` argument.
      */
      PolyfilledHTMLTemplateElement.bootstrap = function bootstrap(doc) {
        var templates = QSA(doc, TEMPLATE_TAG);
        for (var i=0, l=templates.length, t; (i<l) && (t=templates[i]); i++) {
          PolyfilledHTMLTemplateElement.decorate(t);
        }
      };

      // auto-bootstrapping for main document
      document.addEventListener('DOMContentLoaded', function() {
        PolyfilledHTMLTemplateElement.bootstrap(document);
      });

      // Patch document.createElement to ensure newly created templates have content
      Document.prototype.createElement = function createElement() {
        var el = capturedCreateElement.apply(this, arguments);
        if (el.localName === 'template') {
          PolyfilledHTMLTemplateElement.decorate(el);
        }
        return el;
      };

      DOMParser.prototype.parseFromString = function() {
        var el = capturedParseFromString.apply(this, arguments);
        PolyfilledHTMLTemplateElement.bootstrap(el);
        return el;
      };

      Object.defineProperty(HTMLElement.prototype, 'innerHTML', {
        get: function() {
          return getInnerHTML(this);
        },
        set: function(text) {
          capturedHTMLElementInnerHTML.set.call(this, text);
          PolyfilledHTMLTemplateElement.bootstrap(this);
        },
        configurable: true,
        enumerable: true
      });

      // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString
      var escapeAttrRegExp = /[&\u00A0"]/g;
      var escapeDataRegExp = /[&\u00A0<>]/g;

      var escapeReplace = function(c) {
        switch (c) {
          case '&':
            return '&amp;';
          case '<':
            return '&lt;';
          case '>':
            return '&gt;';
          case '"':
            return '&quot;';
          case '\u00A0':
            return '&nbsp;';
        }
      };

      var escapeAttr = function(s) {
        return s.replace(escapeAttrRegExp, escapeReplace);
      };

      var escapeData = function(s) {
        return s.replace(escapeDataRegExp, escapeReplace);
      };

      var makeSet = function(arr) {
        var set = {};
        for (var i = 0; i < arr.length; i++) {
          set[arr[i]] = true;
        }
        return set;
      };

      // http://www.whatwg.org/specs/web-apps/current-work/#void-elements
      var voidElements = makeSet([
        'area',
        'base',
        'br',
        'col',
        'command',
        'embed',
        'hr',
        'img',
        'input',
        'keygen',
        'link',
        'meta',
        'param',
        'source',
        'track',
        'wbr'
      ]);

      var plaintextParents = makeSet([
        'style',
        'script',
        'xmp',
        'iframe',
        'noembed',
        'noframes',
        'plaintext',
        'noscript'
      ]);

      /**
       * @param {Node} node
       * @param {Node} parentNode
       * @param {Function=} callback
       */
      var getOuterHTML = function(node, parentNode, callback) {
        switch (node.nodeType) {
          case Node.ELEMENT_NODE: {
            var tagName = node.localName;
            var s = '<' + tagName;
            var attrs = node.attributes;
            for (var i = 0, attr; (attr = attrs[i]); i++) {
              s += ' ' + attr.name + '="' + escapeAttr(attr.value) + '"';
            }
            s += '>';
            if (voidElements[tagName]) {
              return s;
            }
            return s + getInnerHTML(node, callback) + '</' + tagName + '>';
          }
          case Node.TEXT_NODE: {
            var data = /** @type {Text} */ (node).data;
            if (parentNode && plaintextParents[parentNode.localName]) {
              return data;
            }
            return escapeData(data);
          }
          case Node.COMMENT_NODE: {
            return '<!--' + /** @type {Comment} */ (node).data + '-->';
          }
          default: {
            window.console.error(node);
            throw new Error('not implemented');
          }
        }
      };

      /**
       * @param {Node} node
       * @param {Function=} callback
       */
      var getInnerHTML = function(node, callback) {
        if (node.localName === 'template') {
          node =  /** @type {HTMLTemplateElement} */ (node).content;
        }
        var s = '';
        var c$ = callback ? callback(node) : capturedChildNodes.get.call(node);
        for (var i=0, l=c$.length, child; (i<l) && (child=c$[i]); i++) {
          s += getOuterHTML(child, node, callback);
        }
        return s;
      };

    }

    // make cloning/importing work!
    if (needsTemplate || needsCloning) {

      PolyfilledHTMLTemplateElement._cloneNode = function _cloneNode(template, deep) {
        var clone = capturedCloneNode.call(template, false);
        // NOTE: decorate doesn't auto-fix children because they are already
        // decorated so they need special clone fixup.
        if (this.decorate) {
          this.decorate(clone);
        }
        if (deep) {
          // NOTE: use native clone node to make sure CE's wrapped
          // cloneNode does not cause elements to upgrade.
          capturedAppendChild.call(clone.content, capturedCloneNode.call(template.content, true));
          // now ensure nested templates are cloned correctly.
          fixClonedDom(clone.content, template.content);
        }
        return clone;
      };

      // Given a source and cloned subtree, find <template>'s in the cloned
      // subtree and replace them with cloned <template>'s from source.
      // We must do this because only the source templates have proper .content.
      var fixClonedDom = function fixClonedDom(clone, source) {
        // do nothing if cloned node is not an element
        if (!source.querySelectorAll) return;
        // these two lists should be coincident
        var s$ = QSA(source, TEMPLATE_TAG);
        if (s$.length === 0) {
          return;
        }
        var t$ = QSA(clone, TEMPLATE_TAG);
        for (var i=0, l=t$.length, t, s; i<l; i++) {
          s = s$[i];
          t = t$[i];
          if (PolyfilledHTMLTemplateElement && PolyfilledHTMLTemplateElement.decorate) {
            PolyfilledHTMLTemplateElement.decorate(s);
          }
          capturedReplaceChild.call(t.parentNode, cloneNode.call(s, true), t);
        }
      };

      // make sure scripts inside of a cloned template are executable
      var fixClonedScripts = function fixClonedScripts(fragment) {
        var scripts = QSA(fragment, scriptSelector);
        for (var ns, s, i = 0; i < scripts.length; i++) {
          s = scripts[i];
          ns = capturedCreateElement.call(document, 'script');
          ns.textContent = s.textContent;
          var attrs = s.attributes;
          for (var ai = 0, a; ai < attrs.length; ai++) {
            a = attrs[ai];
            ns.setAttribute(a.name, a.value);
          }
          capturedReplaceChild.call(s.parentNode, ns, s);
        }
      };

      // override all cloning to fix the cloned subtree to contain properly
      // cloned templates.
      var cloneNode = Node.prototype.cloneNode = function cloneNode(deep) {
        var dom;
        // workaround for Edge bug cloning documentFragments
        // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8619646/
        if (!needsDocFrag && brokenDocFragment && this instanceof DocumentFragment) {
          if (!deep) {
            return this.ownerDocument.createDocumentFragment();
          } else {
            dom = importNode.call(this.ownerDocument, this, true);
          }
        } else if (this.nodeType === Node.ELEMENT_NODE &&
                   this.localName === TEMPLATE_TAG &&
                   this.namespaceURI == document.documentElement.namespaceURI) {
          dom = PolyfilledHTMLTemplateElement._cloneNode(this, deep);
        } else {
          dom = capturedCloneNode.call(this, deep);
        }
        // template.content is cloned iff `deep`.
        if (deep) {
          fixClonedDom(dom, this);
        }
        return dom;
      };

      // NOTE: we are cloning instead of importing <template>'s.
      // However, the ownerDocument of the cloned template will be correct!
      // This is because the native import node creates the right document owned
      // subtree and `fixClonedDom` inserts cloned templates into this subtree,
      // thus updating the owner doc.
      var importNode = Document.prototype.importNode = function importNode(element, deep) {
        deep = deep || false;
        if (element.localName === TEMPLATE_TAG) {
          return PolyfilledHTMLTemplateElement._cloneNode(element, deep);
        } else {
          var dom = capturedImportNode.call(this, element, deep);
          if (deep) {
            fixClonedDom(dom, element);
            fixClonedScripts(dom);
          }
          return dom;
        }
      };
    }

    if (needsTemplate) {
      window.HTMLTemplateElement = PolyfilledHTMLTemplateElement;
    }

  })();

  var ApplyThisPrototype = (function() {
    return function ApplyThisPrototype(event, target) {
      if ((typeof target === 'object') && (target !== null)) {
        var proto = Object.getPrototypeOf(target);
        var property;

        for (property in proto) {
          if (!(property in event)) {
            var descriptor = Object.getOwnPropertyDescriptor(proto, property);
            if (descriptor) {
              Object.defineProperty(event, property, descriptor);
            }
          }
        }

        for (property in target) {
          if (!(property in event)) {
            event[property] = target[property];
          }
        }
      }
    }
  })();

  (function(ApplyThisPrototype) {
    /**
     * Polyfill CustomEvent
     */
    try {
      var event = new window.CustomEvent('event', { bubbles: true, cancelable: true });
    } catch (error) {
      var CustomEventOriginal = window.CustomEvent || window.Event;
      var CustomEvent = function(eventName, params) {
        params = params || {};
        var event = document.createEvent('CustomEvent');
        event.initCustomEvent(
          eventName,
          (params.bubbles === void 0) ? false : params.bubbles,
          (params.cancelable === void 0) ? false : params.cancelable,
          (params.detail === void 0) ? {} : params.detail
        );
        ApplyThisPrototype(event, this);
        return event;
      };
      CustomEvent.prototype = CustomEventOriginal.prototype;
      window.CustomEvent = CustomEvent;
    }
  })(ApplyThisPrototype);

  var EventListenerInterceptor = (function() {

    if(typeof EventTarget === 'undefined') {
      window.EventTarget = Node;
    }

    /**
     * Event listener interceptor
     */

    var EventListenerInterceptor = {
      interceptors: [] // { target: EventTarget, interceptors: [{ add: Function, remove: Function }, ...] }
    };


    /**
     * Returns if exists a previously registered listener from a target and the normalized arguments
     * @param target
     * @param normalizedArguments
     * @return {*}
     */
    EventListenerInterceptor.getRegisteredEventListener = function(target, normalizedArguments) {
      var key = normalizedArguments.type + '-' + (normalizedArguments.options.capture ? '1' : '0');
      if(
        (target.__eventListeners !== void 0) &&
        (target.__eventListeners[key] !== void 0)
      ) {
        var map = target.__eventListeners[key];
        for(var i = 0; i < map.length; i++) {
          if(map[i].listener === normalizedArguments.listener) {
            return map[i];
          }
        }
      }
      return null;
    };

    /**
     * Registers a listener on a target with some options
     * @param target
     * @param normalizedArguments
     */
    EventListenerInterceptor.registerEventListener = function(target, normalizedArguments) {
      var key = normalizedArguments.type + '-' + (normalizedArguments.options.capture ? '1' : '0');

      if(target.__eventListeners === void 0) {
        target.__eventListeners = {};
      }

      if(target.__eventListeners[key] === void 0) {
        target.__eventListeners[key] = [];
      }

      target.__eventListeners[key].push(normalizedArguments);
    };

    /**
     * Unregisters a listener on a target with some options
     * @param target
     * @param normalizedArguments
     */
    EventListenerInterceptor.unregisterEventListener = function(target, normalizedArguments) {
      var key = normalizedArguments.type + '-' + (normalizedArguments.options.capture ? '1' : '0');
      if(
        (target.__eventListeners !==  void 0) &&
        (target.__eventListeners[key] !== void 0)
      ) {
        var map = target.__eventListeners[key];
        for(var i = 0; i < map.length; i++) {
          if(map[i].listener === normalizedArguments.listener) {
            map.splice(i, 1);
          }
        }

        if(map.length === 0) {
          delete target.__eventListeners[key];
        }
      }
    };



    EventListenerInterceptor.normalizeListenerCallback = function(listener) {
      if((typeof listener === 'function') || (listener === null) || (listener === void 0)) {
        return listener;
      } else if((typeof listener === 'object') && (typeof listener.handleEvent === 'function')) {
        return listener.handleEvent;
      } else {
        // to support Symbol
        return function(event) {
          listener(event);
        };
      }
    };

    EventListenerInterceptor.normalizeListenerOptions = function(options) {
      switch(typeof options) {
        case 'boolean':
          options = { capture: options };
          break;
        case 'undefined':
          options = { capture: false };
          break;
        case 'object':
          if (options === null) {
            options = { capture: false };
          }
          break;
        default:
          throw new Error('Unsupported options type for addEventListener');
      }

      options.once      = Boolean(options.once);
      options.passive   = Boolean(options.passive);
      options.capture   = Boolean(options.capture);

      return options;
    };

    EventListenerInterceptor.normalizeListenerArguments = function(type, listener, options) {
      return {
        type: type,
        listener: this.normalizeListenerCallback(listener),
        options: this.normalizeListenerOptions(options)
      };
    };



    EventListenerInterceptor.intercept = function(target, interceptors) {
      // get an interceptor with this target or null
      var interceptor = null;
      for (var i = 0; i < this.interceptors.length; i++) {
        if(this.interceptors[i].target === target) {
          interceptor = this.interceptors[i];
        }
      }

      // if no interceptor already set
      if (interceptor === null) {
        interceptor = { target: target, interceptors: [interceptors] };
        this.interceptors.push(interceptor);

        this.interceptAddEventListener(target, interceptor);
        this.interceptRemoveEventListener(target, interceptor);
      } else { // if an interceptor already set, simply add interceptors to the list
        interceptor.interceptors.push(interceptors);
      }

      // var release = function() {
      //   target.prototype.addEventListener = addEventListener;
      //   target.prototype.removeEventListener = removeEventListener;
      // };
      // this.interceptors.push(release);
      // return release;
    };

    EventListenerInterceptor.interceptAddEventListener = function(target, interceptor) {
      var _this = this;

      var addEventListener = target.prototype.addEventListener;
      target.prototype.addEventListener = function(type, listener, options) {
        var normalizedArguments = _this.normalizeListenerArguments(type, listener, options);
        var registeredEventListener = _this.getRegisteredEventListener(this, normalizedArguments);

        if (!registeredEventListener) {

          normalizedArguments.polyfilled = {
            type: normalizedArguments.type,
            listener: normalizedArguments.listener,
            options: {
              capture: normalizedArguments.options.capture,
              once: normalizedArguments.options.once,
              passive: normalizedArguments.options.passive
            }
          };

          for (var i = 0; i < interceptor.interceptors.length; i++) {
            var interceptors = interceptor.interceptors[i];
            if (typeof interceptors.add === 'function') {
              interceptors.add(normalizedArguments);
            }
          }

          // console.log('normalizedArguments', normalizedArguments.polyfilled);

          _this.registerEventListener(this, normalizedArguments);

          addEventListener.call(
            this,
            normalizedArguments.polyfilled.type,
            normalizedArguments.polyfilled.listener,
            normalizedArguments.polyfilled.options
          );
        }
      };

      return function() {
        target.prototype.addEventListener = addEventListener;
      };
    };

    EventListenerInterceptor.interceptRemoveEventListener = function(target, interceptor) {
      var _this = this;

      var removeEventListener = target.prototype.removeEventListener;
      target.prototype.removeEventListener = function(type, listener, options) {
        var normalizedArguments = _this.normalizeListenerArguments(type, listener, options);
        var registeredEventListener = _this.getRegisteredEventListener(this, normalizedArguments);

        if (registeredEventListener) {
          _this.unregisterEventListener(this, normalizedArguments);
          removeEventListener.call(
            this,
            registeredEventListener.polyfilled.type,
            registeredEventListener.polyfilled.listener,
            registeredEventListener.polyfilled.options
          );
        } else {
          removeEventListener.call(this, type, listener, options);
        }
      };

      return function() {
        target.prototype.removeEventListener = removeEventListener;
      };
    };

    EventListenerInterceptor.interceptAll = function(interceptors) {
      this.intercept(EventTarget, interceptors);
      if(!(window instanceof EventTarget)) {
        this.intercept(Window, interceptors);
      }
    };

    EventListenerInterceptor.releaseAll = function() {
      for(var i = 0, l = this.interceptors.length; i < l; i++) {
        this.interceptors();
      }
    };


    EventListenerInterceptor.error = function(error) {
      // throw error;
      console.error(error);
    };

    return EventListenerInterceptor;
  })();

  (function(EventListenerInterceptor) {
    /**
     * Event listener options support
     */

    EventListenerInterceptor.detectSupportedOptions = function() {
      var _this = this;

      this.supportedOptions = {
        once: false,
        passive: false,
        capture: false,

        all: false,
        some: false
      };

      document.createDocumentFragment().addEventListener('test', function() {}, {
        get once() {
          _this.supportedOptions.once = true;
          return false;
        },
        get passive() {
          _this.supportedOptions.passive = true;
          return false;
        },
        get capture() {
          _this.supportedOptions.capture = true;
          return false;
        }
      });

      // useful shortcuts to detect if options are all/some supported
      this.supportedOptions.all  = this.supportedOptions.once && this.supportedOptions.passive && this.supportedOptions.capture;
      this.supportedOptions.some = this.supportedOptions.once || this.supportedOptions.passive || this.supportedOptions.capture;
    };

    EventListenerInterceptor.polyfillListenerOptions = function() {
      this.detectSupportedOptions();
      if (!this.supportedOptions.all) {
        var _this = this;

        this.interceptAll({
          add: function(normalizedArguments) {
            // console.log('intercepted', normalizedArguments);

            var once = normalizedArguments.options.once && !_this.supportedOptions.once;
            var passive = normalizedArguments.options.passive && !_this.supportedOptions.passive;

            if (once || passive) {
              var listener = normalizedArguments.polyfilled.listener;

              normalizedArguments.polyfilled.listener = function(event) {
                if(once) {
                  this.removeEventListener(normalizedArguments.type, normalizedArguments.listener, normalizedArguments.options);
                }

                if(passive) {
                  event.preventDefault = function() {
                    throw new Error('Unable to preventDefault inside passive event listener invocation.');
                  };
                }

                return listener.call(this, event);
              };
            }

            if (!_this.supportedOptions.some) {
              normalizedArguments.polyfilled.options = normalizedArguments.options.capture;
            }
          }
        });
      }
    };


    EventListenerInterceptor.polyfillListenerOptions();


    // var onclick = function() {
    //   console.log('click');
    // };

    // document.body.addEventListener('click', onclick, false);
    // document.body.addEventListener('click', onclick, { once: true });
    // document.body.addEventListener('click', onclick, { once: true });
    // document.body.addEventListener('click', onclick, false);
    // document.body.addEventListener('click', onclick, false);

  })(EventListenerInterceptor);

  // For the IE11 build.
  SVGElement.prototype.contains = SVGElement.prototype.contains || HTMLElement.prototype.contains // .childElementCount polyfill
  // from https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/childElementCount#Polyfill_for_IE8_IE9_Safari
  ;

  (function (constructor) {
    if (constructor && constructor.prototype && constructor.prototype.childElementCount == null) {
      Object.defineProperty(constructor.prototype, 'childElementCount', {
        get: function get() {
          var i = 0,
              count = 0,
              node,
              nodes = this.childNodes;

          while (node = nodes[i++]) {
            if (node.nodeType === 1) count++;
          }

          return count;
        }
      });
    }
  })(window.Node || window.Element);

  var check = function (it) {
    return it && it.Math == Math && it;
  };

  // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
  var global_1 =
    // eslint-disable-next-line no-undef
    check(typeof globalThis == 'object' && globalThis) ||
    check(typeof window == 'object' && window) ||
    check(typeof self == 'object' && self) ||
    check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
    // eslint-disable-next-line no-new-func
    (function () { return this; })() || Function('return this')();

  var fails = function (exec) {
    try {
      return !!exec();
    } catch (error) {
      return true;
    }
  };

  // Detect IE8's incomplete defineProperty implementation
  var descriptors = !fails(function () {
    return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
  });

  var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
  var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;

  // Nashorn ~ JDK8 bug
  var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({ 1: 2 }, 1);

  // `Object.prototype.propertyIsEnumerable` method implementation
  // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
  var f = NASHORN_BUG ? function propertyIsEnumerable(V) {
    var descriptor = getOwnPropertyDescriptor(this, V);
    return !!descriptor && descriptor.enumerable;
  } : nativePropertyIsEnumerable;

  var objectPropertyIsEnumerable = {
  	f: f
  };

  var createPropertyDescriptor = function (bitmap, value) {
    return {
      enumerable: !(bitmap & 1),
      configurable: !(bitmap & 2),
      writable: !(bitmap & 4),
      value: value
    };
  };

  var toString = {}.toString;

  var classofRaw = function (it) {
    return toString.call(it).slice(8, -1);
  };

  var split = ''.split;

  // fallback for non-array-like ES3 and non-enumerable old V8 strings
  var indexedObject = fails(function () {
    // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
    // eslint-disable-next-line no-prototype-builtins
    return !Object('z').propertyIsEnumerable(0);
  }) ? function (it) {
    return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
  } : Object;

  // `RequireObjectCoercible` abstract operation
  // https://tc39.es/ecma262/#sec-requireobjectcoercible
  var requireObjectCoercible = function (it) {
    if (it == undefined) throw TypeError("Can't call method on " + it);
    return it;
  };

  // toObject with fallback for non-array-like ES3 strings



  var toIndexedObject = function (it) {
    return indexedObject(requireObjectCoercible(it));
  };

  var isObject = function (it) {
    return typeof it === 'object' ? it !== null : typeof it === 'function';
  };

  // `ToPrimitive` abstract operation
  // https://tc39.es/ecma262/#sec-toprimitive
  // instead of the ES6 spec version, we didn't implement @@toPrimitive case
  // and the second argument - flag - preferred type is a string
  var toPrimitive = function (input, PREFERRED_STRING) {
    if (!isObject(input)) return input;
    var fn, val;
    if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
    if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val;
    if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val;
    throw TypeError("Can't convert object to primitive value");
  };

  var hasOwnProperty = {}.hasOwnProperty;

  var has = function (it, key) {
    return hasOwnProperty.call(it, key);
  };

  var document$1 = global_1.document;
  // typeof document.createElement is 'object' in old IE
  var EXISTS = isObject(document$1) && isObject(document$1.createElement);

  var documentCreateElement = function (it) {
    return EXISTS ? document$1.createElement(it) : {};
  };

  // Thank's IE8 for his funny defineProperty
  var ie8DomDefine = !descriptors && !fails(function () {
    return Object.defineProperty(documentCreateElement('div'), 'a', {
      get: function () { return 7; }
    }).a != 7;
  });

  var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;

  // `Object.getOwnPropertyDescriptor` method
  // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
  var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
    O = toIndexedObject(O);
    P = toPrimitive(P, true);
    if (ie8DomDefine) try {
      return nativeGetOwnPropertyDescriptor(O, P);
    } catch (error) { /* empty */ }
    if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
  };

  var objectGetOwnPropertyDescriptor = {
  	f: f$1
  };

  var anObject = function (it) {
    if (!isObject(it)) {
      throw TypeError(String(it) + ' is not an object');
    } return it;
  };

  var nativeDefineProperty = Object.defineProperty;

  // `Object.defineProperty` method
  // https://tc39.es/ecma262/#sec-object.defineproperty
  var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
    anObject(O);
    P = toPrimitive(P, true);
    anObject(Attributes);
    if (ie8DomDefine) try {
      return nativeDefineProperty(O, P, Attributes);
    } catch (error) { /* empty */ }
    if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
    if ('value' in Attributes) O[P] = Attributes.value;
    return O;
  };

  var objectDefineProperty = {
  	f: f$2
  };

  var createNonEnumerableProperty = descriptors ? function (object, key, value) {
    return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
  } : function (object, key, value) {
    object[key] = value;
    return object;
  };

  var setGlobal = function (key, value) {
    try {
      createNonEnumerableProperty(global_1, key, value);
    } catch (error) {
      global_1[key] = value;
    } return value;
  };

  var SHARED = '__core-js_shared__';
  var store = global_1[SHARED] || setGlobal(SHARED, {});

  var sharedStore = store;

  var functionToString = Function.toString;

  // this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper
  if (typeof sharedStore.inspectSource != 'function') {
    sharedStore.inspectSource = function (it) {
      return functionToString.call(it);
    };
  }

  var inspectSource = sharedStore.inspectSource;

  var WeakMap = global_1.WeakMap;

  var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap));

  var shared = createCommonjsModule(function (module) {
  (module.exports = function (key, value) {
    return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
  })('versions', []).push({
    version: '3.8.3',
    mode:  'global',
    copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
  });
  });

  var id = 0;
  var postfix = Math.random();

  var uid = function (key) {
    return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36);
  };

  var keys = shared('keys');

  var sharedKey = function (key) {
    return keys[key] || (keys[key] = uid(key));
  };

  var hiddenKeys = {};

  var WeakMap$1 = global_1.WeakMap;
  var set, get, has$1;

  var enforce = function (it) {
    return has$1(it) ? get(it) : set(it, {});
  };

  var getterFor = function (TYPE) {
    return function (it) {
      var state;
      if (!isObject(it) || (state = get(it)).type !== TYPE) {
        throw TypeError('Incompatible receiver, ' + TYPE + ' required');
      } return state;
    };
  };

  if (nativeWeakMap) {
    var store$1 = sharedStore.state || (sharedStore.state = new WeakMap$1());
    var wmget = store$1.get;
    var wmhas = store$1.has;
    var wmset = store$1.set;
    set = function (it, metadata) {
      metadata.facade = it;
      wmset.call(store$1, it, metadata);
      return metadata;
    };
    get = function (it) {
      return wmget.call(store$1, it) || {};
    };
    has$1 = function (it) {
      return wmhas.call(store$1, it);
    };
  } else {
    var STATE = sharedKey('state');
    hiddenKeys[STATE] = true;
    set = function (it, metadata) {
      metadata.facade = it;
      createNonEnumerableProperty(it, STATE, metadata);
      return metadata;
    };
    get = function (it) {
      return has(it, STATE) ? it[STATE] : {};
    };
    has$1 = function (it) {
      return has(it, STATE);
    };
  }

  var internalState = {
    set: set,
    get: get,
    has: has$1,
    enforce: enforce,
    getterFor: getterFor
  };

  var redefine = createCommonjsModule(function (module) {
  var getInternalState = internalState.get;
  var enforceInternalState = internalState.enforce;
  var TEMPLATE = String(String).split('String');

  (module.exports = function (O, key, value, options) {
    var unsafe = options ? !!options.unsafe : false;
    var simple = options ? !!options.enumerable : false;
    var noTargetGet = options ? !!options.noTargetGet : false;
    var state;
    if (typeof value == 'function') {
      if (typeof key == 'string' && !has(value, 'name')) {
        createNonEnumerableProperty(value, 'name', key);
      }
      state = enforceInternalState(value);
      if (!state.source) {
        state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
      }
    }
    if (O === global_1) {
      if (simple) O[key] = value;
      else setGlobal(key, value);
      return;
    } else if (!unsafe) {
      delete O[key];
    } else if (!noTargetGet && O[key]) {
      simple = true;
    }
    if (simple) O[key] = value;
    else createNonEnumerableProperty(O, key, value);
  // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
  })(Function.prototype, 'toString', function toString() {
    return typeof this == 'function' && getInternalState(this).source || inspectSource(this);
  });
  });

  var path = global_1;

  var aFunction = function (variable) {
    return typeof variable == 'function' ? variable : undefined;
  };

  var getBuiltIn = function (namespace, method) {
    return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace])
      : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method];
  };

  var ceil = Math.ceil;
  var floor = Math.floor;

  // `ToInteger` abstract operation
  // https://tc39.es/ecma262/#sec-tointeger
  var toInteger = function (argument) {
    return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
  };

  var min = Math.min;

  // `ToLength` abstract operation
  // https://tc39.es/ecma262/#sec-tolength
  var toLength = function (argument) {
    return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
  };

  var max = Math.max;
  var min$1 = Math.min;

  // Helper for a popular repeating case of the spec:
  // Let integer be ? ToInteger(index).
  // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
  var toAbsoluteIndex = function (index, length) {
    var integer = toInteger(index);
    return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
  };

  // `Array.prototype.{ indexOf, includes }` methods implementation
  var createMethod = function (IS_INCLUDES) {
    return function ($this, el, fromIndex) {
      var O = toIndexedObject($this);
      var length = toLength(O.length);
      var index = toAbsoluteIndex(fromIndex, length);
      var value;
      // Array#includes uses SameValueZero equality algorithm
      // eslint-disable-next-line no-self-compare
      if (IS_INCLUDES && el != el) while (length > index) {
        value = O[index++];
        // eslint-disable-next-line no-self-compare
        if (value != value) return true;
      // Array#indexOf ignores holes, Array#includes - not
      } else for (;length > index; index++) {
        if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
      } return !IS_INCLUDES && -1;
    };
  };

  var arrayIncludes = {
    // `Array.prototype.includes` method
    // https://tc39.es/ecma262/#sec-array.prototype.includes
    includes: createMethod(true),
    // `Array.prototype.indexOf` method
    // https://tc39.es/ecma262/#sec-array.prototype.indexof
    indexOf: createMethod(false)
  };

  var indexOf = arrayIncludes.indexOf;


  var objectKeysInternal = function (object, names) {
    var O = toIndexedObject(object);
    var i = 0;
    var result = [];
    var key;
    for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key);
    // Don't enum bug & hidden keys
    while (names.length > i) if (has(O, key = names[i++])) {
      ~indexOf(result, key) || result.push(key);
    }
    return result;
  };

  // IE8- don't enum bug keys
  var enumBugKeys = [
    'constructor',
    'hasOwnProperty',
    'isPrototypeOf',
    'propertyIsEnumerable',
    'toLocaleString',
    'toString',
    'valueOf'
  ];

  var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype');

  // `Object.getOwnPropertyNames` method
  // https://tc39.es/ecma262/#sec-object.getownpropertynames
  var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
    return objectKeysInternal(O, hiddenKeys$1);
  };

  var objectGetOwnPropertyNames = {
  	f: f$3
  };

  var f$4 = Object.getOwnPropertySymbols;

  var objectGetOwnPropertySymbols = {
  	f: f$4
  };

  // all object keys, includes non-enumerable and symbols
  var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
    var keys = objectGetOwnPropertyNames.f(anObject(it));
    var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
    return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
  };

  var copyConstructorProperties = function (target, source) {
    var keys = ownKeys(source);
    var defineProperty = objectDefineProperty.f;
    var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
    for (var i = 0; i < keys.length; i++) {
      var key = keys[i];
      if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
    }
  };

  var replacement = /#|\.prototype\./;

  var isForced = function (feature, detection) {
    var value = data[normalize(feature)];
    return value == POLYFILL ? true
      : value == NATIVE ? false
      : typeof detection == 'function' ? fails(detection)
      : !!detection;
  };

  var normalize = isForced.normalize = function (string) {
    return String(string).replace(replacement, '.').toLowerCase();
  };

  var data = isForced.data = {};
  var NATIVE = isForced.NATIVE = 'N';
  var POLYFILL = isForced.POLYFILL = 'P';

  var isForced_1 = isForced;

  var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;






  /*
    options.target      - name of the target object
    options.global      - target is the global object
    options.stat        - export as static methods of target
    options.proto       - export as prototype methods of target
    options.real        - real prototype method for the `pure` version
    options.forced      - export even if the native feature is available
    options.bind        - bind methods to the target, required for the `pure` version
    options.wrap        - wrap constructors to preventing global pollution, required for the `pure` version
    options.unsafe      - use the simple assignment of property instead of delete + defineProperty
    options.sham        - add a flag to not completely full polyfills
    options.enumerable  - export as enumerable property
    options.noTargetGet - prevent calling a getter on target
  */
  var _export = function (options, source) {
    var TARGET = options.target;
    var GLOBAL = options.global;
    var STATIC = options.stat;
    var FORCED, target, key, targetProperty, sourceProperty, descriptor;
    if (GLOBAL) {
      target = global_1;
    } else if (STATIC) {
      target = global_1[TARGET] || setGlobal(TARGET, {});
    } else {
      target = (global_1[TARGET] || {}).prototype;
    }
    if (target) for (key in source) {
      sourceProperty = source[key];
      if (options.noTargetGet) {
        descriptor = getOwnPropertyDescriptor$1(target, key);
        targetProperty = descriptor && descriptor.value;
      } else targetProperty = target[key];
      FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
      // contained in target
      if (!FORCED && targetProperty !== undefined) {
        if (typeof sourceProperty === typeof targetProperty) continue;
        copyConstructorProperties(sourceProperty, targetProperty);
      }
      // add a flag to not completely full polyfills
      if (options.sham || (targetProperty && targetProperty.sham)) {
        createNonEnumerableProperty(sourceProperty, 'sham', true);
      }
      // extend global
      redefine(target, key, sourceProperty, options);
    }
  };

  var aFunction$1 = function (it) {
    if (typeof it != 'function') {
      throw TypeError(String(it) + ' is not a function');
    } return it;
  };

  // optional / simple context binding
  var functionBindContext = function (fn, that, length) {
    aFunction$1(fn);
    if (that === undefined) return fn;
    switch (length) {
      case 0: return function () {
        return fn.call(that);
      };
      case 1: return function (a) {
        return fn.call(that, a);
      };
      case 2: return function (a, b) {
        return fn.call(that, a, b);
      };
      case 3: return function (a, b, c) {
        return fn.call(that, a, b, c);
      };
    }
    return function (/* ...args */) {
      return fn.apply(that, arguments);
    };
  };

  // `ToObject` abstract operation
  // https://tc39.es/ecma262/#sec-toobject
  var toObject = function (argument) {
    return Object(requireObjectCoercible(argument));
  };

  // `IsArray` abstract operation
  // https://tc39.es/ecma262/#sec-isarray
  var isArray = Array.isArray || function isArray(arg) {
    return classofRaw(arg) == 'Array';
  };

  var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () {
    // Chrome 38 Symbol has incorrect toString conversion
    // eslint-disable-next-line no-undef
    return !String(Symbol());
  });

  var useSymbolAsUid = nativeSymbol
    // eslint-disable-next-line no-undef
    && !Symbol.sham
    // eslint-disable-next-line no-undef
    && typeof Symbol.iterator == 'symbol';

  var WellKnownSymbolsStore = shared('wks');
  var Symbol$1 = global_1.Symbol;
  var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid;

  var wellKnownSymbol = function (name) {
    if (!has(WellKnownSymbolsStore, name)) {
      if (nativeSymbol && has(Symbol$1, name)) WellKnownSymbolsStore[name] = Symbol$1[name];
      else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name);
    } return WellKnownSymbolsStore[name];
  };

  var SPECIES = wellKnownSymbol('species');

  // `ArraySpeciesCreate` abstract operation
  // https://tc39.es/ecma262/#sec-arrayspeciescreate
  var arraySpeciesCreate = function (originalArray, length) {
    var C;
    if (isArray(originalArray)) {
      C = originalArray.constructor;
      // cross-realm fallback
      if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined;
      else if (isObject(C)) {
        C = C[SPECIES];
        if (C === null) C = undefined;
      }
    } return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
  };

  var push = [].push;

  // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterOut }` methods implementation
  var createMethod$1 = function (TYPE) {
    var IS_MAP = TYPE == 1;
    var IS_FILTER = TYPE == 2;
    var IS_SOME = TYPE == 3;
    var IS_EVERY = TYPE == 4;
    var IS_FIND_INDEX = TYPE == 6;
    var IS_FILTER_OUT = TYPE == 7;
    var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
    return function ($this, callbackfn, that, specificCreate) {
      var O = toObject($this);
      var self = indexedObject(O);
      var boundFunction = functionBindContext(callbackfn, that, 3);
      var length = toLength(self.length);
      var index = 0;
      var create = specificCreate || arraySpeciesCreate;
      var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_OUT ? create($this, 0) : undefined;
      var value, result;
      for (;length > index; index++) if (NO_HOLES || index in self) {
        value = self[index];
        result = boundFunction(value, index, O);
        if (TYPE) {
          if (IS_MAP) target[index] = result; // map
          else if (result) switch (TYPE) {
            case 3: return true;              // some
            case 5: return value;             // find
            case 6: return index;             // findIndex
            case 2: push.call(target, value); // filter
          } else switch (TYPE) {
            case 4: return false;             // every
            case 7: push.call(target, value); // filterOut
          }
        }
      }
      return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
    };
  };

  var arrayIteration = {
    // `Array.prototype.forEach` method
    // https://tc39.es/ecma262/#sec-array.prototype.foreach
    forEach: createMethod$1(0),
    // `Array.prototype.map` method
    // https://tc39.es/ecma262/#sec-array.prototype.map
    map: createMethod$1(1),
    // `Array.prototype.filter` method
    // https://tc39.es/ecma262/#sec-array.prototype.filter
    filter: createMethod$1(2),
    // `Array.prototype.some` method
    // https://tc39.es/ecma262/#sec-array.prototype.some
    some: createMethod$1(3),
    // `Array.prototype.every` method
    // https://tc39.es/ecma262/#sec-array.prototype.every
    every: createMethod$1(4),
    // `Array.prototype.find` method
    // https://tc39.es/ecma262/#sec-array.prototype.find
    find: createMethod$1(5),
    // `Array.prototype.findIndex` method
    // https://tc39.es/ecma262/#sec-array.prototype.findIndex
    findIndex: createMethod$1(6),
    // `Array.prototype.filterOut` method
    // https://github.com/tc39/proposal-array-filtering
    filterOut: createMethod$1(7)
  };

  var engineUserAgent = getBuiltIn('navigator', 'userAgent') || '';

  var process$1 = global_1.process;
  var versions = process$1 && process$1.versions;
  var v8 = versions && versions.v8;
  var match, version;

  if (v8) {
    match = v8.split('.');
    version = match[0] + match[1];
  } else if (engineUserAgent) {
    match = engineUserAgent.match(/Edge\/(\d+)/);
    if (!match || match[1] >= 74) {
      match = engineUserAgent.match(/Chrome\/(\d+)/);
      if (match) version = match[1];
    }
  }

  var engineV8Version = version && +version;

  var SPECIES$1 = wellKnownSymbol('species');

  var arrayMethodHasSpeciesSupport = function (METHOD_NAME) {
    // We can't use this feature detection in V8 since it causes
    // deoptimization and serious performance degradation
    // https://github.com/zloirock/core-js/issues/677
    return engineV8Version >= 51 || !fails(function () {
      var array = [];
      var constructor = array.constructor = {};
      constructor[SPECIES$1] = function () {
        return { foo: 1 };
      };
      return array[METHOD_NAME](Boolean).foo !== 1;
    });
  };

  var defineProperty = Object.defineProperty;
  var cache = {};

  var thrower = function (it) { throw it; };

  var arrayMethodUsesToLength = function (METHOD_NAME, options) {
    if (has(cache, METHOD_NAME)) return cache[METHOD_NAME];
    if (!options) options = {};
    var method = [][METHOD_NAME];
    var ACCESSORS = has(options, 'ACCESSORS') ? options.ACCESSORS : false;
    var argument0 = has(options, 0) ? options[0] : thrower;
    var argument1 = has(options, 1) ? options[1] : undefined;

    return cache[METHOD_NAME] = !!method && !fails(function () {
      if (ACCESSORS && !descriptors) return true;
      var O = { length: -1 };

      if (ACCESSORS) defineProperty(O, 1, { enumerable: true, get: thrower });
      else O[1] = 1;

      method.call(O, argument0, argument1);
    });
  };

  var $filter = arrayIteration.filter;



  var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter');
  // Edge 14- issue
  var USES_TO_LENGTH = arrayMethodUsesToLength('filter');

  // `Array.prototype.filter` method
  // https://tc39.es/ecma262/#sec-array.prototype.filter
  // with adding support of @@species
  _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT || !USES_TO_LENGTH }, {
    filter: function filter(callbackfn /* , thisArg */) {
      return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var arrayMethodIsStrict = function (METHOD_NAME, argument) {
    var method = [][METHOD_NAME];
    return !!method && fails(function () {
      // eslint-disable-next-line no-useless-call,no-throw-literal
      method.call(null, argument || function () { throw 1; }, 1);
    });
  };

  var $forEach = arrayIteration.forEach;



  var STRICT_METHOD = arrayMethodIsStrict('forEach');
  var USES_TO_LENGTH$1 = arrayMethodUsesToLength('forEach');

  // `Array.prototype.forEach` method implementation
  // https://tc39.es/ecma262/#sec-array.prototype.foreach
  var arrayForEach = (!STRICT_METHOD || !USES_TO_LENGTH$1) ? function forEach(callbackfn /* , thisArg */) {
    return $forEach(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
  } : [].forEach;

  // `Array.prototype.forEach` method
  // https://tc39.es/ecma262/#sec-array.prototype.foreach
  _export({ target: 'Array', proto: true, forced: [].forEach != arrayForEach }, {
    forEach: arrayForEach
  });

  var iteratorClose = function (iterator) {
    var returnMethod = iterator['return'];
    if (returnMethod !== undefined) {
      return anObject(returnMethod.call(iterator)).value;
    }
  };

  // call something on iterator step with safe closing on error
  var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
    try {
      return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
    // 7.4.6 IteratorClose(iterator, completion)
    } catch (error) {
      iteratorClose(iterator);
      throw error;
    }
  };

  var iterators = {};

  var ITERATOR = wellKnownSymbol('iterator');
  var ArrayPrototype = Array.prototype;

  // check on default Array iterator
  var isArrayIteratorMethod = function (it) {
    return it !== undefined && (iterators.Array === it || ArrayPrototype[ITERATOR] === it);
  };

  var createProperty = function (object, key, value) {
    var propertyKey = toPrimitive(key);
    if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value));
    else object[propertyKey] = value;
  };

  var TO_STRING_TAG = wellKnownSymbol('toStringTag');
  var test = {};

  test[TO_STRING_TAG] = 'z';

  var toStringTagSupport = String(test) === '[object z]';

  var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
  // ES3 wrong here
  var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';

  // fallback for IE11 Script Access Denied error
  var tryGet = function (it, key) {
    try {
      return it[key];
    } catch (error) { /* empty */ }
  };

  // getting tag from ES6+ `Object.prototype.toString`
  var classof = toStringTagSupport ? classofRaw : function (it) {
    var O, tag, result;
    return it === undefined ? 'Undefined' : it === null ? 'Null'
      // @@toStringTag case
      : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$1)) == 'string' ? tag
      // builtinTag case
      : CORRECT_ARGUMENTS ? classofRaw(O)
      // ES3 arguments fallback
      : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
  };

  var ITERATOR$1 = wellKnownSymbol('iterator');

  var getIteratorMethod = function (it) {
    if (it != undefined) return it[ITERATOR$1]
      || it['@@iterator']
      || iterators[classof(it)];
  };

  // `Array.from` method implementation
  // https://tc39.es/ecma262/#sec-array.from
  var arrayFrom = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {
    var O = toObject(arrayLike);
    var C = typeof this == 'function' ? this : Array;
    var argumentsLength = arguments.length;
    var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
    var mapping = mapfn !== undefined;
    var iteratorMethod = getIteratorMethod(O);
    var index = 0;
    var length, result, step, iterator, next, value;
    if (mapping) mapfn = functionBindContext(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
    // if the target is not iterable or it's an array with the default iterator - use a simple case
    if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
      iterator = iteratorMethod.call(O);
      next = iterator.next;
      result = new C();
      for (;!(step = next.call(iterator)).done; index++) {
        value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
        createProperty(result, index, value);
      }
    } else {
      length = toLength(O.length);
      result = new C(length);
      for (;length > index; index++) {
        value = mapping ? mapfn(O[index], index) : O[index];
        createProperty(result, index, value);
      }
    }
    result.length = index;
    return result;
  };

  var ITERATOR$2 = wellKnownSymbol('iterator');
  var SAFE_CLOSING = false;

  try {
    var called = 0;
    var iteratorWithReturn = {
      next: function () {
        return { done: !!called++ };
      },
      'return': function () {
        SAFE_CLOSING = true;
      }
    };
    iteratorWithReturn[ITERATOR$2] = function () {
      return this;
    };
    // eslint-disable-next-line no-throw-literal
    Array.from(iteratorWithReturn, function () { throw 2; });
  } catch (error) { /* empty */ }

  var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
    if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
    var ITERATION_SUPPORT = false;
    try {
      var object = {};
      object[ITERATOR$2] = function () {
        return {
          next: function () {
            return { done: ITERATION_SUPPORT = true };
          }
        };
      };
      exec(object);
    } catch (error) { /* empty */ }
    return ITERATION_SUPPORT;
  };

  var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
    Array.from(iterable);
  });

  // `Array.from` method
  // https://tc39.es/ecma262/#sec-array.from
  _export({ target: 'Array', stat: true, forced: INCORRECT_ITERATION }, {
    from: arrayFrom
  });

  // `String.prototype.{ codePointAt, at }` methods implementation
  var createMethod$2 = function (CONVERT_TO_STRING) {
    return function ($this, pos) {
      var S = String(requireObjectCoercible($this));
      var position = toInteger(pos);
      var size = S.length;
      var first, second;
      if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
      first = S.charCodeAt(position);
      return first < 0xD800 || first > 0xDBFF || position + 1 === size
        || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
          ? CONVERT_TO_STRING ? S.charAt(position) : first
          : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
    };
  };

  var stringMultibyte = {
    // `String.prototype.codePointAt` method
    // https://tc39.es/ecma262/#sec-string.prototype.codepointat
    codeAt: createMethod$2(false),
    // `String.prototype.at` method
    // https://github.com/mathiasbynens/String.prototype.at
    charAt: createMethod$2(true)
  };

  var correctPrototypeGetter = !fails(function () {
    function F() { /* empty */ }
    F.prototype.constructor = null;
    return Object.getPrototypeOf(new F()) !== F.prototype;
  });

  var IE_PROTO = sharedKey('IE_PROTO');
  var ObjectPrototype = Object.prototype;

  // `Object.getPrototypeOf` method
  // https://tc39.es/ecma262/#sec-object.getprototypeof
  var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
    O = toObject(O);
    if (has(O, IE_PROTO)) return O[IE_PROTO];
    if (typeof O.constructor == 'function' && O instanceof O.constructor) {
      return O.constructor.prototype;
    } return O instanceof Object ? ObjectPrototype : null;
  };

  var ITERATOR$3 = wellKnownSymbol('iterator');
  var BUGGY_SAFARI_ITERATORS = false;

  var returnThis = function () { return this; };

  // `%IteratorPrototype%` object
  // https://tc39.es/ecma262/#sec-%iteratorprototype%-object
  var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;

  if ([].keys) {
    arrayIterator = [].keys();
    // Safari 8 has buggy iterators w/o `next`
    if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;
    else {
      PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
      if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
    }
  }

  var NEW_ITERATOR_PROTOTYPE = IteratorPrototype == undefined || fails(function () {
    var test = {};
    // FF44- legacy iterators case
    return IteratorPrototype[ITERATOR$3].call(test) !== test;
  });

  if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype = {};

  // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
  if ( !has(IteratorPrototype, ITERATOR$3)) {
    createNonEnumerableProperty(IteratorPrototype, ITERATOR$3, returnThis);
  }

  var iteratorsCore = {
    IteratorPrototype: IteratorPrototype,
    BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
  };

  // `Object.keys` method
  // https://tc39.es/ecma262/#sec-object.keys
  var objectKeys = Object.keys || function keys(O) {
    return objectKeysInternal(O, enumBugKeys);
  };

  // `Object.defineProperties` method
  // https://tc39.es/ecma262/#sec-object.defineproperties
  var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
    anObject(O);
    var keys = objectKeys(Properties);
    var length = keys.length;
    var index = 0;
    var key;
    while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]);
    return O;
  };

  var html = getBuiltIn('document', 'documentElement');

  var GT = '>';
  var LT = '<';
  var PROTOTYPE = 'prototype';
  var SCRIPT = 'script';
  var IE_PROTO$1 = sharedKey('IE_PROTO');

  var EmptyConstructor = function () { /* empty */ };

  var scriptTag = function (content) {
    return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
  };

  // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
  var NullProtoObjectViaActiveX = function (activeXDocument) {
    activeXDocument.write(scriptTag(''));
    activeXDocument.close();
    var temp = activeXDocument.parentWindow.Object;
    activeXDocument = null; // avoid memory leak
    return temp;
  };

  // Create object with fake `null` prototype: use iframe Object with cleared prototype
  var NullProtoObjectViaIFrame = function () {
    // Thrash, waste and sodomy: IE GC bug
    var iframe = documentCreateElement('iframe');
    var JS = 'java' + SCRIPT + ':';
    var iframeDocument;
    iframe.style.display = 'none';
    html.appendChild(iframe);
    // https://github.com/zloirock/core-js/issues/475
    iframe.src = String(JS);
    iframeDocument = iframe.contentWindow.document;
    iframeDocument.open();
    iframeDocument.write(scriptTag('document.F=Object'));
    iframeDocument.close();
    return iframeDocument.F;
  };

  // Check for document.domain and active x support
  // No need to use active x approach when document.domain is not set
  // see https://github.com/es-shims/es5-shim/issues/150
  // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
  // avoid IE GC bug
  var activeXDocument;
  var NullProtoObject = function () {
    try {
      /* global ActiveXObject */
      activeXDocument = document.domain && new ActiveXObject('htmlfile');
    } catch (error) { /* ignore */ }
    NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
    var length = enumBugKeys.length;
    while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];
    return NullProtoObject();
  };

  hiddenKeys[IE_PROTO$1] = true;

  // `Object.create` method
  // https://tc39.es/ecma262/#sec-object.create
  var objectCreate = Object.create || function create(O, Properties) {
    var result;
    if (O !== null) {
      EmptyConstructor[PROTOTYPE] = anObject(O);
      result = new EmptyConstructor();
      EmptyConstructor[PROTOTYPE] = null;
      // add "__proto__" for Object.getPrototypeOf polyfill
      result[IE_PROTO$1] = O;
    } else result = NullProtoObject();
    return Properties === undefined ? result : objectDefineProperties(result, Properties);
  };

  var defineProperty$1 = objectDefineProperty.f;



  var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag');

  var setToStringTag = function (it, TAG, STATIC) {
    if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG$2)) {
      defineProperty$1(it, TO_STRING_TAG$2, { configurable: true, value: TAG });
    }
  };

  var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;





  var returnThis$1 = function () { return this; };

  var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
    var TO_STRING_TAG = NAME + ' Iterator';
    IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) });
    setToStringTag(IteratorConstructor, TO_STRING_TAG, false);
    iterators[TO_STRING_TAG] = returnThis$1;
    return IteratorConstructor;
  };

  var aPossiblePrototype = function (it) {
    if (!isObject(it) && it !== null) {
      throw TypeError("Can't set " + String(it) + ' as a prototype');
    } return it;
  };

  // `Object.setPrototypeOf` method
  // https://tc39.es/ecma262/#sec-object.setprototypeof
  // Works with __proto__ only. Old v8 can't work with null proto objects.
  /* eslint-disable no-proto */
  var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
    var CORRECT_SETTER = false;
    var test = {};
    var setter;
    try {
      setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
      setter.call(test, []);
      CORRECT_SETTER = test instanceof Array;
    } catch (error) { /* empty */ }
    return function setPrototypeOf(O, proto) {
      anObject(O);
      aPossiblePrototype(proto);
      if (CORRECT_SETTER) setter.call(O, proto);
      else O.__proto__ = proto;
      return O;
    };
  }() : undefined);

  var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
  var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
  var ITERATOR$4 = wellKnownSymbol('iterator');
  var KEYS = 'keys';
  var VALUES = 'values';
  var ENTRIES = 'entries';

  var returnThis$2 = function () { return this; };

  var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
    createIteratorConstructor(IteratorConstructor, NAME, next);

    var getIterationMethod = function (KIND) {
      if (KIND === DEFAULT && defaultIterator) return defaultIterator;
      if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];
      switch (KIND) {
        case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
        case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
        case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
      } return function () { return new IteratorConstructor(this); };
    };

    var TO_STRING_TAG = NAME + ' Iterator';
    var INCORRECT_VALUES_NAME = false;
    var IterablePrototype = Iterable.prototype;
    var nativeIterator = IterablePrototype[ITERATOR$4]
      || IterablePrototype['@@iterator']
      || DEFAULT && IterablePrototype[DEFAULT];
    var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
    var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
    var CurrentIteratorPrototype, methods, KEY;

    // fix native
    if (anyNativeIterator) {
      CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
      if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) {
        if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) {
          if (objectSetPrototypeOf) {
            objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2);
          } else if (typeof CurrentIteratorPrototype[ITERATOR$4] != 'function') {
            createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$4, returnThis$2);
          }
        }
        // Set @@toStringTag to native iterators
        setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true);
      }
    }

    // fix Array#{values, @@iterator}.name in V8 / FF
    if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
      INCORRECT_VALUES_NAME = true;
      defaultIterator = function values() { return nativeIterator.call(this); };
    }

    // define iterator
    if ( IterablePrototype[ITERATOR$4] !== defaultIterator) {
      createNonEnumerableProperty(IterablePrototype, ITERATOR$4, defaultIterator);
    }
    iterators[NAME] = defaultIterator;

    // export additional methods
    if (DEFAULT) {
      methods = {
        values: getIterationMethod(VALUES),
        keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
        entries: getIterationMethod(ENTRIES)
      };
      if (FORCED) for (KEY in methods) {
        if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
          redefine(IterablePrototype, KEY, methods[KEY]);
        }
      } else _export({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME }, methods);
    }

    return methods;
  };

  var charAt = stringMultibyte.charAt;



  var STRING_ITERATOR = 'String Iterator';
  var setInternalState = internalState.set;
  var getInternalState = internalState.getterFor(STRING_ITERATOR);

  // `String.prototype[@@iterator]` method
  // https://tc39.es/ecma262/#sec-string.prototype-@@iterator
  defineIterator(String, 'String', function (iterated) {
    setInternalState(this, {
      type: STRING_ITERATOR,
      string: String(iterated),
      index: 0
    });
  // `%StringIteratorPrototype%.next` method
  // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
  }, function next() {
    var state = getInternalState(this);
    var string = state.string;
    var index = state.index;
    var point;
    if (index >= string.length) return { value: undefined, done: true };
    point = charAt(string, index);
    state.index += point.length;
    return { value: point, done: false };
  });

  // iterable DOM collections
  // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
  var domIterables = {
    CSSRuleList: 0,
    CSSStyleDeclaration: 0,
    CSSValueList: 0,
    ClientRectList: 0,
    DOMRectList: 0,
    DOMStringList: 0,
    DOMTokenList: 1,
    DataTransferItemList: 0,
    FileList: 0,
    HTMLAllCollection: 0,
    HTMLCollection: 0,
    HTMLFormElement: 0,
    HTMLSelectElement: 0,
    MediaList: 0,
    MimeTypeArray: 0,
    NamedNodeMap: 0,
    NodeList: 1,
    PaintRequestList: 0,
    Plugin: 0,
    PluginArray: 0,
    SVGLengthList: 0,
    SVGNumberList: 0,
    SVGPathSegList: 0,
    SVGPointList: 0,
    SVGStringList: 0,
    SVGTransformList: 0,
    SourceBufferList: 0,
    StyleSheetList: 0,
    TextTrackCueList: 0,
    TextTrackList: 0,
    TouchList: 0
  };

  for (var COLLECTION_NAME in domIterables) {
    var Collection = global_1[COLLECTION_NAME];
    var CollectionPrototype = Collection && Collection.prototype;
    // some Chrome versions have non-configurable methods on DOMTokenList
    if (CollectionPrototype && CollectionPrototype.forEach !== arrayForEach) try {
      createNonEnumerableProperty(CollectionPrototype, 'forEach', arrayForEach);
    } catch (error) {
      CollectionPrototype.forEach = arrayForEach;
    }
  }

  function _typeof(obj) {
    "@babel/helpers - typeof";

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

    return _typeof(obj);
  }

  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
    try {
      var info = gen[key](arg);
      var value = info.value;
    } catch (error) {
      reject(error);
      return;
    }

    if (info.done) {
      resolve(value);
    } else {
      Promise.resolve(value).then(_next, _throw);
    }
  }

  function _asyncToGenerator(fn) {
    return function () {
      var self = this,
          args = arguments;
      return new Promise(function (resolve, reject) {
        var gen = fn.apply(self, args);

        function _next(value) {
          asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
        }

        function _throw(err) {
          asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
        }

        _next(undefined);
      });
    };
  }

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

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

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

  function _defineProperty(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;
  }

  function ownKeys$1(object, enumerableOnly) {
    var keys = Object.keys(object);

    if (Object.getOwnPropertySymbols) {
      var symbols = Object.getOwnPropertySymbols(object);
      if (enumerableOnly) symbols = symbols.filter(function (sym) {
        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
      });
      keys.push.apply(keys, symbols);
    }

    return keys;
  }

  function _objectSpread2(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};

      if (i % 2) {
        ownKeys$1(Object(source), true).forEach(function (key) {
          _defineProperty(target, key, source[key]);
        });
      } else if (Object.getOwnPropertyDescriptors) {
        Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
      } else {
        ownKeys$1(Object(source)).forEach(function (key) {
          Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
        });
      }
    }

    return target;
  }

  function _newArrowCheck(innerThis, boundThis) {
    if (innerThis !== boundThis) {
      throw new TypeError("Cannot instantiate an arrow function");
    }
  }

  function _slicedToArray(arr, i) {
    return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
  }

  function _toConsumableArray(arr) {
    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
  }

  function _arrayWithoutHoles(arr) {
    if (Array.isArray(arr)) return _arrayLikeToArray(arr);
  }

  function _arrayWithHoles(arr) {
    if (Array.isArray(arr)) return arr;
  }

  function _iterableToArray(iter) {
    if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
  }

  function _iterableToArrayLimit(arr, i) {
    if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
    var _arr = [];
    var _n = true;
    var _d = false;
    var _e = undefined;

    try {
      for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
        _arr.push(_s.value);

        if (i && _arr.length === i) break;
      }
    } catch (err) {
      _d = true;
      _e = err;
    } finally {
      try {
        if (!_n && _i["return"] != null) _i["return"]();
      } finally {
        if (_d) throw _e;
      }
    }

    return _arr;
  }

  function _unsupportedIterableToArray(o, minLen) {
    if (!o) return;
    if (typeof o === "string") return _arrayLikeToArray(o, minLen);
    var n = Object.prototype.toString.call(o).slice(8, -1);
    if (n === "Object" && o.constructor) n = o.constructor.name;
    if (n === "Map" || n === "Set") return Array.from(o);
    if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
  }

  function _arrayLikeToArray(arr, len) {
    if (len == null || len > arr.length) len = arr.length;

    for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];

    return arr2;
  }

  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }

  function _nonIterableRest() {
    throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  }

  var runtime_1 = createCommonjsModule(function (module) {
  /**
   * Copyright (c) 2014-present, Facebook, Inc.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   */

  var runtime = (function (exports) {

    var Op = Object.prototype;
    var hasOwn = Op.hasOwnProperty;
    var undefined$1; // More compressible than void 0.
    var $Symbol = typeof Symbol === "function" ? Symbol : {};
    var iteratorSymbol = $Symbol.iterator || "@@iterator";
    var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
    var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";

    function wrap(innerFn, outerFn, self, tryLocsList) {
      // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
      var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
      var generator = Object.create(protoGenerator.prototype);
      var context = new Context(tryLocsList || []);

      // The ._invoke method unifies the implementations of the .next,
      // .throw, and .return methods.
      generator._invoke = makeInvokeMethod(innerFn, self, context);

      return generator;
    }
    exports.wrap = wrap;

    // Try/catch helper to minimize deoptimizations. Returns a completion
    // record like context.tryEntries[i].completion. This interface could
    // have been (and was previously) designed to take a closure to be
    // invoked without arguments, but in all the cases we care about we
    // already have an existing method we want to call, so there's no need
    // to create a new function object. We can even get away with assuming
    // the method takes exactly one argument, since that happens to be true
    // in every case, so we don't have to touch the arguments object. The
    // only additional allocation required is the completion record, which
    // has a stable shape and so hopefully should be cheap to allocate.
    function tryCatch(fn, obj, arg) {
      try {
        return { type: "normal", arg: fn.call(obj, arg) };
      } catch (err) {
        return { type: "throw", arg: err };
      }
    }

    var GenStateSuspendedStart = "suspendedStart";
    var GenStateSuspendedYield = "suspendedYield";
    var GenStateExecuting = "executing";
    var GenStateCompleted = "completed";

    // Returning this object from the innerFn has the same effect as
    // breaking out of the dispatch switch statement.
    var ContinueSentinel = {};

    // Dummy constructor functions that we use as the .constructor and
    // .constructor.prototype properties for functions that return Generator
    // objects. For full spec compliance, you may wish to configure your
    // minifier not to mangle the names of these two functions.
    function Generator() {}
    function GeneratorFunction() {}
    function GeneratorFunctionPrototype() {}

    // This is a polyfill for %IteratorPrototype% for environments that
    // don't natively support it.
    var IteratorPrototype = {};
    IteratorPrototype[iteratorSymbol] = function () {
      return this;
    };

    var getProto = Object.getPrototypeOf;
    var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
    if (NativeIteratorPrototype &&
        NativeIteratorPrototype !== Op &&
        hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
      // This environment has a native %IteratorPrototype%; use it instead
      // of the polyfill.
      IteratorPrototype = NativeIteratorPrototype;
    }

    var Gp = GeneratorFunctionPrototype.prototype =
      Generator.prototype = Object.create(IteratorPrototype);
    GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
    GeneratorFunctionPrototype.constructor = GeneratorFunction;
    GeneratorFunctionPrototype[toStringTagSymbol] =
      GeneratorFunction.displayName = "GeneratorFunction";

    // Helper for defining the .next, .throw, and .return methods of the
    // Iterator interface in terms of a single ._invoke method.
    function defineIteratorMethods(prototype) {
      ["next", "throw", "return"].forEach(function(method) {
        prototype[method] = function(arg) {
          return this._invoke(method, arg);
        };
      });
    }

    exports.isGeneratorFunction = function(genFun) {
      var ctor = typeof genFun === "function" && genFun.constructor;
      return ctor
        ? ctor === GeneratorFunction ||
          // For the native GeneratorFunction constructor, the best we can
          // do is to check its .name property.
          (ctor.displayName || ctor.name) === "GeneratorFunction"
        : false;
    };

    exports.mark = function(genFun) {
      if (Object.setPrototypeOf) {
        Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
      } else {
        genFun.__proto__ = GeneratorFunctionPrototype;
        if (!(toStringTagSymbol in genFun)) {
          genFun[toStringTagSymbol] = "GeneratorFunction";
        }
      }
      genFun.prototype = Object.create(Gp);
      return genFun;
    };

    // Within the body of any async function, `await x` is transformed to
    // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
    // `hasOwn.call(value, "__await")` to determine if the yielded value is
    // meant to be awaited.
    exports.awrap = function(arg) {
      return { __await: arg };
    };

    function AsyncIterator(generator, PromiseImpl) {
      function invoke(method, arg, resolve, reject) {
        var record = tryCatch(generator[method], generator, arg);
        if (record.type === "throw") {
          reject(record.arg);
        } else {
          var result = record.arg;
          var value = result.value;
          if (value &&
              typeof value === "object" &&
              hasOwn.call(value, "__await")) {
            return PromiseImpl.resolve(value.__await).then(function(value) {
              invoke("next", value, resolve, reject);
            }, function(err) {
              invoke("throw", err, resolve, reject);
            });
          }

          return PromiseImpl.resolve(value).then(function(unwrapped) {
            // When a yielded Promise is resolved, its final value becomes
            // the .value of the Promise<{value,done}> result for the
            // current iteration.
            result.value = unwrapped;
            resolve(result);
          }, function(error) {
            // If a rejected Promise was yielded, throw the rejection back
            // into the async generator function so it can be handled there.
            return invoke("throw", error, resolve, reject);
          });
        }
      }

      var previousPromise;

      function enqueue(method, arg) {
        function callInvokeWithMethodAndArg() {
          return new PromiseImpl(function(resolve, reject) {
            invoke(method, arg, resolve, reject);
          });
        }

        return previousPromise =
          // If enqueue has been called before, then we want to wait until
          // all previous Promises have been resolved before calling invoke,
          // so that results are always delivered in the correct order. If
          // enqueue has not been called before, then it is important to
          // call invoke immediately, without waiting on a callback to fire,
          // so that the async generator function has the opportunity to do
          // any necessary setup in a predictable way. This predictability
          // is why the Promise constructor synchronously invokes its
          // executor callback, and why async functions synchronously
          // execute code before the first await. Since we implement simple
          // async functions in terms of async generators, it is especially
          // important to get this right, even though it requires care.
          previousPromise ? previousPromise.then(
            callInvokeWithMethodAndArg,
            // Avoid propagating failures to Promises returned by later
            // invocations of the iterator.
            callInvokeWithMethodAndArg
          ) : callInvokeWithMethodAndArg();
      }

      // Define the unified helper method that is used to implement .next,
      // .throw, and .return (see defineIteratorMethods).
      this._invoke = enqueue;
    }

    defineIteratorMethods(AsyncIterator.prototype);
    AsyncIterator.prototype[asyncIteratorSymbol] = function () {
      return this;
    };
    exports.AsyncIterator = AsyncIterator;

    // Note that simple async functions are implemented on top of
    // AsyncIterator objects; they just return a Promise for the value of
    // the final result produced by the iterator.
    exports.async = function(innerFn, outerFn, self, tryLocsList, PromiseImpl) {
      if (PromiseImpl === void 0) PromiseImpl = Promise;

      var iter = new AsyncIterator(
        wrap(innerFn, outerFn, self, tryLocsList),
        PromiseImpl
      );

      return exports.isGeneratorFunction(outerFn)
        ? iter // If outerFn is a generator, return the full iterator.
        : iter.next().then(function(result) {
            return result.done ? result.value : iter.next();
          });
    };

    function makeInvokeMethod(innerFn, self, context) {
      var state = GenStateSuspendedStart;

      return function invoke(method, arg) {
        if (state === GenStateExecuting) {
          throw new Error("Generator is already running");
        }

        if (state === GenStateCompleted) {
          if (method === "throw") {
            throw arg;
          }

          // Be forgiving, per 25.3.3.3.3 of the spec:
          // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
          return doneResult();
        }

        context.method = method;
        context.arg = arg;

        while (true) {
          var delegate = context.delegate;
          if (delegate) {
            var delegateResult = maybeInvokeDelegate(delegate, context);
            if (delegateResult) {
              if (delegateResult === ContinueSentinel) continue;
              return delegateResult;
            }
          }

          if (context.method === "next") {
            // Setting context._sent for legacy support of Babel's
            // function.sent implementation.
            context.sent = context._sent = context.arg;

          } else if (context.method === "throw") {
            if (state === GenStateSuspendedStart) {
              state = GenStateCompleted;
              throw context.arg;
            }

            context.dispatchException(context.arg);

          } else if (context.method === "return") {
            context.abrupt("return", context.arg);
          }

          state = GenStateExecuting;

          var record = tryCatch(innerFn, self, context);
          if (record.type === "normal") {
            // If an exception is thrown from innerFn, we leave state ===
            // GenStateExecuting and loop back for another invocation.
            state = context.done
              ? GenStateCompleted
              : GenStateSuspendedYield;

            if (record.arg === ContinueSentinel) {
              continue;
            }

            return {
              value: record.arg,
              done: context.done
            };

          } else if (record.type === "throw") {
            state = GenStateCompleted;
            // Dispatch the exception by looping back around to the
            // context.dispatchException(context.arg) call above.
            context.method = "throw";
            context.arg = record.arg;
          }
        }
      };
    }

    // Call delegate.iterator[context.method](context.arg) and handle the
    // result, either by returning a { value, done } result from the
    // delegate iterator, or by modifying context.method and context.arg,
    // setting context.delegate to null, and returning the ContinueSentinel.
    function maybeInvokeDelegate(delegate, context) {
      var method = delegate.iterator[context.method];
      if (method === undefined$1) {
        // A .throw or .return when the delegate iterator has no .throw
        // method always terminates the yield* loop.
        context.delegate = null;

        if (context.method === "throw") {
          // Note: ["return"] must be used for ES3 parsing compatibility.
          if (delegate.iterator["return"]) {
            // If the delegate iterator has a return method, give it a
            // chance to clean up.
            context.method = "return";
            context.arg = undefined$1;
            maybeInvokeDelegate(delegate, context);

            if (context.method === "throw") {
              // If maybeInvokeDelegate(context) changed context.method from
              // "return" to "throw", let that override the TypeError below.
              return ContinueSentinel;
            }
          }

          context.method = "throw";
          context.arg = new TypeError(
            "The iterator does not provide a 'throw' method");
        }

        return ContinueSentinel;
      }

      var record = tryCatch(method, delegate.iterator, context.arg);

      if (record.type === "throw") {
        context.method = "throw";
        context.arg = record.arg;
        context.delegate = null;
        return ContinueSentinel;
      }

      var info = record.arg;

      if (! info) {
        context.method = "throw";
        context.arg = new TypeError("iterator result is not an object");
        context.delegate = null;
        return ContinueSentinel;
      }

      if (info.done) {
        // Assign the result of the finished delegate to the temporary
        // variable specified by delegate.resultName (see delegateYield).
        context[delegate.resultName] = info.value;

        // Resume execution at the desired location (see delegateYield).
        context.next = delegate.nextLoc;

        // If context.method was "throw" but the delegate handled the
        // exception, let the outer generator proceed normally. If
        // context.method was "next", forget context.arg since it has been
        // "consumed" by the delegate iterator. If context.method was
        // "return", allow the original .return call to continue in the
        // outer generator.
        if (context.method !== "return") {
          context.method = "next";
          context.arg = undefined$1;
        }

      } else {
        // Re-yield the result returned by the delegate method.
        return info;
      }

      // The delegate iterator is finished, so forget it and continue with
      // the outer generator.
      context.delegate = null;
      return ContinueSentinel;
    }

    // Define Generator.prototype.{next,throw,return} in terms of the
    // unified ._invoke helper method.
    defineIteratorMethods(Gp);

    Gp[toStringTagSymbol] = "Generator";

    // A Generator should always return itself as the iterator object when the
    // @@iterator function is called on it. Some browsers' implementations of the
    // iterator prototype chain incorrectly implement this, causing the Generator
    // object to not be returned from this call. This ensures that doesn't happen.
    // See https://github.com/facebook/regenerator/issues/274 for more details.
    Gp[iteratorSymbol] = function() {
      return this;
    };

    Gp.toString = function() {
      return "[object Generator]";
    };

    function pushTryEntry(locs) {
      var entry = { tryLoc: locs[0] };

      if (1 in locs) {
        entry.catchLoc = locs[1];
      }

      if (2 in locs) {
        entry.finallyLoc = locs[2];
        entry.afterLoc = locs[3];
      }

      this.tryEntries.push(entry);
    }

    function resetTryEntry(entry) {
      var record = entry.completion || {};
      record.type = "normal";
      delete record.arg;
      entry.completion = record;
    }

    function Context(tryLocsList) {
      // The root entry object (effectively a try statement without a catch
      // or a finally block) gives us a place to store values thrown from
      // locations where there is no enclosing try statement.
      this.tryEntries = [{ tryLoc: "root" }];
      tryLocsList.forEach(pushTryEntry, this);
      this.reset(true);
    }

    exports.keys = function(object) {
      var keys = [];
      for (var key in object) {
        keys.push(key);
      }
      keys.reverse();

      // Rather than returning an object with a next method, we keep
      // things simple and return the next function itself.
      return function next() {
        while (keys.length) {
          var key = keys.pop();
          if (key in object) {
            next.value = key;
            next.done = false;
            return next;
          }
        }

        // To avoid creating an additional object, we just hang the .value
        // and .done properties off the next function object itself. This
        // also ensures that the minifier will not anonymize the function.
        next.done = true;
        return next;
      };
    };

    function values(iterable) {
      if (iterable) {
        var iteratorMethod = iterable[iteratorSymbol];
        if (iteratorMethod) {
          return iteratorMethod.call(iterable);
        }

        if (typeof iterable.next === "function") {
          return iterable;
        }

        if (!isNaN(iterable.length)) {
          var i = -1, next = function next() {
            while (++i < iterable.length) {
              if (hasOwn.call(iterable, i)) {
                next.value = iterable[i];
                next.done = false;
                return next;
              }
            }

            next.value = undefined$1;
            next.done = true;

            return next;
          };

          return next.next = next;
        }
      }

      // Return an iterator with no values.
      return { next: doneResult };
    }
    exports.values = values;

    function doneResult() {
      return { value: undefined$1, done: true };
    }

    Context.prototype = {
      constructor: Context,

      reset: function(skipTempReset) {
        this.prev = 0;
        this.next = 0;
        // Resetting context._sent for legacy support of Babel's
        // function.sent implementation.
        this.sent = this._sent = undefined$1;
        this.done = false;
        this.delegate = null;

        this.method = "next";
        this.arg = undefined$1;

        this.tryEntries.forEach(resetTryEntry);

        if (!skipTempReset) {
          for (var name in this) {
            // Not sure about the optimal order of these conditions:
            if (name.charAt(0) === "t" &&
                hasOwn.call(this, name) &&
                !isNaN(+name.slice(1))) {
              this[name] = undefined$1;
            }
          }
        }
      },

      stop: function() {
        this.done = true;

        var rootEntry = this.tryEntries[0];
        var rootRecord = rootEntry.completion;
        if (rootRecord.type === "throw") {
          throw rootRecord.arg;
        }

        return this.rval;
      },

      dispatchException: function(exception) {
        if (this.done) {
          throw exception;
        }

        var context = this;
        function handle(loc, caught) {
          record.type = "throw";
          record.arg = exception;
          context.next = loc;

          if (caught) {
            // If the dispatched exception was caught by a catch block,
            // then let that catch block handle the exception normally.
            context.method = "next";
            context.arg = undefined$1;
          }

          return !! caught;
        }

        for (var i = this.tryEntries.length - 1; i >= 0; --i) {
          var entry = this.tryEntries[i];
          var record = entry.completion;

          if (entry.tryLoc === "root") {
            // Exception thrown outside of any try block that could handle
            // it, so set the completion value of the entire function to
            // throw the exception.
            return handle("end");
          }

          if (entry.tryLoc <= this.prev) {
            var hasCatch = hasOwn.call(entry, "catchLoc");
            var hasFinally = hasOwn.call(entry, "finallyLoc");

            if (hasCatch && hasFinally) {
              if (this.prev < entry.catchLoc) {
                return handle(entry.catchLoc, true);
              } else if (this.prev < entry.finallyLoc) {
                return handle(entry.finallyLoc);
              }

            } else if (hasCatch) {
              if (this.prev < entry.catchLoc) {
                return handle(entry.catchLoc, true);
              }

            } else if (hasFinally) {
              if (this.prev < entry.finallyLoc) {
                return handle(entry.finallyLoc);
              }

            } else {
              throw new Error("try statement without catch or finally");
            }
          }
        }
      },

      abrupt: function(type, arg) {
        for (var i = this.tryEntries.length - 1; i >= 0; --i) {
          var entry = this.tryEntries[i];
          if (entry.tryLoc <= this.prev &&
              hasOwn.call(entry, "finallyLoc") &&
              this.prev < entry.finallyLoc) {
            var finallyEntry = entry;
            break;
          }
        }

        if (finallyEntry &&
            (type === "break" ||
             type === "continue") &&
            finallyEntry.tryLoc <= arg &&
            arg <= finallyEntry.finallyLoc) {
          // Ignore the finally entry if control is not jumping to a
          // location outside the try/catch block.
          finallyEntry = null;
        }

        var record = finallyEntry ? finallyEntry.completion : {};
        record.type = type;
        record.arg = arg;

        if (finallyEntry) {
          this.method = "next";
          this.next = finallyEntry.finallyLoc;
          return ContinueSentinel;
        }

        return this.complete(record);
      },

      complete: function(record, afterLoc) {
        if (record.type === "throw") {
          throw record.arg;
        }

        if (record.type === "break" ||
            record.type === "continue") {
          this.next = record.arg;
        } else if (record.type === "return") {
          this.rval = this.arg = record.arg;
          this.method = "return";
          this.next = "end";
        } else if (record.type === "normal" && afterLoc) {
          this.next = afterLoc;
        }

        return ContinueSentinel;
      },

      finish: function(finallyLoc) {
        for (var i = this.tryEntries.length - 1; i >= 0; --i) {
          var entry = this.tryEntries[i];
          if (entry.finallyLoc === finallyLoc) {
            this.complete(entry.completion, entry.afterLoc);
            resetTryEntry(entry);
            return ContinueSentinel;
          }
        }
      },

      "catch": function(tryLoc) {
        for (var i = this.tryEntries.length - 1; i >= 0; --i) {
          var entry = this.tryEntries[i];
          if (entry.tryLoc === tryLoc) {
            var record = entry.completion;
            if (record.type === "throw") {
              var thrown = record.arg;
              resetTryEntry(entry);
            }
            return thrown;
          }
        }

        // The context.catch method must only be called with a location
        // argument that corresponds to a known catch block.
        throw new Error("illegal catch attempt");
      },

      delegateYield: function(iterable, resultName, nextLoc) {
        this.delegate = {
          iterator: values(iterable),
          resultName: resultName,
          nextLoc: nextLoc
        };

        if (this.method === "next") {
          // Deliberately forget the last sent value so that we don't
          // accidentally pass it on to the delegate.
          this.arg = undefined$1;
        }

        return ContinueSentinel;
      }
    };

    // Regardless of whether this script is executing as a CommonJS module
    // or not, return the runtime object so that we can declare the variable
    // regeneratorRuntime in the outer scope, which allows this module to be
    // injected easily by `bin/regenerator --include-runtime script.js`.
    return exports;

  }(
    // If this script is executing as a CommonJS module, use module.exports
    // as the regeneratorRuntime namespace. Otherwise create a new empty
    // object. Either way, the resulting object will be used to initialize
    // the regeneratorRuntime variable at the top of this file.
     module.exports 
  ));

  try {
    regeneratorRuntime = runtime;
  } catch (accidentalStrictMode) {
    // This module should not be running in strict mode, so the above
    // assignment should always work unless something is misconfigured. Just
    // in case runtime.js accidentally runs in strict mode, we can escape
    // strict mode using a global Function call. This could conceivably fail
    // if a Content Security Policy forbids using Function, but in that case
    // the proper solution is to fix the accidental strict mode problem. If
    // you've misconfigured your bundler to force strict mode and applied a
    // CSP to forbid Function, and you're not willing to fix either of those
    // problems, please detail your unique predicament in a GitHub issue.
    Function("r", "regeneratorRuntime = r")(runtime);
  }
  });

  var UNSCOPABLES = wellKnownSymbol('unscopables');
  var ArrayPrototype$1 = Array.prototype;

  // Array.prototype[@@unscopables]
  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
  if (ArrayPrototype$1[UNSCOPABLES] == undefined) {
    objectDefineProperty.f(ArrayPrototype$1, UNSCOPABLES, {
      configurable: true,
      value: objectCreate(null)
    });
  }

  // add a key to Array.prototype[@@unscopables]
  var addToUnscopables = function (key) {
    ArrayPrototype$1[UNSCOPABLES][key] = true;
  };

  var $includes = arrayIncludes.includes;



  var USES_TO_LENGTH$2 = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });

  // `Array.prototype.includes` method
  // https://tc39.es/ecma262/#sec-array.prototype.includes
  _export({ target: 'Array', proto: true, forced: !USES_TO_LENGTH$2 }, {
    includes: function includes(el /* , fromIndex = 0 */) {
      return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
  addToUnscopables('includes');

  var $map = arrayIteration.map;



  var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('map');
  // FF49- issue
  var USES_TO_LENGTH$3 = arrayMethodUsesToLength('map');

  // `Array.prototype.map` method
  // https://tc39.es/ecma262/#sec-array.prototype.map
  // with adding support of @@species
  _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 || !USES_TO_LENGTH$3 }, {
    map: function map(callbackfn /* , thisArg */) {
      return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  // `Array.prototype.{ reduce, reduceRight }` methods implementation
  var createMethod$3 = function (IS_RIGHT) {
    return function (that, callbackfn, argumentsLength, memo) {
      aFunction$1(callbackfn);
      var O = toObject(that);
      var self = indexedObject(O);
      var length = toLength(O.length);
      var index = IS_RIGHT ? length - 1 : 0;
      var i = IS_RIGHT ? -1 : 1;
      if (argumentsLength < 2) while (true) {
        if (index in self) {
          memo = self[index];
          index += i;
          break;
        }
        index += i;
        if (IS_RIGHT ? index < 0 : length <= index) {
          throw TypeError('Reduce of empty array with no initial value');
        }
      }
      for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
        memo = callbackfn(memo, self[index], index, O);
      }
      return memo;
    };
  };

  var arrayReduce = {
    // `Array.prototype.reduce` method
    // https://tc39.es/ecma262/#sec-array.prototype.reduce
    left: createMethod$3(false),
    // `Array.prototype.reduceRight` method
    // https://tc39.es/ecma262/#sec-array.prototype.reduceright
    right: createMethod$3(true)
  };

  var engineIsNode = classofRaw(global_1.process) == 'process';

  var $reduce = arrayReduce.left;





  var STRICT_METHOD$1 = arrayMethodIsStrict('reduce');
  var USES_TO_LENGTH$4 = arrayMethodUsesToLength('reduce', { 1: 0 });
  // Chrome 80-82 has a critical bug
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
  var CHROME_BUG = !engineIsNode && engineV8Version > 79 && engineV8Version < 83;

  // `Array.prototype.reduce` method
  // https://tc39.es/ecma262/#sec-array.prototype.reduce
  _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$1 || !USES_TO_LENGTH$4 || CHROME_BUG }, {
    reduce: function reduce(callbackfn /* , initialValue */) {
      return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var $some = arrayIteration.some;



  var STRICT_METHOD$2 = arrayMethodIsStrict('some');
  var USES_TO_LENGTH$5 = arrayMethodUsesToLength('some');

  // `Array.prototype.some` method
  // https://tc39.es/ecma262/#sec-array.prototype.some
  _export({ target: 'Array', proto: true, forced: !STRICT_METHOD$2 || !USES_TO_LENGTH$5 }, {
    some: function some(callbackfn /* , thisArg */) {
      return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var propertyIsEnumerable = objectPropertyIsEnumerable.f;

  // `Object.{ entries, values }` methods implementation
  var createMethod$4 = function (TO_ENTRIES) {
    return function (it) {
      var O = toIndexedObject(it);
      var keys = objectKeys(O);
      var length = keys.length;
      var i = 0;
      var result = [];
      var key;
      while (length > i) {
        key = keys[i++];
        if (!descriptors || propertyIsEnumerable.call(O, key)) {
          result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
        }
      }
      return result;
    };
  };

  var objectToArray = {
    // `Object.entries` method
    // https://tc39.es/ecma262/#sec-object.entries
    entries: createMethod$4(true),
    // `Object.values` method
    // https://tc39.es/ecma262/#sec-object.values
    values: createMethod$4(false)
  };

  var $entries = objectToArray.entries;

  // `Object.entries` method
  // https://tc39.es/ecma262/#sec-object.entries
  _export({ target: 'Object', stat: true }, {
    entries: function entries(O) {
      return $entries(O);
    }
  });

  // `SameValue` abstract operation
  // https://tc39.es/ecma262/#sec-samevalue
  var sameValue = Object.is || function is(x, y) {
    // eslint-disable-next-line no-self-compare
    return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
  };

  // `Object.is` method
  // https://tc39.es/ecma262/#sec-object.is
  _export({ target: 'Object', stat: true }, {
    is: sameValue
  });

  var FAILS_ON_PRIMITIVES = fails(function () { objectKeys(1); });

  // `Object.keys` method
  // https://tc39.es/ecma262/#sec-object.keys
  _export({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES }, {
    keys: function keys(it) {
      return objectKeys(toObject(it));
    }
  });

  // `Object.prototype.toString` method implementation
  // https://tc39.es/ecma262/#sec-object.prototype.tostring
  var objectToString = toStringTagSupport ? {}.toString : function toString() {
    return '[object ' + classof(this) + ']';
  };

  // `Object.prototype.toString` method
  // https://tc39.es/ecma262/#sec-object.prototype.tostring
  if (!toStringTagSupport) {
    redefine(Object.prototype, 'toString', objectToString, { unsafe: true });
  }

  var nativePromiseConstructor = global_1.Promise;

  var redefineAll = function (target, src, options) {
    for (var key in src) redefine(target, key, src[key], options);
    return target;
  };

  var SPECIES$2 = wellKnownSymbol('species');

  var setSpecies = function (CONSTRUCTOR_NAME) {
    var Constructor = getBuiltIn(CONSTRUCTOR_NAME);
    var defineProperty = objectDefineProperty.f;

    if (descriptors && Constructor && !Constructor[SPECIES$2]) {
      defineProperty(Constructor, SPECIES$2, {
        configurable: true,
        get: function () { return this; }
      });
    }
  };

  var anInstance = function (it, Constructor, name) {
    if (!(it instanceof Constructor)) {
      throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
    } return it;
  };

  var Result = function (stopped, result) {
    this.stopped = stopped;
    this.result = result;
  };

  var iterate = function (iterable, unboundFunction, options) {
    var that = options && options.that;
    var AS_ENTRIES = !!(options && options.AS_ENTRIES);
    var IS_ITERATOR = !!(options && options.IS_ITERATOR);
    var INTERRUPTED = !!(options && options.INTERRUPTED);
    var fn = functionBindContext(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
    var iterator, iterFn, index, length, result, next, step;

    var stop = function (condition) {
      if (iterator) iteratorClose(iterator);
      return new Result(true, condition);
    };

    var callFn = function (value) {
      if (AS_ENTRIES) {
        anObject(value);
        return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
      } return INTERRUPTED ? fn(value, stop) : fn(value);
    };

    if (IS_ITERATOR) {
      iterator = iterable;
    } else {
      iterFn = getIteratorMethod(iterable);
      if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
      // optimisation for array iterators
      if (isArrayIteratorMethod(iterFn)) {
        for (index = 0, length = toLength(iterable.length); length > index; index++) {
          result = callFn(iterable[index]);
          if (result && result instanceof Result) return result;
        } return new Result(false);
      }
      iterator = iterFn.call(iterable);
    }

    next = iterator.next;
    while (!(step = next.call(iterator)).done) {
      try {
        result = callFn(step.value);
      } catch (error) {
        iteratorClose(iterator);
        throw error;
      }
      if (typeof result == 'object' && result && result instanceof Result) return result;
    } return new Result(false);
  };

  var SPECIES$3 = wellKnownSymbol('species');

  // `SpeciesConstructor` abstract operation
  // https://tc39.es/ecma262/#sec-speciesconstructor
  var speciesConstructor = function (O, defaultConstructor) {
    var C = anObject(O).constructor;
    var S;
    return C === undefined || (S = anObject(C)[SPECIES$3]) == undefined ? defaultConstructor : aFunction$1(S);
  };

  var engineIsIos = /(iphone|ipod|ipad).*applewebkit/i.test(engineUserAgent);

  var location = global_1.location;
  var set$1 = global_1.setImmediate;
  var clear = global_1.clearImmediate;
  var process$2 = global_1.process;
  var MessageChannel = global_1.MessageChannel;
  var Dispatch = global_1.Dispatch;
  var counter = 0;
  var queue = {};
  var ONREADYSTATECHANGE = 'onreadystatechange';
  var defer, channel, port;

  var run = function (id) {
    // eslint-disable-next-line no-prototype-builtins
    if (queue.hasOwnProperty(id)) {
      var fn = queue[id];
      delete queue[id];
      fn();
    }
  };

  var runner = function (id) {
    return function () {
      run(id);
    };
  };

  var listener = function (event) {
    run(event.data);
  };

  var post = function (id) {
    // old engines have not location.origin
    global_1.postMessage(id + '', location.protocol + '//' + location.host);
  };

  // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
  if (!set$1 || !clear) {
    set$1 = function setImmediate(fn) {
      var args = [];
      var i = 1;
      while (arguments.length > i) args.push(arguments[i++]);
      queue[++counter] = function () {
        // eslint-disable-next-line no-new-func
        (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
      };
      defer(counter);
      return counter;
    };
    clear = function clearImmediate(id) {
      delete queue[id];
    };
    // Node.js 0.8-
    if (engineIsNode) {
      defer = function (id) {
        process$2.nextTick(runner(id));
      };
    // Sphere (JS game engine) Dispatch API
    } else if (Dispatch && Dispatch.now) {
      defer = function (id) {
        Dispatch.now(runner(id));
      };
    // Browsers with MessageChannel, includes WebWorkers
    // except iOS - https://github.com/zloirock/core-js/issues/624
    } else if (MessageChannel && !engineIsIos) {
      channel = new MessageChannel();
      port = channel.port2;
      channel.port1.onmessage = listener;
      defer = functionBindContext(port.postMessage, port, 1);
    // Browsers with postMessage, skip WebWorkers
    // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
    } else if (
      global_1.addEventListener &&
      typeof postMessage == 'function' &&
      !global_1.importScripts &&
      location && location.protocol !== 'file:' &&
      !fails(post)
    ) {
      defer = post;
      global_1.addEventListener('message', listener, false);
    // IE8-
    } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {
      defer = function (id) {
        html.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {
          html.removeChild(this);
          run(id);
        };
      };
    // Rest old browsers
    } else {
      defer = function (id) {
        setTimeout(runner(id), 0);
      };
    }
  }

  var task = {
    set: set$1,
    clear: clear
  };

  var engineIsWebosWebkit = /web0s(?!.*chrome)/i.test(engineUserAgent);

  var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
  var macrotask = task.set;




  var MutationObserver$1 = global_1.MutationObserver || global_1.WebKitMutationObserver;
  var document$2 = global_1.document;
  var process$3 = global_1.process;
  var Promise$1 = global_1.Promise;
  // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
  var queueMicrotaskDescriptor = getOwnPropertyDescriptor$2(global_1, 'queueMicrotask');
  var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;

  var flush, head, last, notify, toggle, node, promise, then;

  // modern engines have queueMicrotask method
  if (!queueMicrotask) {
    flush = function () {
      var parent, fn;
      if (engineIsNode && (parent = process$3.domain)) parent.exit();
      while (head) {
        fn = head.fn;
        head = head.next;
        try {
          fn();
        } catch (error) {
          if (head) notify();
          else last = undefined;
          throw error;
        }
      } last = undefined;
      if (parent) parent.enter();
    };

    // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
    // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898
    if (!engineIsIos && !engineIsNode && !engineIsWebosWebkit && MutationObserver$1 && document$2) {
      toggle = true;
      node = document$2.createTextNode('');
      new MutationObserver$1(flush).observe(node, { characterData: true });
      notify = function () {
        node.data = toggle = !toggle;
      };
    // environments with maybe non-completely correct, but existent Promise
    } else if (Promise$1 && Promise$1.resolve) {
      // Promise.resolve without an argument throws an error in LG WebOS 2
      promise = Promise$1.resolve(undefined);
      then = promise.then;
      notify = function () {
        then.call(promise, flush);
      };
    // Node.js without promises
    } else if (engineIsNode) {
      notify = function () {
        process$3.nextTick(flush);
      };
    // for other environments - macrotask based on:
    // - setImmediate
    // - MessageChannel
    // - window.postMessag
    // - onreadystatechange
    // - setTimeout
    } else {
      notify = function () {
        // strange IE + webpack dev server bug - use .call(global)
        macrotask.call(global_1, flush);
      };
    }
  }

  var microtask = queueMicrotask || function (fn) {
    var task = { fn: fn, next: undefined };
    if (last) last.next = task;
    if (!head) {
      head = task;
      notify();
    } last = task;
  };

  var PromiseCapability = function (C) {
    var resolve, reject;
    this.promise = new C(function ($$resolve, $$reject) {
      if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
      resolve = $$resolve;
      reject = $$reject;
    });
    this.resolve = aFunction$1(resolve);
    this.reject = aFunction$1(reject);
  };

  // 25.4.1.5 NewPromiseCapability(C)
  var f$5 = function (C) {
    return new PromiseCapability(C);
  };

  var newPromiseCapability = {
  	f: f$5
  };

  var promiseResolve = function (C, x) {
    anObject(C);
    if (isObject(x) && x.constructor === C) return x;
    var promiseCapability = newPromiseCapability.f(C);
    var resolve = promiseCapability.resolve;
    resolve(x);
    return promiseCapability.promise;
  };

  var hostReportErrors = function (a, b) {
    var console = global_1.console;
    if (console && console.error) {
      arguments.length === 1 ? console.error(a) : console.error(a, b);
    }
  };

  var perform = function (exec) {
    try {
      return { error: false, value: exec() };
    } catch (error) {
      return { error: true, value: error };
    }
  };

  var task$1 = task.set;











  var SPECIES$4 = wellKnownSymbol('species');
  var PROMISE = 'Promise';
  var getInternalState$1 = internalState.get;
  var setInternalState$1 = internalState.set;
  var getInternalPromiseState = internalState.getterFor(PROMISE);
  var PromiseConstructor = nativePromiseConstructor;
  var TypeError$1 = global_1.TypeError;
  var document$3 = global_1.document;
  var process$4 = global_1.process;
  var $fetch = getBuiltIn('fetch');
  var newPromiseCapability$1 = newPromiseCapability.f;
  var newGenericPromiseCapability = newPromiseCapability$1;
  var DISPATCH_EVENT = !!(document$3 && document$3.createEvent && global_1.dispatchEvent);
  var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
  var UNHANDLED_REJECTION = 'unhandledrejection';
  var REJECTION_HANDLED = 'rejectionhandled';
  var PENDING = 0;
  var FULFILLED = 1;
  var REJECTED = 2;
  var HANDLED = 1;
  var UNHANDLED = 2;
  var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;

  var FORCED = isForced_1(PROMISE, function () {
    var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);
    if (!GLOBAL_CORE_JS_PROMISE) {
      // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
      // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
      // We can't detect it synchronously, so just check versions
      if (engineV8Version === 66) return true;
      // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
      if (!engineIsNode && !NATIVE_REJECTION_EVENT) return true;
    }
    // We can't use @@species feature detection in V8 since it causes
    // deoptimization and performance degradation
    // https://github.com/zloirock/core-js/issues/679
    if (engineV8Version >= 51 && /native code/.test(PromiseConstructor)) return false;
    // Detect correctness of subclassing with @@species support
    var promise = PromiseConstructor.resolve(1);
    var FakePromise = function (exec) {
      exec(function () { /* empty */ }, function () { /* empty */ });
    };
    var constructor = promise.constructor = {};
    constructor[SPECIES$4] = FakePromise;
    return !(promise.then(function () { /* empty */ }) instanceof FakePromise);
  });

  var INCORRECT_ITERATION$1 = FORCED || !checkCorrectnessOfIteration(function (iterable) {
    PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
  });

  // helpers
  var isThenable = function (it) {
    var then;
    return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
  };

  var notify$1 = function (state, isReject) {
    if (state.notified) return;
    state.notified = true;
    var chain = state.reactions;
    microtask(function () {
      var value = state.value;
      var ok = state.state == FULFILLED;
      var index = 0;
      // variable length - can't use forEach
      while (chain.length > index) {
        var reaction = chain[index++];
        var handler = ok ? reaction.ok : reaction.fail;
        var resolve = reaction.resolve;
        var reject = reaction.reject;
        var domain = reaction.domain;
        var result, then, exited;
        try {
          if (handler) {
            if (!ok) {
              if (state.rejection === UNHANDLED) onHandleUnhandled(state);
              state.rejection = HANDLED;
            }
            if (handler === true) result = value;
            else {
              if (domain) domain.enter();
              result = handler(value); // can throw
              if (domain) {
                domain.exit();
                exited = true;
              }
            }
            if (result === reaction.promise) {
              reject(TypeError$1('Promise-chain cycle'));
            } else if (then = isThenable(result)) {
              then.call(result, resolve, reject);
            } else resolve(result);
          } else reject(value);
        } catch (error) {
          if (domain && !exited) domain.exit();
          reject(error);
        }
      }
      state.reactions = [];
      state.notified = false;
      if (isReject && !state.rejection) onUnhandled(state);
    });
  };

  var dispatchEvent = function (name, promise, reason) {
    var event, handler;
    if (DISPATCH_EVENT) {
      event = document$3.createEvent('Event');
      event.promise = promise;
      event.reason = reason;
      event.initEvent(name, false, true);
      global_1.dispatchEvent(event);
    } else event = { promise: promise, reason: reason };
    if (!NATIVE_REJECTION_EVENT && (handler = global_1['on' + name])) handler(event);
    else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
  };

  var onUnhandled = function (state) {
    task$1.call(global_1, function () {
      var promise = state.facade;
      var value = state.value;
      var IS_UNHANDLED = isUnhandled(state);
      var result;
      if (IS_UNHANDLED) {
        result = perform(function () {
          if (engineIsNode) {
            process$4.emit('unhandledRejection', value, promise);
          } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
        });
        // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
        state.rejection = engineIsNode || isUnhandled(state) ? UNHANDLED : HANDLED;
        if (result.error) throw result.value;
      }
    });
  };

  var isUnhandled = function (state) {
    return state.rejection !== HANDLED && !state.parent;
  };

  var onHandleUnhandled = function (state) {
    task$1.call(global_1, function () {
      var promise = state.facade;
      if (engineIsNode) {
        process$4.emit('rejectionHandled', promise);
      } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
    });
  };

  var bind = function (fn, state, unwrap) {
    return function (value) {
      fn(state, value, unwrap);
    };
  };

  var internalReject = function (state, value, unwrap) {
    if (state.done) return;
    state.done = true;
    if (unwrap) state = unwrap;
    state.value = value;
    state.state = REJECTED;
    notify$1(state, true);
  };

  var internalResolve = function (state, value, unwrap) {
    if (state.done) return;
    state.done = true;
    if (unwrap) state = unwrap;
    try {
      if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
      var then = isThenable(value);
      if (then) {
        microtask(function () {
          var wrapper = { done: false };
          try {
            then.call(value,
              bind(internalResolve, wrapper, state),
              bind(internalReject, wrapper, state)
            );
          } catch (error) {
            internalReject(wrapper, error, state);
          }
        });
      } else {
        state.value = value;
        state.state = FULFILLED;
        notify$1(state, false);
      }
    } catch (error) {
      internalReject({ done: false }, error, state);
    }
  };

  // constructor polyfill
  if (FORCED) {
    // 25.4.3.1 Promise(executor)
    PromiseConstructor = function Promise(executor) {
      anInstance(this, PromiseConstructor, PROMISE);
      aFunction$1(executor);
      Internal.call(this);
      var state = getInternalState$1(this);
      try {
        executor(bind(internalResolve, state), bind(internalReject, state));
      } catch (error) {
        internalReject(state, error);
      }
    };
    // eslint-disable-next-line no-unused-vars
    Internal = function Promise(executor) {
      setInternalState$1(this, {
        type: PROMISE,
        done: false,
        notified: false,
        parent: false,
        reactions: [],
        rejection: false,
        state: PENDING,
        value: undefined
      });
    };
    Internal.prototype = redefineAll(PromiseConstructor.prototype, {
      // `Promise.prototype.then` method
      // https://tc39.es/ecma262/#sec-promise.prototype.then
      then: function then(onFulfilled, onRejected) {
        var state = getInternalPromiseState(this);
        var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
        reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
        reaction.fail = typeof onRejected == 'function' && onRejected;
        reaction.domain = engineIsNode ? process$4.domain : undefined;
        state.parent = true;
        state.reactions.push(reaction);
        if (state.state != PENDING) notify$1(state, false);
        return reaction.promise;
      },
      // `Promise.prototype.catch` method
      // https://tc39.es/ecma262/#sec-promise.prototype.catch
      'catch': function (onRejected) {
        return this.then(undefined, onRejected);
      }
    });
    OwnPromiseCapability = function () {
      var promise = new Internal();
      var state = getInternalState$1(promise);
      this.promise = promise;
      this.resolve = bind(internalResolve, state);
      this.reject = bind(internalReject, state);
    };
    newPromiseCapability.f = newPromiseCapability$1 = function (C) {
      return C === PromiseConstructor || C === PromiseWrapper
        ? new OwnPromiseCapability(C)
        : newGenericPromiseCapability(C);
    };

    if ( typeof nativePromiseConstructor == 'function') {
      nativeThen = nativePromiseConstructor.prototype.then;

      // wrap native Promise#then for native async functions
      redefine(nativePromiseConstructor.prototype, 'then', function then(onFulfilled, onRejected) {
        var that = this;
        return new PromiseConstructor(function (resolve, reject) {
          nativeThen.call(that, resolve, reject);
        }).then(onFulfilled, onRejected);
      // https://github.com/zloirock/core-js/issues/640
      }, { unsafe: true });

      // wrap fetch result
      if (typeof $fetch == 'function') _export({ global: true, enumerable: true, forced: true }, {
        // eslint-disable-next-line no-unused-vars
        fetch: function fetch(input /* , init */) {
          return promiseResolve(PromiseConstructor, $fetch.apply(global_1, arguments));
        }
      });
    }
  }

  _export({ global: true, wrap: true, forced: FORCED }, {
    Promise: PromiseConstructor
  });

  setToStringTag(PromiseConstructor, PROMISE, false);
  setSpecies(PROMISE);

  PromiseWrapper = getBuiltIn(PROMISE);

  // statics
  _export({ target: PROMISE, stat: true, forced: FORCED }, {
    // `Promise.reject` method
    // https://tc39.es/ecma262/#sec-promise.reject
    reject: function reject(r) {
      var capability = newPromiseCapability$1(this);
      capability.reject.call(undefined, r);
      return capability.promise;
    }
  });

  _export({ target: PROMISE, stat: true, forced:  FORCED }, {
    // `Promise.resolve` method
    // https://tc39.es/ecma262/#sec-promise.resolve
    resolve: function resolve(x) {
      return promiseResolve( this, x);
    }
  });

  _export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION$1 }, {
    // `Promise.all` method
    // https://tc39.es/ecma262/#sec-promise.all
    all: function all(iterable) {
      var C = this;
      var capability = newPromiseCapability$1(C);
      var resolve = capability.resolve;
      var reject = capability.reject;
      var result = perform(function () {
        var $promiseResolve = aFunction$1(C.resolve);
        var values = [];
        var counter = 0;
        var remaining = 1;
        iterate(iterable, function (promise) {
          var index = counter++;
          var alreadyCalled = false;
          values.push(undefined);
          remaining++;
          $promiseResolve.call(C, promise).then(function (value) {
            if (alreadyCalled) return;
            alreadyCalled = true;
            values[index] = value;
            --remaining || resolve(values);
          }, reject);
        });
        --remaining || resolve(values);
      });
      if (result.error) reject(result.value);
      return capability.promise;
    },
    // `Promise.race` method
    // https://tc39.es/ecma262/#sec-promise.race
    race: function race(iterable) {
      var C = this;
      var capability = newPromiseCapability$1(C);
      var reject = capability.reject;
      var result = perform(function () {
        var $promiseResolve = aFunction$1(C.resolve);
        iterate(iterable, function (promise) {
          $promiseResolve.call(C, promise).then(capability.resolve, reject);
        });
      });
      if (result.error) reject(result.value);
      return capability.promise;
    }
  });

  // `RegExp.prototype.flags` getter implementation
  // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
  var regexpFlags = function () {
    var that = anObject(this);
    var result = '';
    if (that.global) result += 'g';
    if (that.ignoreCase) result += 'i';
    if (that.multiline) result += 'm';
    if (that.dotAll) result += 's';
    if (that.unicode) result += 'u';
    if (that.sticky) result += 'y';
    return result;
  };

  // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
  // so we use an intermediate function.
  function RE(s, f) {
    return RegExp(s, f);
  }

  var UNSUPPORTED_Y = fails(function () {
    // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError
    var re = RE('a', 'y');
    re.lastIndex = 2;
    return re.exec('abcd') != null;
  });

  var BROKEN_CARET = fails(function () {
    // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
    var re = RE('^r', 'gy');
    re.lastIndex = 2;
    return re.exec('str') != null;
  });

  var regexpStickyHelpers = {
  	UNSUPPORTED_Y: UNSUPPORTED_Y,
  	BROKEN_CARET: BROKEN_CARET
  };

  var nativeExec = RegExp.prototype.exec;
  // This always refers to the native implementation, because the
  // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
  // which loads this file before patching the method.
  var nativeReplace = String.prototype.replace;

  var patchedExec = nativeExec;

  var UPDATES_LAST_INDEX_WRONG = (function () {
    var re1 = /a/;
    var re2 = /b*/g;
    nativeExec.call(re1, 'a');
    nativeExec.call(re2, 'a');
    return re1.lastIndex !== 0 || re2.lastIndex !== 0;
  })();

  var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET;

  // nonparticipating capturing group, copied from es5-shim's String#split patch.
  var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;

  var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$1;

  if (PATCH) {
    patchedExec = function exec(str) {
      var re = this;
      var lastIndex, reCopy, match, i;
      var sticky = UNSUPPORTED_Y$1 && re.sticky;
      var flags = regexpFlags.call(re);
      var source = re.source;
      var charsAdded = 0;
      var strCopy = str;

      if (sticky) {
        flags = flags.replace('y', '');
        if (flags.indexOf('g') === -1) {
          flags += 'g';
        }

        strCopy = String(str).slice(re.lastIndex);
        // Support anchored sticky behavior.
        if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
          source = '(?: ' + source + ')';
          strCopy = ' ' + strCopy;
          charsAdded++;
        }
        // ^(? + rx + ) is needed, in combination with some str slicing, to
        // simulate the 'y' flag.
        reCopy = new RegExp('^(?:' + source + ')', flags);
      }

      if (NPCG_INCLUDED) {
        reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
      }
      if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;

      match = nativeExec.call(sticky ? reCopy : re, strCopy);

      if (sticky) {
        if (match) {
          match.input = match.input.slice(charsAdded);
          match[0] = match[0].slice(charsAdded);
          match.index = re.lastIndex;
          re.lastIndex += match[0].length;
        } else re.lastIndex = 0;
      } else if (UPDATES_LAST_INDEX_WRONG && match) {
        re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
      }
      if (NPCG_INCLUDED && match && match.length > 1) {
        // Fix browsers whose `exec` methods don't consistently return `undefined`
        // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
        nativeReplace.call(match[0], reCopy, function () {
          for (i = 1; i < arguments.length - 2; i++) {
            if (arguments[i] === undefined) match[i] = undefined;
          }
        });
      }

      return match;
    };
  }

  var regexpExec = patchedExec;

  // `RegExp.prototype.exec` method
  // https://tc39.es/ecma262/#sec-regexp.prototype.exec
  _export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, {
    exec: regexpExec
  });

  var MATCH = wellKnownSymbol('match');

  // `IsRegExp` abstract operation
  // https://tc39.es/ecma262/#sec-isregexp
  var isRegexp = function (it) {
    var isRegExp;
    return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp');
  };

  var notARegexp = function (it) {
    if (isRegexp(it)) {
      throw TypeError("The method doesn't accept regular expressions");
    } return it;
  };

  var MATCH$1 = wellKnownSymbol('match');

  var correctIsRegexpLogic = function (METHOD_NAME) {
    var regexp = /./;
    try {
      '/./'[METHOD_NAME](regexp);
    } catch (error1) {
      try {
        regexp[MATCH$1] = false;
        return '/./'[METHOD_NAME](regexp);
      } catch (error2) { /* empty */ }
    } return false;
  };

  // `String.prototype.includes` method
  // https://tc39.es/ecma262/#sec-string.prototype.includes
  _export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, {
    includes: function includes(searchString /* , position = 0 */) {
      return !!~String(requireObjectCoercible(this))
        .indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  // TODO: Remove from `core-js@4` since it's moved to entry points







  var SPECIES$5 = wellKnownSymbol('species');

  var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
    // #replace needs built-in support for named groups.
    // #match works fine because it just return the exec results, even if it has
    // a "grops" property.
    var re = /./;
    re.exec = function () {
      var result = [];
      result.groups = { a: '7' };
      return result;
    };
    return ''.replace(re, '$<a>') !== '7';
  });

  // IE <= 11 replaces $0 with the whole match, as if it was $&
  // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
  var REPLACE_KEEPS_$0 = (function () {
    return 'a'.replace(/./, '$0') === '$0';
  })();

  var REPLACE = wellKnownSymbol('replace');
  // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
  var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
    if (/./[REPLACE]) {
      return /./[REPLACE]('a', '$0') === '';
    }
    return false;
  })();

  // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
  // Weex JS has frozen built-in prototypes, so use try / catch wrapper
  var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
    var re = /(?:)/;
    var originalExec = re.exec;
    re.exec = function () { return originalExec.apply(this, arguments); };
    var result = 'ab'.split(re);
    return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
  });

  var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
    var SYMBOL = wellKnownSymbol(KEY);

    var DELEGATES_TO_SYMBOL = !fails(function () {
      // String methods call symbol-named RegEp methods
      var O = {};
      O[SYMBOL] = function () { return 7; };
      return ''[KEY](O) != 7;
    });

    var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
      // Symbol-named RegExp methods call .exec
      var execCalled = false;
      var re = /a/;

      if (KEY === 'split') {
        // We can't use real regex here since it causes deoptimization
        // and serious performance degradation in V8
        // https://github.com/zloirock/core-js/issues/306
        re = {};
        // RegExp[@@split] doesn't call the regex's exec method, but first creates
        // a new one. We need to return the patched regex when creating the new one.
        re.constructor = {};
        re.constructor[SPECIES$5] = function () { return re; };
        re.flags = '';
        re[SYMBOL] = /./[SYMBOL];
      }

      re.exec = function () { execCalled = true; return null; };

      re[SYMBOL]('');
      return !execCalled;
    });

    if (
      !DELEGATES_TO_SYMBOL ||
      !DELEGATES_TO_EXEC ||
      (KEY === 'replace' && !(
        REPLACE_SUPPORTS_NAMED_GROUPS &&
        REPLACE_KEEPS_$0 &&
        !REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
      )) ||
      (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC)
    ) {
      var nativeRegExpMethod = /./[SYMBOL];
      var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
        if (regexp.exec === regexpExec) {
          if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
            // The native String method already delegates to @@method (this
            // polyfilled function), leasing to infinite recursion.
            // We avoid it by directly calling the native @@method method.
            return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
          }
          return { done: true, value: nativeMethod.call(str, regexp, arg2) };
        }
        return { done: false };
      }, {
        REPLACE_KEEPS_$0: REPLACE_KEEPS_$0,
        REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE: REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE
      });
      var stringMethod = methods[0];
      var regexMethod = methods[1];

      redefine(String.prototype, KEY, stringMethod);
      redefine(RegExp.prototype, SYMBOL, length == 2
        // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
        // 21.2.5.11 RegExp.prototype[@@split](string, limit)
        ? function (string, arg) { return regexMethod.call(string, this, arg); }
        // 21.2.5.6 RegExp.prototype[@@match](string)
        // 21.2.5.9 RegExp.prototype[@@search](string)
        : function (string) { return regexMethod.call(string, this); }
      );
    }

    if (sham) createNonEnumerableProperty(RegExp.prototype[SYMBOL], 'sham', true);
  };

  var charAt$1 = stringMultibyte.charAt;

  // `AdvanceStringIndex` abstract operation
  // https://tc39.es/ecma262/#sec-advancestringindex
  var advanceStringIndex = function (S, index, unicode) {
    return index + (unicode ? charAt$1(S, index).length : 1);
  };

  // `RegExpExec` abstract operation
  // https://tc39.es/ecma262/#sec-regexpexec
  var regexpExecAbstract = function (R, S) {
    var exec = R.exec;
    if (typeof exec === 'function') {
      var result = exec.call(R, S);
      if (typeof result !== 'object') {
        throw TypeError('RegExp exec method returned something other than an Object or null');
      }
      return result;
    }

    if (classofRaw(R) !== 'RegExp') {
      throw TypeError('RegExp#exec called on incompatible receiver');
    }

    return regexpExec.call(R, S);
  };

  var arrayPush = [].push;
  var min$2 = Math.min;
  var MAX_UINT32 = 0xFFFFFFFF;

  // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError
  var SUPPORTS_Y = !fails(function () { return !RegExp(MAX_UINT32, 'y'); });

  // @@split logic
  fixRegexpWellKnownSymbolLogic('split', 2, function (SPLIT, nativeSplit, maybeCallNative) {
    var internalSplit;
    if (
      'abbc'.split(/(b)*/)[1] == 'c' ||
      'test'.split(/(?:)/, -1).length != 4 ||
      'ab'.split(/(?:ab)*/).length != 2 ||
      '.'.split(/(.?)(.?)/).length != 4 ||
      '.'.split(/()()/).length > 1 ||
      ''.split(/.?/).length
    ) {
      // based on es5-shim implementation, need to rework it
      internalSplit = function (separator, limit) {
        var string = String(requireObjectCoercible(this));
        var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
        if (lim === 0) return [];
        if (separator === undefined) return [string];
        // If `separator` is not a regex, use native split
        if (!isRegexp(separator)) {
          return nativeSplit.call(string, separator, lim);
        }
        var output = [];
        var flags = (separator.ignoreCase ? 'i' : '') +
                    (separator.multiline ? 'm' : '') +
                    (separator.unicode ? 'u' : '') +
                    (separator.sticky ? 'y' : '');
        var lastLastIndex = 0;
        // Make `global` and avoid `lastIndex` issues by working with a copy
        var separatorCopy = new RegExp(separator.source, flags + 'g');
        var match, lastIndex, lastLength;
        while (match = regexpExec.call(separatorCopy, string)) {
          lastIndex = separatorCopy.lastIndex;
          if (lastIndex > lastLastIndex) {
            output.push(string.slice(lastLastIndex, match.index));
            if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
            lastLength = match[0].length;
            lastLastIndex = lastIndex;
            if (output.length >= lim) break;
          }
          if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
        }
        if (lastLastIndex === string.length) {
          if (lastLength || !separatorCopy.test('')) output.push('');
        } else output.push(string.slice(lastLastIndex));
        return output.length > lim ? output.slice(0, lim) : output;
      };
    // Chakra, V8
    } else if ('0'.split(undefined, 0).length) {
      internalSplit = function (separator, limit) {
        return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
      };
    } else internalSplit = nativeSplit;

    return [
      // `String.prototype.split` method
      // https://tc39.es/ecma262/#sec-string.prototype.split
      function split(separator, limit) {
        var O = requireObjectCoercible(this);
        var splitter = separator == undefined ? undefined : separator[SPLIT];
        return splitter !== undefined
          ? splitter.call(separator, O, limit)
          : internalSplit.call(String(O), separator, limit);
      },
      // `RegExp.prototype[@@split]` method
      // https://tc39.es/ecma262/#sec-regexp.prototype-@@split
      //
      // NOTE: This cannot be properly polyfilled in engines that don't support
      // the 'y' flag.
      function (regexp, limit) {
        var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== nativeSplit);
        if (res.done) return res.value;

        var rx = anObject(regexp);
        var S = String(this);
        var C = speciesConstructor(rx, RegExp);

        var unicodeMatching = rx.unicode;
        var flags = (rx.ignoreCase ? 'i' : '') +
                    (rx.multiline ? 'm' : '') +
                    (rx.unicode ? 'u' : '') +
                    (SUPPORTS_Y ? 'y' : 'g');

        // ^(? + rx + ) is needed, in combination with some S slicing, to
        // simulate the 'y' flag.
        var splitter = new C(SUPPORTS_Y ? rx : '^(?:' + rx.source + ')', flags);
        var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
        if (lim === 0) return [];
        if (S.length === 0) return regexpExecAbstract(splitter, S) === null ? [S] : [];
        var p = 0;
        var q = 0;
        var A = [];
        while (q < S.length) {
          splitter.lastIndex = SUPPORTS_Y ? q : 0;
          var z = regexpExecAbstract(splitter, SUPPORTS_Y ? S : S.slice(q));
          var e;
          if (
            z === null ||
            (e = min$2(toLength(splitter.lastIndex + (SUPPORTS_Y ? 0 : q)), S.length)) === p
          ) {
            q = advanceStringIndex(S, q, unicodeMatching);
          } else {
            A.push(S.slice(p, q));
            if (A.length === lim) return A;
            for (var i = 1; i <= z.length - 1; i++) {
              A.push(z[i]);
              if (A.length === lim) return A;
            }
            q = p = e;
          }
        }
        A.push(S.slice(p));
        return A;
      }
    ];
  }, !SUPPORTS_Y);

  var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable');
  var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
  var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';

  // We can't use this feature detection in V8 since it causes
  // deoptimization and serious performance degradation
  // https://github.com/zloirock/core-js/issues/679
  var IS_CONCAT_SPREADABLE_SUPPORT = engineV8Version >= 51 || !fails(function () {
    var array = [];
    array[IS_CONCAT_SPREADABLE] = false;
    return array.concat()[0] !== array;
  });

  var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat');

  var isConcatSpreadable = function (O) {
    if (!isObject(O)) return false;
    var spreadable = O[IS_CONCAT_SPREADABLE];
    return spreadable !== undefined ? !!spreadable : isArray(O);
  };

  var FORCED$1 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;

  // `Array.prototype.concat` method
  // https://tc39.es/ecma262/#sec-array.prototype.concat
  // with adding support of @@isConcatSpreadable and @@species
  _export({ target: 'Array', proto: true, forced: FORCED$1 }, {
    concat: function concat(arg) { // eslint-disable-line no-unused-vars
      var O = toObject(this);
      var A = arraySpeciesCreate(O, 0);
      var n = 0;
      var i, k, length, len, E;
      for (i = -1, length = arguments.length; i < length; i++) {
        E = i === -1 ? O : arguments[i];
        if (isConcatSpreadable(E)) {
          len = toLength(E.length);
          if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
          for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
        } else {
          if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
          createProperty(A, n++, E);
        }
      }
      A.length = n;
      return A;
    }
  });

  var $find = arrayIteration.find;



  var FIND = 'find';
  var SKIPS_HOLES = true;

  var USES_TO_LENGTH$6 = arrayMethodUsesToLength(FIND);

  // Shouldn't skip holes
  if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES = false; });

  // `Array.prototype.find` method
  // https://tc39.es/ecma262/#sec-array.prototype.find
  _export({ target: 'Array', proto: true, forced: SKIPS_HOLES || !USES_TO_LENGTH$6 }, {
    find: function find(callbackfn /* , that = undefined */) {
      return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
  addToUnscopables(FIND);

  var $indexOf = arrayIncludes.indexOf;



  var nativeIndexOf = [].indexOf;

  var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
  var STRICT_METHOD$3 = arrayMethodIsStrict('indexOf');
  var USES_TO_LENGTH$7 = arrayMethodUsesToLength('indexOf', { ACCESSORS: true, 1: 0 });

  // `Array.prototype.indexOf` method
  // https://tc39.es/ecma262/#sec-array.prototype.indexof
  _export({ target: 'Array', proto: true, forced: NEGATIVE_ZERO || !STRICT_METHOD$3 || !USES_TO_LENGTH$7 }, {
    indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
      return NEGATIVE_ZERO
        // convert -0 to +0
        ? nativeIndexOf.apply(this, arguments) || 0
        : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
    }
  });

  var ARRAY_ITERATOR = 'Array Iterator';
  var setInternalState$2 = internalState.set;
  var getInternalState$2 = internalState.getterFor(ARRAY_ITERATOR);

  // `Array.prototype.entries` method
  // https://tc39.es/ecma262/#sec-array.prototype.entries
  // `Array.prototype.keys` method
  // https://tc39.es/ecma262/#sec-array.prototype.keys
  // `Array.prototype.values` method
  // https://tc39.es/ecma262/#sec-array.prototype.values
  // `Array.prototype[@@iterator]` method
  // https://tc39.es/ecma262/#sec-array.prototype-@@iterator
  // `CreateArrayIterator` internal method
  // https://tc39.es/ecma262/#sec-createarrayiterator
  var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
    setInternalState$2(this, {
      type: ARRAY_ITERATOR,
      target: toIndexedObject(iterated), // target
      index: 0,                          // next index
      kind: kind                         // kind
    });
  // `%ArrayIteratorPrototype%.next` method
  // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
  }, function () {
    var state = getInternalState$2(this);
    var target = state.target;
    var kind = state.kind;
    var index = state.index++;
    if (!target || index >= target.length) {
      state.target = undefined;
      return { value: undefined, done: true };
    }
    if (kind == 'keys') return { value: index, done: false };
    if (kind == 'values') return { value: target[index], done: false };
    return { value: [index, target[index]], done: false };
  }, 'values');

  // argumentsList[@@iterator] is %ArrayProto_values%
  // https://tc39.es/ecma262/#sec-createunmappedargumentsobject
  // https://tc39.es/ecma262/#sec-createmappedargumentsobject
  iterators.Arguments = iterators.Array;

  // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
  addToUnscopables('keys');
  addToUnscopables('values');
  addToUnscopables('entries');

  var nativeJoin = [].join;

  var ES3_STRINGS = indexedObject != Object;
  var STRICT_METHOD$4 = arrayMethodIsStrict('join', ',');

  // `Array.prototype.join` method
  // https://tc39.es/ecma262/#sec-array.prototype.join
  _export({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$4 }, {
    join: function join(separator) {
      return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator);
    }
  });

  var defineProperty$2 = objectDefineProperty.f;

  var FunctionPrototype = Function.prototype;
  var FunctionPrototypeToString = FunctionPrototype.toString;
  var nameRE = /^\s*function ([^ (]*)/;
  var NAME = 'name';

  // Function instances `.name` property
  // https://tc39.es/ecma262/#sec-function-instances-name
  if (descriptors && !(NAME in FunctionPrototype)) {
    defineProperty$2(FunctionPrototype, NAME, {
      configurable: true,
      get: function () {
        try {
          return FunctionPrototypeToString.call(this).match(nameRE)[1];
        } catch (error) {
          return '';
        }
      }
    });
  }

  // makes subclassing work correct for wrapped built-ins
  var inheritIfRequired = function ($this, dummy, Wrapper) {
    var NewTarget, NewTargetPrototype;
    if (
      // it can work only with native `setPrototypeOf`
      objectSetPrototypeOf &&
      // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
      typeof (NewTarget = dummy.constructor) == 'function' &&
      NewTarget !== Wrapper &&
      isObject(NewTargetPrototype = NewTarget.prototype) &&
      NewTargetPrototype !== Wrapper.prototype
    ) objectSetPrototypeOf($this, NewTargetPrototype);
    return $this;
  };

  // a string of all valid unicode whitespaces
  // eslint-disable-next-line max-len
  var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';

  var whitespace = '[' + whitespaces + ']';
  var ltrim = RegExp('^' + whitespace + whitespace + '*');
  var rtrim = RegExp(whitespace + whitespace + '*$');

  // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
  var createMethod$5 = function (TYPE) {
    return function ($this) {
      var string = String(requireObjectCoercible($this));
      if (TYPE & 1) string = string.replace(ltrim, '');
      if (TYPE & 2) string = string.replace(rtrim, '');
      return string;
    };
  };

  var stringTrim = {
    // `String.prototype.{ trimLeft, trimStart }` methods
    // https://tc39.es/ecma262/#sec-string.prototype.trimstart
    start: createMethod$5(1),
    // `String.prototype.{ trimRight, trimEnd }` methods
    // https://tc39.es/ecma262/#sec-string.prototype.trimend
    end: createMethod$5(2),
    // `String.prototype.trim` method
    // https://tc39.es/ecma262/#sec-string.prototype.trim
    trim: createMethod$5(3)
  };

  var getOwnPropertyNames = objectGetOwnPropertyNames.f;
  var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
  var defineProperty$3 = objectDefineProperty.f;
  var trim = stringTrim.trim;

  var NUMBER = 'Number';
  var NativeNumber = global_1[NUMBER];
  var NumberPrototype = NativeNumber.prototype;

  // Opera ~12 has broken Object#toString
  var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER;

  // `ToNumber` abstract operation
  // https://tc39.es/ecma262/#sec-tonumber
  var toNumber = function (argument) {
    var it = toPrimitive(argument, false);
    var first, third, radix, maxCode, digits, length, index, code;
    if (typeof it == 'string' && it.length > 2) {
      it = trim(it);
      first = it.charCodeAt(0);
      if (first === 43 || first === 45) {
        third = it.charCodeAt(2);
        if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
      } else if (first === 48) {
        switch (it.charCodeAt(1)) {
          case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i
          case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i
          default: return +it;
        }
        digits = it.slice(2);
        length = digits.length;
        for (index = 0; index < length; index++) {
          code = digits.charCodeAt(index);
          // parseInt parses a string to a first unavailable symbol
          // but ToNumber should return NaN if a string contains unavailable symbols
          if (code < 48 || code > maxCode) return NaN;
        } return parseInt(digits, radix);
      }
    } return +it;
  };

  // `Number` constructor
  // https://tc39.es/ecma262/#sec-number-constructor
  if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
    var NumberWrapper = function Number(value) {
      var it = arguments.length < 1 ? 0 : value;
      var dummy = this;
      return dummy instanceof NumberWrapper
        // check on 1..constructor(foo) case
        && (BROKEN_CLASSOF ? fails(function () { NumberPrototype.valueOf.call(dummy); }) : classofRaw(dummy) != NUMBER)
          ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it);
    };
    for (var keys$1 = descriptors ? getOwnPropertyNames(NativeNumber) : (
      // ES3:
      'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +
      // ES2015 (in case, if modules with ES2015 Number statics required before):
      'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +
      'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,' +
      // ESNext
      'fromString,range'
    ).split(','), j = 0, key; keys$1.length > j; j++) {
      if (has(NativeNumber, key = keys$1[j]) && !has(NumberWrapper, key)) {
        defineProperty$3(NumberWrapper, key, getOwnPropertyDescriptor$3(NativeNumber, key));
      }
    }
    NumberWrapper.prototype = NumberPrototype;
    NumberPrototype.constructor = NumberWrapper;
    redefine(global_1, NUMBER, NumberWrapper);
  }

  var nativeAssign = Object.assign;
  var defineProperty$4 = Object.defineProperty;

  // `Object.assign` method
  // https://tc39.es/ecma262/#sec-object.assign
  var objectAssign = !nativeAssign || fails(function () {
    // should have correct order of operations (Edge bug)
    if (descriptors && nativeAssign({ b: 1 }, nativeAssign(defineProperty$4({}, 'a', {
      enumerable: true,
      get: function () {
        defineProperty$4(this, 'b', {
          value: 3,
          enumerable: false
        });
      }
    }), { b: 2 })).b !== 1) return true;
    // should work with symbols and should have deterministic property order (V8 bug)
    var A = {};
    var B = {};
    // eslint-disable-next-line no-undef
    var symbol = Symbol();
    var alphabet = 'abcdefghijklmnopqrst';
    A[symbol] = 7;
    alphabet.split('').forEach(function (chr) { B[chr] = chr; });
    return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet;
  }) ? function assign(target, source) { // eslint-disable-line no-unused-vars
    var T = toObject(target);
    var argumentsLength = arguments.length;
    var index = 1;
    var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
    var propertyIsEnumerable = objectPropertyIsEnumerable.f;
    while (argumentsLength > index) {
      var S = indexedObject(arguments[index++]);
      var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S);
      var length = keys.length;
      var j = 0;
      var key;
      while (length > j) {
        key = keys[j++];
        if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key];
      }
    } return T;
  } : nativeAssign;

  // `Object.assign` method
  // https://tc39.es/ecma262/#sec-object.assign
  _export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, {
    assign: objectAssign
  });

  var $values = objectToArray.values;

  // `Object.values` method
  // https://tc39.es/ecma262/#sec-object.values
  _export({ target: 'Object', stat: true }, {
    values: function values(O) {
      return $values(O);
    }
  });

  var freezing = !fails(function () {
    return Object.isExtensible(Object.preventExtensions({}));
  });

  var internalMetadata = createCommonjsModule(function (module) {
  var defineProperty = objectDefineProperty.f;



  var METADATA = uid('meta');
  var id = 0;

  var isExtensible = Object.isExtensible || function () {
    return true;
  };

  var setMetadata = function (it) {
    defineProperty(it, METADATA, { value: {
      objectID: 'O' + ++id, // object ID
      weakData: {}          // weak collections IDs
    } });
  };

  var fastKey = function (it, create) {
    // return a primitive with prefix
    if (!isObject(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
    if (!has(it, METADATA)) {
      // can't set metadata to uncaught frozen object
      if (!isExtensible(it)) return 'F';
      // not necessary to add metadata
      if (!create) return 'E';
      // add missing metadata
      setMetadata(it);
    // return object ID
    } return it[METADATA].objectID;
  };

  var getWeakData = function (it, create) {
    if (!has(it, METADATA)) {
      // can't set metadata to uncaught frozen object
      if (!isExtensible(it)) return true;
      // not necessary to add metadata
      if (!create) return false;
      // add missing metadata
      setMetadata(it);
    // return the store of weak collections IDs
    } return it[METADATA].weakData;
  };

  // add metadata on freeze-family methods calling
  var onFreeze = function (it) {
    if (freezing && meta.REQUIRED && isExtensible(it) && !has(it, METADATA)) setMetadata(it);
    return it;
  };

  var meta = module.exports = {
    REQUIRED: false,
    fastKey: fastKey,
    getWeakData: getWeakData,
    onFreeze: onFreeze
  };

  hiddenKeys[METADATA] = true;
  });
  var internalMetadata_1 = internalMetadata.REQUIRED;
  var internalMetadata_2 = internalMetadata.fastKey;
  var internalMetadata_3 = internalMetadata.getWeakData;
  var internalMetadata_4 = internalMetadata.onFreeze;

  var collection = function (CONSTRUCTOR_NAME, wrapper, common) {
    var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
    var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
    var ADDER = IS_MAP ? 'set' : 'add';
    var NativeConstructor = global_1[CONSTRUCTOR_NAME];
    var NativePrototype = NativeConstructor && NativeConstructor.prototype;
    var Constructor = NativeConstructor;
    var exported = {};

    var fixMethod = function (KEY) {
      var nativeMethod = NativePrototype[KEY];
      redefine(NativePrototype, KEY,
        KEY == 'add' ? function add(value) {
          nativeMethod.call(this, value === 0 ? 0 : value);
          return this;
        } : KEY == 'delete' ? function (key) {
          return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
        } : KEY == 'get' ? function get(key) {
          return IS_WEAK && !isObject(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
        } : KEY == 'has' ? function has(key) {
          return IS_WEAK && !isObject(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
        } : function set(key, value) {
          nativeMethod.call(this, key === 0 ? 0 : key, value);
          return this;
        }
      );
    };

    // eslint-disable-next-line max-len
    if (isForced_1(CONSTRUCTOR_NAME, typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails(function () {
      new NativeConstructor().entries().next();
    })))) {
      // create collection constructor
      Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
      internalMetadata.REQUIRED = true;
    } else if (isForced_1(CONSTRUCTOR_NAME, true)) {
      var instance = new Constructor();
      // early implementations not supports chaining
      var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;
      // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
      var THROWS_ON_PRIMITIVES = fails(function () { instance.has(1); });
      // most early implementations doesn't supports iterables, most modern - not close it correctly
      // eslint-disable-next-line no-new
      var ACCEPT_ITERABLES = checkCorrectnessOfIteration(function (iterable) { new NativeConstructor(iterable); });
      // for early implementations -0 and +0 not the same
      var BUGGY_ZERO = !IS_WEAK && fails(function () {
        // V8 ~ Chromium 42- fails only with 5+ elements
        var $instance = new NativeConstructor();
        var index = 5;
        while (index--) $instance[ADDER](index, index);
        return !$instance.has(-0);
      });

      if (!ACCEPT_ITERABLES) {
        Constructor = wrapper(function (dummy, iterable) {
          anInstance(dummy, Constructor, CONSTRUCTOR_NAME);
          var that = inheritIfRequired(new NativeConstructor(), dummy, Constructor);
          if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
          return that;
        });
        Constructor.prototype = NativePrototype;
        NativePrototype.constructor = Constructor;
      }

      if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
        fixMethod('delete');
        fixMethod('has');
        IS_MAP && fixMethod('get');
      }

      if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);

      // weak collections should not contains .clear method
      if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
    }

    exported[CONSTRUCTOR_NAME] = Constructor;
    _export({ global: true, forced: Constructor != NativeConstructor }, exported);

    setToStringTag(Constructor, CONSTRUCTOR_NAME);

    if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);

    return Constructor;
  };

  var defineProperty$5 = objectDefineProperty.f;








  var fastKey = internalMetadata.fastKey;


  var setInternalState$3 = internalState.set;
  var internalStateGetterFor = internalState.getterFor;

  var collectionStrong = {
    getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
      var C = wrapper(function (that, iterable) {
        anInstance(that, C, CONSTRUCTOR_NAME);
        setInternalState$3(that, {
          type: CONSTRUCTOR_NAME,
          index: objectCreate(null),
          first: undefined,
          last: undefined,
          size: 0
        });
        if (!descriptors) that.size = 0;
        if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
      });

      var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);

      var define = function (that, key, value) {
        var state = getInternalState(that);
        var entry = getEntry(that, key);
        var previous, index;
        // change existing entry
        if (entry) {
          entry.value = value;
        // create new entry
        } else {
          state.last = entry = {
            index: index = fastKey(key, true),
            key: key,
            value: value,
            previous: previous = state.last,
            next: undefined,
            removed: false
          };
          if (!state.first) state.first = entry;
          if (previous) previous.next = entry;
          if (descriptors) state.size++;
          else that.size++;
          // add to index
          if (index !== 'F') state.index[index] = entry;
        } return that;
      };

      var getEntry = function (that, key) {
        var state = getInternalState(that);
        // fast case
        var index = fastKey(key);
        var entry;
        if (index !== 'F') return state.index[index];
        // frozen object case
        for (entry = state.first; entry; entry = entry.next) {
          if (entry.key == key) return entry;
        }
      };

      redefineAll(C.prototype, {
        // 23.1.3.1 Map.prototype.clear()
        // 23.2.3.2 Set.prototype.clear()
        clear: function clear() {
          var that = this;
          var state = getInternalState(that);
          var data = state.index;
          var entry = state.first;
          while (entry) {
            entry.removed = true;
            if (entry.previous) entry.previous = entry.previous.next = undefined;
            delete data[entry.index];
            entry = entry.next;
          }
          state.first = state.last = undefined;
          if (descriptors) state.size = 0;
          else that.size = 0;
        },
        // 23.1.3.3 Map.prototype.delete(key)
        // 23.2.3.4 Set.prototype.delete(value)
        'delete': function (key) {
          var that = this;
          var state = getInternalState(that);
          var entry = getEntry(that, key);
          if (entry) {
            var next = entry.next;
            var prev = entry.previous;
            delete state.index[entry.index];
            entry.removed = true;
            if (prev) prev.next = next;
            if (next) next.previous = prev;
            if (state.first == entry) state.first = next;
            if (state.last == entry) state.last = prev;
            if (descriptors) state.size--;
            else that.size--;
          } return !!entry;
        },
        // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
        // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
        forEach: function forEach(callbackfn /* , that = undefined */) {
          var state = getInternalState(this);
          var boundFunction = functionBindContext(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
          var entry;
          while (entry = entry ? entry.next : state.first) {
            boundFunction(entry.value, entry.key, this);
            // revert to the last existing entry
            while (entry && entry.removed) entry = entry.previous;
          }
        },
        // 23.1.3.7 Map.prototype.has(key)
        // 23.2.3.7 Set.prototype.has(value)
        has: function has(key) {
          return !!getEntry(this, key);
        }
      });

      redefineAll(C.prototype, IS_MAP ? {
        // 23.1.3.6 Map.prototype.get(key)
        get: function get(key) {
          var entry = getEntry(this, key);
          return entry && entry.value;
        },
        // 23.1.3.9 Map.prototype.set(key, value)
        set: function set(key, value) {
          return define(this, key === 0 ? 0 : key, value);
        }
      } : {
        // 23.2.3.1 Set.prototype.add(value)
        add: function add(value) {
          return define(this, value = value === 0 ? 0 : value, value);
        }
      });
      if (descriptors) defineProperty$5(C.prototype, 'size', {
        get: function () {
          return getInternalState(this).size;
        }
      });
      return C;
    },
    setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
      var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
      var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
      var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
      // add .keys, .values, .entries, [@@iterator]
      // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11
      defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
        setInternalState$3(this, {
          type: ITERATOR_NAME,
          target: iterated,
          state: getInternalCollectionState(iterated),
          kind: kind,
          last: undefined
        });
      }, function () {
        var state = getInternalIteratorState(this);
        var kind = state.kind;
        var entry = state.last;
        // revert to the last existing entry
        while (entry && entry.removed) entry = entry.previous;
        // get next entry
        if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
          // or finish the iteration
          state.target = undefined;
          return { value: undefined, done: true };
        }
        // return step by kind
        if (kind == 'keys') return { value: entry.key, done: false };
        if (kind == 'values') return { value: entry.value, done: false };
        return { value: [entry.key, entry.value], done: false };
      }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);

      // add [@@species], 23.1.2.2, 23.2.2.2
      setSpecies(CONSTRUCTOR_NAME);
    }
  };

  // `Set` constructor
  // https://tc39.es/ecma262/#sec-set-objects
  var es_set = collection('Set', function (init) {
    return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };
  }, collectionStrong);

  // @@match logic
  fixRegexpWellKnownSymbolLogic('match', 1, function (MATCH, nativeMatch, maybeCallNative) {
    return [
      // `String.prototype.match` method
      // https://tc39.es/ecma262/#sec-string.prototype.match
      function match(regexp) {
        var O = requireObjectCoercible(this);
        var matcher = regexp == undefined ? undefined : regexp[MATCH];
        return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
      },
      // `RegExp.prototype[@@match]` method
      // https://tc39.es/ecma262/#sec-regexp.prototype-@@match
      function (regexp) {
        var res = maybeCallNative(nativeMatch, regexp, this);
        if (res.done) return res.value;

        var rx = anObject(regexp);
        var S = String(this);

        if (!rx.global) return regexpExecAbstract(rx, S);

        var fullUnicode = rx.unicode;
        rx.lastIndex = 0;
        var A = [];
        var n = 0;
        var result;
        while ((result = regexpExecAbstract(rx, S)) !== null) {
          var matchStr = String(result[0]);
          A[n] = matchStr;
          if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
          n++;
        }
        return n === 0 ? null : A;
      }
    ];
  });

  var floor$1 = Math.floor;
  var replace = ''.replace;
  var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d\d?|<[^>]*>)/g;
  var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d\d?)/g;

  // https://tc39.es/ecma262/#sec-getsubstitution
  var getSubstitution = function (matched, str, position, captures, namedCaptures, replacement) {
    var tailPos = position + matched.length;
    var m = captures.length;
    var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
    if (namedCaptures !== undefined) {
      namedCaptures = toObject(namedCaptures);
      symbols = SUBSTITUTION_SYMBOLS;
    }
    return replace.call(replacement, symbols, function (match, ch) {
      var capture;
      switch (ch.charAt(0)) {
        case '$': return '$';
        case '&': return matched;
        case '`': return str.slice(0, position);
        case "'": return str.slice(tailPos);
        case '<':
          capture = namedCaptures[ch.slice(1, -1)];
          break;
        default: // \d\d?
          var n = +ch;
          if (n === 0) return match;
          if (n > m) {
            var f = floor$1(n / 10);
            if (f === 0) return match;
            if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
            return match;
          }
          capture = captures[n - 1];
      }
      return capture === undefined ? '' : capture;
    });
  };

  var max$1 = Math.max;
  var min$3 = Math.min;

  var maybeToString = function (it) {
    return it === undefined ? it : String(it);
  };

  // @@replace logic
  fixRegexpWellKnownSymbolLogic('replace', 2, function (REPLACE, nativeReplace, maybeCallNative, reason) {
    var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = reason.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE;
    var REPLACE_KEEPS_$0 = reason.REPLACE_KEEPS_$0;
    var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';

    return [
      // `String.prototype.replace` method
      // https://tc39.es/ecma262/#sec-string.prototype.replace
      function replace(searchValue, replaceValue) {
        var O = requireObjectCoercible(this);
        var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
        return replacer !== undefined
          ? replacer.call(searchValue, O, replaceValue)
          : nativeReplace.call(String(O), searchValue, replaceValue);
      },
      // `RegExp.prototype[@@replace]` method
      // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
      function (regexp, replaceValue) {
        if (
          (!REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE && REPLACE_KEEPS_$0) ||
          (typeof replaceValue === 'string' && replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1)
        ) {
          var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
          if (res.done) return res.value;
        }

        var rx = anObject(regexp);
        var S = String(this);

        var functionalReplace = typeof replaceValue === 'function';
        if (!functionalReplace) replaceValue = String(replaceValue);

        var global = rx.global;
        if (global) {
          var fullUnicode = rx.unicode;
          rx.lastIndex = 0;
        }
        var results = [];
        while (true) {
          var result = regexpExecAbstract(rx, S);
          if (result === null) break;

          results.push(result);
          if (!global) break;

          var matchStr = String(result[0]);
          if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
        }

        var accumulatedResult = '';
        var nextSourcePosition = 0;
        for (var i = 0; i < results.length; i++) {
          result = results[i];

          var matched = String(result[0]);
          var position = max$1(min$3(toInteger(result.index), S.length), 0);
          var captures = [];
          // NOTE: This is equivalent to
          //   captures = result.slice(1).map(maybeToString)
          // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
          // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
          // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
          for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
          var namedCaptures = result.groups;
          if (functionalReplace) {
            var replacerArgs = [matched].concat(captures, position, S);
            if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
            var replacement = String(replaceValue.apply(undefined, replacerArgs));
          } else {
            replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
          }
          if (position >= nextSourcePosition) {
            accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
            nextSourcePosition = position + matched.length;
          }
        }
        return accumulatedResult + S.slice(nextSourcePosition);
      }
    ];
  });

  var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;






  var nativeStartsWith = ''.startsWith;
  var min$4 = Math.min;

  var CORRECT_IS_REGEXP_LOGIC = correctIsRegexpLogic('startsWith');
  // https://github.com/zloirock/core-js/pull/702
  var MDN_POLYFILL_BUG =  !CORRECT_IS_REGEXP_LOGIC && !!function () {
    var descriptor = getOwnPropertyDescriptor$4(String.prototype, 'startsWith');
    return descriptor && !descriptor.writable;
  }();

  // `String.prototype.startsWith` method
  // https://tc39.es/ecma262/#sec-string.prototype.startswith
  _export({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
    startsWith: function startsWith(searchString /* , position = 0 */) {
      var that = String(requireObjectCoercible(this));
      notARegexp(searchString);
      var index = toLength(min$4(arguments.length > 1 ? arguments[1] : undefined, that.length));
      var search = String(searchString);
      return nativeStartsWith
        ? nativeStartsWith.call(that, search, index)
        : that.slice(index, index + search.length) === search;
    }
  });

  var non = '\u200B\u0085\u180E';

  // check that a method works with the correct list
  // of whitespaces and has a correct name
  var stringTrimForced = function (METHOD_NAME) {
    return fails(function () {
      return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
    });
  };

  var $trim = stringTrim.trim;


  // `String.prototype.trim` method
  // https://tc39.es/ecma262/#sec-string.prototype.trim
  _export({ target: 'String', proto: true, forced: stringTrimForced('trim') }, {
    trim: function trim() {
      return $trim(this);
    }
  });

  var ITERATOR$5 = wellKnownSymbol('iterator');
  var TO_STRING_TAG$3 = wellKnownSymbol('toStringTag');
  var ArrayValues = es_array_iterator.values;

  for (var COLLECTION_NAME$1 in domIterables) {
    var Collection$1 = global_1[COLLECTION_NAME$1];
    var CollectionPrototype$1 = Collection$1 && Collection$1.prototype;
    if (CollectionPrototype$1) {
      // some Chrome versions have non-configurable methods on DOMTokenList
      if (CollectionPrototype$1[ITERATOR$5] !== ArrayValues) try {
        createNonEnumerableProperty(CollectionPrototype$1, ITERATOR$5, ArrayValues);
      } catch (error) {
        CollectionPrototype$1[ITERATOR$5] = ArrayValues;
      }
      if (!CollectionPrototype$1[TO_STRING_TAG$3]) {
        createNonEnumerableProperty(CollectionPrototype$1, TO_STRING_TAG$3, COLLECTION_NAME$1);
      }
      if (domIterables[COLLECTION_NAME$1]) for (var METHOD_NAME in es_array_iterator) {
        // some Chrome versions have non-configurable methods on DOMTokenList
        if (CollectionPrototype$1[METHOD_NAME] !== es_array_iterator[METHOD_NAME]) try {
          createNonEnumerableProperty(CollectionPrototype$1, METHOD_NAME, es_array_iterator[METHOD_NAME]);
        } catch (error) {
          CollectionPrototype$1[METHOD_NAME] = es_array_iterator[METHOD_NAME];
        }
      }
    }
  }

  var _this3 = undefined;

  // Thanks @stimulus:
  // https://github.com/stimulusjs/stimulus/blob/master/packages/%40stimulus/core/src/application.ts
  function domReady() {
    var _this = this;

    return new Promise(function (resolve) {
      _newArrowCheck(this, _this);

      if (document.readyState == "loading") {
        document.addEventListener("DOMContentLoaded", resolve);
      } else {
        resolve();
      }
    }.bind(this));
  }
  function arrayUnique(array) {
    return Array.from(new Set(array));
  }
  function isTesting() {
    return navigator.userAgent.includes("Node.js") || navigator.userAgent.includes("jsdom");
  }
  function checkedAttrLooseCompare(valueA, valueB) {
    return valueA == valueB;
  }
  function warnIfMalformedTemplate(el, directive) {
    if (el.tagName.toLowerCase() !== 'template') {
      console.warn("Alpine: [".concat(directive, "] directive should only be added to <template> tags. See https://github.com/alpinejs/alpine#").concat(directive));
    } else if (el.content.childElementCount !== 1) {
      console.warn("Alpine: <template> tag with [".concat(directive, "] encountered with an unexpected number of root elements. Make sure <template> has a single root element. "));
    }
  }
  function kebabCase(subject) {
    return subject.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/[_\s]/, '-').toLowerCase();
  }
  function camelCase(subject) {
    var _this2 = this;

    return subject.toLowerCase().replace(/-(\w)/g, function (match, _char) {
      _newArrowCheck(this, _this2);

      return _char.toUpperCase();
    }.bind(this));
  }
  function walk(el, callback) {
    if (callback(el) === false) return;
    var node = el.firstElementChild;

    while (node) {
      walk(node, callback);
      node = node.nextElementSibling;
    }
  }
  function debounce(func, wait) {
    var timeout;
    return function () {
      var context = this,
          args = arguments;

      var later = function later() {
        timeout = null;
        func.apply(context, args);
      };

      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  var handleError = function handleError(el, expression, error) {
    _newArrowCheck(this, _this3);

    console.warn("Alpine Error: \"".concat(error, "\"\n\nExpression: \"").concat(expression, "\"\nElement:"), el);

    if (!isTesting()) {
      Object.assign(error, {
        el: el,
        expression: expression
      });
      throw error;
    }
  }.bind(undefined);

  function tryCatch(cb, _ref) {
    var _this4 = this;

    var el = _ref.el,
        expression = _ref.expression;

    try {
      var value = cb();
      return value instanceof Promise ? value["catch"](function (e) {
        _newArrowCheck(this, _this4);

        return handleError(el, expression, e);
      }.bind(this)) : value;
    } catch (e) {
      handleError(el, expression, e);
    }
  }

  function saferEval(el, expression, dataContext) {
    var _this5 = this;

    var additionalHelperVariables = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    return tryCatch(function () {
      _newArrowCheck(this, _this5);

      if (typeof expression === 'function') {
        return expression.call(dataContext);
      }

      return new Function(['$data'].concat(_toConsumableArray(Object.keys(additionalHelperVariables))), "var __alpine_result; with($data) { __alpine_result = ".concat(expression, " }; return __alpine_result")).apply(void 0, [dataContext].concat(_toConsumableArray(Object.values(additionalHelperVariables))));
    }.bind(this), {
      el: el,
      expression: expression
    });
  }
  function saferEvalNoReturn(el, expression, dataContext) {
    var _this6 = this;

    var additionalHelperVariables = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    return tryCatch(function () {
      _newArrowCheck(this, _this6);

      if (typeof expression === 'function') {
        return Promise.resolve(expression.call(dataContext, additionalHelperVariables['$event']));
      }

      var AsyncFunction = Function; // For the cases when users pass only a function reference to the caller: `x-on:click="foo"`
      // Where "foo" is a function. Also, we'll pass the function the event instance when we call it.

      if (Object.keys(dataContext).includes(expression)) {
        var methodReference = new Function(['dataContext'].concat(_toConsumableArray(Object.keys(additionalHelperVariables))), "with(dataContext) { return ".concat(expression, " }")).apply(void 0, [dataContext].concat(_toConsumableArray(Object.values(additionalHelperVariables))));

        if (typeof methodReference === 'function') {
          return Promise.resolve(methodReference.call(dataContext, additionalHelperVariables['$event']));
        } else {
          return Promise.resolve();
        }
      }

      return Promise.resolve(new AsyncFunction(['dataContext'].concat(_toConsumableArray(Object.keys(additionalHelperVariables))), "with(dataContext) { ".concat(expression, " }")).apply(void 0, [dataContext].concat(_toConsumableArray(Object.values(additionalHelperVariables)))));
    }.bind(this), {
      el: el,
      expression: expression
    });
  }
  var xAttrRE = /^x-(on|bind|data|text|html|model|if|for|show|cloak|transition|ref|spread)\b/;
  function isXAttr(attr) {
    var name = replaceAtAndColonWithStandardSyntax(attr.name);
    return xAttrRE.test(name);
  }
  function getXAttrs(el, component, type) {
    var _this7 = this;

    var directives = Array.from(el.attributes).filter(isXAttr).map(parseHtmlAttribute); // Get an object of directives from x-spread.

    var spreadDirective = directives.filter(function (directive) {
      _newArrowCheck(this, _this7);

      return directive.type === 'spread';
    }.bind(this))[0];

    if (spreadDirective) {
      var spreadObject = saferEval(el, spreadDirective.expression, component.$data); // Add x-spread directives to the pile of existing directives.

      directives = directives.concat(Object.entries(spreadObject).map(function (_ref2) {
        _newArrowCheck(this, _this7);

        var _ref3 = _slicedToArray(_ref2, 2),
            name = _ref3[0],
            value = _ref3[1];

        return parseHtmlAttribute({
          name: name,
          value: value
        });
      }.bind(this)));
    }

    if (type) return directives.filter(function (i) {
      _newArrowCheck(this, _this7);

      return i.type === type;
    }.bind(this));
    return sortDirectives(directives);
  }

  function sortDirectives(directives) {
    var _this8 = this;

    var directiveOrder = ['bind', 'model', 'show', 'catch-all'];
    return directives.sort(function (a, b) {
      _newArrowCheck(this, _this8);

      var typeA = directiveOrder.indexOf(a.type) === -1 ? 'catch-all' : a.type;
      var typeB = directiveOrder.indexOf(b.type) === -1 ? 'catch-all' : b.type;
      return directiveOrder.indexOf(typeA) - directiveOrder.indexOf(typeB);
    }.bind(this));
  }

  function parseHtmlAttribute(_ref4) {
    var _this9 = this;

    var name = _ref4.name,
        value = _ref4.value;
    var normalizedName = replaceAtAndColonWithStandardSyntax(name);
    var typeMatch = normalizedName.match(xAttrRE);
    var valueMatch = normalizedName.match(/:([a-zA-Z0-9\-:]+)/);
    var modifiers = normalizedName.match(/\.[^.\]]+(?=[^\]]*$)/g) || [];
    return {
      type: typeMatch ? typeMatch[1] : null,
      value: valueMatch ? valueMatch[1] : null,
      modifiers: modifiers.map(function (i) {
        _newArrowCheck(this, _this9);

        return i.replace('.', '');
      }.bind(this)),
      expression: value
    };
  }
  function isBooleanAttr(attrName) {
    // As per HTML spec table https://html.spec.whatwg.org/multipage/indices.html#attributes-3:boolean-attribute
    // Array roughly ordered by estimated usage
    var booleanAttributes = ['disabled', 'checked', 'required', 'readonly', 'hidden', 'open', 'selected', 'autofocus', 'itemscope', 'multiple', 'novalidate', 'allowfullscreen', 'allowpaymentrequest', 'formnovalidate', 'autoplay', 'controls', 'loop', 'muted', 'playsinline', 'default', 'ismap', 'reversed', 'async', 'defer', 'nomodule'];
    return booleanAttributes.includes(attrName);
  }
  function replaceAtAndColonWithStandardSyntax(name) {
    if (name.startsWith('@')) {
      return name.replace('@', 'x-on:');
    } else if (name.startsWith(':')) {
      return name.replace(':', 'x-bind:');
    }

    return name;
  }
  function convertClassStringToArray(classList) {
    var filterFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Boolean;
    return classList.split(' ').filter(filterFn);
  }
  var TRANSITION_TYPE_IN = 'in';
  var TRANSITION_TYPE_OUT = 'out';
  var TRANSITION_CANCELLED = 'cancelled';
  function transitionIn(el, show, reject, component) {
    var _this10 = this;

    var forceSkip = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
    // We don't want to transition on the initial page load.
    if (forceSkip) return show();

    if (el.__x_transition && el.__x_transition.type === TRANSITION_TYPE_IN) {
      // there is already a similar transition going on, this was probably triggered by
      // a change in a different property, let's just leave the previous one doing its job
      return;
    }

    var attrs = getXAttrs(el, component, 'transition');
    var showAttr = getXAttrs(el, component, 'show')[0]; // If this is triggered by a x-show.transition.

    if (showAttr && showAttr.modifiers.includes('transition')) {
      var modifiers = showAttr.modifiers; // If x-show.transition.out, we'll skip the "in" transition.

      if (modifiers.includes('out') && !modifiers.includes('in')) return show();
      var settingBothSidesOfTransition = modifiers.includes('in') && modifiers.includes('out'); // If x-show.transition.in...out... only use "in" related modifiers for this transition.

      modifiers = settingBothSidesOfTransition ? modifiers.filter(function (i, index) {
        _newArrowCheck(this, _this10);

        return index < modifiers.indexOf('out');
      }.bind(this)) : modifiers;
      transitionHelperIn(el, modifiers, show, reject); // Otherwise, we can assume x-transition:enter.
    } else if (attrs.some(function (attr) {
      _newArrowCheck(this, _this10);

      return ['enter', 'enter-start', 'enter-end'].includes(attr.value);
    }.bind(this))) {
      transitionClassesIn(el, component, attrs, show, reject);
    } else {
      // If neither, just show that damn thing.
      show();
    }
  }
  function transitionOut(el, hide, reject, component) {
    var _this11 = this;

    var forceSkip = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
    // We don't want to transition on the initial page load.
    if (forceSkip) return hide();

    if (el.__x_transition && el.__x_transition.type === TRANSITION_TYPE_OUT) {
      // there is already a similar transition going on, this was probably triggered by
      // a change in a different property, let's just leave the previous one doing its job
      return;
    }

    var attrs = getXAttrs(el, component, 'transition');
    var showAttr = getXAttrs(el, component, 'show')[0];

    if (showAttr && showAttr.modifiers.includes('transition')) {
      var modifiers = showAttr.modifiers;
      if (modifiers.includes('in') && !modifiers.includes('out')) return hide();
      var settingBothSidesOfTransition = modifiers.includes('in') && modifiers.includes('out');
      modifiers = settingBothSidesOfTransition ? modifiers.filter(function (i, index) {
        _newArrowCheck(this, _this11);

        return index > modifiers.indexOf('out');
      }.bind(this)) : modifiers;
      transitionHelperOut(el, modifiers, settingBothSidesOfTransition, hide, reject);
    } else if (attrs.some(function (attr) {
      _newArrowCheck(this, _this11);

      return ['leave', 'leave-start', 'leave-end'].includes(attr.value);
    }.bind(this))) {
      transitionClassesOut(el, component, attrs, hide, reject);
    } else {
      hide();
    }
  }
  function transitionHelperIn(el, modifiers, showCallback, reject) {
    var _this12 = this;

    // Default values inspired by: https://material.io/design/motion/speed.html#duration
    var styleValues = {
      duration: modifierValue(modifiers, 'duration', 150),
      origin: modifierValue(modifiers, 'origin', 'center'),
      first: {
        opacity: 0,
        scale: modifierValue(modifiers, 'scale', 95)
      },
      second: {
        opacity: 1,
        scale: 100
      }
    };
    transitionHelper(el, modifiers, showCallback, function () {
      _newArrowCheck(this, _this12);
    }.bind(this), reject, styleValues, TRANSITION_TYPE_IN);
  }
  function transitionHelperOut(el, modifiers, settingBothSidesOfTransition, hideCallback, reject) {
    var _this13 = this;

    // Make the "out" transition .5x slower than the "in". (Visually better)
    // HOWEVER, if they explicitly set a duration for the "out" transition,
    // use that.
    var duration = settingBothSidesOfTransition ? modifierValue(modifiers, 'duration', 150) : modifierValue(modifiers, 'duration', 150) / 2;
    var styleValues = {
      duration: duration,
      origin: modifierValue(modifiers, 'origin', 'center'),
      first: {
        opacity: 1,
        scale: 100
      },
      second: {
        opacity: 0,
        scale: modifierValue(modifiers, 'scale', 95)
      }
    };
    transitionHelper(el, modifiers, function () {
      _newArrowCheck(this, _this13);
    }.bind(this), hideCallback, reject, styleValues, TRANSITION_TYPE_OUT);
  }

  function modifierValue(modifiers, key, fallback) {
    // If the modifier isn't present, use the default.
    if (modifiers.indexOf(key) === -1) return fallback; // If it IS present, grab the value after it: x-show.transition.duration.500ms

    var rawValue = modifiers[modifiers.indexOf(key) + 1];
    if (!rawValue) return fallback;

    if (key === 'scale') {
      // Check if the very next value is NOT a number and return the fallback.
      // If x-show.transition.scale, we'll use the default scale value.
      // That is how a user opts out of the opacity transition.
      if (!isNumeric(rawValue)) return fallback;
    }

    if (key === 'duration') {
      // Support x-show.transition.duration.500ms && duration.500
      var match = rawValue.match(/([0-9]+)ms/);
      if (match) return match[1];
    }

    if (key === 'origin') {
      // Support chaining origin directions: x-show.transition.top.right
      if (['top', 'right', 'left', 'center', 'bottom'].includes(modifiers[modifiers.indexOf(key) + 2])) {
        return [rawValue, modifiers[modifiers.indexOf(key) + 2]].join(' ');
      }
    }

    return rawValue;
  }

  function transitionHelper(el, modifiers, hook1, hook2, reject, styleValues, type) {
    // clear the previous transition if exists to avoid caching the wrong styles
    if (el.__x_transition) {
      el.__x_transition.cancel && el.__x_transition.cancel();
    } // If the user set these style values, we'll put them back when we're done with them.


    var opacityCache = el.style.opacity;
    var transformCache = el.style.transform;
    var transformOriginCache = el.style.transformOrigin; // If no modifiers are present: x-show.transition, we'll default to both opacity and scale.

    var noModifiers = !modifiers.includes('opacity') && !modifiers.includes('scale');
    var transitionOpacity = noModifiers || modifiers.includes('opacity');
    var transitionScale = noModifiers || modifiers.includes('scale'); // These are the explicit stages of a transition (same stages for in and for out).
    // This way you can get a birds eye view of the hooks, and the differences
    // between them.

    var stages = {
      start: function start() {
        if (transitionOpacity) el.style.opacity = styleValues.first.opacity;
        if (transitionScale) el.style.transform = "scale(".concat(styleValues.first.scale / 100, ")");
      },
      during: function during() {
        if (transitionScale) el.style.transformOrigin = styleValues.origin;
        el.style.transitionProperty = [transitionOpacity ? "opacity" : "", transitionScale ? "transform" : ""].join(' ').trim();
        el.style.transitionDuration = "".concat(styleValues.duration / 1000, "s");
        el.style.transitionTimingFunction = "cubic-bezier(0.4, 0.0, 0.2, 1)";
      },
      show: function show() {
        hook1();
      },
      end: function end() {
        if (transitionOpacity) el.style.opacity = styleValues.second.opacity;
        if (transitionScale) el.style.transform = "scale(".concat(styleValues.second.scale / 100, ")");
      },
      hide: function hide() {
        hook2();
      },
      cleanup: function cleanup() {
        if (transitionOpacity) el.style.opacity = opacityCache;
        if (transitionScale) el.style.transform = transformCache;
        if (transitionScale) el.style.transformOrigin = transformOriginCache;
        el.style.transitionProperty = null;
        el.style.transitionDuration = null;
        el.style.transitionTimingFunction = null;
      }
    };
    transition(el, stages, type, reject);
  }

  var ensureStringExpression = function ensureStringExpression(expression, el, component) {
    _newArrowCheck(this, _this3);

    return typeof expression === 'function' ? component.evaluateReturnExpression(el, expression) : expression;
  }.bind(undefined);

  function transitionClassesIn(el, component, directives, showCallback, reject) {
    var _this14 = this;

    var enter = convertClassStringToArray(ensureStringExpression((directives.find(function (i) {
      _newArrowCheck(this, _this14);

      return i.value === 'enter';
    }.bind(this)) || {
      expression: ''
    }).expression, el, component));
    var enterStart = convertClassStringToArray(ensureStringExpression((directives.find(function (i) {
      _newArrowCheck(this, _this14);

      return i.value === 'enter-start';
    }.bind(this)) || {
      expression: ''
    }).expression, el, component));
    var enterEnd = convertClassStringToArray(ensureStringExpression((directives.find(function (i) {
      _newArrowCheck(this, _this14);

      return i.value === 'enter-end';
    }.bind(this)) || {
      expression: ''
    }).expression, el, component));
    transitionClasses(el, enter, enterStart, enterEnd, showCallback, function () {
      _newArrowCheck(this, _this14);
    }.bind(this), TRANSITION_TYPE_IN, reject);
  }
  function transitionClassesOut(el, component, directives, hideCallback, reject) {
    var _this15 = this;

    var leave = convertClassStringToArray(ensureStringExpression((directives.find(function (i) {
      _newArrowCheck(this, _this15);

      return i.value === 'leave';
    }.bind(this)) || {
      expression: ''
    }).expression, el, component));
    var leaveStart = convertClassStringToArray(ensureStringExpression((directives.find(function (i) {
      _newArrowCheck(this, _this15);

      return i.value === 'leave-start';
    }.bind(this)) || {
      expression: ''
    }).expression, el, component));
    var leaveEnd = convertClassStringToArray(ensureStringExpression((directives.find(function (i) {
      _newArrowCheck(this, _this15);

      return i.value === 'leave-end';
    }.bind(this)) || {
      expression: ''
    }).expression, el, component));
    transitionClasses(el, leave, leaveStart, leaveEnd, function () {
      _newArrowCheck(this, _this15);
    }.bind(this), hideCallback, TRANSITION_TYPE_OUT, reject);
  }
  function transitionClasses(el, classesDuring, classesStart, classesEnd, hook1, hook2, type, reject) {
    // clear the previous transition if exists to avoid caching the wrong classes
    if (el.__x_transition) {
      el.__x_transition.cancel && el.__x_transition.cancel();
    }

    var originalClasses = el.__x_original_classes || [];
    var stages = {
      start: function start() {
        var _el$classList;

        (_el$classList = el.classList).add.apply(_el$classList, _toConsumableArray(classesStart));
      },
      during: function during() {
        var _el$classList2;

        (_el$classList2 = el.classList).add.apply(_el$classList2, _toConsumableArray(classesDuring));
      },
      show: function show() {
        hook1();
      },
      end: function end() {
        var _el$classList3,
            _this16 = this,
            _el$classList4;

        // Don't remove classes that were in the original class attribute.
        (_el$classList3 = el.classList).remove.apply(_el$classList3, _toConsumableArray(classesStart.filter(function (i) {
          _newArrowCheck(this, _this16);

          return !originalClasses.includes(i);
        }.bind(this))));

        (_el$classList4 = el.classList).add.apply(_el$classList4, _toConsumableArray(classesEnd));
      },
      hide: function hide() {
        hook2();
      },
      cleanup: function cleanup() {
        var _el$classList5,
            _this17 = this,
            _el$classList6;

        (_el$classList5 = el.classList).remove.apply(_el$classList5, _toConsumableArray(classesDuring.filter(function (i) {
          _newArrowCheck(this, _this17);

          return !originalClasses.includes(i);
        }.bind(this))));

        (_el$classList6 = el.classList).remove.apply(_el$classList6, _toConsumableArray(classesEnd.filter(function (i) {
          _newArrowCheck(this, _this17);

          return !originalClasses.includes(i);
        }.bind(this))));
      }
    };
    transition(el, stages, type, reject);
  }
  function transition(el, stages, type, reject) {
    var _this18 = this;

    var finish = once(function () {
      _newArrowCheck(this, _this18);

      stages.hide(); // Adding an "isConnected" check, in case the callback
      // removed the element from the DOM.

      if (el.isConnected) {
        stages.cleanup();
      }

      delete el.__x_transition;
    }.bind(this));
    el.__x_transition = {
      // Set transition type so we can avoid clearing transition if the direction is the same
      type: type,
      // create a callback for the last stages of the transition so we can call it
      // from different point and early terminate it. Once will ensure that function
      // is only called one time.
      cancel: once(function () {
        _newArrowCheck(this, _this18);

        reject(TRANSITION_CANCELLED);
        finish();
      }.bind(this)),
      finish: finish,
      // This store the next animation frame so we can cancel it
      nextFrame: null
    };
    stages.start();
    stages.during();
    el.__x_transition.nextFrame = requestAnimationFrame(function () {
      var _this19 = this;

      _newArrowCheck(this, _this18);

      // Note: Safari's transitionDuration property will list out comma separated transition durations
      // for every single transition property. Let's grab the first one and call it a day.
      var duration = Number(getComputedStyle(el).transitionDuration.replace(/,.*/, '').replace('s', '')) * 1000;

      if (duration === 0) {
        duration = Number(getComputedStyle(el).animationDuration.replace('s', '')) * 1000;
      }

      stages.show();
      el.__x_transition.nextFrame = requestAnimationFrame(function () {
        _newArrowCheck(this, _this19);

        stages.end();
        setTimeout(el.__x_transition.finish, duration);
      }.bind(this));
    }.bind(this));
  }
  function isNumeric(subject) {
    return !Array.isArray(subject) && !isNaN(subject);
  } // Thanks @vuejs
  // https://github.com/vuejs/vue/blob/4de4649d9637262a9b007720b59f80ac72a5620c/src/shared/util.js

  function once(callback) {
    var called = false;
    return function () {
      if (!called) {
        called = true;
        callback.apply(this, arguments);
      }
    };
  }

  function handleForDirective(component, templateEl, expression, initialUpdate, extraVars) {
    var _this = this;

    warnIfMalformedTemplate(templateEl, 'x-for');
    var iteratorNames = typeof expression === 'function' ? parseForExpression(component.evaluateReturnExpression(templateEl, expression)) : parseForExpression(expression);
    var items = evaluateItemsAndReturnEmptyIfXIfIsPresentAndFalseOnElement(component, templateEl, iteratorNames, extraVars); // As we walk the array, we'll also walk the DOM (updating/creating as we go).

    var currentEl = templateEl;
    items.forEach(function (item, index) {
      var _this2 = this;

      _newArrowCheck(this, _this);

      var iterationScopeVariables = getIterationScopeVariables(iteratorNames, item, index, items, extraVars());
      var currentKey = generateKeyForIteration(component, templateEl, index, iterationScopeVariables);
      var nextEl = lookAheadForMatchingKeyedElementAndMoveItIfFound(currentEl.nextElementSibling, currentKey); // If we haven't found a matching key, insert the element at the current position.

      if (!nextEl) {
        nextEl = addElementInLoopAfterCurrentEl(templateEl, currentEl); // And transition it in if it's not the first page load.

        transitionIn(nextEl, function () {
          _newArrowCheck(this, _this2);
        }.bind(this), function () {
          _newArrowCheck(this, _this2);
        }.bind(this), component, initialUpdate);
        nextEl.__x_for = iterationScopeVariables;
        component.initializeElements(nextEl, function () {
          _newArrowCheck(this, _this2);

          return nextEl.__x_for;
        }.bind(this)); // Otherwise update the element we found.
      } else {
        // Temporarily remove the key indicator to allow the normal "updateElements" to work.
        delete nextEl.__x_for_key;
        nextEl.__x_for = iterationScopeVariables;
        component.updateElements(nextEl, function () {
          _newArrowCheck(this, _this2);

          return nextEl.__x_for;
        }.bind(this));
      }

      currentEl = nextEl;
      currentEl.__x_for_key = currentKey;
    }.bind(this));
    removeAnyLeftOverElementsFromPreviousUpdate(currentEl, component);
  } // This was taken from VueJS 2.* core. Thanks Vue!

  function parseForExpression(expression) {
    var forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;
    var stripParensRE = /^\(|\)$/g;
    var forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;
    var inMatch = String(expression).match(forAliasRE);
    if (!inMatch) return;
    var res = {};
    res.items = inMatch[2].trim();
    var item = inMatch[1].trim().replace(stripParensRE, '');
    var iteratorMatch = item.match(forIteratorRE);

    if (iteratorMatch) {
      res.item = item.replace(forIteratorRE, '').trim();
      res.index = iteratorMatch[1].trim();

      if (iteratorMatch[2]) {
        res.collection = iteratorMatch[2].trim();
      }
    } else {
      res.item = item;
    }

    return res;
  }

  function getIterationScopeVariables(iteratorNames, item, index, items, extraVars) {
    // We must create a new object, so each iteration has a new scope
    var scopeVariables = extraVars ? _objectSpread2({}, extraVars) : {};
    scopeVariables[iteratorNames.item] = item;
    if (iteratorNames.index) scopeVariables[iteratorNames.index] = index;
    if (iteratorNames.collection) scopeVariables[iteratorNames.collection] = items;
    return scopeVariables;
  }

  function generateKeyForIteration(component, el, index, iterationScopeVariables) {
    var _this3 = this;

    var bindKeyAttribute = getXAttrs(el, component, 'bind').filter(function (attr) {
      _newArrowCheck(this, _this3);

      return attr.value === 'key';
    }.bind(this))[0]; // If the dev hasn't specified a key, just return the index of the iteration.

    if (!bindKeyAttribute) return index;
    return component.evaluateReturnExpression(el, bindKeyAttribute.expression, function () {
      _newArrowCheck(this, _this3);

      return iterationScopeVariables;
    }.bind(this));
  }

  function evaluateItemsAndReturnEmptyIfXIfIsPresentAndFalseOnElement(component, el, iteratorNames, extraVars) {
    var _this4 = this;

    var ifAttribute = getXAttrs(el, component, 'if')[0];

    if (ifAttribute && !component.evaluateReturnExpression(el, ifAttribute.expression)) {
      return [];
    }

    var items = component.evaluateReturnExpression(el, iteratorNames.items, extraVars); // This adds support for the `i in n` syntax.

    if (isNumeric(items) && items >= 0) {
      items = Array.from(Array(items).keys(), function (i) {
        _newArrowCheck(this, _this4);

        return i + 1;
      }.bind(this));
    }

    return items;
  }

  function addElementInLoopAfterCurrentEl(templateEl, currentEl) {
    var clone = document.importNode(templateEl.content, true);
    currentEl.parentElement.insertBefore(clone, currentEl.nextElementSibling);
    return currentEl.nextElementSibling;
  }

  function lookAheadForMatchingKeyedElementAndMoveItIfFound(nextEl, currentKey) {
    if (!nextEl) return; // If we are already past the x-for generated elements, we don't need to look ahead.

    if (nextEl.__x_for_key === undefined) return; // If the the key's DO match, no need to look ahead.

    if (nextEl.__x_for_key === currentKey) return nextEl; // If they don't, we'll look ahead for a match.
    // If we find it, we'll move it to the current position in the loop.

    var tmpNextEl = nextEl;

    while (tmpNextEl) {
      if (tmpNextEl.__x_for_key === currentKey) {
        return tmpNextEl.parentElement.insertBefore(tmpNextEl, nextEl);
      }

      tmpNextEl = tmpNextEl.nextElementSibling && tmpNextEl.nextElementSibling.__x_for_key !== undefined ? tmpNextEl.nextElementSibling : false;
    }
  }

  function removeAnyLeftOverElementsFromPreviousUpdate(currentEl, component) {
    var nextElementFromOldLoop = currentEl.nextElementSibling && currentEl.nextElementSibling.__x_for_key !== undefined ? currentEl.nextElementSibling : false;

    var _loop = function _loop() {
      var _this5 = this;

      var nextElementFromOldLoopImmutable = nextElementFromOldLoop;
      var nextSibling = nextElementFromOldLoop.nextElementSibling;
      transitionOut(nextElementFromOldLoop, function () {
        _newArrowCheck(this, _this5);

        nextElementFromOldLoopImmutable.remove();
      }.bind(this), function () {
        _newArrowCheck(this, _this5);
      }.bind(this), component);
      nextElementFromOldLoop = nextSibling && nextSibling.__x_for_key !== undefined ? nextSibling : false;
    };

    while (nextElementFromOldLoop) {
      _loop();
    }
  }

  function handleAttributeBindingDirective(component, el, attrName, expression, extraVars, attrType, modifiers) {
    var _this = this;

    var value = component.evaluateReturnExpression(el, expression, extraVars);

    if (attrName === 'value') {
      if (Alpine.ignoreFocusedForValueBinding && document.activeElement.isSameNode(el)) return; // If nested model key is undefined, set the default value to empty string.

      if (value === undefined && String(expression).match(/\./)) {
        value = '';
      }

      if (el.type === 'radio') {
        // Set radio value from x-bind:value, if no "value" attribute exists.
        // If there are any initial state values, radio will have a correct
        // "checked" value since x-bind:value is processed before x-model.
        if (el.attributes.value === undefined && attrType === 'bind') {
          el.value = value;
        } else if (attrType !== 'bind') {
          el.checked = checkedAttrLooseCompare(el.value, value);
        }
      } else if (el.type === 'checkbox') {
        // If we are explicitly binding a string to the :value, set the string,
        // If the value is a boolean, leave it alone, it will be set to "on"
        // automatically.
        if (typeof value !== 'boolean' && ![null, undefined].includes(value) && attrType === 'bind') {
          el.value = String(value);
        } else if (attrType !== 'bind') {
          if (Array.isArray(value)) {
            // I'm purposely not using Array.includes here because it's
            // strict, and because of Numeric/String mis-casting, I
            // want the "includes" to be "fuzzy".
            el.checked = value.some(function (val) {
              _newArrowCheck(this, _this);

              return checkedAttrLooseCompare(val, el.value);
            }.bind(this));
          } else {
            el.checked = !!value;
          }
        }
      } else if (el.tagName === 'SELECT') {
        updateSelect(el, value);
      } else {
        if (el.value === value) return;
        el.value = value;
      }
    } else if (attrName === 'class') {
      if (Array.isArray(value)) {
        var originalClasses = el.__x_original_classes || [];
        el.setAttribute('class', arrayUnique(originalClasses.concat(value)).join(' '));
      } else if (_typeof(value) === 'object') {
        // Sorting the keys / class names by their boolean value will ensure that
        // anything that evaluates to `false` and needs to remove classes is run first.
        var keysSortedByBooleanValue = Object.keys(value).sort(function (a, b) {
          _newArrowCheck(this, _this);

          return value[a] - value[b];
        }.bind(this));
        keysSortedByBooleanValue.forEach(function (classNames) {
          var _this2 = this;

          _newArrowCheck(this, _this);

          if (value[classNames]) {
            convertClassStringToArray(classNames).forEach(function (className) {
              _newArrowCheck(this, _this2);

              return el.classList.add(className);
            }.bind(this));
          } else {
            convertClassStringToArray(classNames).forEach(function (className) {
              _newArrowCheck(this, _this2);

              return el.classList.remove(className);
            }.bind(this));
          }
        }.bind(this));
      } else {
        var _originalClasses = el.__x_original_classes || [];

        var newClasses = value ? convertClassStringToArray(value) : [];
        el.setAttribute('class', arrayUnique(_originalClasses.concat(newClasses)).join(' '));
      }
    } else {
      attrName = modifiers.includes('camel') ? camelCase(attrName) : attrName; // If an attribute's bound value is null, undefined or false, remove the attribute

      if ([null, undefined, false].includes(value)) {
        el.removeAttribute(attrName);
      } else {
        isBooleanAttr(attrName) ? setIfChanged(el, attrName, attrName) : setIfChanged(el, attrName, value);
      }
    }
  }

  function setIfChanged(el, attrName, value) {
    if (el.getAttribute(attrName) != value) {
      el.setAttribute(attrName, value);
    }
  }

  function updateSelect(el, value) {
    var _this3 = this;

    var arrayWrappedValue = [].concat(value).map(function (value) {
      _newArrowCheck(this, _this3);

      return value + '';
    }.bind(this));
    Array.from(el.options).forEach(function (option) {
      _newArrowCheck(this, _this3);

      option.selected = arrayWrappedValue.includes(option.value || option.text);
    }.bind(this));
  }

  function handleTextDirective(el, output, expression) {
    // If nested model key is undefined, set the default value to empty string.
    if (output === undefined && String(expression).match(/\./)) {
      output = '';
    }

    el.textContent = output;
  }

  function handleHtmlDirective(component, el, expression, extraVars) {
    el.innerHTML = component.evaluateReturnExpression(el, expression, extraVars);
  }

  function handleShowDirective(component, el, value, modifiers) {
    var _this = this;

    var initialUpdate = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;

    var hide = function hide() {
      _newArrowCheck(this, _this);

      el.style.display = 'none';
      el.__x_is_shown = false;
    }.bind(this);

    var show = function show() {
      _newArrowCheck(this, _this);

      if (el.style.length === 1 && el.style.display === 'none') {
        el.removeAttribute('style');
      } else {
        el.style.removeProperty('display');
      }

      el.__x_is_shown = true;
    }.bind(this);

    if (initialUpdate === true) {
      if (value) {
        show();
      } else {
        hide();
      }

      return;
    }

    var handle = function handle(resolve, reject) {
      var _this2 = this;

      _newArrowCheck(this, _this);

      if (value) {
        if (el.style.display === 'none' || el.__x_transition) {
          transitionIn(el, function () {
            _newArrowCheck(this, _this2);

            show();
          }.bind(this), reject, component);
        }

        resolve(function () {
          _newArrowCheck(this, _this2);
        }.bind(this));
      } else {
        if (el.style.display !== 'none') {
          transitionOut(el, function () {
            var _this3 = this;

            _newArrowCheck(this, _this2);

            resolve(function () {
              _newArrowCheck(this, _this3);

              hide();
            }.bind(this));
          }.bind(this), reject, component);
        } else {
          resolve(function () {
            _newArrowCheck(this, _this2);
          }.bind(this));
        }
      }
    }.bind(this); // The working of x-show is a bit complex because we need to
    // wait for any child transitions to finish before hiding
    // some element. Also, this has to be done recursively.
    // If x-show.immediate, foregoe the waiting.


    if (modifiers.includes('immediate')) {
      handle(function (finish) {
        _newArrowCheck(this, _this);

        return finish();
      }.bind(this), function () {
        _newArrowCheck(this, _this);
      }.bind(this));
      return;
    } // x-show is encountered during a DOM tree walk. If an element
    // we encounter is NOT a child of another x-show element we
    // can execute the previous x-show stack (if one exists).


    if (component.showDirectiveLastElement && !component.showDirectiveLastElement.contains(el)) {
      component.executeAndClearRemainingShowDirectiveStack();
    }

    component.showDirectiveStack.push(handle);
    component.showDirectiveLastElement = el;
  }

  function handleIfDirective(component, el, expressionResult, initialUpdate, extraVars) {
    var _this = this;

    warnIfMalformedTemplate(el, 'x-if');
    var elementHasAlreadyBeenAdded = el.nextElementSibling && el.nextElementSibling.__x_inserted_me === true;

    if (expressionResult && (!elementHasAlreadyBeenAdded || el.__x_transition)) {
      var clone = document.importNode(el.content, true);
      el.parentElement.insertBefore(clone, el.nextElementSibling);
      transitionIn(el.nextElementSibling, function () {
        _newArrowCheck(this, _this);
      }.bind(this), function () {
        _newArrowCheck(this, _this);
      }.bind(this), component, initialUpdate);
      component.initializeElements(el.nextElementSibling, extraVars);
      el.nextElementSibling.__x_inserted_me = true;
    } else if (!expressionResult && elementHasAlreadyBeenAdded) {
      transitionOut(el.nextElementSibling, function () {
        _newArrowCheck(this, _this);

        el.nextElementSibling.remove();
      }.bind(this), function () {
        _newArrowCheck(this, _this);
      }.bind(this), component, initialUpdate);
    }
  }

  var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport('splice');
  var USES_TO_LENGTH$8 = arrayMethodUsesToLength('splice', { ACCESSORS: true, 0: 0, 1: 2 });

  var max$2 = Math.max;
  var min$5 = Math.min;
  var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
  var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';

  // `Array.prototype.splice` method
  // https://tc39.es/ecma262/#sec-array.prototype.splice
  // with adding support of @@species
  _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 || !USES_TO_LENGTH$8 }, {
    splice: function splice(start, deleteCount /* , ...items */) {
      var O = toObject(this);
      var len = toLength(O.length);
      var actualStart = toAbsoluteIndex(start, len);
      var argumentsLength = arguments.length;
      var insertCount, actualDeleteCount, A, k, from, to;
      if (argumentsLength === 0) {
        insertCount = actualDeleteCount = 0;
      } else if (argumentsLength === 1) {
        insertCount = 0;
        actualDeleteCount = len - actualStart;
      } else {
        insertCount = argumentsLength - 2;
        actualDeleteCount = min$5(max$2(toInteger(deleteCount), 0), len - actualStart);
      }
      if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) {
        throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
      }
      A = arraySpeciesCreate(O, actualDeleteCount);
      for (k = 0; k < actualDeleteCount; k++) {
        from = actualStart + k;
        if (from in O) createProperty(A, k, O[from]);
      }
      A.length = actualDeleteCount;
      if (insertCount < actualDeleteCount) {
        for (k = actualStart; k < len - actualDeleteCount; k++) {
          from = k + actualDeleteCount;
          to = k + insertCount;
          if (from in O) O[to] = O[from];
          else delete O[to];
        }
        for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
      } else if (insertCount > actualDeleteCount) {
        for (k = len - actualDeleteCount; k > actualStart; k--) {
          from = k + actualDeleteCount - 1;
          to = k + insertCount - 1;
          if (from in O) O[to] = O[from];
          else delete O[to];
        }
      }
      for (k = 0; k < insertCount; k++) {
        O[k + actualStart] = arguments[k + 2];
      }
      O.length = len - actualDeleteCount + insertCount;
      return A;
    }
  });

  function registerListener(component, el, event, modifiers, expression) {
    var _this = this;

    var extraVars = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
    var options = {
      passive: modifiers.includes('passive')
    };

    if (modifiers.includes('camel')) {
      event = camelCase(event);
    }

    var _handler2, listenerTarget;

    if (modifiers.includes('away')) {
      listenerTarget = document;

      _handler2 = function handler(e) {
        _newArrowCheck(this, _this);

        // Don't do anything if the click came from the element or within it.
        if (el.contains(e.target)) return; // Don't do anything if this element isn't currently visible.

        if (el.offsetWidth < 1 && el.offsetHeight < 1) return; // Now that we are sure the element is visible, AND the click
        // is from outside it, let's run the expression.

        runListenerHandler(component, expression, e, extraVars);

        if (modifiers.includes('once')) {
          document.removeEventListener(event, _handler2, options);
        }
      }.bind(this);
    } else {
      listenerTarget = modifiers.includes('window') ? window : modifiers.includes('document') ? document : el;

      _handler2 = function _handler(e) {
        var _this2 = this;

        _newArrowCheck(this, _this);

        // Remove this global event handler if the element that declared it
        // has been removed. It's now stale.
        if (listenerTarget === window || listenerTarget === document) {
          if (!document.body.contains(el)) {
            listenerTarget.removeEventListener(event, _handler2, options);
            return;
          }
        }

        if (isKeyEvent(event)) {
          if (isListeningForASpecificKeyThatHasntBeenPressed(e, modifiers)) {
            return;
          }
        }

        if (modifiers.includes('prevent')) e.preventDefault();
        if (modifiers.includes('stop')) e.stopPropagation(); // If the .self modifier isn't present, or if it is present and
        // the target element matches the element we are registering the
        // event on, run the handler

        if (!modifiers.includes('self') || e.target === el) {
          var returnValue = runListenerHandler(component, expression, e, extraVars);
          returnValue.then(function (value) {
            _newArrowCheck(this, _this2);

            if (value === false) {
              e.preventDefault();
            } else {
              if (modifiers.includes('once')) {
                listenerTarget.removeEventListener(event, _handler2, options);
              }
            }
          }.bind(this));
        }
      }.bind(this);
    }

    if (modifiers.includes('debounce')) {
      var nextModifier = modifiers[modifiers.indexOf('debounce') + 1] || 'invalid-wait';
      var wait = isNumeric(nextModifier.split('ms')[0]) ? Number(nextModifier.split('ms')[0]) : 250;
      _handler2 = debounce(_handler2, wait);
    }

    listenerTarget.addEventListener(event, _handler2, options);
  }

  function runListenerHandler(component, expression, e, extraVars) {
    var _this3 = this;

    return component.evaluateCommandExpression(e.target, expression, function () {
      _newArrowCheck(this, _this3);

      return _objectSpread2(_objectSpread2({}, extraVars()), {}, {
        '$event': e
      });
    }.bind(this));
  }

  function isKeyEvent(event) {
    return ['keydown', 'keyup'].includes(event);
  }

  function isListeningForASpecificKeyThatHasntBeenPressed(e, modifiers) {
    var _this4 = this;

    var keyModifiers = modifiers.filter(function (i) {
      _newArrowCheck(this, _this4);

      return !['window', 'document', 'prevent', 'stop'].includes(i);
    }.bind(this));

    if (keyModifiers.includes('debounce')) {
      var debounceIndex = keyModifiers.indexOf('debounce');
      keyModifiers.splice(debounceIndex, isNumeric((keyModifiers[debounceIndex + 1] || 'invalid-wait').split('ms')[0]) ? 2 : 1);
    } // If no modifier is specified, we'll call it a press.


    if (keyModifiers.length === 0) return false; // If one is passed, AND it matches the key pressed, we'll call it a press.

    if (keyModifiers.length === 1 && keyModifiers[0] === keyToModifier(e.key)) return false; // The user is listening for key combinations.

    var systemKeyModifiers = ['ctrl', 'shift', 'alt', 'meta', 'cmd', 'super'];
    var selectedSystemKeyModifiers = systemKeyModifiers.filter(function (modifier) {
      _newArrowCheck(this, _this4);

      return keyModifiers.includes(modifier);
    }.bind(this));
    keyModifiers = keyModifiers.filter(function (i) {
      _newArrowCheck(this, _this4);

      return !selectedSystemKeyModifiers.includes(i);
    }.bind(this));

    if (selectedSystemKeyModifiers.length > 0) {
      var activelyPressedKeyModifiers = selectedSystemKeyModifiers.filter(function (modifier) {
        _newArrowCheck(this, _this4);

        // Alias "cmd" and "super" to "meta"
        if (modifier === 'cmd' || modifier === 'super') modifier = 'meta';
        return e["".concat(modifier, "Key")];
      }.bind(this)); // If all the modifiers selected are pressed, ...

      if (activelyPressedKeyModifiers.length === selectedSystemKeyModifiers.length) {
        // AND the remaining key is pressed as well. It's a press.
        if (keyModifiers[0] === keyToModifier(e.key)) return false;
      }
    } // We'll call it NOT a valid keypress.


    return true;
  }

  function keyToModifier(key) {
    switch (key) {
      case '/':
        return 'slash';

      case ' ':
      case 'Spacebar':
        return 'space';

      default:
        return key && kebabCase(key);
    }
  }

  function registerModelListener(component, el, modifiers, expression, extraVars) {
    var _this = this;

    // If the element we are binding to is a select, a radio, or checkbox
    // we'll listen for the change event instead of the "input" event.
    var event = el.tagName.toLowerCase() === 'select' || ['checkbox', 'radio'].includes(el.type) || modifiers.includes('lazy') ? 'change' : 'input';
    var listenerExpression = "".concat(expression, " = rightSideOfExpression($event, ").concat(expression, ")");
    registerListener(component, el, event, modifiers, listenerExpression, function () {
      _newArrowCheck(this, _this);

      return _objectSpread2(_objectSpread2({}, extraVars()), {}, {
        rightSideOfExpression: generateModelAssignmentFunction(el, modifiers, expression)
      });
    }.bind(this));
  }

  function generateModelAssignmentFunction(el, modifiers, expression) {
    var _this2 = this;

    if (el.type === 'radio') {
      // Radio buttons only work properly when they share a name attribute.
      // People might assume we take care of that for them, because
      // they already set a shared "x-model" attribute.
      if (!el.hasAttribute('name')) el.setAttribute('name', expression);
    }

    return function (event, currentValue) {
      var _this3 = this;

      _newArrowCheck(this, _this2);

      // Check for event.detail due to an issue where IE11 handles other events as a CustomEvent.
      if (event instanceof CustomEvent && event.detail) {
        return event.detail;
      } else if (el.type === 'checkbox') {
        // If the data we are binding to is an array, toggle its value inside the array.
        if (Array.isArray(currentValue)) {
          var newValue = modifiers.includes('number') ? safeParseNumber(event.target.value) : event.target.value;
          return event.target.checked ? currentValue.concat([newValue]) : currentValue.filter(function (el) {
            _newArrowCheck(this, _this3);

            return !checkedAttrLooseCompare(el, newValue);
          }.bind(this));
        } else {
          return event.target.checked;
        }
      } else if (el.tagName.toLowerCase() === 'select' && el.multiple) {
        return modifiers.includes('number') ? Array.from(event.target.selectedOptions).map(function (option) {
          _newArrowCheck(this, _this3);

          var rawValue = option.value || option.text;
          return safeParseNumber(rawValue);
        }.bind(this)) : Array.from(event.target.selectedOptions).map(function (option) {
          _newArrowCheck(this, _this3);

          return option.value || option.text;
        }.bind(this));
      } else {
        var rawValue = event.target.value;
        return modifiers.includes('number') ? safeParseNumber(rawValue) : modifiers.includes('trim') ? rawValue.trim() : rawValue;
      }
    }.bind(this);
  }

  function safeParseNumber(rawValue) {
    var number = rawValue ? parseFloat(rawValue) : null;
    return isNumeric(number) ? number : rawValue;
  }

  // `Reflect.set` method
  // https://tc39.es/ecma262/#sec-reflect.set
  function set$2(target, propertyKey, V /* , receiver */) {
    var receiver = arguments.length < 4 ? target : arguments[3];
    var ownDescriptor = objectGetOwnPropertyDescriptor.f(anObject(target), propertyKey);
    var existingDescriptor, prototype;
    if (!ownDescriptor) {
      if (isObject(prototype = objectGetPrototypeOf(target))) {
        return set$2(prototype, propertyKey, V, receiver);
      }
      ownDescriptor = createPropertyDescriptor(0);
    }
    if (has(ownDescriptor, 'value')) {
      if (ownDescriptor.writable === false || !isObject(receiver)) return false;
      if (existingDescriptor = objectGetOwnPropertyDescriptor.f(receiver, propertyKey)) {
        if (existingDescriptor.get || existingDescriptor.set || existingDescriptor.writable === false) return false;
        existingDescriptor.value = V;
        objectDefineProperty.f(receiver, propertyKey, existingDescriptor);
      } else objectDefineProperty.f(receiver, propertyKey, createPropertyDescriptor(0, V));
      return true;
    }
    return ownDescriptor.set === undefined ? false : (ownDescriptor.set.call(receiver, V), true);
  }

  // MS Edge 17-18 Reflect.set allows setting the property to object
  // with non-writable property on the prototype
  var MS_EDGE_BUG = fails(function () {
    var Constructor = function () { /* empty */ };
    var object = objectDefineProperty.f(new Constructor(), 'a', { configurable: true });
    // eslint-disable-next-line no-undef
    return Reflect.set(Constructor.prototype, 'a', 1, object) !== false;
  });

  _export({ target: 'Reflect', stat: true, forced: MS_EDGE_BUG }, {
    set: set$2
  });

  function wrap(data, mutationCallback) {
    /* IE11-ONLY:START */
    return wrapForIe11(data, mutationCallback);
  }
  function unwrap(membrane, observable) {
    var _this = this;

    var unwrappedData = membrane.unwrapProxy(observable);
    var copy = {};
    Object.keys(unwrappedData).forEach(function (key) {
      _newArrowCheck(this, _this);

      if (['$el', '$refs', '$nextTick', '$watch'].includes(key)) return;
      copy[key] = unwrappedData[key];
    }.bind(this));
    return copy;
  }

  function wrapForIe11(data, mutationCallback) {
    var proxyHandler = {
      set: function set(target, key, value) {
        // Set the value converting it to a "Deep Proxy" when required
        // Note that if a project is not a valid object, it won't be converted to a proxy
        var setWasSuccessful = Reflect.set(target, key, deepProxy(value, proxyHandler));
        mutationCallback(target, key);
        return setWasSuccessful;
      },
      get: function get(target, key) {
        // Provide a way to determine if this object is an Alpine proxy or not.
        if (key === "$isAlpineProxy") return true; // Just return the flippin' value. Gawsh.

        return target[key];
      }
    };
    return {
      data: deepProxy(data, proxyHandler),
      membrane: {
        unwrapProxy: function unwrapProxy(proxy) {
          return proxy;
        }
      }
    };
  }

  function deepProxy(target, proxyHandler) {
    // If target is null, return it.
    if (target === null) return target; // If target is not an object, return it.

    if (_typeof(target) !== 'object') return target; // If target is a DOM node (like in the case of this.$el), return it.

    if (target instanceof Node) return target; // If target is already an Alpine proxy, return it.

    if (target['$isAlpineProxy']) return target; // Otherwise proxy the properties recursively.
    // This enables reactivity on setting nested data.
    // Note that if a project is not a valid object, it won't be converted to a proxy

    for (var property in target) {
      target[property] = deepProxy(target[property], proxyHandler);
    }

    return new Proxy(target, proxyHandler);
  }

  var Component = /*#__PURE__*/function () {
    function Component(el) {
      var _this = this;

      var componentForClone = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;

      _classCallCheck(this, Component);

      this.$el = el;
      var dataAttr = this.$el.getAttribute('x-data');
      var dataExpression = dataAttr === '' ? '{}' : dataAttr;
      var initExpression = this.$el.getAttribute('x-init');
      var dataExtras = {
        $el: this.$el
      };
      var canonicalComponentElementReference = componentForClone ? componentForClone.$el : this.$el;
      Object.entries(Alpine.magicProperties).forEach(function (_ref) {
        _newArrowCheck(this, _this);

        var _ref2 = _slicedToArray(_ref, 2),
            name = _ref2[0],
            callback = _ref2[1];

        Object.defineProperty(dataExtras, "$".concat(name), {
          get: function get() {
            return callback(canonicalComponentElementReference);
          }
        });
      }.bind(this));
      this.unobservedData = componentForClone ? componentForClone.getUnobservedData() : saferEval(el, dataExpression, dataExtras);
      /* IE11-ONLY:START */
      // For IE11, add our magic properties to the original data for access.
      // The Proxy polyfill does not allow properties to be added after creation.

      this.unobservedData.$el = null;
      this.unobservedData.$refs = null;
      this.unobservedData.$nextTick = null;
      this.unobservedData.$watch = null; // The IE build uses a proxy polyfill which doesn't allow properties
      // to be defined after the proxy object is created so,
      // for IE only, we need to define our helpers earlier.

      Object.entries(Alpine.magicProperties).forEach(function (_ref3) {
        _newArrowCheck(this, _this);

        var _ref4 = _slicedToArray(_ref3, 2),
            name = _ref4[0],
            callback = _ref4[1];

        Object.defineProperty(this.unobservedData, "$".concat(name), {
          get: function get() {
            return callback(canonicalComponentElementReference, this.$el);
          }
        });
      }.bind(this));
      /* IE11-ONLY:END */
      // Construct a Proxy-based observable. This will be used to handle reactivity.

      var _this$wrapDataInObser = this.wrapDataInObservable(this.unobservedData),
          membrane = _this$wrapDataInObser.membrane,
          data = _this$wrapDataInObser.data;

      this.$data = data;
      this.membrane = membrane; // After making user-supplied data methods reactive, we can now add
      // our magic properties to the original data for access.

      this.unobservedData.$el = this.$el;
      this.unobservedData.$refs = this.getRefsProxy();
      this.nextTickStack = [];

      this.unobservedData.$nextTick = function (callback) {
        _newArrowCheck(this, _this);

        this.nextTickStack.push(callback);
      }.bind(this);

      this.watchers = {};

      this.unobservedData.$watch = function (property, callback) {
        _newArrowCheck(this, _this);

        if (!this.watchers[property]) this.watchers[property] = [];
        this.watchers[property].push(callback);
      }.bind(this);

      this.showDirectiveStack = [];
      this.showDirectiveLastElement;
      componentForClone || Alpine.onBeforeComponentInitializeds.forEach(function (callback) {
        _newArrowCheck(this, _this);

        return callback(this);
      }.bind(this));
      var initReturnedCallback; // If x-init is present AND we aren't cloning (skip x-init on clone)

      if (initExpression && !componentForClone) {
        // We want to allow data manipulation, but not trigger DOM updates just yet.
        // We haven't even initialized the elements with their Alpine bindings. I mean c'mon.
        this.pauseReactivity = true;
        initReturnedCallback = this.evaluateReturnExpression(this.$el, initExpression);
        this.pauseReactivity = false;
      } // Register all our listeners and set all our attribute bindings.
      // If we're cloning a component, the third parameter ensures no duplicate
      // event listeners are registered (the mutation observer will take care of them)


      this.initializeElements(this.$el, function () {
        _newArrowCheck(this, _this);
      }.bind(this), componentForClone); // Use mutation observer to detect new elements being added within this component at run-time.
      // Alpine's just so darn flexible amirite?

      this.listenForNewElementsToInitialize();

      if (typeof initReturnedCallback === 'function') {
        // Run the callback returned from the "x-init" hook to allow the user to do stuff after
        // Alpine's got it's grubby little paws all over everything.
        initReturnedCallback.call(this.$data);
      }

      componentForClone || setTimeout(function () {
        var _this2 = this;

        _newArrowCheck(this, _this);

        Alpine.onComponentInitializeds.forEach(function (callback) {
          _newArrowCheck(this, _this2);

          return callback(this);
        }.bind(this));
      }.bind(this), 0);
    }

    _createClass(Component, [{
      key: "getUnobservedData",
      value: function getUnobservedData() {
        return unwrap(this.membrane, this.$data);
      }
    }, {
      key: "wrapDataInObservable",
      value: function wrapDataInObservable(data) {
        var _this3 = this;

        var self = this;
        var updateDom = debounce(function () {
          self.updateElements(self.$el);
        }, 0);
        return wrap(data, function (target, key) {
          var _this4 = this;

          _newArrowCheck(this, _this3);

          if (self.watchers[key]) {
            // If there's a watcher for this specific key, run it.
            self.watchers[key].forEach(function (callback) {
              _newArrowCheck(this, _this4);

              return callback(target[key]);
            }.bind(this));
          } else if (Array.isArray(target)) {
            // Arrays are special cases, if any of the items change, we consider the array as mutated.
            Object.keys(self.watchers).forEach(function (fullDotNotationKey) {
              var _this5 = this;

              _newArrowCheck(this, _this4);

              var dotNotationParts = fullDotNotationKey.split('.'); // Ignore length mutations since they would result in duplicate calls.
              // For example, when calling push, we would get a mutation for the item's key
              // and a second mutation for the length property.

              if (key === 'length') return;
              dotNotationParts.reduce(function (comparisonData, part) {
                var _this6 = this;

                _newArrowCheck(this, _this5);

                if (Object.is(target, comparisonData[part])) {
                  self.watchers[fullDotNotationKey].forEach(function (callback) {
                    _newArrowCheck(this, _this6);

                    return callback(target);
                  }.bind(this));
                }

                return comparisonData[part];
              }.bind(this), self.unobservedData);
            }.bind(this));
          } else {
            // Let's walk through the watchers with "dot-notation" (foo.bar) and see
            // if this mutation fits any of them.
            Object.keys(self.watchers).filter(function (i) {
              _newArrowCheck(this, _this4);

              return i.includes('.');
            }.bind(this)).forEach(function (fullDotNotationKey) {
              var _this7 = this;

              _newArrowCheck(this, _this4);

              var dotNotationParts = fullDotNotationKey.split('.'); // If this dot-notation watcher's last "part" doesn't match the current
              // key, then skip it early for performance reasons.

              if (key !== dotNotationParts[dotNotationParts.length - 1]) return; // Now, walk through the dot-notation "parts" recursively to find
              // a match, and call the watcher if one's found.

              dotNotationParts.reduce(function (comparisonData, part) {
                var _this8 = this;

                _newArrowCheck(this, _this7);

                if (Object.is(target, comparisonData)) {
                  // Run the watchers.
                  self.watchers[fullDotNotationKey].forEach(function (callback) {
                    _newArrowCheck(this, _this8);

                    return callback(target[key]);
                  }.bind(this));
                }

                return comparisonData[part];
              }.bind(this), self.unobservedData);
            }.bind(this));
          } // Don't react to data changes for cases like the `x-created` hook.


          if (self.pauseReactivity) return;
          updateDom();
        }.bind(this));
      }
    }, {
      key: "walkAndSkipNestedComponents",
      value: function walkAndSkipNestedComponents(el, callback) {
        var _this9 = this;

        var initializeComponentCallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
          _newArrowCheck(this, _this9);
        }.bind(this);
        walk(el, function (el) {
          _newArrowCheck(this, _this9);

          // We've hit a component.
          if (el.hasAttribute('x-data')) {
            // If it's not the current one.
            if (!el.isSameNode(this.$el)) {
              // Initialize it if it's not.
              if (!el.__x) initializeComponentCallback(el); // Now we'll let that sub-component deal with itself.

              return false;
            }
          }

          return callback(el);
        }.bind(this));
      }
    }, {
      key: "initializeElements",
      value: function initializeElements(rootEl) {
        var _this10 = this;

        var extraVars = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
          _newArrowCheck(this, _this10);
        }.bind(this);
        var componentForClone = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
        this.walkAndSkipNestedComponents(rootEl, function (el) {
          _newArrowCheck(this, _this10);

          // Don't touch spawns from for loop
          if (el.__x_for_key !== undefined) return false; // Don't touch spawns from if directives

          if (el.__x_inserted_me !== undefined) return false;
          this.initializeElement(el, extraVars, componentForClone ? false : true);
        }.bind(this), function (el) {
          _newArrowCheck(this, _this10);

          if (!componentForClone) el.__x = new Component(el);
        }.bind(this));
        this.executeAndClearRemainingShowDirectiveStack();
        this.executeAndClearNextTickStack(rootEl);
      }
    }, {
      key: "initializeElement",
      value: function initializeElement(el, extraVars) {
        var shouldRegisterListeners = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;

        // To support class attribute merging, we have to know what the element's
        // original class attribute looked like for reference.
        if (el.hasAttribute('class') && getXAttrs(el, this).length > 0) {
          el.__x_original_classes = convertClassStringToArray(el.getAttribute('class'));
        }

        shouldRegisterListeners && this.registerListeners(el, extraVars);
        this.resolveBoundAttributes(el, true, extraVars);
      }
    }, {
      key: "updateElements",
      value: function updateElements(rootEl) {
        var _this11 = this;

        var extraVars = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
          _newArrowCheck(this, _this11);
        }.bind(this);
        this.walkAndSkipNestedComponents(rootEl, function (el) {
          _newArrowCheck(this, _this11);

          // Don't touch spawns from for loop (and check if the root is actually a for loop in a parent, don't skip it.)
          if (el.__x_for_key !== undefined && !el.isSameNode(this.$el)) return false;
          this.updateElement(el, extraVars);
        }.bind(this), function (el) {
          _newArrowCheck(this, _this11);

          el.__x = new Component(el);
        }.bind(this));
        this.executeAndClearRemainingShowDirectiveStack();
        this.executeAndClearNextTickStack(rootEl);
      }
    }, {
      key: "executeAndClearNextTickStack",
      value: function executeAndClearNextTickStack(el) {
        var _this12 = this;

        // Skip spawns from alpine directives
        if (el === this.$el && this.nextTickStack.length > 0) {
          // We run the tick stack after the next frame to allow any
          // running transitions to pass the initial show stage.
          requestAnimationFrame(function () {
            _newArrowCheck(this, _this12);

            while (this.nextTickStack.length > 0) {
              this.nextTickStack.shift()();
            }
          }.bind(this));
        }
      }
    }, {
      key: "executeAndClearRemainingShowDirectiveStack",
      value: function executeAndClearRemainingShowDirectiveStack() {
        var _this13 = this;

        // The goal here is to start all the x-show transitions
        // and build a nested promise chain so that elements
        // only hide when the children are finished hiding.
        this.showDirectiveStack.reverse().map(function (handler) {
          var _this14 = this;

          _newArrowCheck(this, _this13);

          return new Promise(function (resolve, reject) {
            _newArrowCheck(this, _this14);

            handler(resolve, reject);
          }.bind(this));
        }.bind(this)).reduce(function (promiseChain, promise) {
          var _this15 = this;

          _newArrowCheck(this, _this13);

          return promiseChain.then(function () {
            var _this16 = this;

            _newArrowCheck(this, _this15);

            return promise.then(function (finishElement) {
              _newArrowCheck(this, _this16);

              finishElement();
            }.bind(this));
          }.bind(this));
        }.bind(this), Promise.resolve(function () {
          _newArrowCheck(this, _this13);
        }.bind(this)))["catch"](function (e) {
          _newArrowCheck(this, _this13);

          if (e !== TRANSITION_CANCELLED) throw e;
        }.bind(this)); // We've processed the handler stack. let's clear it.

        this.showDirectiveStack = [];
        this.showDirectiveLastElement = undefined;
      }
    }, {
      key: "updateElement",
      value: function updateElement(el, extraVars) {
        this.resolveBoundAttributes(el, false, extraVars);
      }
    }, {
      key: "registerListeners",
      value: function registerListeners(el, extraVars) {
        var _this17 = this;

        getXAttrs(el, this).forEach(function (_ref5) {
          _newArrowCheck(this, _this17);

          var type = _ref5.type,
              value = _ref5.value,
              modifiers = _ref5.modifiers,
              expression = _ref5.expression;

          switch (type) {
            case 'on':
              registerListener(this, el, value, modifiers, expression, extraVars);
              break;

            case 'model':
              registerModelListener(this, el, modifiers, expression, extraVars);
              break;
          }
        }.bind(this));
      }
    }, {
      key: "resolveBoundAttributes",
      value: function resolveBoundAttributes(el) {
        var _this18 = this;

        var initialUpdate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
        var extraVars = arguments.length > 2 ? arguments[2] : undefined;
        var attrs = getXAttrs(el, this);
        attrs.forEach(function (_ref6) {
          var _this19 = this;

          _newArrowCheck(this, _this18);

          var type = _ref6.type,
              value = _ref6.value,
              modifiers = _ref6.modifiers,
              expression = _ref6.expression;

          switch (type) {
            case 'model':
              handleAttributeBindingDirective(this, el, 'value', expression, extraVars, type, modifiers);
              break;

            case 'bind':
              // The :key binding on an x-for is special, ignore it.
              if (el.tagName.toLowerCase() === 'template' && value === 'key') return;
              handleAttributeBindingDirective(this, el, value, expression, extraVars, type, modifiers);
              break;

            case 'text':
              var output = this.evaluateReturnExpression(el, expression, extraVars);
              handleTextDirective(el, output, expression);
              break;

            case 'html':
              handleHtmlDirective(this, el, expression, extraVars);
              break;

            case 'show':
              var output = this.evaluateReturnExpression(el, expression, extraVars);
              handleShowDirective(this, el, output, modifiers, initialUpdate);
              break;

            case 'if':
              // If this element also has x-for on it, don't process x-if.
              // We will let the "x-for" directive handle the "if"ing.
              if (attrs.some(function (i) {
                _newArrowCheck(this, _this19);

                return i.type === 'for';
              }.bind(this))) return;
              var output = this.evaluateReturnExpression(el, expression, extraVars);
              handleIfDirective(this, el, output, initialUpdate, extraVars);
              break;

            case 'for':
              handleForDirective(this, el, expression, initialUpdate, extraVars);
              break;

            case 'cloak':
              el.removeAttribute('x-cloak');
              break;
          }
        }.bind(this));
      }
    }, {
      key: "evaluateReturnExpression",
      value: function evaluateReturnExpression(el, expression) {
        var _this20 = this;

        var extraVars = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
          _newArrowCheck(this, _this20);
        }.bind(this);
        return saferEval(el, expression, this.$data, _objectSpread2(_objectSpread2({}, extraVars()), {}, {
          $dispatch: this.getDispatchFunction(el)
        }));
      }
    }, {
      key: "evaluateCommandExpression",
      value: function evaluateCommandExpression(el, expression) {
        var _this21 = this;

        var extraVars = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
          _newArrowCheck(this, _this21);
        }.bind(this);
        return saferEvalNoReturn(el, expression, this.$data, _objectSpread2(_objectSpread2({}, extraVars()), {}, {
          $dispatch: this.getDispatchFunction(el)
        }));
      }
    }, {
      key: "getDispatchFunction",
      value: function getDispatchFunction(el) {
        return function (event) {
          var detail = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
          el.dispatchEvent(new CustomEvent(event, {
            detail: detail,
            bubbles: true
          }));
        };
      }
    }, {
      key: "listenForNewElementsToInitialize",
      value: function listenForNewElementsToInitialize() {
        var _this22 = this;

        var targetNode = this.$el;
        var observerOptions = {
          childList: true,
          attributes: true,
          subtree: true
        };
        var observer = new MutationObserver(function (mutations) {
          var _this23 = this;

          _newArrowCheck(this, _this22);

          for (var i = 0; i < mutations.length; i++) {
            // Filter out mutations triggered from child components.
            var closestParentComponent = mutations[i].target.closest('[x-data]');
            if (!(closestParentComponent && closestParentComponent.isSameNode(this.$el))) continue;

            if (mutations[i].type === 'attributes' && mutations[i].attributeName === 'x-data') {
              (function () {
                var _this24 = this;

                var xAttr = mutations[i].target.getAttribute('x-data') || '{}';
                var rawData = saferEval(_this23.$el, xAttr, {
                  $el: _this23.$el
                });
                Object.keys(rawData).forEach(function (key) {
                  _newArrowCheck(this, _this24);

                  if (_this23.$data[key] !== rawData[key]) {
                    _this23.$data[key] = rawData[key];
                  }
                }.bind(this));
              })();
            }

            if (mutations[i].addedNodes.length > 0) {
              mutations[i].addedNodes.forEach(function (node) {
                _newArrowCheck(this, _this23);

                if (node.nodeType !== 1 || node.__x_inserted_me) return;

                if (node.matches('[x-data]') && !node.__x) {
                  node.__x = new Component(node);
                  return;
                }

                this.initializeElements(node);
              }.bind(this));
            }
          }
        }.bind(this));
        observer.observe(targetNode, observerOptions);
      }
    }, {
      key: "getRefsProxy",
      value: function getRefsProxy() {
        var _this25 = this;

        var self = this;
        var refObj = {};
        /* IE11-ONLY:START */
        // Add any properties up-front that might be necessary for the Proxy polyfill.

        refObj.$isRefsProxy = false;
        refObj.$isAlpineProxy = false; // If we are in IE, since the polyfill needs all properties to be defined before building the proxy,
        // we just loop on the element, look for any x-ref and create a tmp property on a fake object.

        this.walkAndSkipNestedComponents(self.$el, function (el) {
          _newArrowCheck(this, _this25);

          if (el.hasAttribute('x-ref')) {
            refObj[el.getAttribute('x-ref')] = true;
          }
        }.bind(this));
        /* IE11-ONLY:END */
        // One of the goals of this is to not hold elements in memory, but rather re-evaluate
        // the DOM when the system needs something from it. This way, the framework is flexible and
        // friendly to outside DOM changes from libraries like Vue/Livewire.
        // For this reason, I'm using an "on-demand" proxy to fake a "$refs" object.

        return new Proxy(refObj, {
          get: function get(object, property) {
            var _this26 = this;

            if (property === '$isAlpineProxy') return true;
            var ref; // We can't just query the DOM because it's hard to filter out refs in
            // nested components.

            self.walkAndSkipNestedComponents(self.$el, function (el) {
              _newArrowCheck(this, _this26);

              if (el.hasAttribute('x-ref') && el.getAttribute('x-ref') === property) {
                ref = el;
              }
            }.bind(this));
            return ref;
          }
        });
      }
    }]);

    return Component;
  }();

  var Alpine = {
    version: "2.8.2",
    pauseMutationObserver: false,
    magicProperties: {},
    onComponentInitializeds: [],
    onBeforeComponentInitializeds: [],
    ignoreFocusedForValueBinding: false,
    start: function () {
      var _start = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
        var _this = this;

        return regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                if (isTesting()) {
                  _context.next = 3;
                  break;
                }

                _context.next = 3;
                return domReady();

              case 3:
                this.discoverComponents(function (el) {
                  _newArrowCheck(this, _this);

                  this.initializeComponent(el);
                }.bind(this)); // It's easier and more performant to just support Turbolinks than listen
                // to MutationObserver mutations at the document level.

                document.addEventListener("turbolinks:load", function () {
                  var _this2 = this;

                  _newArrowCheck(this, _this);

                  this.discoverUninitializedComponents(function (el) {
                    _newArrowCheck(this, _this2);

                    this.initializeComponent(el);
                  }.bind(this));
                }.bind(this));
                this.listenForNewUninitializedComponentsAtRunTime();

              case 6:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

      function start() {
        return _start.apply(this, arguments);
      }

      return start;
    }(),
    discoverComponents: function discoverComponents(callback) {
      var _this3 = this;

      var rootEls = document.querySelectorAll('[x-data]');
      rootEls.forEach(function (rootEl) {
        _newArrowCheck(this, _this3);

        callback(rootEl);
      }.bind(this));
    },
    discoverUninitializedComponents: function discoverUninitializedComponents(callback) {
      var _this4 = this;

      var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
      var rootEls = (el || document).querySelectorAll('[x-data]');
      Array.from(rootEls).filter(function (el) {
        _newArrowCheck(this, _this4);

        return el.__x === undefined;
      }.bind(this)).forEach(function (rootEl) {
        _newArrowCheck(this, _this4);

        callback(rootEl);
      }.bind(this));
    },
    listenForNewUninitializedComponentsAtRunTime: function listenForNewUninitializedComponentsAtRunTime() {
      var _this5 = this;

      var targetNode = document.querySelector('body');
      var observerOptions = {
        childList: true,
        attributes: true,
        subtree: true
      };
      var observer = new MutationObserver(function (mutations) {
        var _this6 = this;

        _newArrowCheck(this, _this5);

        if (this.pauseMutationObserver) return;

        for (var i = 0; i < mutations.length; i++) {
          if (mutations[i].addedNodes.length > 0) {
            mutations[i].addedNodes.forEach(function (node) {
              var _this7 = this;

              _newArrowCheck(this, _this6);

              // Discard non-element nodes (like line-breaks)
              if (node.nodeType !== 1) return; // Discard any changes happening within an existing component.
              // They will take care of themselves.

              if (node.parentElement && node.parentElement.closest('[x-data]')) return;
              this.discoverUninitializedComponents(function (el) {
                _newArrowCheck(this, _this7);

                this.initializeComponent(el);
              }.bind(this), node.parentElement);
            }.bind(this));
          }
        }
      }.bind(this));
      observer.observe(targetNode, observerOptions);
    },
    initializeComponent: function initializeComponent(el) {
      var _this8 = this;

      if (!el.__x) {
        // Wrap in a try/catch so that we don't prevent other components
        // from initializing when one component contains an error.
        try {
          el.__x = new Component(el);
        } catch (error) {
          setTimeout(function () {
            _newArrowCheck(this, _this8);

            throw error;
          }.bind(this), 0);
        }
      }
    },
    clone: function clone(component, newEl) {
      if (!newEl.__x) {
        newEl.__x = new Component(newEl, component);
      }
    },
    addMagicProperty: function addMagicProperty(name, callback) {
      this.magicProperties[name] = callback;
    },
    onComponentInitialized: function onComponentInitialized(callback) {
      this.onComponentInitializeds.push(callback);
    },
    onBeforeComponentInitialized: function onBeforeComponentInitialized(callback) {
      this.onBeforeComponentInitializeds.push(callback);
    }
  };

  if (!isTesting()) {
    window.Alpine = Alpine;

    if (window.deferLoadingAlpine) {
      window.deferLoadingAlpine(function () {
        window.Alpine.start();
      });
    } else {
      window.Alpine.start();
    }
  }

})));

/*!
 * 
 * Super simple WYSIWYG editor v0.9.1
 * https://summernote.org
 *
 * Copyright 2013~ Hackerwins and contributors
 * Summernote may be freely distributed under the MIT license.
 *
 * Date: 2024-10-09T10:28Z
 *
 */
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("jquery"));
	else if(typeof define === 'function' && define.amd)
		define(["jquery"], factory);
	else {
		var a = typeof exports === 'object' ? factory(require("jquery")) : factory(root["jQuery"]);
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}
})(self, (__WEBPACK_EXTERNAL_MODULE__8938__) => {
return /******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ({

/***/ 7000:
/***/ ((__unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__) => {

/* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8938);
/* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);

(jquery__WEBPACK_IMPORTED_MODULE_0___default().summernote) = (jquery__WEBPACK_IMPORTED_MODULE_0___default().summernote) || {
  lang: {}
};
jquery__WEBPACK_IMPORTED_MODULE_0___default().extend(true, (jquery__WEBPACK_IMPORTED_MODULE_0___default().summernote).lang, {
  'en-US': {
    font: {
      bold: 'Bold',
      italic: 'Italic',
      underline: 'Underline',
      clear: 'Remove Font Style',
      height: 'Line Height',
      name: 'Font Family',
      strikethrough: 'Strikethrough',
      subscript: 'Subscript',
      superscript: 'Superscript',
      size: 'Font Size',
      sizeunit: 'Font Size Unit'
    },
    image: {
      image: 'Picture',
      insert: 'Insert Image',
      resizeFull: 'Resize full',
      resizeHalf: 'Resize half',
      resizeQuarter: 'Resize quarter',
      resizeNone: 'Original size',
      floatLeft: 'Float Left',
      floatRight: 'Float Right',
      floatNone: 'Remove float',
      shapeRounded: 'Shape: Rounded',
      shapeCircle: 'Shape: Circle',
      shapeThumbnail: 'Shape: Thumbnail',
      shapeNone: 'Shape: None',
      dragImageHere: 'Drag image or text here',
      dropImage: 'Drop image or Text',
      selectFromFiles: 'Select from files',
      maximumFileSize: 'Maximum file size',
      maximumFileSizeError: 'Maximum file size exceeded.',
      url: 'Image URL',
      remove: 'Remove Image',
      original: 'Original'
    },
    video: {
      video: 'Video',
      videoLink: 'Video Link',
      insert: 'Insert Video',
      url: 'Video URL',
      providers: '(YouTube, Google Drive, Vimeo, Vine, Instagram, DailyMotion, Youku, Peertube)'
    },
    link: {
      link: 'Link',
      insert: 'Insert Link',
      unlink: 'Unlink',
      edit: 'Edit',
      textToDisplay: 'Text to display',
      url: 'To what URL should this link go?',
      openInNewWindow: 'Open in new window'
    },
    table: {
      table: 'Table',
      addRowAbove: 'Add row above',
      addRowBelow: 'Add row below',
      addColLeft: 'Add column left',
      addColRight: 'Add column right',
      delRow: 'Delete row',
      delCol: 'Delete column',
      delTable: 'Delete table'
    },
    hr: {
      insert: 'Insert Horizontal Rule'
    },
    style: {
      style: 'Style',
      p: 'Normal',
      blockquote: 'Quote',
      pre: 'Code',
      h1: 'Header 1',
      h2: 'Header 2',
      h3: 'Header 3',
      h4: 'Header 4',
      h5: 'Header 5',
      h6: 'Header 6'
    },
    lists: {
      unordered: 'Unordered list',
      ordered: 'Ordered list'
    },
    options: {
      help: 'Help',
      fullscreen: 'Full Screen',
      codeview: 'Code View'
    },
    paragraph: {
      paragraph: 'Paragraph',
      outdent: 'Outdent',
      indent: 'Indent',
      left: 'Align left',
      center: 'Align center',
      right: 'Align right',
      justify: 'Justify full'
    },
    color: {
      recent: 'Recent Color',
      more: 'More Color',
      background: 'Background Color',
      foreground: 'Text Color',
      transparent: 'Transparent',
      setTransparent: 'Set transparent',
      reset: 'Reset',
      resetToDefault: 'Reset to default',
      cpSelect: 'Select'
    },
    shortcut: {
      shortcuts: 'Keyboard shortcuts',
      close: 'Close',
      textFormatting: 'Text formatting',
      action: 'Action',
      paragraphFormatting: 'Paragraph formatting',
      documentStyle: 'Document Style',
      extraKeys: 'Extra keys'
    },
    help: {
      'escape': 'Escape',
      'insertParagraph': 'Insert Paragraph',
      'undo': 'Undo the last command',
      'redo': 'Redo the last command',
      'tab': 'Tab',
      'untab': 'Untab',
      'bold': 'Set a bold style',
      'italic': 'Set a italic style',
      'underline': 'Set a underline style',
      'strikethrough': 'Set a strikethrough style',
      'removeFormat': 'Clean a style',
      'justifyLeft': 'Set left align',
      'justifyCenter': 'Set center align',
      'justifyRight': 'Set right align',
      'justifyFull': 'Set full align',
      'insertUnorderedList': 'Toggle unordered list',
      'insertOrderedList': 'Toggle ordered list',
      'outdent': 'Outdent on current paragraph',
      'indent': 'Indent on current paragraph',
      'formatPara': 'Change current block\'s format as a paragraph(P tag)',
      'formatH1': 'Change current block\'s format as H1',
      'formatH2': 'Change current block\'s format as H2',
      'formatH3': 'Change current block\'s format as H3',
      'formatH4': 'Change current block\'s format as H4',
      'formatH5': 'Change current block\'s format as H5',
      'formatH6': 'Change current block\'s format as H6',
      'insertHorizontalRule': 'Insert horizontal rule',
      'linkDialog.show': 'Show Link Dialog'
    },
    history: {
      undo: 'Undo',
      redo: 'Redo'
    },
    specialChar: {
      specialChar: 'SPECIAL CHARACTERS',
      select: 'Select Special characters'
    },
    output: {
      noSelection: 'No Selection Made!'
    }
  }
});

/***/ }),

/***/ 8938:
/***/ ((module) => {

module.exports = __WEBPACK_EXTERNAL_MODULE__8938__;

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
/******/ 		if (cachedModule !== undefined) {
/******/ 			return cachedModule.exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/compat get default export */
/******/ 	(() => {
/******/ 		// getDefaultExport function for compatibility with non-harmony modules
/******/ 		__webpack_require__.n = (module) => {
/******/ 			var getter = module && module.__esModule ?
/******/ 				() => (module['default']) :
/******/ 				() => (module);
/******/ 			__webpack_require__.d(getter, { a: getter });
/******/ 			return getter;
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};

// EXTERNAL MODULE: external {"root":"jQuery","commonjs":"jquery","commonjs2":"jquery","amd":"jquery"}
var external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_ = __webpack_require__(8938);
var external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default = /*#__PURE__*/__webpack_require__.n(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_);
// EXTERNAL MODULE: ./src/lang/summernote-en-US.js
var summernote_en_US = __webpack_require__(7000);
;// CONCATENATED MODULE: ./src/js/core/env.js


/**
 * returns whether font is installed or not.
 *
 * @param {String} fontName
 * @return {Boolean}
 */
var genericFontFamilies = ['sans-serif', 'serif', 'monospace', 'cursive', 'fantasy'];
function validFontName(fontName) {
  return external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().inArray(fontName.toLowerCase(), genericFontFamilies) === -1 ? "'".concat(fontName, "'") : fontName;
}
function createIsFontInstalledFunc() {
  var testText = "mw";
  var fontSize = "20px";
  var canvasWidth = 40;
  var canvasHeight = 20;
  var canvas = document.createElement("canvas");
  var context = canvas.getContext("2d", {
    willReadFrequently: true
  });
  canvas.width = canvasWidth;
  canvas.height = canvasHeight;
  context.textAlign = "center";
  context.fillStyle = "black";
  context.textBaseline = "middle";
  function getPxInfo(font, testFontName) {
    context.clearRect(0, 0, canvasWidth, canvasHeight);
    context.font = fontSize + ' ' + validFontName(font) + ', "' + testFontName + '"';
    context.fillText(testText, canvasWidth / 2, canvasHeight / 2);
    // Get pixel information
    var pxInfo = context.getImageData(0, 0, canvasWidth, canvasHeight).data;
    return pxInfo.join("");
  }
  return function (fontName) {
    var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';
    var testInfo = getPxInfo(testFontName, testFontName);
    var fontInfo = getPxInfo(fontName, testFontName);
    return testInfo !== fontInfo;
  };
}
var userAgent = navigator.userAgent;
var isMSIE = /MSIE|Trident/i.test(userAgent);
var browserVersion;
if (isMSIE) {
  var matches = /MSIE (\d+[.]\d+)/.exec(userAgent);
  if (matches) {
    browserVersion = parseFloat(matches[1]);
  }
  matches = /Trident\/.*rv:([0-9]{1,}[.0-9]{0,})/.exec(userAgent);
  if (matches) {
    browserVersion = parseFloat(matches[1]);
  }
}
var isEdge = /Edge\/\d+/.test(userAgent);
var isSupportTouch = 'ontouchstart' in window || navigator.MaxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;

// [workaround] IE doesn't have input events for contentEditable
// - see: https://goo.gl/4bfIvA
var inputEventName = isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';

/**
 * @class core.env
 *
 * Object which check platform and agent
 *
 * @singleton
 * @alternateClassName env
 */
/* harmony default export */ const env = ({
  isMac: navigator.appVersion.indexOf('Mac') > -1,
  isMSIE: isMSIE,
  isEdge: isEdge,
  isFF: !isEdge && /firefox/i.test(userAgent),
  isPhantom: /PhantomJS/i.test(userAgent),
  isWebkit: !isEdge && /webkit/i.test(userAgent),
  isChrome: !isEdge && /chrome/i.test(userAgent),
  isSafari: !isEdge && /safari/i.test(userAgent) && !/chrome/i.test(userAgent),
  browserVersion: browserVersion,
  isSupportTouch: isSupportTouch,
  isFontInstalled: createIsFontInstalledFunc(),
  isW3CRangeSupport: !!document.createRange,
  inputEventName: inputEventName,
  genericFontFamilies: genericFontFamilies,
  validFontName: validFontName
});
;// CONCATENATED MODULE: ./src/js/core/func.js


/**
 * @class core.func
 *
 * func utils (for high-order func's arg)
 *
 * @singleton
 * @alternateClassName func
 */
function eq(itemA) {
  return function (itemB) {
    return itemA === itemB;
  };
}
function eq2(itemA, itemB) {
  return itemA === itemB;
}
function peq2(propName) {
  return function (itemA, itemB) {
    return itemA[propName] === itemB[propName];
  };
}
function ok() {
  return true;
}
function fail() {
  return false;
}
function not(f) {
  return function () {
    return !f.apply(f, arguments);
  };
}
function and(fA, fB) {
  return function (item) {
    return fA(item) && fB(item);
  };
}
function func_self(a) {
  return a;
}
function invoke(obj, method) {
  return function () {
    return obj[method].apply(obj, arguments);
  };
}
var idCounter = 0;

/**
 * reset globally-unique id
 *
 */
function resetUniqueId() {
  idCounter = 0;
}

/**
 * generate a globally-unique id
 *
 * @param {String} [prefix]
 */
function uniqueId(prefix) {
  var id = ++idCounter + '';
  return prefix ? prefix + id : id;
}

/**
 * returns bnd (bounds) from rect
 *
 * - IE Compatibility Issue: http://goo.gl/sRLOAo
 * - Scroll Issue: http://goo.gl/sNjUc
 *
 * @param {Rect} rect
 * @return {Object} bounds
 * @return {Number} bounds.top
 * @return {Number} bounds.left
 * @return {Number} bounds.width
 * @return {Number} bounds.height
 */
function rect2bnd(rect) {
  var $document = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document);
  return {
    top: rect.top + $document.scrollTop(),
    left: rect.left + $document.scrollLeft(),
    width: rect.right - rect.left,
    height: rect.bottom - rect.top
  };
}

/**
 * returns a copy of the object where the keys have become the values and the values the keys.
 * @param {Object} obj
 * @return {Object}
 */
function invertObject(obj) {
  var inverted = {};
  for (var key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      inverted[obj[key]] = key;
    }
  }
  return inverted;
}

/**
 * @param {String} namespace
 * @param {String} [prefix]
 * @return {String}
 */
function namespaceToCamel(namespace, prefix) {
  prefix = prefix || '';
  return prefix + namespace.split('.').map(function (name) {
    return name.substring(0, 1).toUpperCase() + name.substring(1);
  }).join('');
}

/**
 * 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.
 * @param {Function} func
 * @param {Number} wait
 * @param {Boolean} immediate
 * @return {Function}
 */
function debounce(func, wait, immediate) {
  var timeout;
  return function () {
    var context = this;
    var args = arguments;
    var later = function later() {
      timeout = null;
      if (!immediate) {
        func.apply(context, args);
      }
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) {
      func.apply(context, args);
    }
  };
}

/**
 *
 * @param {String} url
 * @return {Boolean}
 */
function isValidUrl(url) {
  var expression = /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/gi;
  return expression.test(url);
}
/* harmony default export */ const func = ({
  eq: eq,
  eq2: eq2,
  peq2: peq2,
  ok: ok,
  fail: fail,
  self: func_self,
  not: not,
  and: and,
  invoke: invoke,
  resetUniqueId: resetUniqueId,
  uniqueId: uniqueId,
  rect2bnd: rect2bnd,
  invertObject: invertObject,
  namespaceToCamel: namespaceToCamel,
  debounce: debounce,
  isValidUrl: isValidUrl
});
;// CONCATENATED MODULE: ./src/js/core/lists.js


/**
 * returns the first item of an array.
 *
 * @param {Array} array
 */
function head(array) {
  return array[0];
}

/**
 * returns the last item of an array.
 *
 * @param {Array} array
 */
function last(array) {
  return array[array.length - 1];
}

/**
 * returns everything but the last entry of the array.
 *
 * @param {Array} array
 */
function initial(array) {
  return array.slice(0, array.length - 1);
}

/**
 * returns the rest of the items in an array.
 *
 * @param {Array} array
 */
function tail(array) {
  return array.slice(1);
}

/**
 * returns item of array
 */
function find(array, pred) {
  for (var idx = 0, len = array.length; idx < len; idx++) {
    var item = array[idx];
    if (pred(item)) {
      return item;
    }
  }
}

/**
 * returns true if all of the values in the array pass the predicate truth test.
 */
function lists_all(array, pred) {
  for (var idx = 0, len = array.length; idx < len; idx++) {
    if (!pred(array[idx])) {
      return false;
    }
  }
  return true;
}

/**
 * returns true if the value is present in the list.
 */
function contains(array, item) {
  if (array && array.length && item) {
    if (array.indexOf) {
      return array.indexOf(item) !== -1;
    } else if (array.contains) {
      // `DOMTokenList` doesn't implement `.indexOf`, but it implements `.contains`
      return array.contains(item);
    }
  }
  return false;
}

/**
 * get sum from a list
 *
 * @param {Array} array - array
 * @param {Function} fn - iterator
 */
function sum(array, fn) {
  fn = fn || func.self;
  return array.reduce(function (memo, v) {
    return memo + fn(v);
  }, 0);
}

/**
 * returns a copy of the collection with array type.
 * @param {Collection} collection - collection eg) node.childNodes, ...
 */
function from(collection) {
  var result = [];
  var length = collection.length;
  var idx = -1;
  while (++idx < length) {
    result[idx] = collection[idx];
  }
  return result;
}

/**
 * returns whether list is empty or not
 */
function isEmpty(array) {
  return !array || !array.length;
}

/**
 * cluster elements by predicate function.
 *
 * @param {Array} array - array
 * @param {Function} fn - predicate function for cluster rule
 * @param {Array[]}
 */
function clusterBy(array, fn) {
  if (!array.length) {
    return [];
  }
  var aTail = tail(array);
  return aTail.reduce(function (memo, v) {
    var aLast = last(memo);
    if (fn(last(aLast), v)) {
      aLast[aLast.length] = v;
    } else {
      memo[memo.length] = [v];
    }
    return memo;
  }, [[head(array)]]);
}

/**
 * returns a copy of the array with all false values removed
 *
 * @param {Array} array - array
 * @param {Function} fn - predicate function for cluster rule
 */
function compact(array) {
  var aResult = [];
  for (var idx = 0, len = array.length; idx < len; idx++) {
    if (array[idx]) {
      aResult.push(array[idx]);
    }
  }
  return aResult;
}

/**
 * produces a duplicate-free version of the array
 *
 * @param {Array} array
 */
function unique(array) {
  var results = [];
  for (var idx = 0, len = array.length; idx < len; idx++) {
    if (!contains(results, array[idx])) {
      results.push(array[idx]);
    }
  }
  return results;
}

/**
 * returns next item.
 * @param {Array} array
 */
function next(array, item) {
  if (array && array.length && item) {
    var idx = array.indexOf(item);
    return idx === -1 ? null : array[idx + 1];
  }
  return null;
}

/**
 * returns prev item.
 * @param {Array} array
 */
function prev(array, item) {
  if (array && array.length && item) {
    var idx = array.indexOf(item);
    return idx === -1 ? null : array[idx - 1];
  }
  return null;
}

/**
 * @class core.list
 *
 * list utils
 *
 * @singleton
 * @alternateClassName list
 */
/* harmony default export */ const lists = ({
  head: head,
  last: last,
  initial: initial,
  tail: tail,
  prev: prev,
  next: next,
  find: find,
  contains: contains,
  all: lists_all,
  sum: sum,
  from: from,
  isEmpty: isEmpty,
  clusterBy: clusterBy,
  compact: compact,
  unique: unique
});
;// CONCATENATED MODULE: ./src/js/core/dom.js




var NBSP_CHAR = String.fromCharCode(160);
var ZERO_WIDTH_NBSP_CHAR = "\uFEFF";

/**
 * @method isEditable
 *
 * returns whether node is `note-editable` or not.
 *
 * @param {Node} node
 * @return {Boolean}
 */
function isEditable(node) {
  return node && external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(node).hasClass('note-editable');
}

/**
 * @method isControlSizing
 *
 * returns whether node is `note-control-sizing` or not.
 *
 * @param {Node} node
 * @return {Boolean}
 */
function isControlSizing(node) {
  return node && external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(node).hasClass('note-control-sizing');
}

/**
 * @method makePredByNodeName
 *
 * returns predicate which judge whether nodeName is same
 *
 * @param {String} nodeName
 * @return {Function}
 */
function makePredByNodeName(nodeName) {
  nodeName = nodeName.toUpperCase();
  return function (node) {
    return node && node.nodeName.toUpperCase() === nodeName;
  };
}

/**
 * @method isText
 *
 *
 *
 * @param {Node} node
 * @return {Boolean} true if node's type is text(3)
 */
function isText(node) {
  return node && node.nodeType === 3;
}

/**
 * @method isElement
 *
 *
 *
 * @param {Node} node
 * @return {Boolean} true if node's type is element(1)
 */
function isElement(node) {
  return node && node.nodeType === 1;
}

/**
 * ex) br, col, embed, hr, img, input, ...
 * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
 */
function isVoid(node) {
  return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON|^INPUT|^AUDIO|^VIDEO|^EMBED/.test(node.nodeName.toUpperCase());
}
function isPara(node) {
  if (isEditable(node)) {
    return false;
  }

  // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph
  return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());
}
function isHeading(node) {
  return node && /^H[1-7]/.test(node.nodeName.toUpperCase());
}
var isPre = makePredByNodeName('PRE');
var isLi = makePredByNodeName('LI');
function isPurePara(node) {
  return isPara(node) && !isLi(node);
}
var isTable = makePredByNodeName('TABLE');
var isData = makePredByNodeName('DATA');
function isInline(node) {
  return !isBodyContainer(node) && !isList(node) && !isHr(node) && !isPara(node) && !isTable(node) && !isBlockquote(node) && !isData(node);
}
function isList(node) {
  return node && /^UL|^OL/.test(node.nodeName.toUpperCase());
}
var isHr = makePredByNodeName('HR');
function isCell(node) {
  return node && /^TD|^TH/.test(node.nodeName.toUpperCase());
}
var isBlockquote = makePredByNodeName('BLOCKQUOTE');
function isBodyContainer(node) {
  return isCell(node) || isBlockquote(node) || isEditable(node);
}
var isAnchor = makePredByNodeName('A');
function isParaInline(node) {
  return isInline(node) && !!ancestor(node, isPara);
}
function isBodyInline(node) {
  return isInline(node) && !ancestor(node, isPara);
}
var isBody = makePredByNodeName('BODY');

/**
 * returns whether nodeB is closest sibling of nodeA
 *
 * @param {Node} nodeA
 * @param {Node} nodeB
 * @return {Boolean}
 */
function isClosestSibling(nodeA, nodeB) {
  return nodeA.nextSibling === nodeB || nodeA.previousSibling === nodeB;
}

/**
 * returns array of closest siblings with node
 *
 * @param {Node} node
 * @param {function} [pred] - predicate function
 * @return {Node[]}
 */
function withClosestSiblings(node, pred) {
  pred = pred || func.ok;
  var siblings = [];
  if (node.previousSibling && pred(node.previousSibling)) {
    siblings.push(node.previousSibling);
  }
  siblings.push(node);
  if (node.nextSibling && pred(node.nextSibling)) {
    siblings.push(node.nextSibling);
  }
  return siblings;
}

/**
 * blank HTML for cursor position
 * - [workaround] old IE only works with &nbsp;
 * - [workaround] IE11 and other browser works with bogus br
 */
var blankHTML = env.isMSIE && env.browserVersion < 11 ? '&nbsp;' : '<br>';

/**
 * @method nodeLength
 *
 * returns #text's text size or element's childNodes size
 *
 * @param {Node} node
 */
function nodeLength(node) {
  if (isText(node)) {
    return node.nodeValue.length;
  }
  if (node) {
    return node.childNodes.length;
  }
  return 0;
}

/**
 * returns whether deepest child node is empty or not.
 *
 * @param {Node} node
 * @return {Boolean}
 */
function deepestChildIsEmpty(node) {
  do {
    if (node.firstElementChild === null || node.firstElementChild.innerHTML === '') break;
  } while (node = node.firstElementChild);
  return dom_isEmpty(node);
}

/**
 * returns whether node is empty or not.
 *
 * @param {Node} node
 * @return {Boolean}
 */
function dom_isEmpty(node) {
  var len = nodeLength(node);
  if (len === 0) {
    return true;
  } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {
    // ex) <p><br></p>, <span><br></span>
    return true;
  } else if (lists.all(node.childNodes, isText) && node.innerHTML === '') {
    // ex) <p></p>, <span></span>
    return true;
  }
  return false;
}

/**
 * padding blankHTML if node is empty (for cursor position)
 */
function paddingBlankHTML(node) {
  if (!isVoid(node) && !nodeLength(node)) {
    node.innerHTML = blankHTML;
  }
}

/**
 * find nearest ancestor predicate hit
 *
 * @param {Node} node
 * @param {Function} pred - predicate function
 */
function ancestor(node, pred) {
  while (node) {
    if (pred(node)) {
      return node;
    }
    if (isEditable(node)) {
      break;
    }
    node = node.parentNode;
  }
  return null;
}

/**
 * find nearest ancestor only single child blood line and predicate hit
 *
 * @param {Node} node
 * @param {Function} pred - predicate function
 */
function singleChildAncestor(node, pred) {
  node = node.parentNode;
  while (node) {
    if (nodeLength(node) !== 1) {
      break;
    }
    if (pred(node)) {
      return node;
    }
    if (isEditable(node)) {
      break;
    }
    node = node.parentNode;
  }
  return null;
}

/**
 * returns new array of ancestor nodes (until predicate hit).
 *
 * @param {Node} node
 * @param {Function} [optional] pred - predicate function
 */
function listAncestor(node, pred) {
  pred = pred || func.fail;
  var ancestors = [];
  ancestor(node, function (el) {
    if (!isEditable(el)) {
      ancestors.push(el);
    }
    return pred(el);
  });
  return ancestors;
}

/**
 * find farthest ancestor predicate hit
 */
function lastAncestor(node, pred) {
  var ancestors = listAncestor(node);
  return lists.last(ancestors.filter(pred));
}

/**
 * returns common ancestor node between two nodes.
 *
 * @param {Node} nodeA
 * @param {Node} nodeB
 */
function commonAncestor(nodeA, nodeB) {
  var ancestors = listAncestor(nodeA);
  for (var n = nodeB; n; n = n.parentNode) {
    if (ancestors.indexOf(n) > -1) return n;
  }
  return null; // difference document area
}

/**
 * listing all previous siblings (until predicate hit).
 *
 * @param {Node} node
 * @param {Function} [optional] pred - predicate function
 */
function listPrev(node, pred) {
  pred = pred || func.fail;
  var nodes = [];
  while (node) {
    if (pred(node)) {
      break;
    }
    nodes.push(node);
    node = node.previousSibling;
  }
  return nodes;
}

/**
 * listing next siblings (until predicate hit).
 *
 * @param {Node} node
 * @param {Function} [pred] - predicate function
 */
function listNext(node, pred) {
  pred = pred || func.fail;
  var nodes = [];
  while (node) {
    if (pred(node)) {
      break;
    }
    nodes.push(node);
    node = node.nextSibling;
  }
  return nodes;
}

/**
 * listing descendant nodes
 *
 * @param {Node} node
 * @param {Function} [pred] - predicate function
 */
function listDescendant(node, pred) {
  var descendants = [];
  pred = pred || func.ok;

  // start DFS(depth first search) with node
  (function fnWalk(current) {
    if (node !== current && pred(current)) {
      descendants.push(current);
    }
    for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {
      fnWalk(current.childNodes[idx]);
    }
  })(node);
  return descendants;
}

/**
 * wrap node with new tag.
 *
 * @param {Node} node
 * @param {Node} tagName of wrapper
 * @return {Node} - wrapper
 */
function wrap(node, wrapperName) {
  var parent = node.parentNode;
  var wrapper = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<' + wrapperName + '>')[0];
  parent.insertBefore(wrapper, node);
  wrapper.appendChild(node);
  return wrapper;
}

/**
 * insert node after preceding
 *
 * @param {Node} node
 * @param {Node} preceding - predicate function
 */
function insertAfter(node, preceding) {
  var next = preceding.nextSibling;
  var parent = preceding.parentNode;
  if (next) {
    parent.insertBefore(node, next);
  } else {
    parent.appendChild(node);
  }
  return node;
}

/**
 * append elements.
 *
 * @param {Node} node
 * @param {Collection} aChild
 */
function appendChildNodes(node, aChild, isSkipPaddingBlankHTML) {
  external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(aChild, function (idx, child) {
    // special case: appending a pure UL/OL to a LI element creates inaccessible LI element
    // e.g. press enter in last LI which has UL/OL-subelements
    // Therefore, if current node is LI element with no child nodes (text-node) and appending a list, add a br before
    if (!isSkipPaddingBlankHTML && isLi(node) && node.firstChild === null && isList(child)) {
      node.appendChild(create("br"));
    }
    node.appendChild(child);
  });
  return node;
}

/**
 * returns whether boundaryPoint is left edge or not.
 *
 * @param {BoundaryPoint} point
 * @return {Boolean}
 */
function isLeftEdgePoint(point) {
  return point.offset === 0;
}

/**
 * returns whether boundaryPoint is right edge or not.
 *
 * @param {BoundaryPoint} point
 * @return {Boolean}
 */
function isRightEdgePoint(point) {
  return point.offset === nodeLength(point.node);
}

/**
 * returns whether boundaryPoint is edge or not.
 *
 * @param {BoundaryPoint} point
 * @return {Boolean}
 */
function isEdgePoint(point) {
  return isLeftEdgePoint(point) || isRightEdgePoint(point);
}

/**
 * returns whether node is left edge of ancestor or not.
 *
 * @param {Node} node
 * @param {Node} ancestor
 * @return {Boolean}
 */
function isLeftEdgeOf(node, ancestor) {
  while (node && node !== ancestor) {
    if (position(node) !== 0) {
      return false;
    }
    node = node.parentNode;
  }
  return true;
}

/**
 * returns whether node is right edge of ancestor or not.
 *
 * @param {Node} node
 * @param {Node} ancestor
 * @return {Boolean}
 */
function isRightEdgeOf(node, ancestor) {
  if (!ancestor) {
    return false;
  }
  while (node && node !== ancestor) {
    if (position(node) !== nodeLength(node.parentNode) - 1) {
      return false;
    }
    node = node.parentNode;
  }
  return true;
}

/**
 * returns whether point is left edge of ancestor or not.
 * @param {BoundaryPoint} point
 * @param {Node} ancestor
 * @return {Boolean}
 */
function isLeftEdgePointOf(point, ancestor) {
  return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor);
}

/**
 * returns whether point is right edge of ancestor or not.
 * @param {BoundaryPoint} point
 * @param {Node} ancestor
 * @return {Boolean}
 */
function isRightEdgePointOf(point, ancestor) {
  return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);
}

/**
 * returns offset from parent.
 *
 * @param {Node} node
 */
function position(node) {
  var offset = 0;
  while (node = node.previousSibling) {
    offset += 1;
  }
  return offset;
}
function hasChildren(node) {
  return !!(node && node.childNodes && node.childNodes.length);
}

/**
 * returns previous boundaryPoint
 *
 * @param {BoundaryPoint} point
 * @param {Boolean} isSkipInnerOffset
 * @return {BoundaryPoint}
 */
function prevPoint(point, isSkipInnerOffset) {
  var node;
  var offset;
  if (point.offset === 0) {
    if (isEditable(point.node)) {
      return null;
    }
    node = point.node.parentNode;
    offset = position(point.node);
  } else if (hasChildren(point.node)) {
    node = point.node.childNodes[point.offset - 1];
    offset = nodeLength(node);
  } else {
    node = point.node;
    offset = isSkipInnerOffset ? 0 : point.offset - 1;
  }
  return {
    node: node,
    offset: offset
  };
}

/**
 * returns next boundaryPoint
 *
 * @param {BoundaryPoint} point
 * @param {Boolean} isSkipInnerOffset
 * @return {BoundaryPoint}
 */
function nextPoint(point, isSkipInnerOffset) {
  var node, offset;
  if (nodeLength(point.node) === point.offset) {
    if (isEditable(point.node)) {
      return null;
    }
    var nextTextNode = getNextTextNode(point.node);
    if (nextTextNode) {
      node = nextTextNode;
      offset = 0;
    } else {
      node = point.node.parentNode;
      offset = position(point.node) + 1;
    }
  } else if (hasChildren(point.node)) {
    node = point.node.childNodes[point.offset];
    offset = 0;
  } else {
    node = point.node;
    offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;
  }
  return {
    node: node,
    offset: offset
  };
}

/**
 * Find next boundaryPoint for preorder / depth first traversal of the DOM
 * returns next boundaryPoint with empty node
 *
 * @param {BoundaryPoint} point
 * @param {Boolean} isSkipInnerOffset
 * @return {BoundaryPoint}
 */
function nextPointWithEmptyNode(point, isSkipInnerOffset) {
  var node,
    offset = 0;
  if (nodeLength(point.node) === point.offset) {
    if (isEditable(point.node)) {
      return null;
    }
    node = point.node.parentNode;
    offset = position(point.node) + 1;

    // if parent node is editable,  return current node's sibling node.
    if (isEditable(node)) {
      node = point.node.nextSibling;
      offset = 0;
    }
  } else if (hasChildren(point.node)) {
    node = point.node.childNodes[point.offset];
    offset = 0;
  } else {
    node = point.node;
    offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;
  }
  return {
    node: node,
    offset: offset
  };
}

/*
* returns the next Text node index or 0 if not found.
*/
function getNextTextNode(actual) {
  if (!actual.nextSibling) return undefined;
  if (actual.parent !== actual.nextSibling.parent) return undefined;
  if (isText(actual.nextSibling)) return actual.nextSibling;else return getNextTextNode(actual.nextSibling);
}

/**
 * returns whether pointA and pointB is same or not.
 *
 * @param {BoundaryPoint} pointA
 * @param {BoundaryPoint} pointB
 * @return {Boolean}
 */
function isSamePoint(pointA, pointB) {
  return pointA.node === pointB.node && pointA.offset === pointB.offset;
}

/**
 * returns whether point is visible (can set cursor) or not.
 *
 * @param {BoundaryPoint} point
 * @return {Boolean}
 */
function isVisiblePoint(point) {
  if (isText(point.node) || !hasChildren(point.node) || dom_isEmpty(point.node)) {
    return true;
  }
  var leftNode = point.node.childNodes[point.offset - 1];
  var rightNode = point.node.childNodes[point.offset];
  if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode)) || isTable(rightNode)) {
    return true;
  }
  return false;
}

/**
 * @method prevPointUtil
 *
 * @param {BoundaryPoint} point
 * @param {Function} pred
 * @return {BoundaryPoint}
 */
function prevPointUntil(point, pred) {
  while (point) {
    if (pred(point)) {
      return point;
    }
    point = prevPoint(point);
  }
  return null;
}

/**
 * @method nextPointUntil
 *
 * @param {BoundaryPoint} point
 * @param {Function} pred
 * @return {BoundaryPoint}
 */
function nextPointUntil(point, pred) {
  while (point) {
    if (pred(point)) {
      return point;
    }
    point = nextPoint(point);
  }
  return null;
}

/**
 * returns whether point has character or not.
 *
 * @param {Point} point
 * @return {Boolean}
 */
function isCharPoint(point) {
  if (!isText(point.node)) {
    return false;
  }
  var ch = point.node.nodeValue.charAt(point.offset - 1);
  return ch && ch !== ' ' && ch !== NBSP_CHAR;
}

/**
 * returns whether point has space or not.
 *
 * @param {Point} point
 * @return {Boolean}
 */
function isSpacePoint(point) {
  if (!isText(point.node)) {
    return false;
  }
  var ch = point.node.nodeValue.charAt(point.offset - 1);
  return ch === ' ' || ch === NBSP_CHAR;
}

/**
 * @method walkPoint - preorder / depth first traversal of the DOM
 *
 * @param {BoundaryPoint} startPoint
 * @param {BoundaryPoint} endPoint
 * @param {Function} handler
 * @param {Boolean} isSkipInnerOffset
 */
function walkPoint(startPoint, endPoint, handler, isSkipInnerOffset) {
  var point = startPoint;
  while (point && point.node) {
    handler(point);
    if (isSamePoint(point, endPoint)) {
      break;
    }
    var isSkipOffset = isSkipInnerOffset && startPoint.node !== point.node && endPoint.node !== point.node;
    point = nextPointWithEmptyNode(point, isSkipOffset);
  }
}

/**
 * @method makeOffsetPath
 *
 * return offsetPath(array of offset) from ancestor
 *
 * @param {Node} ancestor - ancestor node
 * @param {Node} node
 */
function makeOffsetPath(ancestor, node) {
  var ancestors = listAncestor(node, func.eq(ancestor));
  return ancestors.map(position).reverse();
}

/**
 * @method fromOffsetPath
 *
 * return element from offsetPath(array of offset)
 *
 * @param {Node} ancestor - ancestor node
 * @param {array} offsets - offsetPath
 */
function fromOffsetPath(ancestor, offsets) {
  var current = ancestor;
  for (var i = 0, len = offsets.length; i < len; i++) {
    if (current.childNodes.length <= offsets[i]) {
      current = current.childNodes[current.childNodes.length - 1];
    } else {
      current = current.childNodes[offsets[i]];
    }
  }
  return current;
}

/**
 * @method splitNode
 *
 * split element or #text
 *
 * @param {BoundaryPoint} point
 * @param {Object} [options]
 * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
 * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
 * @param {Boolean} [options.isDiscardEmptySplits] - default: false
 * @return {Node} right node of boundaryPoint
 */
function splitNode(point, options) {
  var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
  var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;
  var isDiscardEmptySplits = options && options.isDiscardEmptySplits;
  if (isDiscardEmptySplits) {
    isSkipPaddingBlankHTML = true;
  }

  // edge case
  if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {
    if (isLeftEdgePoint(point)) {
      return point.node;
    } else if (isRightEdgePoint(point)) {
      return point.node.nextSibling;
    }
  }

  // split #text
  if (isText(point.node)) {
    return point.node.splitText(point.offset);
  } else {
    var childNode = point.node.childNodes[point.offset];
    var childNodes = listNext(childNode);
    var clone = insertAfter(point.node.cloneNode(false), point.node);
    appendChildNodes(clone, childNodes);
    if (!isSkipPaddingBlankHTML) {
      paddingBlankHTML(point.node);
      paddingBlankHTML(clone);
    }
    if (isDiscardEmptySplits) {
      if (dom_isEmpty(point.node)) {
        remove(point.node);
      }
      if (dom_isEmpty(clone)) {
        remove(clone);
        return point.node.nextSibling;
      }
    }
    return clone;
  }
}

/**
 * @method splitTree
 *
 * split tree by point
 *
 * @param {Node} root - split root
 * @param {BoundaryPoint} point
 * @param {Object} [options]
 * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
 * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
 * @return {Node} right node of boundaryPoint
 */
function splitTree(root, point, options) {
  // ex) [#text, <span>, <p>]
  var ancestors = listAncestor(point.node, func.eq(root));
  if (!ancestors.length) {
    return null;
  } else if (ancestors.length === 1) {
    return splitNode(point, options);
  }
  // Filter elements with sibling elements
  if (ancestors.length > 2) {
    var domList = ancestors.slice(0, ancestors.length - 1);
    var ifHasNextSibling = domList.find(function (item) {
      return item.nextSibling;
    });
    if (ifHasNextSibling && point.offset != 0 && isRightEdgePoint(point)) {
      var nestSibling = ifHasNextSibling.nextSibling;
      var textNode;
      if (nestSibling.nodeType == 1) {
        textNode = nestSibling.childNodes[0];
        ancestors = listAncestor(textNode, func.eq(root));
        point = {
          node: textNode,
          offset: 0
        };
      } else if (nestSibling.nodeType == 3 && !nestSibling.data.match(/[\n\r]/g)) {
        textNode = nestSibling;
        ancestors = listAncestor(textNode, func.eq(root));
        point = {
          node: textNode,
          offset: 0
        };
      }
    }
  }
  return ancestors.reduce(function (node, parent) {
    if (node === point.node) {
      node = splitNode(point, options);
    }
    return splitNode({
      node: parent,
      offset: node ? position(node) : nodeLength(parent)
    }, options);
  });
}

/**
 * split point
 *
 * @param {Point} point
 * @param {Boolean} isInline
 * @return {Object}
 */
function splitPoint(point, isInline) {
  // find splitRoot, container
  //  - inline: splitRoot is a child of paragraph
  //  - block: splitRoot is a child of bodyContainer
  var pred = isInline ? isPara : isBodyContainer;
  var ancestors = listAncestor(point.node, pred);
  var topAncestor = lists.last(ancestors) || point.node;
  var splitRoot, container;
  if (pred(topAncestor)) {
    splitRoot = ancestors[ancestors.length - 2];
    container = topAncestor;
  } else {
    splitRoot = topAncestor;
    container = splitRoot.parentNode;
  }

  // if splitRoot is exists, split with splitTree
  var pivot = splitRoot && splitTree(splitRoot, point, {
    isSkipPaddingBlankHTML: isInline,
    isNotSplitEdgePoint: isInline
  });

  // if container is point.node, find pivot with point.offset
  if (!pivot && container === point.node) {
    pivot = point.node.childNodes[point.offset];
  }
  return {
    rightNode: pivot,
    container: container
  };
}
function create(nodeName) {
  return document.createElement(nodeName);
}
function createText(text) {
  return document.createTextNode(text);
}

/**
 * @method remove
 *
 * remove node, (isRemoveChild: remove child or not)
 *
 * @param {Node} node
 * @param {Boolean} isRemoveChild
 */
function remove(node, isRemoveChild) {
  if (!node || !node.parentNode) {
    return;
  }
  if (node.removeNode) {
    return node.removeNode(isRemoveChild);
  }
  var parent = node.parentNode;
  if (!isRemoveChild) {
    var nodes = [];
    for (var i = 0, len = node.childNodes.length; i < len; i++) {
      nodes.push(node.childNodes[i]);
    }
    for (var _i = 0, _len = nodes.length; _i < _len; _i++) {
      parent.insertBefore(nodes[_i], node);
    }
  }
  parent.removeChild(node);
}

/**
 * @method removeWhile
 *
 * @param {Node} node
 * @param {Function} pred
 */
function removeWhile(node, pred) {
  while (node) {
    if (isEditable(node) || !pred(node)) {
      break;
    }
    var parent = node.parentNode;
    remove(node);
    node = parent;
  }
}

/**
 * @method replace
 *
 * replace node with provided nodeName
 *
 * @param {Node} node
 * @param {String} nodeName
 * @return {Node} - new node
 */
function replace(node, nodeName) {
  if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {
    return node;
  }
  var newNode = create(nodeName);
  if (node.style.cssText) {
    newNode.style.cssText = node.style.cssText;
  }
  appendChildNodes(newNode, lists.from(node.childNodes));
  insertAfter(newNode, node);
  remove(node);
  return newNode;
}
var isTextarea = makePredByNodeName('TEXTAREA');

/**
 * @param {jQuery} $node
 * @param {Boolean} [stripLinebreaks] - default: false
 */
function value($node, stripLinebreaks) {
  var val = isTextarea($node[0]) ? $node.val() : $node.html();
  if (stripLinebreaks) {
    return val.replace(/[\n\r]/g, '');
  }
  return val;
}

/**
 * @method html
 *
 * get the HTML contents of node
 *
 * @param {jQuery} $node
 * @param {Boolean} [isNewlineOnBlock]
 */
function html($node, isNewlineOnBlock) {
  var markup = value($node);
  if (isNewlineOnBlock) {
    var regexTag = /<(\/?)(\b(?!!)[^>\s]*)(.*?)(\s*\/?>)/g;
    markup = markup.replace(regexTag, function (match, endSlash, name) {
      name = name.toUpperCase();
      var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) && !!endSlash;
      var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);
      return match + (isEndOfInlineContainer || isBlockNode ? '\n' : '');
    });
    markup = markup.trim();
  }
  return markup;
}
function posFromPlaceholder(placeholder) {
  var $placeholder = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(placeholder);
  var pos = $placeholder.offset();
  var height = $placeholder.outerHeight(true); // include margin

  return {
    left: pos.left,
    top: pos.top + height
  };
}
function attachEvents($node, events) {
  Object.keys(events).forEach(function (key) {
    $node.on(key, events[key]);
  });
}
function detachEvents($node, events) {
  Object.keys(events).forEach(function (key) {
    $node.off(key, events[key]);
  });
}

/**
 * @method isCustomStyleTag
 *
 * assert if a node contains a "note-styletag" class,
 * which implies that's a custom-made style tag node
 *
 * @param {Node} an HTML DOM node
 */
function isCustomStyleTag(node) {
  return node && !isText(node) && lists.contains(node.classList, 'note-styletag');
}
/* harmony default export */ const dom = ({
  /** @property {String} NBSP_CHAR */
  NBSP_CHAR: NBSP_CHAR,
  /** @property {String} ZERO_WIDTH_NBSP_CHAR */
  ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,
  /** @property {String} blank */
  blank: blankHTML,
  /** @property {String} emptyPara */
  emptyPara: "<p>".concat(blankHTML, "</p>"),
  makePredByNodeName: makePredByNodeName,
  isEditable: isEditable,
  isControlSizing: isControlSizing,
  isText: isText,
  isElement: isElement,
  isVoid: isVoid,
  isPara: isPara,
  isPurePara: isPurePara,
  isHeading: isHeading,
  isInline: isInline,
  isBlock: func.not(isInline),
  isBodyInline: isBodyInline,
  isBody: isBody,
  isParaInline: isParaInline,
  isPre: isPre,
  isList: isList,
  isTable: isTable,
  isData: isData,
  isCell: isCell,
  isBlockquote: isBlockquote,
  isBodyContainer: isBodyContainer,
  isAnchor: isAnchor,
  isDiv: makePredByNodeName('DIV'),
  isLi: isLi,
  isBR: makePredByNodeName('BR'),
  isSpan: makePredByNodeName('SPAN'),
  isB: makePredByNodeName('B'),
  isU: makePredByNodeName('U'),
  isS: makePredByNodeName('S'),
  isI: makePredByNodeName('I'),
  isImg: makePredByNodeName('IMG'),
  isTextarea: isTextarea,
  deepestChildIsEmpty: deepestChildIsEmpty,
  isEmpty: dom_isEmpty,
  isEmptyAnchor: func.and(isAnchor, dom_isEmpty),
  isClosestSibling: isClosestSibling,
  withClosestSiblings: withClosestSiblings,
  nodeLength: nodeLength,
  isLeftEdgePoint: isLeftEdgePoint,
  isRightEdgePoint: isRightEdgePoint,
  isEdgePoint: isEdgePoint,
  isLeftEdgeOf: isLeftEdgeOf,
  isRightEdgeOf: isRightEdgeOf,
  isLeftEdgePointOf: isLeftEdgePointOf,
  isRightEdgePointOf: isRightEdgePointOf,
  prevPoint: prevPoint,
  nextPoint: nextPoint,
  nextPointWithEmptyNode: nextPointWithEmptyNode,
  isSamePoint: isSamePoint,
  isVisiblePoint: isVisiblePoint,
  prevPointUntil: prevPointUntil,
  nextPointUntil: nextPointUntil,
  isCharPoint: isCharPoint,
  isSpacePoint: isSpacePoint,
  walkPoint: walkPoint,
  ancestor: ancestor,
  singleChildAncestor: singleChildAncestor,
  listAncestor: listAncestor,
  lastAncestor: lastAncestor,
  listNext: listNext,
  listPrev: listPrev,
  listDescendant: listDescendant,
  commonAncestor: commonAncestor,
  wrap: wrap,
  insertAfter: insertAfter,
  appendChildNodes: appendChildNodes,
  position: position,
  hasChildren: hasChildren,
  makeOffsetPath: makeOffsetPath,
  fromOffsetPath: fromOffsetPath,
  splitTree: splitTree,
  splitPoint: splitPoint,
  create: create,
  createText: createText,
  remove: remove,
  removeWhile: removeWhile,
  replace: replace,
  html: html,
  value: value,
  posFromPlaceholder: posFromPlaceholder,
  attachEvents: attachEvents,
  detachEvents: detachEvents,
  isCustomStyleTag: isCustomStyleTag
});
;// CONCATENATED MODULE: ./src/js/Context.js
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }




var Context = /*#__PURE__*/function () {
  /**
   * @param {jQuery} $note
   * @param {Object} options
   */
  function Context($note, options) {
    _classCallCheck(this, Context);
    this.$note = $note;
    this.memos = {};
    this.modules = {};
    this.layoutInfo = {};
    this.options = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend(true, {}, options);

    // init ui with options
    (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().summernote.ui_template(this.options);
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.initialize();
  }

  /**
   * create layout and initialize modules and other resources
   */
  return _createClass(Context, [{
    key: "initialize",
    value: function initialize() {
      this.layoutInfo = this.ui.createLayout(this.$note);
      this._initialize();
      this.$note.hide();
      return this;
    }

    /**
     * destroy modules and other resources and remove layout
     */
  }, {
    key: "destroy",
    value: function destroy() {
      this._destroy();
      this.$note.removeData('summernote');
      this.ui.removeLayout(this.$note, this.layoutInfo);
    }

    /**
     * destory modules and other resources and initialize it again
     */
  }, {
    key: "reset",
    value: function reset() {
      var disabled = this.isDisabled();
      this.code(dom.emptyPara);
      this._destroy();
      this._initialize();
      if (disabled) {
        this.disable();
      }
    }
  }, {
    key: "_initialize",
    value: function _initialize() {
      var _this = this;
      // set own id
      this.options.id = func.uniqueId(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().now());
      // set default container for tooltips, popovers, and dialogs
      this.options.container = this.options.container || this.layoutInfo.editor;

      // add optional buttons
      var buttons = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend({}, this.options.buttons);
      Object.keys(buttons).forEach(function (key) {
        _this.memo('button.' + key, buttons[key]);
      });
      var modules = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend({}, this.options.modules, (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.plugins || {});

      // add and initialize modules
      Object.keys(modules).forEach(function (key) {
        _this.module(key, modules[key], true);
      });
      Object.keys(this.modules).forEach(function (key) {
        _this.initializeModule(key);
      });
    }
  }, {
    key: "_destroy",
    value: function _destroy() {
      var _this2 = this;
      // destroy modules with reversed order
      Object.keys(this.modules).reverse().forEach(function (key) {
        _this2.removeModule(key);
      });
      Object.keys(this.memos).forEach(function (key) {
        _this2.removeMemo(key);
      });
      // trigger custom onDestroy callback
      this.triggerEvent('destroy', this);
    }
  }, {
    key: "code",
    value: function code(html) {
      var isActivated = this.invoke('codeview.isActivated');
      if (html === undefined) {
        this.invoke('codeview.sync');
        return isActivated ? this.layoutInfo.codable.val() : this.layoutInfo.editable.html();
      } else {
        if (isActivated) {
          this.invoke('codeview.sync', html);
        } else {
          this.layoutInfo.editable.html(html);
        }
        this.$note.val(html);
        this.triggerEvent('change', html, this.layoutInfo.editable);
      }
    }
  }, {
    key: "isDisabled",
    value: function isDisabled() {
      return this.layoutInfo.editable.attr('contenteditable') === 'false';
    }
  }, {
    key: "enable",
    value: function enable() {
      this.layoutInfo.editable.attr('contenteditable', true);
      this.invoke('toolbar.activate', true);
      this.triggerEvent('disable', false);
      this.options.editing = true;
    }
  }, {
    key: "disable",
    value: function disable() {
      // close codeview if codeview is opend
      if (this.invoke('codeview.isActivated')) {
        this.invoke('codeview.deactivate');
      }
      this.layoutInfo.editable.attr('contenteditable', false);
      this.options.editing = false;
      this.invoke('toolbar.deactivate', true);
      this.triggerEvent('disable', true);
    }
  }, {
    key: "triggerEvent",
    value: function triggerEvent() {
      var namespace = lists.head(arguments);
      var args = lists.tail(lists.from(arguments));
      var callback = this.options.callbacks[func.namespaceToCamel(namespace, 'on')];
      if (callback) {
        callback.apply(this.$note[0], args);
      }
      this.$note.trigger('summernote.' + namespace, args);
    }
  }, {
    key: "initializeModule",
    value: function initializeModule(key) {
      var module = this.modules[key];
      module.shouldInitialize = module.shouldInitialize || func.ok;
      if (!module.shouldInitialize()) {
        return;
      }

      // initialize module
      if (module.initialize) {
        module.initialize();
      }

      // attach events
      if (module.events) {
        dom.attachEvents(this.$note, module.events);
      }
    }
  }, {
    key: "module",
    value: function module(key, ModuleClass, withoutIntialize) {
      if (arguments.length === 1) {
        return this.modules[key];
      }
      this.modules[key] = new ModuleClass(this);
      if (!withoutIntialize) {
        this.initializeModule(key);
      }
    }
  }, {
    key: "removeModule",
    value: function removeModule(key) {
      var module = this.modules[key];
      if (module.shouldInitialize()) {
        if (module.events) {
          dom.detachEvents(this.$note, module.events);
        }
        if (module.destroy) {
          module.destroy();
        }
      }
      delete this.modules[key];
    }
  }, {
    key: "memo",
    value: function memo(key, obj) {
      if (arguments.length === 1) {
        return this.memos[key];
      }
      this.memos[key] = obj;
    }
  }, {
    key: "removeMemo",
    value: function removeMemo(key) {
      if (this.memos[key] && this.memos[key].destroy) {
        this.memos[key].destroy();
      }
      delete this.memos[key];
    }

    /**
     * Some buttons need to change their visual style immediately once they get pressed
     */
  }, {
    key: "createInvokeHandlerAndUpdateState",
    value: function createInvokeHandlerAndUpdateState(namespace, value) {
      var _this3 = this;
      return function (event) {
        _this3.createInvokeHandler(namespace, value)(event);
        _this3.invoke('buttons.updateCurrentStyle');
      };
    }
  }, {
    key: "createInvokeHandler",
    value: function createInvokeHandler(namespace, value) {
      var _this4 = this;
      return function (event) {
        event.preventDefault();
        var $target = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.target);
        _this4.invoke(namespace, value || $target.closest('[data-value]').data('value'), $target);
      };
    }
  }, {
    key: "invoke",
    value: function invoke() {
      var namespace = lists.head(arguments);
      var args = lists.tail(lists.from(arguments));
      var splits = namespace.split('.');
      var hasSeparator = splits.length > 1;
      var moduleName = hasSeparator && lists.head(splits);
      var methodName = hasSeparator ? lists.last(splits) : lists.head(splits);
      var module = this.modules[moduleName || 'editor'];
      if (!moduleName && this[methodName]) {
        return this[methodName].apply(this, args);
      } else if (module && module[methodName] && module.shouldInitialize()) {
        return module[methodName].apply(module, args);
      }
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/summernote.js
function summernote_typeof(o) { "@babel/helpers - typeof"; return summernote_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, summernote_typeof(o); }




external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().fn.extend({
  /**
   * Summernote API
   *
   * @param {Object|String}
   * @return {this}
   */
  summernote: function summernote() {
    var type = summernote_typeof(lists.head(arguments));
    var isExternalAPICalled = type === 'string';
    var hasInitOptions = type === 'object';
    var options = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend({}, (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.options, hasInitOptions ? lists.head(arguments) : {});

    // Update options
    options.langInfo = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend(true, {}, (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.lang['en-US'], (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.lang[options.lang]);
    options.icons = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend(true, {}, (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.options.icons, options.icons);
    options.tooltip = options.tooltip === 'auto' ? !env.isSupportTouch : options.tooltip;
    this.each(function (idx, note) {
      var $note = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(note);
      if (!$note.data('summernote')) {
        var context = new Context($note, options);
        $note.data('summernote', context);
        $note.data('summernote').triggerEvent('init', context.layoutInfo);
      }
    });
    var $note = this.first();
    if ($note.length) {
      var context = $note.data('summernote');
      if (isExternalAPICalled) {
        return context.invoke.apply(context, lists.from(arguments));
      } else if (options.focus) {
        context.invoke('editor.focus');
      }
    }
    return this;
  }
});
;// CONCATENATED MODULE: ./src/js/core/range.js
function range_typeof(o) { "@babel/helpers - typeof"; return range_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, range_typeof(o); }
function range_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function range_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, range_toPropertyKey(o.key), o); } }
function range_createClass(e, r, t) { return r && range_defineProperties(e.prototype, r), t && range_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function range_toPropertyKey(t) { var i = range_toPrimitive(t, "string"); return "symbol" == range_typeof(i) ? i : i + ""; }
function range_toPrimitive(t, r) { if ("object" != range_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != range_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }






/**
 * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js
 *
 * @param {TextRange} textRange
 * @param {Boolean} isStart
 * @return {BoundaryPoint}
 *
 * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx
 */
function textRangeToPoint(textRange, isStart) {
  var container = textRange.parentElement();
  var offset;
  var tester = document.body.createTextRange();
  var prevContainer;
  var childNodes = lists.from(container.childNodes);
  for (offset = 0; offset < childNodes.length; offset++) {
    if (dom.isText(childNodes[offset])) {
      continue;
    }
    tester.moveToElementText(childNodes[offset]);
    if (tester.compareEndPoints('StartToStart', textRange) >= 0) {
      break;
    }
    prevContainer = childNodes[offset];
  }
  if (offset !== 0 && dom.isText(childNodes[offset - 1])) {
    var textRangeStart = document.body.createTextRange();
    var curTextNode = null;
    textRangeStart.moveToElementText(prevContainer || container);
    textRangeStart.collapse(!prevContainer);
    curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;
    var pointTester = textRange.duplicate();
    pointTester.setEndPoint('StartToStart', textRangeStart);
    var textCount = pointTester.text.replace(/[\r\n]/g, '').length;
    while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {
      textCount -= curTextNode.nodeValue.length;
      curTextNode = curTextNode.nextSibling;
    }

    // [workaround] enforce IE to re-reference curTextNode, hack
    var dummy = curTextNode.nodeValue; // eslint-disable-line

    if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) && textCount === curTextNode.nodeValue.length) {
      textCount -= curTextNode.nodeValue.length;
      curTextNode = curTextNode.nextSibling;
    }
    container = curTextNode;
    offset = textCount;
  }
  return {
    cont: container,
    offset: offset
  };
}

/**
 * return TextRange from boundary point (inspired by google closure-library)
 * @param {BoundaryPoint} point
 * @return {TextRange}
 */
function pointToTextRange(point) {
  var textRangeInfo = function textRangeInfo(container, offset) {
    var node, isCollapseToStart;
    if (dom.isText(container)) {
      var prevTextNodes = dom.listPrev(container, func.not(dom.isText));
      var prevContainer = lists.last(prevTextNodes).previousSibling;
      node = prevContainer || container.parentNode;
      offset += lists.sum(lists.tail(prevTextNodes), dom.nodeLength);
      isCollapseToStart = !prevContainer;
    } else {
      node = container.childNodes[offset] || container;
      if (dom.isText(node)) {
        return textRangeInfo(node, 0);
      }
      offset = 0;
      isCollapseToStart = false;
    }
    return {
      node: node,
      collapseToStart: isCollapseToStart,
      offset: offset
    };
  };
  var textRange = document.body.createTextRange();
  var info = textRangeInfo(point.node, point.offset);
  textRange.moveToElementText(info.node);
  textRange.collapse(info.collapseToStart);
  textRange.moveStart('character', info.offset);
  return textRange;
}

/**
   * Wrapped Range
   *
   * @constructor
   * @param {Node} sc - start container
   * @param {Number} so - start offset
   * @param {Node} ec - end container
   * @param {Number} eo - end offset
   */
var WrappedRange = /*#__PURE__*/function () {
  function WrappedRange(sc, so, ec, eo) {
    range_classCallCheck(this, WrappedRange);
    this.sc = sc;
    this.so = so;
    this.ec = ec;
    this.eo = eo;

    // isOnEditable: judge whether range is on editable or not
    this.isOnEditable = this.makeIsOn(dom.isEditable);
    // isOnList: judge whether range is on list node or not
    this.isOnList = this.makeIsOn(dom.isList);
    // isOnAnchor: judge whether range is on anchor node or not
    this.isOnAnchor = this.makeIsOn(dom.isAnchor);
    // isOnCell: judge whether range is on cell node or not
    this.isOnCell = this.makeIsOn(dom.isCell);
    // isOnData: judge whether range is on data node or not
    this.isOnData = this.makeIsOn(dom.isData);
  }

  // nativeRange: get nativeRange from sc, so, ec, eo
  return range_createClass(WrappedRange, [{
    key: "nativeRange",
    value: function nativeRange() {
      if (env.isW3CRangeSupport) {
        var w3cRange = document.createRange();
        w3cRange.setStart(this.sc, this.so);
        w3cRange.setEnd(this.ec, this.eo);
        return w3cRange;
      } else {
        var textRange = pointToTextRange({
          node: this.sc,
          offset: this.so
        });
        textRange.setEndPoint('EndToEnd', pointToTextRange({
          node: this.ec,
          offset: this.eo
        }));
        return textRange;
      }
    }
  }, {
    key: "getPoints",
    value: function getPoints() {
      return {
        sc: this.sc,
        so: this.so,
        ec: this.ec,
        eo: this.eo
      };
    }
  }, {
    key: "getStartPoint",
    value: function getStartPoint() {
      return {
        node: this.sc,
        offset: this.so
      };
    }
  }, {
    key: "getEndPoint",
    value: function getEndPoint() {
      return {
        node: this.ec,
        offset: this.eo
      };
    }

    /**
     * select update visible range
     */
  }, {
    key: "select",
    value: function select() {
      var nativeRng = this.nativeRange();
      if (env.isW3CRangeSupport) {
        var selection = document.getSelection();
        if (selection.rangeCount > 0) {
          selection.removeAllRanges();
        }
        selection.addRange(nativeRng);
      } else {
        nativeRng.select();
      }
      return this;
    }

    /**
     * Moves the scrollbar to start container(sc) of current range
     *
     * @return {WrappedRange}
     */
  }, {
    key: "scrollIntoView",
    value: function scrollIntoView(container) {
      var height = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(container).height();
      if (container.scrollTop + height < this.sc.offsetTop) {
        container.scrollTop += Math.abs(container.scrollTop + height - this.sc.offsetTop);
      }
      return this;
    }

    /**
     * @return {WrappedRange}
     */
  }, {
    key: "normalize",
    value: function normalize() {
      /**
       * @param {BoundaryPoint} point
       * @param {Boolean} isLeftToRight - true: prefer to choose right node
       *                                - false: prefer to choose left node
       * @return {BoundaryPoint}
       */
      var getVisiblePoint = function getVisiblePoint(point, isLeftToRight) {
        if (!point) {
          return point;
        }

        // Just use the given point [XXX:Adhoc]
        //  - case 01. if the point is on the middle of the node
        //  - case 02. if the point is on the right edge and prefer to choose left node
        //  - case 03. if the point is on the left edge and prefer to choose right node
        //  - case 04. if the point is on the right edge and prefer to choose right node but the node is void
        //  - case 05. if the point is on the left edge and prefer to choose left node but the node is void
        //  - case 06. if the point is on the block node and there is no children
        if (dom.isVisiblePoint(point)) {
          if (!dom.isEdgePoint(point) || dom.isRightEdgePoint(point) && !isLeftToRight || dom.isLeftEdgePoint(point) && isLeftToRight || dom.isRightEdgePoint(point) && isLeftToRight && dom.isVoid(point.node.nextSibling) || dom.isLeftEdgePoint(point) && !isLeftToRight && dom.isVoid(point.node.previousSibling) || dom.isBlock(point.node) && dom.isEmpty(point.node)) {
            return point;
          }
        }

        // point on block's edge
        var block = dom.ancestor(point.node, dom.isBlock);
        var hasRightNode = false;
        if (!hasRightNode) {
          var prevPoint = dom.prevPoint(point) || {
            node: null
          };
          hasRightNode = (dom.isLeftEdgePointOf(point, block) || dom.isVoid(prevPoint.node)) && !isLeftToRight;
        }
        var hasLeftNode = false;
        if (!hasLeftNode) {
          var _nextPoint = dom.nextPoint(point) || {
            node: null
          };
          hasLeftNode = (dom.isRightEdgePointOf(point, block) || dom.isVoid(_nextPoint.node)) && isLeftToRight;
        }
        if (hasRightNode || hasLeftNode) {
          // returns point already on visible point
          if (dom.isVisiblePoint(point)) {
            return point;
          }
          // reverse direction
          isLeftToRight = !isLeftToRight;
        }
        var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint) : dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);
        return nextPoint || point;
      };
      var endPoint = getVisiblePoint(this.getEndPoint(), false);
      var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);
      return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
    }

    /**
     * returns matched nodes on range
     *
     * @param {Function} [pred] - predicate function
     * @param {Object} [options]
     * @param {Boolean} [options.includeAncestor]
     * @param {Boolean} [options.fullyContains]
     * @return {Node[]}
     */
  }, {
    key: "nodes",
    value: function nodes(pred, options) {
      pred = pred || func.ok;
      var includeAncestor = options && options.includeAncestor;
      var fullyContains = options && options.fullyContains;

      // TODO compare points and sort
      var startPoint = this.getStartPoint();
      var endPoint = this.getEndPoint();
      var nodes = [];
      var leftEdgeNodes = [];
      dom.walkPoint(startPoint, endPoint, function (point) {
        if (dom.isEditable(point.node)) {
          return;
        }
        var node;
        if (fullyContains) {
          if (dom.isLeftEdgePoint(point)) {
            leftEdgeNodes.push(point.node);
          }
          if (dom.isRightEdgePoint(point) && lists.contains(leftEdgeNodes, point.node)) {
            node = point.node;
          }
        } else if (includeAncestor) {
          node = dom.ancestor(point.node, pred);
        } else {
          node = point.node;
        }
        if (node && pred(node)) {
          nodes.push(node);
        }
      }, true);
      return lists.unique(nodes);
    }

    /**
     * returns commonAncestor of range
     * @return {Element} - commonAncestor
     */
  }, {
    key: "commonAncestor",
    value: function commonAncestor() {
      return dom.commonAncestor(this.sc, this.ec);
    }

    /**
     * returns expanded range by pred
     *
     * @param {Function} pred - predicate function
     * @return {WrappedRange}
     */
  }, {
    key: "expand",
    value: function expand(pred) {
      var startAncestor = dom.ancestor(this.sc, pred);
      var endAncestor = dom.ancestor(this.ec, pred);
      if (!startAncestor && !endAncestor) {
        return new WrappedRange(this.sc, this.so, this.ec, this.eo);
      }
      var boundaryPoints = this.getPoints();
      if (startAncestor) {
        boundaryPoints.sc = startAncestor;
        boundaryPoints.so = 0;
      }
      if (endAncestor) {
        boundaryPoints.ec = endAncestor;
        boundaryPoints.eo = dom.nodeLength(endAncestor);
      }
      return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);
    }

    /**
     * @param {Boolean} isCollapseToStart
     * @return {WrappedRange}
     */
  }, {
    key: "collapse",
    value: function collapse(isCollapseToStart) {
      if (isCollapseToStart) {
        return new WrappedRange(this.sc, this.so, this.sc, this.so);
      } else {
        return new WrappedRange(this.ec, this.eo, this.ec, this.eo);
      }
    }

    /**
     * splitText on range
     */
  }, {
    key: "splitText",
    value: function splitText() {
      var isSameContainer = this.sc === this.ec;
      var boundaryPoints = this.getPoints();
      if (dom.isText(this.ec) && !dom.isEdgePoint(this.getEndPoint())) {
        this.ec.splitText(this.eo);
      }
      if (dom.isText(this.sc) && !dom.isEdgePoint(this.getStartPoint())) {
        boundaryPoints.sc = this.sc.splitText(this.so);
        boundaryPoints.so = 0;
        if (isSameContainer) {
          boundaryPoints.ec = boundaryPoints.sc;
          boundaryPoints.eo = this.eo - this.so;
        }
      }
      return new WrappedRange(boundaryPoints.sc, boundaryPoints.so, boundaryPoints.ec, boundaryPoints.eo);
    }

    /**
     * delete contents on range
     * @return {WrappedRange}
     */
  }, {
    key: "deleteContents",
    value: function deleteContents() {
      if (this.isCollapsed()) {
        return this;
      }
      var rng = this.splitText();
      var nodes = rng.nodes(null, {
        fullyContains: true
      });

      // find new cursor point
      var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {
        return !lists.contains(nodes, point.node);
      });
      var emptyParents = [];
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(nodes, function (idx, node) {
        // find empty parents
        var parent = node.parentNode;
        if (point.node !== parent && dom.nodeLength(parent) === 1) {
          emptyParents.push(parent);
        }
        dom.remove(node, false);
      });

      // remove empty parents
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(emptyParents, function (idx, node) {
        dom.remove(node, false);
      });
      return new WrappedRange(point.node, point.offset, point.node, point.offset).normalize();
    }

    /**
     * makeIsOn: return isOn(pred) function
     */
  }, {
    key: "makeIsOn",
    value: function makeIsOn(pred) {
      return function () {
        var ancestor = dom.ancestor(this.sc, pred);
        return !!ancestor && ancestor === dom.ancestor(this.ec, pred);
      };
    }

    /**
     * @param {Function} pred
     * @return {Boolean}
     */
  }, {
    key: "isLeftEdgeOf",
    value: function isLeftEdgeOf(pred) {
      if (!dom.isLeftEdgePoint(this.getStartPoint())) {
        return false;
      }
      var node = dom.ancestor(this.sc, pred);
      return node && dom.isLeftEdgeOf(this.sc, node);
    }

    /**
     * returns whether range was collapsed or not
     */
  }, {
    key: "isCollapsed",
    value: function isCollapsed() {
      return this.sc === this.ec && this.so === this.eo;
    }

    /**
     * wrap inline nodes which children of body with paragraph
     *
     * @return {WrappedRange}
     */
  }, {
    key: "wrapBodyInlineWithPara",
    value: function wrapBodyInlineWithPara() {
      if (dom.isBodyContainer(this.sc) && dom.isEmpty(this.sc)) {
        this.sc.innerHTML = dom.emptyPara;
        return new WrappedRange(this.sc.firstChild, 0, this.sc.firstChild, 0);
      }

      /**
       * [workaround] firefox often create range on not visible point. so normalize here.
       *  - firefox: |<p>text</p>|
       *  - chrome: <p>|text|</p>
       */
      var rng = this.normalize();
      if (dom.isParaInline(this.sc) || dom.isPara(this.sc)) {
        return rng;
      }

      // find inline top ancestor
      var topAncestor;
      if (dom.isInline(rng.sc)) {
        var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));
        topAncestor = lists.last(ancestors);
        if (!dom.isInline(topAncestor)) {
          topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];
        }
      } else {
        topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];
      }
      if (topAncestor) {
        // siblings not in paragraph
        var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();
        inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline));

        // wrap with paragraph
        if (inlineSiblings.length) {
          var para = dom.wrap(lists.head(inlineSiblings), 'p');
          dom.appendChildNodes(para, lists.tail(inlineSiblings));
        }
      }
      return this.normalize();
    }

    /**
     * insert node at current cursor
     *
     * @param {Node} node
     * @param {Boolean} doNotInsertPara - default is false, removes added <p> that's added if true
     * @return {Node}
     */
  }, {
    key: "insertNode",
    value: function insertNode(node) {
      var doNotInsertPara = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
      var rng = this;
      if (dom.isText(node) || dom.isInline(node)) {
        rng = this.wrapBodyInlineWithPara().deleteContents();
      }
      var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));
      if (info.rightNode) {
        info.rightNode.parentNode.insertBefore(node, info.rightNode);
        if (dom.isEmpty(info.rightNode) && (doNotInsertPara || dom.isPara(node))) {
          info.rightNode.parentNode.removeChild(info.rightNode);
        }
      } else {
        info.container.appendChild(node);
      }
      return node;
    }

    /**
     * insert html at current cursor
     */
  }, {
    key: "pasteHTML",
    value: function pasteHTML(markup) {
      markup = ((markup || '') + '').trim(markup);
      var contentsContainer = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div></div>').html(markup)[0];
      var childNodes = lists.from(contentsContainer.childNodes);

      // const rng = this.wrapBodyInlineWithPara().deleteContents();
      var rng = this;
      var reversed = false;
      if (rng.so >= 0) {
        childNodes = childNodes.reverse();
        reversed = true;
      }
      childNodes = childNodes.map(function (childNode) {
        return rng.insertNode(childNode, !dom.isInline(childNode));
      });
      if (reversed) {
        childNodes = childNodes.reverse();
      }
      return childNodes;
    }

    /**
     * returns text in range
     *
     * @return {String}
     */
  }, {
    key: "toString",
    value: function toString() {
      var nativeRng = this.nativeRange();
      return env.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;
    }

    /**
     * returns range for word before cursor
     *
     * @param {Boolean} [findAfter] - find after cursor, default: false
     * @return {WrappedRange}
     */
  }, {
    key: "getWordRange",
    value: function getWordRange(findAfter) {
      var endPoint = this.getEndPoint();
      if (!dom.isCharPoint(endPoint)) {
        return this;
      }
      var startPoint = dom.prevPointUntil(endPoint, function (point) {
        return !dom.isCharPoint(point);
      });
      if (findAfter) {
        endPoint = dom.nextPointUntil(endPoint, function (point) {
          return !dom.isCharPoint(point);
        });
      }
      return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
    }

    /**
     * returns range for words before cursor
     *
     * @param {Boolean} [findAfter] - find after cursor, default: false
     * @return {WrappedRange}
     */
  }, {
    key: "getWordsRange",
    value: function getWordsRange(findAfter) {
      var endPoint = this.getEndPoint();
      var isNotTextPoint = function isNotTextPoint(point) {
        return !dom.isCharPoint(point) && !dom.isSpacePoint(point);
      };
      if (isNotTextPoint(endPoint)) {
        return this;
      }
      var startPoint = dom.prevPointUntil(endPoint, isNotTextPoint);
      if (findAfter) {
        endPoint = dom.nextPointUntil(endPoint, isNotTextPoint);
      }
      return new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
    }

    /**
     * returns range for words before cursor that match with a Regex
     *
     * example:
     *  range: 'hi @Peter Pan'
     *  regex: '/@[a-z ]+/i'
     *  return range: '@Peter Pan'
     *
     * @param {RegExp} [regex]
     * @return {WrappedRange|null}
     */
  }, {
    key: "getWordsMatchRange",
    value: function getWordsMatchRange(regex) {
      var endPoint = this.getEndPoint();
      var startPoint = dom.prevPointUntil(endPoint, function (point) {
        if (!dom.isCharPoint(point) && !dom.isSpacePoint(point)) {
          return true;
        }
        var rng = new WrappedRange(point.node, point.offset, endPoint.node, endPoint.offset);
        var result = regex.exec(rng.toString());
        return result && result.index === 0;
      });
      var rng = new WrappedRange(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
      var text = rng.toString();
      var result = regex.exec(text);
      if (result && result[0].length === text.length) {
        return rng;
      } else {
        return null;
      }
    }

    /**
     * create offsetPath bookmark
     *
     * @param {Node} editable
     */
  }, {
    key: "bookmark",
    value: function bookmark(editable) {
      return {
        s: {
          path: dom.makeOffsetPath(editable, this.sc),
          offset: this.so
        },
        e: {
          path: dom.makeOffsetPath(editable, this.ec),
          offset: this.eo
        }
      };
    }

    /**
     * create offsetPath bookmark base on paragraph
     *
     * @param {Node[]} paras
     */
  }, {
    key: "paraBookmark",
    value: function paraBookmark(paras) {
      return {
        s: {
          path: lists.tail(dom.makeOffsetPath(lists.head(paras), this.sc)),
          offset: this.so
        },
        e: {
          path: lists.tail(dom.makeOffsetPath(lists.last(paras), this.ec)),
          offset: this.eo
        }
      };
    }

    /**
     * getClientRects
     * @return {Rect[]}
     */
  }, {
    key: "getClientRects",
    value: function getClientRects() {
      var nativeRng = this.nativeRange();
      return nativeRng.getClientRects();
    }
  }]);
}();
/**
 * Data structure
 *  * BoundaryPoint: a point of dom tree
 *  * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range
 *
 * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position
 */
/* harmony default export */ const range = ({
  /**
   * create Range Object From arguments or Browser Selection
   *
   * @param {Node} sc - start container
   * @param {Number} so - start offset
   * @param {Node} ec - end container
   * @param {Number} eo - end offset
   * @return {WrappedRange}
   */
  create: function create(sc, so, ec, eo) {
    if (arguments.length === 4) {
      return new WrappedRange(sc, so, ec, eo);
    } else if (arguments.length === 2) {
      // collapsed
      ec = sc;
      eo = so;
      return new WrappedRange(sc, so, ec, eo);
    } else {
      var wrappedRange = this.createFromSelection();
      if (!wrappedRange && arguments.length === 1) {
        var bodyElement = arguments[0];
        if (dom.isEditable(bodyElement)) {
          bodyElement = bodyElement.lastChild;
        }
        return this.createFromBodyElement(bodyElement, dom.emptyPara === arguments[0].innerHTML);
      }
      return wrappedRange;
    }
  },
  createFromBodyElement: function createFromBodyElement(bodyElement) {
    var isCollapseToStart = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
    var wrappedRange = this.createFromNode(bodyElement);
    return wrappedRange.collapse(isCollapseToStart);
  },
  createFromSelection: function createFromSelection() {
    var sc, so, ec, eo;
    if (env.isW3CRangeSupport) {
      var selection = document.getSelection();
      if (!selection || selection.rangeCount === 0) {
        return null;
      } else if (dom.isBody(selection.anchorNode)) {
        // Firefox: returns entire body as range on initialization.
        // We won't never need it.
        return null;
      }
      var nativeRng = selection.getRangeAt(0);
      sc = nativeRng.startContainer;
      so = nativeRng.startOffset;
      ec = nativeRng.endContainer;
      eo = nativeRng.endOffset;
    } else {
      // IE8: TextRange
      var textRange = document.selection.createRange();
      var textRangeEnd = textRange.duplicate();
      textRangeEnd.collapse(false);
      var textRangeStart = textRange;
      textRangeStart.collapse(true);
      var startPoint = textRangeToPoint(textRangeStart, true);
      var endPoint = textRangeToPoint(textRangeEnd, false);

      // same visible point case: range was collapsed.
      if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) && dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) && endPoint.node.nextSibling === startPoint.node) {
        startPoint = endPoint;
      }
      sc = startPoint.cont;
      so = startPoint.offset;
      ec = endPoint.cont;
      eo = endPoint.offset;
    }
    return new WrappedRange(sc, so, ec, eo);
  },
  /**
   * @method
   *
   * create WrappedRange from node
   *
   * @param {Node} node
   * @return {WrappedRange}
   */
  createFromNode: function createFromNode(node) {
    var sc = node;
    var so = 0;
    var ec = node;
    var eo = dom.nodeLength(ec);

    // browsers can't target a picture or void node
    if (dom.isVoid(sc)) {
      so = dom.listPrev(sc).length - 1;
      sc = sc.parentNode;
    }
    if (dom.isBR(ec)) {
      eo = dom.listPrev(ec).length - 1;
      ec = ec.parentNode;
    } else if (dom.isVoid(ec)) {
      eo = dom.listPrev(ec).length;
      ec = ec.parentNode;
    }
    return this.create(sc, so, ec, eo);
  },
  /**
   * create WrappedRange from node after position
   *
   * @param {Node} node
   * @return {WrappedRange}
   */
  createFromNodeBefore: function createFromNodeBefore(node) {
    return this.createFromNode(node).collapse(true);
  },
  /**
   * create WrappedRange from node after position
   *
   * @param {Node} node
   * @return {WrappedRange}
   */
  createFromNodeAfter: function createFromNodeAfter(node) {
    return this.createFromNode(node).collapse();
  },
  /**
   * @method
   *
   * create WrappedRange from bookmark
   *
   * @param {Node} editable
   * @param {Object} bookmark
   * @return {WrappedRange}
   */
  createFromBookmark: function createFromBookmark(editable, bookmark) {
    var sc = dom.fromOffsetPath(editable, bookmark.s.path);
    var so = bookmark.s.offset;
    var ec = dom.fromOffsetPath(editable, bookmark.e.path);
    var eo = bookmark.e.offset;
    return new WrappedRange(sc, so, ec, eo);
  },
  /**
   * @method
   *
   * create WrappedRange from paraBookmark
   *
   * @param {Object} bookmark
   * @param {Node[]} paras
   * @return {WrappedRange}
   */
  createFromParaBookmark: function createFromParaBookmark(bookmark, paras) {
    var so = bookmark.s.offset;
    var eo = bookmark.e.offset;
    var sc = dom.fromOffsetPath(lists.head(paras), bookmark.s.path);
    var ec = dom.fromOffsetPath(lists.last(paras), bookmark.e.path);
    return new WrappedRange(sc, so, ec, eo);
  }
});
;// CONCATENATED MODULE: ./src/js/core/key.js


var KEY_MAP = {
  'BACKSPACE': 8,
  'TAB': 9,
  'ENTER': 13,
  'ESCAPE': 27,
  'SPACE': 32,
  'DELETE': 46,
  // Arrow
  'LEFT': 37,
  'UP': 38,
  'RIGHT': 39,
  'DOWN': 40,
  // Number: 0-9
  'NUM0': 48,
  'NUM1': 49,
  'NUM2': 50,
  'NUM3': 51,
  'NUM4': 52,
  'NUM5': 53,
  'NUM6': 54,
  'NUM7': 55,
  'NUM8': 56,
  // Alphabet: a-z
  'B': 66,
  'E': 69,
  'I': 73,
  'J': 74,
  'K': 75,
  'L': 76,
  'R': 82,
  'S': 83,
  'U': 85,
  'V': 86,
  'Y': 89,
  'Z': 90,
  'SLASH': 191,
  'LEFTBRACKET': 219,
  'BACKSLASH': 220,
  'RIGHTBRACKET': 221,
  // Navigation
  'HOME': 36,
  'END': 35,
  'PAGEUP': 33,
  'PAGEDOWN': 34
};

/**
 * @class core.key
 *
 * Object for keycodes.
 *
 * @singleton
 * @alternateClassName key
 */
/* harmony default export */ const key = ({
  /**
   * @method isEdit
   *
   * @param {Number} keyCode
   * @return {Boolean}
   */
  isEdit: function isEdit(keyCode) {
    return lists.contains([KEY_MAP.BACKSPACE, KEY_MAP.TAB, KEY_MAP.ENTER, KEY_MAP.SPACE, KEY_MAP.DELETE], keyCode);
  },
  /**
   * @method isRemove
   *
   * @param {Number} keyCode
   * @return {Boolean}
   */
  isRemove: function isRemove(keyCode) {
    // LB
    return lists.contains([KEY_MAP.BACKSPACE, KEY_MAP.DELETE], keyCode);
  },
  /**
   * @method isMove
   *
   * @param {Number} keyCode
   * @return {Boolean}
   */
  isMove: function isMove(keyCode) {
    return lists.contains([KEY_MAP.LEFT, KEY_MAP.UP, KEY_MAP.RIGHT, KEY_MAP.DOWN], keyCode);
  },
  /**
   * @method isNavigation
   *
   * @param {Number} keyCode
   * @return {Boolean}
   */
  isNavigation: function isNavigation(keyCode) {
    return lists.contains([KEY_MAP.HOME, KEY_MAP.END, KEY_MAP.PAGEUP, KEY_MAP.PAGEDOWN], keyCode);
  },
  /**
   * @property {Object} nameFromCode
   * @property {String} nameFromCode.8 "BACKSPACE"
   */
  nameFromCode: func.invertObject(KEY_MAP),
  code: KEY_MAP
});
;// CONCATENATED MODULE: ./src/js/core/async.js


/**
 * @method readFileAsDataURL
 *
 * read contents of file as representing URL
 *
 * @param {File} file
 * @return {Promise} - then: dataUrl
 */
function readFileAsDataURL(file) {
  return external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().Deferred(function (deferred) {
    external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend(new FileReader(), {
      onload: function onload(event) {
        var dataURL = event.target.result;
        deferred.resolve(dataURL);
      },
      onerror: function onerror(err) {
        deferred.reject(err);
      }
    }).readAsDataURL(file);
  }).promise();
}

/**
 * @method createImage
 *
 * create `<image>` from url string
 *
 * @param {String} url
 * @return {Promise} - then: $image
 */
function createImage(url) {
  return external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().Deferred(function (deferred) {
    var $img = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<img>');
    $img.one('load', function () {
      $img.off('error abort');
      deferred.resolve($img);
    }).one('error abort', function () {
      $img.off('load').detach();
      deferred.reject($img);
    }).css({
      display: 'none'
    }).appendTo(document.body).attr('src', url);
  }).promise();
}
;// CONCATENATED MODULE: ./src/js/editing/History.js
function History_typeof(o) { "@babel/helpers - typeof"; return History_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, History_typeof(o); }
function History_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function History_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, History_toPropertyKey(o.key), o); } }
function History_createClass(e, r, t) { return r && History_defineProperties(e.prototype, r), t && History_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function History_toPropertyKey(t) { var i = History_toPrimitive(t, "string"); return "symbol" == History_typeof(i) ? i : i + ""; }
function History_toPrimitive(t, r) { if ("object" != History_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != History_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var History = /*#__PURE__*/function () {
  function History(context) {
    History_classCallCheck(this, History);
    this.stack = [];
    this.stackOffset = -1;
    this.context = context;
    this.$editable = context.layoutInfo.editable;
    this.editable = this.$editable[0];
  }
  return History_createClass(History, [{
    key: "makeSnapshot",
    value: function makeSnapshot() {
      var rng = range.create(this.editable);
      var emptyBookmark = {
        s: {
          path: [],
          offset: 0
        },
        e: {
          path: [],
          offset: 0
        }
      };
      return {
        contents: this.$editable.html(),
        bookmark: rng && rng.isOnEditable() ? rng.bookmark(this.editable) : emptyBookmark
      };
    }
  }, {
    key: "applySnapshot",
    value: function applySnapshot(snapshot) {
      if (snapshot.contents !== null) {
        this.$editable.html(snapshot.contents);
      }
      if (snapshot.bookmark !== null) {
        range.createFromBookmark(this.editable, snapshot.bookmark).select();
      }
    }

    /**
    * @method rewind
    * Rewinds the history stack back to the first snapshot taken.
    * Leaves the stack intact, so that "Redo" can still be used.
    */
  }, {
    key: "rewind",
    value: function rewind() {
      // Create snap shot if not yet recorded
      if (this.$editable.html() !== this.stack[this.stackOffset].contents) {
        this.recordUndo();
      }

      // Return to the first available snapshot.
      this.stackOffset = 0;

      // Apply that snapshot.
      this.applySnapshot(this.stack[this.stackOffset]);
    }

    /**
    *  @method commit
    *  Resets history stack, but keeps current editor's content.
    */
  }, {
    key: "commit",
    value: function commit() {
      // Clear the stack.
      this.stack = [];

      // Restore stackOffset to its original value.
      this.stackOffset = -1;

      // Record our first snapshot (of nothing).
      this.recordUndo();
    }

    /**
    * @method reset
    * Resets the history stack completely; reverting to an empty editor.
    */
  }, {
    key: "reset",
    value: function reset() {
      // Clear the stack.
      this.stack = [];

      // Restore stackOffset to its original value.
      this.stackOffset = -1;

      // Clear the editable area.
      this.$editable.html('');

      // Record our first snapshot (of nothing).
      this.recordUndo();
    }

    /**
     * undo
     */
  }, {
    key: "undo",
    value: function undo() {
      // Create snap shot if not yet recorded
      if (this.$editable.html() !== this.stack[this.stackOffset].contents) {
        this.recordUndo();
      }
      if (this.stackOffset > 0) {
        this.stackOffset--;
        this.applySnapshot(this.stack[this.stackOffset]);
      }
    }

    /**
     * redo
     */
  }, {
    key: "redo",
    value: function redo() {
      if (this.stack.length - 1 > this.stackOffset) {
        this.stackOffset++;
        this.applySnapshot(this.stack[this.stackOffset]);
      }
    }

    /**
     * recorded undo
     */
  }, {
    key: "recordUndo",
    value: function recordUndo() {
      this.stackOffset++;

      // Wash out stack after stackOffset
      if (this.stack.length > this.stackOffset) {
        this.stack = this.stack.slice(0, this.stackOffset);
      }

      // Create new snapshot and push it to the end
      this.stack.push(this.makeSnapshot());

      // If the stack size reachs to the limit, then slice it
      if (this.stack.length > this.context.options.historyLimit) {
        this.stack.shift();
        this.stackOffset -= 1;
      }
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/editing/Style.js
function Style_typeof(o) { "@babel/helpers - typeof"; return Style_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Style_typeof(o); }
function Style_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Style_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Style_toPropertyKey(o.key), o); } }
function Style_createClass(e, r, t) { return r && Style_defineProperties(e.prototype, r), t && Style_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Style_toPropertyKey(t) { var i = Style_toPrimitive(t, "string"); return "symbol" == Style_typeof(i) ? i : i + ""; }
function Style_toPrimitive(t, r) { if ("object" != Style_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Style_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }




var Style = /*#__PURE__*/function () {
  function Style() {
    Style_classCallCheck(this, Style);
  }
  return Style_createClass(Style, [{
    key: "jQueryCSS",
    value:
    /**
     * @method jQueryCSS
     *
     * [workaround] for old jQuery
     * passing an array of style properties to .css()
     * will result in an object of property-value pairs.
     * (compability with version < 1.9)
     *
     * @private
     * @param  {jQuery} $obj
     * @param  {Array} propertyNames - An array of one or more CSS properties.
     * @return {Object}
     */
    function jQueryCSS($obj, propertyNames) {
      var result = {};
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(propertyNames, function (idx, propertyName) {
        result[propertyName] = $obj.css(propertyName);
      });
      return result;
    }

    /**
     * returns style object from node
     *
     * @param {jQuery} $node
     * @return {Object}
     */
  }, {
    key: "fromNode",
    value: function fromNode($node) {
      var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];
      var styleInfo = this.jQueryCSS($node, properties) || {};
      var fontSize = $node[0].style.fontSize || styleInfo['font-size'];
      styleInfo['font-size'] = parseInt(fontSize, 10);
      styleInfo['font-size-unit'] = fontSize.match(/[a-z%]+$/);
      return styleInfo;
    }

    /**
     * paragraph level style
     *
     * @param {WrappedRange} rng
     * @param {Object} styleInfo
     */
  }, {
    key: "stylePara",
    value: function stylePara(rng, styleInfo) {
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(rng.nodes(dom.isPara, {
        includeAncestor: true
      }), function (idx, para) {
        external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(para).css(styleInfo);
      });
    }

    /**
     * insert and returns styleNodes on range.
     *
     * @param {WrappedRange} rng
     * @param {Object} [options] - options for styleNodes
     * @param {String} [options.nodeName] - default: `SPAN`
     * @param {Boolean} [options.expandClosestSibling] - default: `false`
     * @param {Boolean} [options.onlyPartialContains] - default: `false`
     * @return {Node[]}
     */
  }, {
    key: "styleNodes",
    value: function styleNodes(rng, options) {
      rng = rng.splitText();
      var nodeName = options && options.nodeName || 'SPAN';
      var expandClosestSibling = !!(options && options.expandClosestSibling);
      var onlyPartialContains = !!(options && options.onlyPartialContains);
      if (rng.isCollapsed()) {
        return [rng.insertNode(dom.create(nodeName))];
      }
      var pred = dom.makePredByNodeName(nodeName);
      var nodes = rng.nodes(dom.isText, {
        fullyContains: true
      }).map(function (text) {
        return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);
      });
      if (expandClosestSibling) {
        if (onlyPartialContains) {
          var nodesInRange = rng.nodes();
          // compose with partial contains predication
          pred = func.and(pred, function (node) {
            return lists.contains(nodesInRange, node);
          });
        }
        return nodes.map(function (node) {
          var siblings = dom.withClosestSiblings(node, pred);
          var head = lists.head(siblings);
          var tails = lists.tail(siblings);
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(tails, function (idx, elem) {
            dom.appendChildNodes(head, elem.childNodes);
            dom.remove(elem);
          });
          return lists.head(siblings);
        });
      } else {
        return nodes;
      }
    }

    /**
     * get current style on cursor
     *
     * @param {WrappedRange} rng
     * @return {Object} - object contains style properties.
     */
  }, {
    key: "current",
    value: function current(rng) {
      var $cont = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(!dom.isElement(rng.sc) ? rng.sc.parentNode : rng.sc);
      var styleInfo = this.fromNode($cont);

      // document.queryCommandState for toggle state
      // [workaround] prevent Firefox nsresult: "0x80004005 (NS_ERROR_FAILURE)"
      try {
        styleInfo = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend(styleInfo, {
          'font-bold': document.queryCommandState('bold') ? 'bold' : 'normal',
          'font-italic': document.queryCommandState('italic') ? 'italic' : 'normal',
          'font-underline': document.queryCommandState('underline') ? 'underline' : 'normal',
          'font-subscript': document.queryCommandState('subscript') ? 'subscript' : 'normal',
          'font-superscript': document.queryCommandState('superscript') ? 'superscript' : 'normal',
          'font-strikethrough': document.queryCommandState('strikethrough') ? 'strikethrough' : 'normal',
          'font-family': document.queryCommandValue('fontname') || styleInfo['font-family']
        });
      } catch (e) {
        // eslint-disable-next-line
      }

      // list-style-type to list-style(unordered, ordered)
      if (!rng.isOnList()) {
        styleInfo['list-style'] = 'none';
      } else {
        var orderedTypes = ['circle', 'disc', 'disc-leading-zero', 'square'];
        var isUnordered = orderedTypes.indexOf(styleInfo['list-style-type']) > -1;
        styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';
      }
      var para = dom.ancestor(rng.sc, dom.isPara);
      if (para && para.style['line-height']) {
        styleInfo['line-height'] = para.style.lineHeight;
      } else {
        var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);
        styleInfo['line-height'] = lineHeight.toFixed(1);
      }
      styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);
      styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);
      styleInfo.range = rng;
      return styleInfo;
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/editing/Bullet.js
function Bullet_typeof(o) { "@babel/helpers - typeof"; return Bullet_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Bullet_typeof(o); }
function Bullet_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Bullet_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Bullet_toPropertyKey(o.key), o); } }
function Bullet_createClass(e, r, t) { return r && Bullet_defineProperties(e.prototype, r), t && Bullet_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Bullet_toPropertyKey(t) { var i = Bullet_toPrimitive(t, "string"); return "symbol" == Bullet_typeof(i) ? i : i + ""; }
function Bullet_toPrimitive(t, r) { if ("object" != Bullet_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Bullet_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }





var Bullet = /*#__PURE__*/function () {
  function Bullet() {
    Bullet_classCallCheck(this, Bullet);
  }
  return Bullet_createClass(Bullet, [{
    key: "insertOrderedList",
    value:
    /**
     * toggle ordered list
     */
    function insertOrderedList(editable) {
      this.toggleList('OL', editable);
    }

    /**
     * toggle unordered list
     */
  }, {
    key: "insertUnorderedList",
    value: function insertUnorderedList(editable) {
      this.toggleList('UL', editable);
    }

    /**
     * indent
     */
  }, {
    key: "indent",
    value: function indent(editable) {
      var _this = this;
      var rng = range.create(editable).wrapBodyInlineWithPara();
      var paras = rng.nodes(dom.isPara, {
        includeAncestor: true
      });
      var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(clustereds, function (idx, paras) {
        var head = lists.head(paras);
        if (dom.isLi(head)) {
          var previousList = _this.findList(head.previousSibling);
          if (previousList) {
            paras.map(function (para) {
              return previousList.appendChild(para);
            });
          } else {
            _this.wrapList(paras, head.parentNode.nodeName);
            paras.map(function (para) {
              return para.parentNode;
            }).map(function (para) {
              return _this.appendToPrevious(para);
            });
          }
        } else {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(paras, function (idx, para) {
            external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(para).css('marginLeft', function (idx, val) {
              return (parseInt(val, 10) || 0) + 25;
            });
          });
        }
      });
      rng.select();
    }

    /**
     * outdent
     */
  }, {
    key: "outdent",
    value: function outdent(editable) {
      var _this2 = this;
      var rng = range.create(editable).wrapBodyInlineWithPara();
      var paras = rng.nodes(dom.isPara, {
        includeAncestor: true
      });
      var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(clustereds, function (idx, paras) {
        var head = lists.head(paras);
        if (dom.isLi(head)) {
          _this2.releaseList([paras]);
        } else {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(paras, function (idx, para) {
            external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(para).css('marginLeft', function (idx, val) {
              val = parseInt(val, 10) || 0;
              return val > 25 ? val - 25 : '';
            });
          });
        }
      });
      rng.select();
    }

    /**
     * toggle list
     *
     * @param {String} listName - OL or UL
     */
  }, {
    key: "toggleList",
    value: function toggleList(listName, editable) {
      var _this3 = this;
      var rng = range.create(editable).wrapBodyInlineWithPara();
      var paras = rng.nodes(dom.isPara, {
        includeAncestor: true
      });
      var bookmark = rng.paraBookmark(paras);
      var clustereds = lists.clusterBy(paras, func.peq2('parentNode'));

      // paragraph to list
      if (lists.find(paras, dom.isPurePara)) {
        var wrappedParas = [];
        external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(clustereds, function (idx, paras) {
          wrappedParas = wrappedParas.concat(_this3.wrapList(paras, listName));
        });
        paras = wrappedParas;
        // list to paragraph or change list style
      } else {
        var diffLists = rng.nodes(dom.isList, {
          includeAncestor: true
        }).filter(function (listNode) {
          return !external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().nodeName(listNode, listName);
        });
        if (diffLists.length) {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(diffLists, function (idx, listNode) {
            dom.replace(listNode, listName);
          });
        } else {
          paras = this.releaseList(clustereds, true);
        }
      }
      range.createFromParaBookmark(bookmark, paras).select();
    }

    /**
     * @param {Node[]} paras
     * @param {String} listName
     * @return {Node[]}
     */
  }, {
    key: "wrapList",
    value: function wrapList(paras, listName) {
      var head = lists.head(paras);
      var last = lists.last(paras);
      var prevList = dom.isList(head.previousSibling) && head.previousSibling;
      var nextList = dom.isList(last.nextSibling) && last.nextSibling;
      var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last);

      // P to LI
      paras = paras.map(function (para) {
        return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;
      });

      // append to list(<ul>, <ol>)
      dom.appendChildNodes(listNode, paras, true);
      if (nextList) {
        dom.appendChildNodes(listNode, lists.from(nextList.childNodes), true);
        dom.remove(nextList);
      }
      return paras;
    }

    /**
     * @method releaseList
     *
     * @param {Array[]} clustereds
     * @param {Boolean} isEscapseToBody
     * @return {Node[]}
     */
  }, {
    key: "releaseList",
    value: function releaseList(clustereds, isEscapseToBody) {
      var _this4 = this;
      var releasedParas = [];
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(clustereds, function (idx, paras) {
        var head = lists.head(paras);
        var last = lists.last(paras);
        var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) : head.parentNode;
        var parentItem = headList.parentNode;
        if (headList.parentNode.nodeName === 'LI') {
          paras.map(function (para) {
            var newList = _this4.findNextSiblings(para);
            if (parentItem.nextSibling) {
              parentItem.parentNode.insertBefore(para, parentItem.nextSibling);
            } else {
              parentItem.parentNode.appendChild(para);
            }
            if (newList.length) {
              _this4.wrapList(newList, headList.nodeName);
              para.appendChild(newList[0].parentNode);
            }
          });
          if (headList.children.length === 0) {
            parentItem.removeChild(headList);
          }
          if (parentItem.childNodes.length === 0) {
            parentItem.parentNode.removeChild(parentItem);
          }
        } else {
          var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {
            node: last.parentNode,
            offset: dom.position(last) + 1
          }, {
            isSkipPaddingBlankHTML: true
          }) : null;
          var middleList = dom.splitTree(headList, {
            node: head.parentNode,
            offset: dom.position(head)
          }, {
            isSkipPaddingBlankHTML: true
          });
          paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) : lists.from(middleList.childNodes).filter(dom.isLi);

          // LI to P
          if (isEscapseToBody || !dom.isList(headList.parentNode)) {
            paras = paras.map(function (para) {
              return dom.replace(para, 'P');
            });
          }
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(lists.from(paras).reverse(), function (idx, para) {
            dom.insertAfter(para, headList);
          });

          // remove empty lists
          var rootLists = lists.compact([headList, middleList, lastList]);
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(rootLists, function (idx, rootList) {
            var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));
            external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(listNodes.reverse(), function (idx, listNode) {
              if (!dom.nodeLength(listNode)) {
                dom.remove(listNode, true);
              }
            });
          });
        }
        releasedParas = releasedParas.concat(paras);
      });
      return releasedParas;
    }

    /**
     * @method appendToPrevious
     *
     * Appends list to previous list item, if
     * none exist it wraps the list in a new list item.
     *
     * @param {HTMLNode} ListItem
     * @return {HTMLNode}
     */
  }, {
    key: "appendToPrevious",
    value: function appendToPrevious(node) {
      return node.previousSibling ? dom.appendChildNodes(node.previousSibling, [node]) : this.wrapList([node], 'LI');
    }

    /**
     * @method findList
     *
     * Finds an existing list in list item
     *
     * @param {HTMLNode} ListItem
     * @return {Array[]}
     */
  }, {
    key: "findList",
    value: function findList(node) {
      return node ? lists.find(node.children, function (child) {
        return ['OL', 'UL'].indexOf(child.nodeName) > -1;
      }) : null;
    }

    /**
     * @method findNextSiblings
     *
     * Finds all list item siblings that follow it
     *
     * @param {HTMLNode} ListItem
     * @return {HTMLNode}
     */
  }, {
    key: "findNextSiblings",
    value: function findNextSiblings(node) {
      var siblings = [];
      while (node.nextSibling) {
        siblings.push(node.nextSibling);
        node = node.nextSibling;
      }
      return siblings;
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/editing/Typing.js
function Typing_typeof(o) { "@babel/helpers - typeof"; return Typing_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Typing_typeof(o); }
function Typing_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Typing_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Typing_toPropertyKey(o.key), o); } }
function Typing_createClass(e, r, t) { return r && Typing_defineProperties(e.prototype, r), t && Typing_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Typing_toPropertyKey(t) { var i = Typing_toPrimitive(t, "string"); return "symbol" == Typing_typeof(i) ? i : i + ""; }
function Typing_toPrimitive(t, r) { if ("object" != Typing_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Typing_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }





/**
 * @class editing.Typing
 *
 * Typing
 *
 */
var Typing = /*#__PURE__*/function () {
  function Typing(context) {
    Typing_classCallCheck(this, Typing);
    // a Bullet instance to toggle lists off
    this.bullet = new Bullet();
    this.options = context.options;
  }

  /**
   * insert tab
   *
   * @param {WrappedRange} rng
   * @param {Number} tabsize
   */
  return Typing_createClass(Typing, [{
    key: "insertTab",
    value: function insertTab(rng, tabsize) {
      var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));
      rng = rng.deleteContents();
      rng.insertNode(tab, true);
      rng = range.create(tab, tabsize);
      rng.select();
    }

    /**
     * insert paragraph
     *
     * @param {jQuery} $editable
     * @param {WrappedRange} rng Can be used in unit tests to "mock" the range
     *
     * blockquoteBreakingLevel
     *   0 - No break, the new paragraph remains inside the quote
     *   1 - Break the first blockquote in the ancestors list
     *   2 - Break all blockquotes, so that the new paragraph is not quoted (this is the default)
     */
  }, {
    key: "insertParagraph",
    value: function insertParagraph(editable, rng) {
      rng = rng || range.create(editable);

      // deleteContents on range.
      rng = rng.deleteContents();

      // Wrap range if it needs to be wrapped by paragraph
      rng = rng.wrapBodyInlineWithPara();

      // finding paragraph
      var splitRoot = dom.ancestor(rng.sc, dom.isPara);
      var nextPara;
      // on paragraph: split paragraph
      if (splitRoot) {
        // if it is an empty line with li
        if (dom.isLi(splitRoot) && (dom.isEmpty(splitRoot) || dom.deepestChildIsEmpty(splitRoot))) {
          // toggle UL/OL and escape
          this.bullet.toggleList(splitRoot.parentNode.nodeName);
          return;
        } else {
          var blockquote = null;
          if (this.options.blockquoteBreakingLevel === 1) {
            blockquote = dom.ancestor(splitRoot, dom.isBlockquote);
          } else if (this.options.blockquoteBreakingLevel === 2) {
            blockquote = dom.lastAncestor(splitRoot, dom.isBlockquote);
          }
          if (blockquote) {
            // We're inside a blockquote and options ask us to break it
            nextPara = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(dom.emptyPara)[0];
            // If the split is right before a <br>, remove it so that there's no "empty line"
            // after the split in the new blockquote created
            if (dom.isRightEdgePoint(rng.getStartPoint()) && dom.isBR(rng.sc.nextSibling)) {
              external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(rng.sc.nextSibling).remove();
            }
            var split = dom.splitTree(blockquote, rng.getStartPoint(), {
              isDiscardEmptySplits: true
            });
            if (split) {
              split.parentNode.insertBefore(nextPara, split);
            } else {
              dom.insertAfter(nextPara, blockquote); // There's no split if we were at the end of the blockquote
            }
          } else {
            nextPara = dom.splitTree(splitRoot, rng.getStartPoint());

            // not a blockquote, just insert the paragraph
            var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);
            emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));
            external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(emptyAnchors, function (idx, anchor) {
              dom.remove(anchor);
            });

            // replace empty heading, pre or custom-made styleTag with P tag
            if ((dom.isHeading(nextPara) || dom.isPre(nextPara) || dom.isCustomStyleTag(nextPara)) && dom.isEmpty(nextPara)) {
              nextPara = dom.replace(nextPara, 'p');
            }
          }
        }
        // no paragraph: insert empty paragraph
      } else {
        var next = rng.sc.childNodes[rng.so];
        nextPara = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(dom.emptyPara)[0];
        if (next) {
          rng.sc.insertBefore(nextPara, next);
        } else {
          rng.sc.appendChild(nextPara);
        }
      }
      range.create(nextPara, 0).normalize().select().scrollIntoView(editable);
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/editing/Table.js
function Table_typeof(o) { "@babel/helpers - typeof"; return Table_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Table_typeof(o); }
function Table_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Table_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Table_toPropertyKey(o.key), o); } }
function Table_createClass(e, r, t) { return r && Table_defineProperties(e.prototype, r), t && Table_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Table_toPropertyKey(t) { var i = Table_toPrimitive(t, "string"); return "symbol" == Table_typeof(i) ? i : i + ""; }
function Table_toPrimitive(t, r) { if ("object" != Table_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Table_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }





/**
 * @class Create a virtual table to create what actions to do in change.
 * @param {object} startPoint Cell selected to apply change.
 * @param {enum} where  Where change will be applied Row or Col. Use enum: TableResultAction.where
 * @param {enum} action Action to be applied. Use enum: TableResultAction.requestAction
 * @param {object} domTable Dom element of table to make changes.
 */
var TableResultAction = function TableResultAction(startPoint, where, action, domTable) {
  var _startPoint = {
    'colPos': 0,
    'rowPos': 0
  };
  var _virtualTable = [];
  var _actionCellList = [];

  /// ///////////////////////////////////////////
  // Private functions
  /// ///////////////////////////////////////////

  /**
   * Set the startPoint of action.
   */
  function setStartPoint() {
    if (!startPoint || !startPoint.tagName || startPoint.tagName.toLowerCase() !== 'td' && startPoint.tagName.toLowerCase() !== 'th') {
      // Impossible to identify start Cell point
      return;
    }
    _startPoint.colPos = startPoint.cellIndex;
    if (!startPoint.parentElement || !startPoint.parentElement.tagName || startPoint.parentElement.tagName.toLowerCase() !== 'tr') {
      // Impossible to identify start Row point
      return;
    }
    _startPoint.rowPos = startPoint.parentElement.rowIndex;
  }

  /**
   * Define virtual table position info object.
   *
   * @param {int} rowIndex Index position in line of virtual table.
   * @param {int} cellIndex Index position in column of virtual table.
   * @param {object} baseRow Row affected by this position.
   * @param {object} baseCell Cell affected by this position.
   * @param {bool} isSpan Inform if it is an span cell/row.
   */
  function setVirtualTablePosition(rowIndex, cellIndex, baseRow, baseCell, isRowSpan, isColSpan, isVirtualCell) {
    var objPosition = {
      'baseRow': baseRow,
      'baseCell': baseCell,
      'isRowSpan': isRowSpan,
      'isColSpan': isColSpan,
      'isVirtual': isVirtualCell
    };
    if (!_virtualTable[rowIndex]) {
      _virtualTable[rowIndex] = [];
    }
    _virtualTable[rowIndex][cellIndex] = objPosition;
  }

  /**
   * Create action cell object.
   *
   * @param {object} virtualTableCellObj Object of specific position on virtual table.
   * @param {enum} resultAction Action to be applied in that item.
   */
  function getActionCell(virtualTableCellObj, resultAction, virtualRowPosition, virtualColPosition) {
    return {
      'baseCell': virtualTableCellObj.baseCell,
      'action': resultAction,
      'virtualTable': {
        'rowIndex': virtualRowPosition,
        'cellIndex': virtualColPosition
      }
    };
  }

  /**
   * Recover free index of row to append Cell.
   *
   * @param {int} rowIndex Index of row to find free space.
   * @param {int} cellIndex Index of cell to find free space in table.
   */
  function recoverCellIndex(rowIndex, cellIndex) {
    if (!_virtualTable[rowIndex]) {
      return cellIndex;
    }
    if (!_virtualTable[rowIndex][cellIndex]) {
      return cellIndex;
    }
    var newCellIndex = cellIndex;
    while (_virtualTable[rowIndex][newCellIndex]) {
      newCellIndex++;
      if (!_virtualTable[rowIndex][newCellIndex]) {
        return newCellIndex;
      }
    }
  }

  /**
   * Recover info about row and cell and add information to virtual table.
   *
   * @param {object} row Row to recover information.
   * @param {object} cell Cell to recover information.
   */
  function addCellInfoToVirtual(row, cell) {
    var cellIndex = recoverCellIndex(row.rowIndex, cell.cellIndex);
    var cellHasColspan = cell.colSpan > 1;
    var cellHasRowspan = cell.rowSpan > 1;
    var isThisSelectedCell = row.rowIndex === _startPoint.rowPos && cell.cellIndex === _startPoint.colPos;
    setVirtualTablePosition(row.rowIndex, cellIndex, row, cell, cellHasRowspan, cellHasColspan, false);

    // Add span rows to virtual Table.
    var rowspanNumber = cell.attributes.rowSpan ? parseInt(cell.attributes.rowSpan.value, 10) : 0;
    if (rowspanNumber > 1) {
      for (var rp = 1; rp < rowspanNumber; rp++) {
        var rowspanIndex = row.rowIndex + rp;
        adjustStartPoint(rowspanIndex, cellIndex, cell, isThisSelectedCell);
        setVirtualTablePosition(rowspanIndex, cellIndex, row, cell, true, cellHasColspan, true);
      }
    }

    // Add span cols to virtual table.
    var colspanNumber = cell.attributes.colSpan ? parseInt(cell.attributes.colSpan.value, 10) : 0;
    if (colspanNumber > 1) {
      for (var cp = 1; cp < colspanNumber; cp++) {
        var cellspanIndex = recoverCellIndex(row.rowIndex, cellIndex + cp);
        adjustStartPoint(row.rowIndex, cellspanIndex, cell, isThisSelectedCell);
        setVirtualTablePosition(row.rowIndex, cellspanIndex, row, cell, cellHasRowspan, true, true);
      }
    }
  }

  /**
   * Process validation and adjust of start point if needed
   *
   * @param {int} rowIndex
   * @param {int} cellIndex
   * @param {object} cell
   * @param {bool} isSelectedCell
   */
  function adjustStartPoint(rowIndex, cellIndex, cell, isSelectedCell) {
    if (rowIndex === _startPoint.rowPos && _startPoint.colPos >= cell.cellIndex && cell.cellIndex <= cellIndex && !isSelectedCell) {
      _startPoint.colPos++;
    }
  }

  /**
   * Create virtual table of cells with all cells, including span cells.
   */
  function createVirtualTable() {
    var rows = domTable.rows;
    for (var rowIndex = 0; rowIndex < rows.length; rowIndex++) {
      var cells = rows[rowIndex].cells;
      for (var cellIndex = 0; cellIndex < cells.length; cellIndex++) {
        addCellInfoToVirtual(rows[rowIndex], cells[cellIndex]);
      }
    }
  }

  /**
   * Get action to be applied on the cell.
   *
   * @param {object} cell virtual table cell to apply action
   */
  function getDeleteResultActionToCell(cell) {
    switch (where) {
      case TableResultAction.where.Column:
        if (cell.isColSpan) {
          return TableResultAction.resultAction.SubtractSpanCount;
        }
        break;
      case TableResultAction.where.Row:
        if (!cell.isVirtual && cell.isRowSpan) {
          return TableResultAction.resultAction.AddCell;
        } else if (cell.isRowSpan) {
          return TableResultAction.resultAction.SubtractSpanCount;
        }
        break;
    }
    return TableResultAction.resultAction.RemoveCell;
  }

  /**
   * Get action to be applied on the cell.
   *
   * @param {object} cell virtual table cell to apply action
   */
  function getAddResultActionToCell(cell) {
    switch (where) {
      case TableResultAction.where.Column:
        if (cell.isColSpan) {
          return TableResultAction.resultAction.SumSpanCount;
        } else if (cell.isRowSpan && cell.isVirtual) {
          return TableResultAction.resultAction.Ignore;
        }
        break;
      case TableResultAction.where.Row:
        if (cell.isRowSpan) {
          return TableResultAction.resultAction.SumSpanCount;
        } else if (cell.isColSpan && cell.isVirtual) {
          return TableResultAction.resultAction.Ignore;
        }
        break;
    }
    return TableResultAction.resultAction.AddCell;
  }
  function init() {
    setStartPoint();
    createVirtualTable();
  }

  /// ///////////////////////////////////////////
  // Public functions
  /// ///////////////////////////////////////////

  /**
   * Recover array os what to do in table.
   */
  this.getActionList = function () {
    var fixedRow = where === TableResultAction.where.Row ? _startPoint.rowPos : -1;
    var fixedCol = where === TableResultAction.where.Column ? _startPoint.colPos : -1;
    var actualPosition = 0;
    var canContinue = true;
    while (canContinue) {
      var rowPosition = fixedRow >= 0 ? fixedRow : actualPosition;
      var colPosition = fixedCol >= 0 ? fixedCol : actualPosition;
      var row = _virtualTable[rowPosition];
      if (!row) {
        canContinue = false;
        return _actionCellList;
      }
      var cell = row[colPosition];
      if (!cell) {
        canContinue = false;
        return _actionCellList;
      }

      // Define action to be applied in this cell
      var resultAction = TableResultAction.resultAction.Ignore;
      switch (action) {
        case TableResultAction.requestAction.Add:
          resultAction = getAddResultActionToCell(cell);
          break;
        case TableResultAction.requestAction.Delete:
          resultAction = getDeleteResultActionToCell(cell);
          break;
      }
      _actionCellList.push(getActionCell(cell, resultAction, rowPosition, colPosition));
      actualPosition++;
    }
    return _actionCellList;
  };
  init();
};
/**
*
* Where action occours enum.
*/
TableResultAction.where = {
  'Row': 0,
  'Column': 1
};
/**
*
* Requested action to apply enum.
*/
TableResultAction.requestAction = {
  'Add': 0,
  'Delete': 1
};
/**
*
* Result action to be executed enum.
*/
TableResultAction.resultAction = {
  'Ignore': 0,
  'SubtractSpanCount': 1,
  'RemoveCell': 2,
  'AddCell': 3,
  'SumSpanCount': 4
};

/**
 *
 * @class editing.Table
 *
 * Table
 *
 */
var Table = /*#__PURE__*/function () {
  function Table() {
    Table_classCallCheck(this, Table);
  }
  return Table_createClass(Table, [{
    key: "tab",
    value:
    /**
     * handle tab key
     *
     * @param {WrappedRange} rng
     * @param {Boolean} isShift
     */
    function tab(rng, isShift) {
      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
      var table = dom.ancestor(cell, dom.isTable);
      var cells = dom.listDescendant(table, dom.isCell);
      var nextCell = lists[isShift ? 'prev' : 'next'](cells, cell);
      if (nextCell) {
        range.create(nextCell, 0).select();
      }
    }

    /**
     * Add a new row
     *
     * @param {WrappedRange} rng
     * @param {String} position (top/bottom)
     * @return {Node}
     */
  }, {
    key: "addRow",
    value: function addRow(rng, position) {
      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
      var currentTr = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(cell).closest('tr');
      var trAttributes = this.recoverAttributes(currentTr);
      var html = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<tr' + trAttributes + '></tr>');
      var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Add, external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(currentTr).closest('table')[0]);
      var actions = vTable.getActionList();
      for (var idCell = 0; idCell < actions.length; idCell++) {
        var currentCell = actions[idCell];
        var tdAttributes = this.recoverAttributes(currentCell.baseCell);
        switch (currentCell.action) {
          case TableResultAction.resultAction.AddCell:
            html.append('<td' + tdAttributes + '>' + dom.blank + '</td>');
            break;
          case TableResultAction.resultAction.SumSpanCount:
            {
              if (position === 'top') {
                var baseCellTr = currentCell.baseCell.parent;
                var isTopFromRowSpan = (!baseCellTr ? 0 : currentCell.baseCell.closest('tr').rowIndex) <= currentTr[0].rowIndex;
                if (isTopFromRowSpan) {
                  var newTd = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div></div>').append(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<td' + tdAttributes + '>' + dom.blank + '</td>').removeAttr('rowspan')).html();
                  html.append(newTd);
                  break;
                }
              }
              var rowspanNumber = parseInt(currentCell.baseCell.rowSpan, 10);
              rowspanNumber++;
              currentCell.baseCell.setAttribute('rowSpan', rowspanNumber);
            }
            break;
        }
      }
      if (position === 'top') {
        currentTr.before(html);
      } else {
        var cellHasRowspan = cell.rowSpan > 1;
        if (cellHasRowspan) {
          var lastTrIndex = currentTr[0].rowIndex + (cell.rowSpan - 2);
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(currentTr).parent().find('tr')[lastTrIndex]).after(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(html));
          return;
        }
        currentTr.after(html);
      }
    }

    /**
     * Add a new col
     *
     * @param {WrappedRange} rng
     * @param {String} position (left/right)
     * @return {Node}
     */
  }, {
    key: "addCol",
    value: function addCol(rng, position) {
      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
      var row = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(cell).closest('tr');
      var rowsGroup = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(row).siblings();
      rowsGroup.push(row);
      var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Add, external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(row).closest('table')[0]);
      var actions = vTable.getActionList();
      for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
        var currentCell = actions[actionIndex];
        var tdAttributes = this.recoverAttributes(currentCell.baseCell);
        switch (currentCell.action) {
          case TableResultAction.resultAction.AddCell:
            if (position === 'right') {
              external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(currentCell.baseCell).after('<td' + tdAttributes + '>' + dom.blank + '</td>');
            } else {
              external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');
            }
            break;
          case TableResultAction.resultAction.SumSpanCount:
            if (position === 'right') {
              var colspanNumber = parseInt(currentCell.baseCell.colSpan, 10);
              colspanNumber++;
              currentCell.baseCell.setAttribute('colSpan', colspanNumber);
            } else {
              external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(currentCell.baseCell).before('<td' + tdAttributes + '>' + dom.blank + '</td>');
            }
            break;
        }
      }
    }

    /*
    * Copy attributes from element.
    *
    * @param {object} Element to recover attributes.
    * @return {string} Copied string elements.
    */
  }, {
    key: "recoverAttributes",
    value: function recoverAttributes(el) {
      var resultStr = '';
      if (!el) {
        return resultStr;
      }
      var attrList = el.attributes || [];
      for (var i = 0; i < attrList.length; i++) {
        if (attrList[i].name.toLowerCase() === 'id') {
          continue;
        }
        if (attrList[i].specified) {
          resultStr += ' ' + attrList[i].name + '=\'' + attrList[i].value + '\'';
        }
      }
      return resultStr;
    }

    /**
     * Delete current row
     *
     * @param {WrappedRange} rng
     * @return {Node}
     */
  }, {
    key: "deleteRow",
    value: function deleteRow(rng) {
      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
      var row = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(cell).closest('tr');
      var cellPos = row.children('td, th').index(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(cell));
      var rowPos = row[0].rowIndex;
      var vTable = new TableResultAction(cell, TableResultAction.where.Row, TableResultAction.requestAction.Delete, external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(row).closest('table')[0]);
      var actions = vTable.getActionList();
      for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
        if (!actions[actionIndex]) {
          continue;
        }
        var baseCell = actions[actionIndex].baseCell;
        var virtualPosition = actions[actionIndex].virtualTable;
        var hasRowspan = baseCell.rowSpan && baseCell.rowSpan > 1;
        var rowspanNumber = hasRowspan ? parseInt(baseCell.rowSpan, 10) : 0;
        switch (actions[actionIndex].action) {
          case TableResultAction.resultAction.Ignore:
            continue;
          case TableResultAction.resultAction.AddCell:
            {
              var nextRow = row.next('tr')[0];
              if (!nextRow) {
                continue;
              }
              var cloneRow = row[0].cells[cellPos];
              if (hasRowspan) {
                if (rowspanNumber > 2) {
                  rowspanNumber--;
                  nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);
                  nextRow.cells[cellPos].setAttribute('rowSpan', rowspanNumber);
                  nextRow.cells[cellPos].innerHTML = '';
                } else if (rowspanNumber === 2) {
                  nextRow.insertBefore(cloneRow, nextRow.cells[cellPos]);
                  nextRow.cells[cellPos].removeAttribute('rowSpan');
                  nextRow.cells[cellPos].innerHTML = '';
                }
              }
            }
            continue;
          case TableResultAction.resultAction.SubtractSpanCount:
            if (hasRowspan) {
              if (rowspanNumber > 2) {
                rowspanNumber--;
                baseCell.setAttribute('rowSpan', rowspanNumber);
                if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {
                  baseCell.innerHTML = '';
                }
              } else if (rowspanNumber === 2) {
                baseCell.removeAttribute('rowSpan');
                if (virtualPosition.rowIndex !== rowPos && baseCell.cellIndex === cellPos) {
                  baseCell.innerHTML = '';
                }
              }
            }
            continue;
          case TableResultAction.resultAction.RemoveCell:
            // Do not need remove cell because row will be deleted.
            continue;
        }
      }
      row.remove();
    }

    /**
     * Delete current col
     *
     * @param {WrappedRange} rng
     * @return {Node}
     */
  }, {
    key: "deleteCol",
    value: function deleteCol(rng) {
      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
      var row = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(cell).closest('tr');
      var cellPos = row.children('td, th').index(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(cell));
      var vTable = new TableResultAction(cell, TableResultAction.where.Column, TableResultAction.requestAction.Delete, external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(row).closest('table')[0]);
      var actions = vTable.getActionList();
      for (var actionIndex = 0; actionIndex < actions.length; actionIndex++) {
        if (!actions[actionIndex]) {
          continue;
        }
        switch (actions[actionIndex].action) {
          case TableResultAction.resultAction.Ignore:
            continue;
          case TableResultAction.resultAction.SubtractSpanCount:
            {
              var baseCell = actions[actionIndex].baseCell;
              var hasColspan = baseCell.colSpan && baseCell.colSpan > 1;
              if (hasColspan) {
                var colspanNumber = baseCell.colSpan ? parseInt(baseCell.colSpan, 10) : 0;
                if (colspanNumber > 2) {
                  colspanNumber--;
                  baseCell.setAttribute('colSpan', colspanNumber);
                  if (baseCell.cellIndex === cellPos) {
                    baseCell.innerHTML = '';
                  }
                } else if (colspanNumber === 2) {
                  baseCell.removeAttribute('colSpan');
                  if (baseCell.cellIndex === cellPos) {
                    baseCell.innerHTML = '';
                  }
                }
              }
            }
            continue;
          case TableResultAction.resultAction.RemoveCell:
            dom.remove(actions[actionIndex].baseCell, true);
            continue;
        }
      }
    }

    /**
     * create empty table element
     *
     * @param {Number} rowCount
     * @param {Number} colCount
     * @return {Node}
     */
  }, {
    key: "createTable",
    value: function createTable(colCount, rowCount, options) {
      var tds = [];
      var tdHTML;
      for (var idxCol = 0; idxCol < colCount; idxCol++) {
        tds.push('<td>' + dom.blank + '</td>');
      }
      tdHTML = tds.join('');
      var trs = [];
      var trHTML;
      for (var idxRow = 0; idxRow < rowCount; idxRow++) {
        trs.push('<tr>' + tdHTML + '</tr>');
      }
      trHTML = trs.join('');
      var $table = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<table>' + trHTML + '</table>');
      if (options && options.tableClassName) {
        $table.addClass(options.tableClassName);
      }
      return $table[0];
    }

    /**
     * Delete current table
     *
     * @param {WrappedRange} rng
     * @return {Node}
     */
  }, {
    key: "deleteTable",
    value: function deleteTable(rng) {
      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(cell).closest('table').remove();
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Editor.js
function Editor_typeof(o) { "@babel/helpers - typeof"; return Editor_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Editor_typeof(o); }
function Editor_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Editor_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Editor_toPropertyKey(o.key), o); } }
function Editor_createClass(e, r, t) { return r && Editor_defineProperties(e.prototype, r), t && Editor_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Editor_toPropertyKey(t) { var i = Editor_toPrimitive(t, "string"); return "symbol" == Editor_typeof(i) ? i : i + ""; }
function Editor_toPrimitive(t, r) { if ("object" != Editor_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Editor_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }













var KEY_BOGUS = 'bogus';
var MAILTO_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
var TEL_PATTERN = /^(\+?\d{1,3}[\s-]?)?(\d{1,4})[\s-]?(\d{1,4})[\s-]?(\d{1,4})$/;
var URL_SCHEME_PATTERN = /^([A-Za-z][A-Za-z0-9+-.]*\:|#|\/)/;

/**
 * @class Editor
 */
var Editor = /*#__PURE__*/function () {
  function Editor(context) {
    var _this = this;
    Editor_classCallCheck(this, Editor);
    this.context = context;
    this.$note = context.layoutInfo.note;
    this.$editor = context.layoutInfo.editor;
    this.$editable = context.layoutInfo.editable;
    this.options = context.options;
    this.lang = this.options.langInfo;
    this.editable = this.$editable[0];
    this.lastRange = null;
    this.snapshot = null;
    this.style = new Style();
    this.table = new Table();
    this.typing = new Typing(context);
    this.bullet = new Bullet();
    this.history = new History(context);
    this.context.memo('help.escape', this.lang.help.escape);
    this.context.memo('help.undo', this.lang.help.undo);
    this.context.memo('help.redo', this.lang.help.redo);
    this.context.memo('help.tab', this.lang.help.tab);
    this.context.memo('help.untab', this.lang.help.untab);
    this.context.memo('help.insertParagraph', this.lang.help.insertParagraph);
    this.context.memo('help.insertOrderedList', this.lang.help.insertOrderedList);
    this.context.memo('help.insertUnorderedList', this.lang.help.insertUnorderedList);
    this.context.memo('help.indent', this.lang.help.indent);
    this.context.memo('help.outdent', this.lang.help.outdent);
    this.context.memo('help.formatPara', this.lang.help.formatPara);
    this.context.memo('help.insertHorizontalRule', this.lang.help.insertHorizontalRule);
    this.context.memo('help.fontName', this.lang.help.fontName);

    // native commands(with execCommand), generate function for execCommand
    var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', 'formatBlock', 'removeFormat', 'backColor'];
    for (var idx = 0, len = commands.length; idx < len; idx++) {
      this[commands[idx]] = function (sCmd) {
        return function (value) {
          _this.beforeCommand();
          document.execCommand(sCmd, false, value);
          _this.afterCommand(true);
        };
      }(commands[idx]);
      this.context.memo('help.' + commands[idx], this.lang.help[commands[idx]]);
    }
    this.fontName = this.wrapCommand(function (value) {
      return _this.fontStyling('font-family', env.validFontName(value));
    });
    this.fontSize = this.wrapCommand(function (value) {
      var unit = _this.currentStyle()['font-size-unit'];
      return _this.fontStyling('font-size', value + unit);
    });
    this.fontSizeUnit = this.wrapCommand(function (value) {
      var size = _this.currentStyle()['font-size'];
      return _this.fontStyling('font-size', size + value);
    });
    for (var _idx = 1; _idx <= 6; _idx++) {
      this['formatH' + _idx] = function (idx) {
        return function () {
          _this.formatBlock('H' + idx);
        };
      }(_idx);
      this.context.memo('help.formatH' + _idx, this.lang.help['formatH' + _idx]);
    }
    this.insertParagraph = this.wrapCommand(function () {
      _this.typing.insertParagraph(_this.editable);
    });
    this.insertOrderedList = this.wrapCommand(function () {
      _this.bullet.insertOrderedList(_this.editable);
    });
    this.insertUnorderedList = this.wrapCommand(function () {
      _this.bullet.insertUnorderedList(_this.editable);
    });
    this.indent = this.wrapCommand(function () {
      _this.bullet.indent(_this.editable);
    });
    this.outdent = this.wrapCommand(function () {
      _this.bullet.outdent(_this.editable);
    });

    /**
     * insertNode
     * insert node
     * @param {Node} node
     */
    this.insertNode = this.wrapCommand(function (node) {
      if (_this.isLimited(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(node).text().length)) {
        return;
      }
      var rng = _this.getLastRange();
      rng.insertNode(node);
      _this.setLastRange(range.createFromNodeAfter(node).select());
    });

    /**
     * insert text
     * @param {String} text
     */
    this.insertText = this.wrapCommand(function (text) {
      if (_this.isLimited(text.length)) {
        return;
      }
      var rng = _this.getLastRange();
      var textNode = rng.insertNode(dom.createText(text));
      _this.setLastRange(range.create(textNode, dom.nodeLength(textNode)).select());
    });

    /**
     * paste HTML
     * @param {String} markup
     */
    this.pasteHTML = this.wrapCommand(function (markup) {
      if (_this.isLimited(markup.length)) {
        return;
      }
      markup = _this.context.invoke('codeview.purify', markup);
      var contents = _this.getLastRange().pasteHTML(markup);
      _this.setLastRange(range.createFromNodeAfter(lists.last(contents)).select());
    });

    /**
     * formatBlock
     *
     * @param {String} tagName
     */
    this.formatBlock = this.wrapCommand(function (tagName, $target) {
      var onApplyCustomStyle = _this.options.callbacks.onApplyCustomStyle;
      if (onApplyCustomStyle) {
        onApplyCustomStyle.call(_this, $target, _this.context, _this.onFormatBlock);
      } else {
        _this.onFormatBlock(tagName, $target);
      }
    });

    /**
     * insert horizontal rule
     */
    this.insertHorizontalRule = this.wrapCommand(function () {
      var hrNode = _this.getLastRange().insertNode(dom.create('HR'));
      if (hrNode.nextSibling) {
        _this.setLastRange(range.create(hrNode.nextSibling, 0).normalize().select());
      }
    });

    /**
     * lineHeight
     * @param {String} value
     */
    this.lineHeight = this.wrapCommand(function (value) {
      _this.style.stylePara(_this.getLastRange(), {
        lineHeight: value
      });
    });

    /**
     * create link (command)
     *
     * @param {Object} linkInfo
     */
    this.createLink = this.wrapCommand(function (linkInfo) {
      var rel = [];
      var linkUrl = linkInfo.url;
      var linkText = linkInfo.text;
      var isNewWindow = linkInfo.isNewWindow;
      var addNoReferrer = _this.options.linkAddNoReferrer;
      var addNoOpener = _this.options.linkAddNoOpener;
      var rng = linkInfo.range || _this.getLastRange();
      var additionalTextLength = linkText.length - rng.toString().length;
      if (additionalTextLength > 0 && _this.isLimited(additionalTextLength)) {
        return;
      }
      var isTextChanged = rng.toString() !== linkText;

      // handle spaced urls from input
      if (typeof linkUrl === 'string') {
        linkUrl = linkUrl.trim();
      }
      if (_this.options.onCreateLink) {
        linkUrl = _this.options.onCreateLink(linkUrl);
      } else {
        linkUrl = _this.checkLinkUrl(linkUrl);
      }
      var anchors = [];
      if (isTextChanged) {
        rng = rng.deleteContents();
        var anchor = rng.insertNode(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<A></A>').text(linkText)[0]);
        anchors.push(anchor);
      } else {
        anchors = _this.style.styleNodes(rng, {
          nodeName: 'A',
          expandClosestSibling: true,
          onlyPartialContains: true
        });
      }
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(anchors, function (idx, anchor) {
        external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(anchor).attr('href', linkUrl);
        if (isNewWindow) {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(anchor).attr('target', '_blank');
          if (addNoReferrer) {
            rel.push('noreferrer');
          }
          if (addNoOpener) {
            rel.push('noopener');
          }
          if (rel.length) {
            external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(anchor).attr('rel', rel.join(' '));
          }
        } else {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(anchor).removeAttr('target');
        }
      });
      _this.setLastRange(_this.createRangeFromList(anchors).select());
    });

    /**
     * setting color
     *
     * @param {Object} sObjColor  color code
     * @param {String} sObjColor.foreColor foreground color
     * @param {String} sObjColor.backColor background color
     */
    this.color = this.wrapCommand(function (colorInfo) {
      var foreColor = colorInfo.foreColor;
      var backColor = colorInfo.backColor;
      if (foreColor) {
        document.execCommand('foreColor', false, foreColor);
      }
      if (backColor) {
        document.execCommand('backColor', false, backColor);
      }
    });

    /**
     * Set foreground color
     *
     * @param {String} colorCode foreground color code
     */
    this.foreColor = this.wrapCommand(function (colorInfo) {
      document.execCommand('foreColor', false, colorInfo);
    });

    /**
     * insert Table
     *
     * @param {String} dimension of table (ex : "5x5")
     */
    this.insertTable = this.wrapCommand(function (dim) {
      var dimension = dim.split('x');
      var rng = _this.getLastRange().deleteContents();
      rng.insertNode(_this.table.createTable(dimension[0], dimension[1], _this.options));
    });

    /**
     * remove media object and Figure Elements if media object is img with Figure.
     */
    this.removeMedia = this.wrapCommand(function () {
      var $target = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(_this.restoreTarget()).parent();
      if ($target.closest('figure').length) {
        $target.closest('figure').remove();
      } else {
        $target = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(_this.restoreTarget()).detach();
      }
      _this.setLastRange(range.createFromSelection($target).select());
      _this.context.triggerEvent('media.delete', $target, _this.$editable);
    });

    /**
     * float me
     *
     * @param {String} value
     */
    this.floatMe = this.wrapCommand(function (value) {
      var $target = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(_this.restoreTarget());
      $target.toggleClass('note-float-left', value === 'left');
      $target.toggleClass('note-float-right', value === 'right');
      $target.css('float', value === 'none' ? '' : value);
    });

    /**
     * resize overlay element
     * @param {String} value
     */
    this.resize = this.wrapCommand(function (value) {
      var $target = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(_this.restoreTarget());
      value = parseFloat(value);
      if (value === 0) {
        $target.css('width', '');
      } else {
        $target.css({
          width: value * 100 + '%',
          height: ''
        });
      }
    });
  }
  return Editor_createClass(Editor, [{
    key: "initialize",
    value: function initialize() {
      var _this2 = this;
      // bind custom events
      this.$editable.on('keydown', function (event) {
        if (event.keyCode === key.code.ENTER) {
          _this2.context.triggerEvent('enter', event);
        }
        _this2.context.triggerEvent('keydown', event);

        // keep a snapshot to limit text on input event
        _this2.snapshot = _this2.history.makeSnapshot();
        _this2.hasKeyShortCut = false;
        if (!event.isDefaultPrevented()) {
          if (_this2.options.shortcuts) {
            _this2.hasKeyShortCut = _this2.handleKeyMap(event);
          } else {
            _this2.preventDefaultEditableShortCuts(event);
          }
        }
        if (_this2.isLimited(1, event)) {
          var lastRange = _this2.getLastRange();
          if (lastRange.eo - lastRange.so === 0) {
            return false;
          }
        }
        _this2.setLastRange();

        // record undo in the key event except keyMap.
        if (_this2.options.recordEveryKeystroke) {
          if (_this2.hasKeyShortCut === false) {
            _this2.history.recordUndo();
          }
        }
      }).on('keyup', function (event) {
        _this2.setLastRange();
        _this2.context.triggerEvent('keyup', event);
      }).on('focus', function (event) {
        _this2.setLastRange();
        _this2.context.triggerEvent('focus', event);
      }).on('blur', function (event) {
        _this2.context.triggerEvent('blur', event);
      }).on('mousedown', function (event) {
        _this2.context.triggerEvent('mousedown', event);
      }).on('mouseup', function (event) {
        _this2.setLastRange();
        _this2.history.recordUndo();
        _this2.context.triggerEvent('mouseup', event);
      }).on('scroll', function (event) {
        _this2.context.triggerEvent('scroll', event);
      }).on('paste', function (event) {
        _this2.setLastRange();
        _this2.context.triggerEvent('paste', event);
      }).on('copy', function (event) {
        _this2.context.triggerEvent('copy', event);
      }).on('input', function () {
        // To limit composition characters (e.g. Korean)
        if (_this2.isLimited(0) && _this2.snapshot) {
          _this2.history.applySnapshot(_this2.snapshot);
        }
      });
      this.$editable.attr('spellcheck', this.options.spellCheck);
      this.$editable.attr('autocorrect', this.options.spellCheck);
      if (this.options.disableGrammar) {
        this.$editable.attr('data-gramm', false);
      }

      // init content before set event
      this.$editable.html(dom.html(this.$note) || dom.emptyPara);
      this.$editable.on(env.inputEventName, func.debounce(function () {
        _this2.context.triggerEvent('change', _this2.$editable.html(), _this2.$editable);
      }, 10));
      this.$editable.on('focusin', function (event) {
        _this2.context.triggerEvent('focusin', event);
      }).on('focusout', function (event) {
        _this2.context.triggerEvent('focusout', event);
      });
      if (this.options.airMode) {
        if (this.options.overrideContextMenu) {
          this.$editor.on('contextmenu', function (event) {
            _this2.context.triggerEvent('contextmenu', event);
            return false;
          });
        }
      } else {
        if (this.options.width) {
          this.$editor.outerWidth(this.options.width);
        }
        if (this.options.height) {
          this.$editable.outerHeight(this.options.height);
        }
        if (this.options.maxHeight) {
          this.$editable.css('max-height', this.options.maxHeight);
        }
        if (this.options.minHeight) {
          this.$editable.css('min-height', this.options.minHeight);
        }
      }
      this.history.recordUndo();
      this.setLastRange();
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$editable.off();
    }
  }, {
    key: "handleKeyMap",
    value: function handleKeyMap(event) {
      var keyMap = this.options.keyMap[env.isMac ? 'mac' : 'pc'];
      var keys = [];
      if (event.metaKey) {
        keys.push('CMD');
      }
      if (event.ctrlKey && !event.altKey) {
        keys.push('CTRL');
      }
      if (event.shiftKey) {
        keys.push('SHIFT');
      }
      var keyName = key.nameFromCode[event.keyCode];
      if (keyName) {
        keys.push(keyName);
      }
      var eventName = keyMap[keys.join('+')];
      if (keyName === 'TAB' && !this.options.tabDisable) {
        this.afterCommand();
      } else if (eventName) {
        if (this.context.invoke(eventName) !== false) {
          event.preventDefault();
          return true;
        }
      } else if (key.isEdit(event.keyCode)) {
        if (key.isRemove(event.keyCode)) {
          this.context.invoke('removed');
        }
        this.afterCommand();
      }
      return false;
    }
  }, {
    key: "preventDefaultEditableShortCuts",
    value: function preventDefaultEditableShortCuts(event) {
      // B(Bold, 66) / I(Italic, 73) / U(Underline, 85)
      if ((event.ctrlKey || event.metaKey) && lists.contains([66, 73, 85], event.keyCode)) {
        event.preventDefault();
      }
    }
  }, {
    key: "isLimited",
    value: function isLimited(pad, event) {
      pad = pad || 0;
      if (typeof event !== 'undefined') {
        if (key.isMove(event.keyCode) || key.isNavigation(event.keyCode) || event.ctrlKey || event.metaKey || lists.contains([key.code.BACKSPACE, key.code.DELETE], event.keyCode)) {
          return false;
        }
      }
      if (this.options.maxTextLength > 0) {
        if (this.$editable.text().length + pad > this.options.maxTextLength) {
          return true;
        }
      }
      return false;
    }
  }, {
    key: "checkLinkUrl",
    value: function checkLinkUrl(linkUrl) {
      if (MAILTO_PATTERN.test(linkUrl)) {
        return 'mailto://' + linkUrl;
      } else if (TEL_PATTERN.test(linkUrl)) {
        return 'tel://' + linkUrl;
      } else if (!URL_SCHEME_PATTERN.test(linkUrl)) {
        return 'http://' + linkUrl;
      }
      return linkUrl;
    }

    /**
     * create range
     * @return {WrappedRange}
     */
  }, {
    key: "createRange",
    value: function createRange() {
      this.focus();
      this.setLastRange();
      return this.getLastRange();
    }

    /**
     * create a new range from the list of elements
     *
     * @param {list} dom element list
     * @return {WrappedRange}
     */
  }, {
    key: "createRangeFromList",
    value: function createRangeFromList(lst) {
      var startRange = range.createFromNodeBefore(lists.head(lst));
      var startPoint = startRange.getStartPoint();
      var endRange = range.createFromNodeAfter(lists.last(lst));
      var endPoint = endRange.getEndPoint();
      return range.create(startPoint.node, startPoint.offset, endPoint.node, endPoint.offset);
    }

    /**
     * set the last range
     *
     * if given rng is exist, set rng as the last range
     * or create a new range at the end of the document
     *
     * @param {WrappedRange} rng
     */
  }, {
    key: "setLastRange",
    value: function setLastRange(rng) {
      if (rng) {
        this.lastRange = rng;
      } else {
        this.lastRange = range.create(this.editable);
        if (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.lastRange.sc).closest('.note-editable').length === 0) {
          this.lastRange = range.createFromBodyElement(this.editable);
        }
      }
    }

    /**
     * get the last range
     *
     * if there is a saved last range, return it
     * or create a new range and return it
     *
     * @return {WrappedRange}
     */
  }, {
    key: "getLastRange",
    value: function getLastRange() {
      if (!this.lastRange) {
        this.setLastRange();
      }
      return this.lastRange;
    }

    /**
     * saveRange
     *
     * save current range
     *
     * @param {Boolean} [thenCollapse=false]
     */
  }, {
    key: "saveRange",
    value: function saveRange(thenCollapse) {
      if (thenCollapse) {
        this.getLastRange().collapse().select();
      }
    }

    /**
     * restoreRange
     *
     * restore lately range
     */
  }, {
    key: "restoreRange",
    value: function restoreRange() {
      if (this.lastRange) {
        this.lastRange.select();
        this.focus();
      }
    }
  }, {
    key: "saveTarget",
    value: function saveTarget(node) {
      this.$editable.data('target', node);
    }
  }, {
    key: "clearTarget",
    value: function clearTarget() {
      this.$editable.removeData('target');
    }
  }, {
    key: "restoreTarget",
    value: function restoreTarget() {
      return this.$editable.data('target');
    }

    /**
     * currentStyle
     *
     * current style
     * @return {Object|Boolean} unfocus
     */
  }, {
    key: "currentStyle",
    value: function currentStyle() {
      var rng = range.create();
      if (rng) {
        rng = rng.normalize();
      }
      return rng ? this.style.current(rng) : this.style.fromNode(this.$editable);
    }

    /**
     * style from node
     *
     * @param {jQuery} $node
     * @return {Object}
     */
  }, {
    key: "styleFromNode",
    value: function styleFromNode($node) {
      return this.style.fromNode($node);
    }

    /**
     * undo
     */
  }, {
    key: "undo",
    value: function undo() {
      this.context.triggerEvent('before.command', this.$editable.html());
      this.history.undo();
      this.context.triggerEvent('change', this.$editable.html(), this.$editable);
    }

    /*
    * commit
    */
  }, {
    key: "commit",
    value: function commit() {
      this.context.triggerEvent('before.command', this.$editable.html());
      this.history.commit();
      this.context.triggerEvent('change', this.$editable.html(), this.$editable);
    }

    /**
     * redo
     */
  }, {
    key: "redo",
    value: function redo() {
      this.context.triggerEvent('before.command', this.$editable.html());
      this.history.redo();
      this.context.triggerEvent('change', this.$editable.html(), this.$editable);
    }

    /**
     * before command
     */
  }, {
    key: "beforeCommand",
    value: function beforeCommand() {
      this.context.triggerEvent('before.command', this.$editable.html());

      // Set styleWithCSS before run a command
      document.execCommand('styleWithCSS', false, this.options.styleWithCSS);

      // keep focus on editable before command execution
      this.focus();
    }

    /**
     * after command
     * @param {Boolean} isPreventTrigger
     */
  }, {
    key: "afterCommand",
    value: function afterCommand(isPreventTrigger) {
      this.normalizeContent();
      this.history.recordUndo();
      if (!isPreventTrigger) {
        this.context.triggerEvent('change', this.$editable.html(), this.$editable);
      }
    }

    /**
     * handle tab key
     */
  }, {
    key: "tab",
    value: function tab() {
      var rng = this.getLastRange();
      if (rng.isCollapsed() && rng.isOnCell()) {
        this.table.tab(rng);
      } else {
        if (this.options.tabSize === 0) {
          return false;
        }
        if (!this.isLimited(this.options.tabSize)) {
          this.beforeCommand();
          this.typing.insertTab(rng, this.options.tabSize);
          this.afterCommand();
        }
      }
    }

    /**
     * handle shift+tab key
     */
  }, {
    key: "untab",
    value: function untab() {
      var rng = this.getLastRange();
      if (rng.isCollapsed() && rng.isOnCell()) {
        this.table.tab(rng, true);
      } else {
        if (this.options.tabSize === 0) {
          return false;
        }
      }
    }

    /**
     * run given function between beforeCommand and afterCommand
     */
  }, {
    key: "wrapCommand",
    value: function wrapCommand(fn) {
      return function () {
        this.beforeCommand();
        fn.apply(this, arguments);
        this.afterCommand();
      };
    }
    /**
     * removed (function added by 1der1)
    */
  }, {
    key: "removed",
    value: function removed(rng, node, tagName) {
      // LB
      rng = range.create();
      if (rng.isCollapsed() && rng.isOnCell()) {
        node = rng.ec;
        if ((tagName = node.tagName) && node.childElementCount === 1 && node.childNodes[0].tagName === "BR") {
          if (tagName === "P") {
            node.remove();
          } else if (['TH', 'TD'].indexOf(tagName) >= 0) {
            node.firstChild.remove();
          }
        }
      }
    }
    /**
     * insert image
     *
     * @param {String} src
     * @param {String|Function} param
     * @return {Promise}
     */
  }, {
    key: "insertImage",
    value: function insertImage(src, param) {
      var _this3 = this;
      return createImage(src, param).then(function ($image) {
        _this3.beforeCommand();
        if (typeof param === 'function') {
          param($image);
        } else {
          if (typeof param === 'string') {
            $image.attr('data-filename', param);
          }
          $image.css('width', Math.min(_this3.$editable.width(), $image.width()));
        }
        $image.show();
        _this3.getLastRange().insertNode($image[0]);
        _this3.setLastRange(range.createFromNodeAfter($image[0]).select());
        _this3.afterCommand();
      }).fail(function (e) {
        _this3.context.triggerEvent('image.upload.error', e);
      });
    }

    /**
     * insertImages
     * @param {File[]} files
     */
  }, {
    key: "insertImagesAsDataURL",
    value: function insertImagesAsDataURL(files) {
      var _this4 = this;
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(files, function (idx, file) {
        var filename = file.name;
        if (_this4.options.maximumImageFileSize && _this4.options.maximumImageFileSize < file.size) {
          _this4.context.triggerEvent('image.upload.error', _this4.lang.image.maximumFileSizeError);
        } else {
          readFileAsDataURL(file).then(function (dataURL) {
            return _this4.insertImage(dataURL, filename);
          }).fail(function () {
            _this4.context.triggerEvent('image.upload.error');
          });
        }
      });
    }

    /**
     * insertImagesOrCallback
     * @param {File[]} files
     */
  }, {
    key: "insertImagesOrCallback",
    value: function insertImagesOrCallback(files) {
      var callbacks = this.options.callbacks;
      // If onImageUpload set,
      if (callbacks.onImageUpload) {
        this.context.triggerEvent('image.upload', files);
        // else insert Image as dataURL
      } else {
        this.insertImagesAsDataURL(files);
      }
    }

    /**
     * return selected plain text
     * @return {String} text
     */
  }, {
    key: "getSelectedText",
    value: function getSelectedText() {
      var rng = this.getLastRange();

      // if range on anchor, expand range with anchor
      if (rng.isOnAnchor()) {
        rng = range.createFromNode(dom.ancestor(rng.sc, dom.isAnchor));
      }
      return rng.toString();
    }
  }, {
    key: "onFormatBlock",
    value: function onFormatBlock(tagName, $target) {
      // [workaround] for MSIE, IE need `<`
      document.execCommand('FormatBlock', false, env.isMSIE ? '<' + tagName + '>' : tagName);

      // support custom class
      if ($target && $target.length) {
        // find the exact element has given tagName
        if ($target[0].tagName.toUpperCase() !== tagName.toUpperCase()) {
          $target = $target.find(tagName);
        }
        if ($target && $target.length) {
          var currentRange = this.createRange();
          var $parent = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()([currentRange.sc, currentRange.ec]).closest(tagName);
          // remove class added for current block
          $parent.removeClass();
          var className = $target[0].className || '';
          if (className) {
            $parent.addClass(className);
          }
        }
      }
    }
  }, {
    key: "formatPara",
    value: function formatPara() {
      this.formatBlock('P');
    }
  }, {
    key: "fontStyling",
    value: function fontStyling(target, value) {
      var rng = this.getLastRange();
      if (rng !== '') {
        var spans = this.style.styleNodes(rng);
        this.$editor.find('.note-status-output').html('');
        external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(spans).css(target, value);

        // [workaround] added styled bogus span for style
        //  - also bogus character needed for cursor position
        if (rng.isCollapsed()) {
          var firstSpan = lists.head(spans);
          if (firstSpan && !dom.nodeLength(firstSpan)) {
            firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR;
            range.createFromNode(firstSpan.firstChild).select();
            this.setLastRange();
            this.$editable.data(KEY_BOGUS, firstSpan);
          }
        } else {
          rng.select();
        }
      } else {
        var noteStatusOutput = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().now();
        this.$editor.find('.note-status-output').html('<div id="note-status-output-' + noteStatusOutput + '" class="alert alert-info">' + this.lang.output.noSelection + '</div>');
        setTimeout(function () {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('#note-status-output-' + noteStatusOutput).remove();
        }, 5000);
      }
    }

    /**
     * unlink
     *
     * @type command
     */
  }, {
    key: "unlink",
    value: function unlink() {
      var rng = this.getLastRange();
      if (rng.isOnAnchor()) {
        var anchor = dom.ancestor(rng.sc, dom.isAnchor);
        rng = range.createFromNode(anchor);
        rng.select();
        this.setLastRange();
        this.beforeCommand();
        document.execCommand('unlink');
        this.afterCommand();
      }
    }

    /**
     * returns link info
     *
     * @return {Object}
     * @return {WrappedRange} return.range
     * @return {String} return.text
     * @return {Boolean} [return.isNewWindow=true]
     * @return {String} [return.url=""]
     */
  }, {
    key: "getLinkInfo",
    value: function getLinkInfo() {
      if (!this.hasFocus()) {
        this.focus();
      }
      var rng = this.getLastRange().expand(dom.isAnchor);
      // Get the first anchor on range(for edit).
      var $anchor = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(lists.head(rng.nodes(dom.isAnchor)));
      var linkInfo = {
        range: rng,
        text: rng.toString(),
        url: $anchor.length ? $anchor.attr('href') : ''
      };

      // When anchor exists,
      if ($anchor.length) {
        // Set isNewWindow by checking its target.
        linkInfo.isNewWindow = $anchor.attr('target') === '_blank';
      }
      return linkInfo;
    }
  }, {
    key: "addRow",
    value: function addRow(position) {
      var rng = this.getLastRange(this.$editable);
      if (rng.isCollapsed() && rng.isOnCell()) {
        this.beforeCommand();
        this.table.addRow(rng, position);
        this.afterCommand();
      }
    }
  }, {
    key: "addCol",
    value: function addCol(position) {
      var rng = this.getLastRange(this.$editable);
      if (rng.isCollapsed() && rng.isOnCell()) {
        this.beforeCommand();
        this.table.addCol(rng, position);
        this.afterCommand();
      }
    }
  }, {
    key: "deleteRow",
    value: function deleteRow() {
      var rng = this.getLastRange(this.$editable);
      if (rng.isCollapsed() && rng.isOnCell()) {
        this.beforeCommand();
        this.table.deleteRow(rng);
        this.afterCommand();
      }
    }
  }, {
    key: "deleteCol",
    value: function deleteCol() {
      var rng = this.getLastRange(this.$editable);
      if (rng.isCollapsed() && rng.isOnCell()) {
        this.beforeCommand();
        this.table.deleteCol(rng);
        this.afterCommand();
      }
    }
  }, {
    key: "deleteTable",
    value: function deleteTable() {
      var rng = this.getLastRange(this.$editable);
      if (rng.isCollapsed() && rng.isOnCell()) {
        this.beforeCommand();
        this.table.deleteTable(rng);
        this.afterCommand();
      }
    }

    /**
     * @param {Position} pos
     * @param {jQuery} $target - target element
     * @param {Boolean} [bKeepRatio] - keep ratio
     */
  }, {
    key: "resizeTo",
    value: function resizeTo(pos, $target, bKeepRatio) {
      var imageSize;
      if (bKeepRatio) {
        var newRatio = pos.y / pos.x;
        var ratio = $target.data('ratio');
        imageSize = {
          width: ratio > newRatio ? pos.x : pos.y / ratio,
          height: ratio > newRatio ? pos.x * ratio : pos.y
        };
      } else {
        imageSize = {
          width: pos.x,
          height: pos.y
        };
      }
      $target.css(imageSize);
    }

    /**
     * returns whether editable area has focus or not.
     */
  }, {
    key: "hasFocus",
    value: function hasFocus() {
      return this.$editable.is(':focus');
    }

    /**
     * set focus
     */
  }, {
    key: "focus",
    value: function focus() {
      // [workaround] Screen will move when page is scolled in IE.
      //  - do focus when not focused
      if (!this.hasFocus()) {
        this.$editable.trigger('focus');
      }
    }

    /**
     * returns whether contents is empty or not.
     * @return {Boolean}
     */
  }, {
    key: "isEmpty",
    value: function isEmpty() {
      return dom.isEmpty(this.$editable[0]) || dom.emptyPara === this.$editable.html();
    }

    /**
     * Removes all contents and restores the editable instance to an _emptyPara_.
     */
  }, {
    key: "empty",
    value: function empty() {
      this.context.invoke('code', dom.emptyPara);
    }

    /**
     * normalize content
     */
  }, {
    key: "normalizeContent",
    value: function normalizeContent() {
      this.$editable[0].normalize();
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Clipboard.js
function Clipboard_typeof(o) { "@babel/helpers - typeof"; return Clipboard_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Clipboard_typeof(o); }
function Clipboard_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Clipboard_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Clipboard_toPropertyKey(o.key), o); } }
function Clipboard_createClass(e, r, t) { return r && Clipboard_defineProperties(e.prototype, r), t && Clipboard_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Clipboard_toPropertyKey(t) { var i = Clipboard_toPrimitive(t, "string"); return "symbol" == Clipboard_typeof(i) ? i : i + ""; }
function Clipboard_toPrimitive(t, r) { if ("object" != Clipboard_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Clipboard_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
var Clipboard = /*#__PURE__*/function () {
  function Clipboard(context) {
    Clipboard_classCallCheck(this, Clipboard);
    this.context = context;
    this.options = context.options;
    this.$editable = context.layoutInfo.editable;
  }
  return Clipboard_createClass(Clipboard, [{
    key: "initialize",
    value: function initialize() {
      this.$editable.on('paste', this.pasteByEvent.bind(this));
    }

    /**
     * paste by clipboard event
     *
     * @param {Event} event
     */
  }, {
    key: "pasteByEvent",
    value: function pasteByEvent(event) {
      var _this = this;
      if (this.context.isDisabled()) {
        return;
      }
      var clipboardData = event.originalEvent.clipboardData;
      if (clipboardData && clipboardData.items && clipboardData.items.length) {
        var clipboardFiles = clipboardData.files;
        var clipboardText = clipboardData.getData('Text');

        // paste img file
        if (clipboardFiles.length > 0 && this.options.allowClipboardImagePasting) {
          this.context.invoke('editor.insertImagesOrCallback', clipboardFiles);
          event.preventDefault();
        }

        // paste text with maxTextLength check
        if (clipboardText.length > 0 && this.context.invoke('editor.isLimited', clipboardText.length)) {
          event.preventDefault();
        }
      } else if (window.clipboardData) {
        // for IE
        var text = window.clipboardData.getData('text');
        if (this.context.invoke('editor.isLimited', text.length)) {
          event.preventDefault();
        }
      }

      // Call editor.afterCommand after proceeding default event handler
      setTimeout(function () {
        _this.context.invoke('editor.afterCommand');
      }, 10);
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Dropzone.js
function Dropzone_typeof(o) { "@babel/helpers - typeof"; return Dropzone_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Dropzone_typeof(o); }
function Dropzone_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Dropzone_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Dropzone_toPropertyKey(o.key), o); } }
function Dropzone_createClass(e, r, t) { return r && Dropzone_defineProperties(e.prototype, r), t && Dropzone_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Dropzone_toPropertyKey(t) { var i = Dropzone_toPrimitive(t, "string"); return "symbol" == Dropzone_typeof(i) ? i : i + ""; }
function Dropzone_toPrimitive(t, r) { if ("object" != Dropzone_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Dropzone_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var Dropzone = /*#__PURE__*/function () {
  function Dropzone(context) {
    Dropzone_classCallCheck(this, Dropzone);
    this.context = context;
    this.$eventListener = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document);
    this.$editor = context.layoutInfo.editor;
    this.$editable = context.layoutInfo.editable;
    this.options = context.options;
    this.lang = this.options.langInfo;
    this.documentEventHandlers = {};
    this.$dropzone = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(['<div class="note-dropzone">', '<div class="note-dropzone-message"></div>', '</div>'].join('')).prependTo(this.$editor);
  }

  /**
   * attach Drag and Drop Events
   */
  return Dropzone_createClass(Dropzone, [{
    key: "initialize",
    value: function initialize() {
      if (this.options.disableDragAndDrop) {
        // prevent default drop event
        this.documentEventHandlers.onDrop = function (e) {
          e.preventDefault();
        };
        // do not consider outside of dropzone
        this.$eventListener = this.$dropzone;
        this.$eventListener.on('drop', this.documentEventHandlers.onDrop);
      } else {
        this.attachDragAndDropEvent();
      }
    }

    /**
     * attach Drag and Drop Events
     */
  }, {
    key: "attachDragAndDropEvent",
    value: function attachDragAndDropEvent() {
      var _this = this;
      var collection = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()();
      var $dropzoneMessage = this.$dropzone.find('.note-dropzone-message');
      this.documentEventHandlers.onDragenter = function (e) {
        var isCodeview = _this.context.invoke('codeview.isActivated');
        var hasEditorSize = _this.$editor.width() > 0 && _this.$editor.height() > 0;
        if (!isCodeview && !collection.length && hasEditorSize) {
          _this.$editor.addClass('dragover');
          _this.$dropzone.width(_this.$editor.width());
          _this.$dropzone.height(_this.$editor.height());
          $dropzoneMessage.text(_this.lang.image.dragImageHere);
        }
        collection = collection.add(e.target);
      };
      this.documentEventHandlers.onDragleave = function (e) {
        collection = collection.not(e.target);

        // If nodeName is BODY, then just make it over (fix for IE)
        if (!collection.length || e.target.nodeName === 'BODY') {
          collection = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()();
          _this.$editor.removeClass('dragover');
        }
      };
      this.documentEventHandlers.onDrop = function () {
        collection = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()();
        _this.$editor.removeClass('dragover');
      };

      // show dropzone on dragenter when dragging a object to document
      // -but only if the editor is visible, i.e. has a positive width and height
      this.$eventListener.on('dragenter', this.documentEventHandlers.onDragenter).on('dragleave', this.documentEventHandlers.onDragleave).on('drop', this.documentEventHandlers.onDrop);

      // change dropzone's message on hover.
      this.$dropzone.on('dragenter', function () {
        _this.$dropzone.addClass('hover');
        $dropzoneMessage.text(_this.lang.image.dropImage);
      }).on('dragleave', function () {
        _this.$dropzone.removeClass('hover');
        $dropzoneMessage.text(_this.lang.image.dragImageHere);
      });

      // attach dropImage
      this.$dropzone.on('drop', function (event) {
        var dataTransfer = event.originalEvent.dataTransfer;

        // stop the browser from opening the dropped content
        event.preventDefault();
        if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
          _this.$editable.trigger('focus');
          _this.context.invoke('editor.insertImagesOrCallback', dataTransfer.files);
        } else {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(dataTransfer.types, function (idx, type) {
            // skip moz-specific types
            if (type.toLowerCase().indexOf('_moz_') > -1) {
              return;
            }
            var content = dataTransfer.getData(type);
            if (type.toLowerCase().indexOf('text') > -1) {
              _this.context.invoke('editor.pasteHTML', content);
            } else {
              external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(content).each(function (idx, item) {
                _this.context.invoke('editor.insertNode', item);
              });
            }
          });
        }
      }).on('dragover', false); // prevent default dragover event
    }
  }, {
    key: "destroy",
    value: function destroy() {
      var _this2 = this;
      Object.keys(this.documentEventHandlers).forEach(function (key) {
        _this2.$eventListener.off(key.slice(2).toLowerCase(), _this2.documentEventHandlers[key]);
      });
      this.documentEventHandlers = {};
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Codeview.js
function Codeview_typeof(o) { "@babel/helpers - typeof"; return Codeview_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Codeview_typeof(o); }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function Codeview_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Codeview_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Codeview_toPropertyKey(o.key), o); } }
function Codeview_createClass(e, r, t) { return r && Codeview_defineProperties(e.prototype, r), t && Codeview_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Codeview_toPropertyKey(t) { var i = Codeview_toPrimitive(t, "string"); return "symbol" == Codeview_typeof(i) ? i : i + ""; }
function Codeview_toPrimitive(t, r) { if ("object" != Codeview_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Codeview_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }



/**
 * @class Codeview
 */
var CodeView = /*#__PURE__*/function () {
  function CodeView(context) {
    Codeview_classCallCheck(this, CodeView);
    this.context = context;
    this.$editor = context.layoutInfo.editor;
    this.$editable = context.layoutInfo.editable;
    this.$codable = context.layoutInfo.codable;
    this.options = context.options;
    this.CodeMirrorConstructor = window.CodeMirror;
    if (this.options.codemirror.CodeMirrorConstructor) {
      this.CodeMirrorConstructor = this.options.codemirror.CodeMirrorConstructor;
    }
  }
  return Codeview_createClass(CodeView, [{
    key: "sync",
    value: function sync(html) {
      var isCodeview = this.isActivated();
      var CodeMirror = this.CodeMirrorConstructor;
      if (isCodeview) {
        if (html) {
          if (CodeMirror) {
            this.$codable.data('cmEditor').getDoc().setValue(html);
          } else {
            this.$codable.val(html);
          }
        } else {
          if (CodeMirror) {
            this.$codable.data('cmEditor').save();
          }
        }
      }
    }
  }, {
    key: "initialize",
    value: function initialize() {
      var _this = this;
      this.$codable.on('keyup', function (event) {
        if (event.keyCode === key.code.ESCAPE) {
          _this.deactivate();
        }
      });
    }

    /**
     * @return {Boolean}
     */
  }, {
    key: "isActivated",
    value: function isActivated() {
      return this.$editor.hasClass('codeview');
    }

    /**
     * toggle codeview
     */
  }, {
    key: "toggle",
    value: function toggle() {
      if (this.isActivated()) {
        this.deactivate();
      } else {
        this.activate();
      }
      this.context.triggerEvent('codeview.toggled');
    }

    /**
     * purify input value
     * @param value
     * @returns {*}
     */
  }, {
    key: "purify",
    value: function purify(value) {
      if (this.options.codeviewFilter) {
        // filter code view regex
        value = value.replace(this.options.codeviewFilterRegex, '');
        // allow specific iframe tag
        if (this.options.codeviewIframeFilter) {
          var whitelist = this.options.codeviewIframeWhitelistSrc.concat(this.options.codeviewIframeWhitelistSrcBase);
          value = value.replace(/(<iframe.*?>.*?(?:<\/iframe>)?)/gi, function (tag) {
            // remove if src attribute is duplicated
            if (/<.+src(?==?('|"|\s)?)[\s\S]+src(?=('|"|\s)?)[^>]*?>/i.test(tag)) {
              return '';
            }
            var _iterator = _createForOfIteratorHelper(whitelist),
              _step;
            try {
              for (_iterator.s(); !(_step = _iterator.n()).done;) {
                var src = _step.value;
                // pass if src is trusted
                if (new RegExp('src="(https?:)?\/\/' + src.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '\/(.+)"').test(tag)) {
                  return tag;
                }
              }
            } catch (err) {
              _iterator.e(err);
            } finally {
              _iterator.f();
            }
            return '';
          });
        }
      }
      return value;
    }

    /**
     * activate code view
     */
  }, {
    key: "activate",
    value: function activate() {
      var _this2 = this;
      var CodeMirror = this.CodeMirrorConstructor;
      this.$codable.val(dom.html(this.$editable, this.options.prettifyHtml));
      this.$codable.height(this.$editable.height());
      this.context.invoke('toolbar.updateCodeview', true);
      this.context.invoke('airPopover.updateCodeview', true);
      this.$editor.addClass('codeview');
      this.$codable.trigger('focus');

      // activate CodeMirror as codable
      if (CodeMirror) {
        var cmEditor = CodeMirror.fromTextArea(this.$codable[0], this.options.codemirror);

        // CodeMirror TernServer
        if (this.options.codemirror.tern) {
          var server = new CodeMirror.TernServer(this.options.codemirror.tern);
          cmEditor.ternServer = server;
          cmEditor.on('cursorActivity', function (cm) {
            server.updateArgHints(cm);
          });
        }
        cmEditor.on('blur', function (event) {
          _this2.context.triggerEvent('blur.codeview', cmEditor.getValue(), event);
        });
        cmEditor.on('change', function () {
          _this2.context.triggerEvent('change.codeview', cmEditor.getValue(), cmEditor);
        });

        // CodeMirror hasn't Padding.
        cmEditor.setSize(null, this.$editable.outerHeight());
        this.$codable.data('cmEditor', cmEditor);
      } else {
        this.$codable.on('blur', function (event) {
          _this2.context.triggerEvent('blur.codeview', _this2.$codable.val(), event);
        });
        this.$codable.on('input', function () {
          _this2.context.triggerEvent('change.codeview', _this2.$codable.val(), _this2.$codable);
        });
      }
    }

    /**
     * deactivate code view
     */
  }, {
    key: "deactivate",
    value: function deactivate() {
      var CodeMirror = this.CodeMirrorConstructor;
      // deactivate CodeMirror as codable
      if (CodeMirror) {
        var cmEditor = this.$codable.data('cmEditor');
        this.$codable.val(cmEditor.getValue());
        cmEditor.toTextArea();
      }
      var value = this.purify(dom.value(this.$codable, this.options.prettifyHtml) || dom.emptyPara);
      var isChange = this.$editable.html() !== value;
      this.$editable.html(value);
      this.$editable.height(this.options.height ? this.$codable.height() : 'auto');
      this.$editor.removeClass('codeview');
      if (isChange) {
        this.context.triggerEvent('change', this.$editable.html(), this.$editable);
      }
      this.$editable.trigger('focus');
      this.context.invoke('toolbar.updateCodeview', false);
      this.context.invoke('airPopover.updateCodeview', false);
    }
  }, {
    key: "destroy",
    value: function destroy() {
      if (this.isActivated()) {
        this.deactivate();
      }
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Statusbar.js
function Statusbar_typeof(o) { "@babel/helpers - typeof"; return Statusbar_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Statusbar_typeof(o); }
function Statusbar_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Statusbar_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Statusbar_toPropertyKey(o.key), o); } }
function Statusbar_createClass(e, r, t) { return r && Statusbar_defineProperties(e.prototype, r), t && Statusbar_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Statusbar_toPropertyKey(t) { var i = Statusbar_toPrimitive(t, "string"); return "symbol" == Statusbar_typeof(i) ? i : i + ""; }
function Statusbar_toPrimitive(t, r) { if ("object" != Statusbar_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Statusbar_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var EDITABLE_PADDING = 24;
var Statusbar = /*#__PURE__*/function () {
  function Statusbar(context) {
    Statusbar_classCallCheck(this, Statusbar);
    this.$document = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document);
    this.$statusbar = context.layoutInfo.statusbar;
    this.$editable = context.layoutInfo.editable;
    this.$codable = context.layoutInfo.codable;
    this.options = context.options;
  }
  return Statusbar_createClass(Statusbar, [{
    key: "initialize",
    value: function initialize() {
      var _this = this;
      if (this.options.airMode || this.options.disableResizeEditor) {
        this.destroy();
        return;
      }
      this.$statusbar.on('mousedown touchstart', function (event) {
        event.preventDefault();
        event.stopPropagation();
        var editableTop = _this.$editable.offset().top - _this.$document.scrollTop();
        var editableCodeTop = _this.$codable.offset().top - _this.$document.scrollTop();
        var onStatusbarMove = function onStatusbarMove(event) {
          var originalEvent = event.type == 'mousemove' ? event : event.originalEvent.touches[0];
          var height = originalEvent.clientY - (editableTop + EDITABLE_PADDING);
          var heightCode = originalEvent.clientY - (editableCodeTop + EDITABLE_PADDING);
          height = _this.options.minheight > 0 ? Math.max(height, _this.options.minheight) : height;
          height = _this.options.maxHeight > 0 ? Math.min(height, _this.options.maxHeight) : height;
          heightCode = _this.options.minheight > 0 ? Math.max(heightCode, _this.options.minheight) : heightCode;
          heightCode = _this.options.maxHeight > 0 ? Math.min(heightCode, _this.options.maxHeight) : heightCode;
          _this.$editable.height(height);
          _this.$codable.height(heightCode);
        };
        _this.$document.on('mousemove touchmove', onStatusbarMove).one('mouseup touchend', function () {
          _this.$document.off('mousemove touchmove', onStatusbarMove);
        });
      });
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$statusbar.off();
      this.$statusbar.addClass('locked');
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Fullscreen.js
function Fullscreen_typeof(o) { "@babel/helpers - typeof"; return Fullscreen_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Fullscreen_typeof(o); }
function Fullscreen_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Fullscreen_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Fullscreen_toPropertyKey(o.key), o); } }
function Fullscreen_createClass(e, r, t) { return r && Fullscreen_defineProperties(e.prototype, r), t && Fullscreen_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Fullscreen_toPropertyKey(t) { var i = Fullscreen_toPrimitive(t, "string"); return "symbol" == Fullscreen_typeof(i) ? i : i + ""; }
function Fullscreen_toPrimitive(t, r) { if ("object" != Fullscreen_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Fullscreen_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var Fullscreen = /*#__PURE__*/function () {
  function Fullscreen(context) {
    var _this = this;
    Fullscreen_classCallCheck(this, Fullscreen);
    this.context = context;
    this.$editor = context.layoutInfo.editor;
    this.$toolbar = context.layoutInfo.toolbar;
    this.$editable = context.layoutInfo.editable;
    this.$codable = context.layoutInfo.codable;
    this.$window = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(window);
    this.$scrollbar = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('html, body');
    this.scrollbarClassName = 'note-fullscreen-body';
    this.onResize = function () {
      _this.resizeTo({
        h: _this.$window.height() - _this.$toolbar.outerHeight()
      });
    };
  }
  return Fullscreen_createClass(Fullscreen, [{
    key: "resizeTo",
    value: function resizeTo(size) {
      this.$editable.css('height', size.h);
      this.$codable.css('height', size.h);
      if (this.$codable.data('cmeditor')) {
        this.$codable.data('cmeditor').setsize(null, size.h);
      }
    }

    /**
     * toggle fullscreen
     */
  }, {
    key: "toggle",
    value: function toggle() {
      this.$editor.toggleClass('fullscreen');
      var isFullscreen = this.isFullscreen();
      this.$scrollbar.toggleClass(this.scrollbarClassName, isFullscreen);
      if (isFullscreen) {
        this.$editable.data('orgHeight', this.$editable.css('height'));
        this.$editable.data('orgMaxHeight', this.$editable.css('maxHeight'));
        this.$editable.css('maxHeight', '');
        this.$window.on('resize', this.onResize).trigger('resize');
      } else {
        this.$window.off('resize', this.onResize);
        this.resizeTo({
          h: this.$editable.data('orgHeight')
        });
        this.$editable.css('maxHeight', this.$editable.css('orgMaxHeight'));
      }
      this.context.invoke('toolbar.updateFullscreen', isFullscreen);
    }
  }, {
    key: "isFullscreen",
    value: function isFullscreen() {
      return this.$editor.hasClass('fullscreen');
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$scrollbar.removeClass(this.scrollbarClassName);
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Handle.js
function Handle_typeof(o) { "@babel/helpers - typeof"; return Handle_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Handle_typeof(o); }
function Handle_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Handle_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Handle_toPropertyKey(o.key), o); } }
function Handle_createClass(e, r, t) { return r && Handle_defineProperties(e.prototype, r), t && Handle_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Handle_toPropertyKey(t) { var i = Handle_toPrimitive(t, "string"); return "symbol" == Handle_typeof(i) ? i : i + ""; }
function Handle_toPrimitive(t, r) { if ("object" != Handle_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Handle_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }


var Handle = /*#__PURE__*/function () {
  function Handle(context) {
    var _this = this;
    Handle_classCallCheck(this, Handle);
    this.context = context;
    this.$document = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document);
    this.$editingArea = context.layoutInfo.editingArea;
    this.options = context.options;
    this.lang = this.options.langInfo;
    this.events = {
      'summernote.mousedown': function summernoteMousedown(we, e) {
        if (_this.update(e.target, e)) {
          e.preventDefault();
        }
      },
      'summernote.keyup summernote.scroll summernote.change summernote.dialog.shown': function summernoteKeyupSummernoteScrollSummernoteChangeSummernoteDialogShown() {
        _this.update();
      },
      'summernote.disable summernote.blur': function summernoteDisableSummernoteBlur() {
        _this.hide();
      },
      'summernote.codeview.toggled': function summernoteCodeviewToggled() {
        _this.update();
      }
    };
  }
  return Handle_createClass(Handle, [{
    key: "initialize",
    value: function initialize() {
      var _this2 = this;
      this.$handle = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(['<div class="note-handle">', '<div class="note-control-selection">', '<div class="note-control-selection-bg"></div>', '<div class="note-control-holder note-control-nw"></div>', '<div class="note-control-holder note-control-ne"></div>', '<div class="note-control-holder note-control-sw"></div>', '<div class="', this.options.disableResizeImage ? 'note-control-holder' : 'note-control-sizing', ' note-control-se"></div>', this.options.disableResizeImage ? '' : '<div class="note-control-selection-info"></div>', '</div>', '</div>'].join('')).prependTo(this.$editingArea);
      this.$handle.on('mousedown', function (event) {
        if (dom.isControlSizing(event.target)) {
          event.preventDefault();
          event.stopPropagation();
          var $target = _this2.$handle.find('.note-control-selection').data('target');
          var posStart = $target.offset();
          var scrollTop = _this2.$document.scrollTop();
          var onMouseMove = function onMouseMove(event) {
            _this2.context.invoke('editor.resizeTo', {
              x: event.clientX - posStart.left,
              y: event.clientY - (posStart.top - scrollTop)
            }, $target, !event.shiftKey);
            _this2.update($target[0], event);
          };
          _this2.$document.on('mousemove', onMouseMove).one('mouseup', function (e) {
            e.preventDefault();
            _this2.$document.off('mousemove', onMouseMove);
            _this2.context.invoke('editor.afterCommand');
          });
          if (!$target.data('ratio')) {
            // original ratio.
            $target.data('ratio', $target.height() / $target.width());
          }
        }
      });

      // Listen for scrolling on the handle overlay.
      this.$handle.on('wheel', function (event) {
        event.preventDefault();
        _this2.update();
      });
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$handle.remove();
    }
  }, {
    key: "update",
    value: function update(target, event) {
      if (this.context.isDisabled()) {
        return false;
      }
      var isImage = dom.isImg(target);
      var $selection = this.$handle.find('.note-control-selection');
      this.context.invoke('imagePopover.update', target, event);
      if (isImage) {
        var $image = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(target);
        var areaRect = this.$editingArea[0].getBoundingClientRect();
        var imageRect = target.getBoundingClientRect();
        $selection.css({
          display: 'block',
          left: imageRect.left - areaRect.left,
          top: imageRect.top - areaRect.top,
          width: imageRect.width,
          height: imageRect.height
        }).data('target', $image); // save current image element.

        var origImageObj = new Image();
        origImageObj.src = $image.attr('src');
        var sizingText = imageRect.width + 'x' + imageRect.height + ' (' + this.lang.image.original + ': ' + origImageObj.width + 'x' + origImageObj.height + ')';
        $selection.find('.note-control-selection-info').text(sizingText);
        this.context.invoke('editor.saveTarget', target);
      } else {
        this.hide();
      }
      return isImage;
    }

    /**
     * hide
     *
     * @param {jQuery} $handle
     */
  }, {
    key: "hide",
    value: function hide() {
      this.context.invoke('editor.clearTarget');
      this.$handle.children().hide();
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/AutoLink.js
function AutoLink_typeof(o) { "@babel/helpers - typeof"; return AutoLink_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AutoLink_typeof(o); }
function AutoLink_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function AutoLink_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, AutoLink_toPropertyKey(o.key), o); } }
function AutoLink_createClass(e, r, t) { return r && AutoLink_defineProperties(e.prototype, r), t && AutoLink_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function AutoLink_toPropertyKey(t) { var i = AutoLink_toPrimitive(t, "string"); return "symbol" == AutoLink_typeof(i) ? i : i + ""; }
function AutoLink_toPrimitive(t, r) { if ("object" != AutoLink_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != AutoLink_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }



var defaultScheme = 'http://';
var linkPattern = /^([A-Za-z][A-Za-z0-9+-.]*\:[\/]{2}|tel:|mailto:[A-Z0-9._%+-]+@|xmpp:[A-Z0-9._%+-]+@)?(www\.)?(.+)$/i;
var AutoLink = /*#__PURE__*/function () {
  function AutoLink(context) {
    var _this = this;
    AutoLink_classCallCheck(this, AutoLink);
    this.context = context;
    this.options = context.options;
    this.$editable = context.layoutInfo.editable;
    this.events = {
      'summernote.keyup': function summernoteKeyup(we, event) {
        if (!event.isDefaultPrevented()) {
          _this.handleKeyup(event);
        }
      },
      'summernote.keydown': function summernoteKeydown(we, event) {
        _this.handleKeydown(event);
      }
    };
  }
  return AutoLink_createClass(AutoLink, [{
    key: "initialize",
    value: function initialize() {
      this.lastWordRange = null;
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.lastWordRange = null;
    }
  }, {
    key: "replace",
    value: function replace() {
      if (!this.lastWordRange) {
        return;
      }
      var keyword = this.lastWordRange.toString();
      var match = keyword.match(linkPattern);
      if (match && (match[1] || match[2])) {
        var link = match[1] ? keyword : defaultScheme + keyword;
        var urlText = this.options.showDomainOnlyForAutolink ? keyword.replace(/^(?:https?:\/\/)?(?:tel?:?)?(?:mailto?:?)?(?:xmpp?:?)?(?:www\.)?/i, '').split('/')[0] : keyword;
        var node = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<a></a>').html(urlText).attr('href', link)[0];
        if (this.context.options.linkTargetBlank) {
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(node).attr('target', '_blank');
        }
        this.lastWordRange.insertNode(node);
        this.lastWordRange = null;
        this.context.invoke('editor.focus');
        this.context.triggerEvent('change', this.$editable.html(), this.$editable);
      }
    }
  }, {
    key: "handleKeydown",
    value: function handleKeydown(event) {
      if (lists.contains([key.code.ENTER, key.code.SPACE], event.keyCode)) {
        var wordRange = this.context.invoke('editor.createRange').getWordRange();
        this.lastWordRange = wordRange;
      }
    }
  }, {
    key: "handleKeyup",
    value: function handleKeyup(event) {
      if (key.code.SPACE === event.keyCode || key.code.ENTER === event.keyCode && !event.shiftKey) {
        this.replace();
      }
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/AutoSync.js
function AutoSync_typeof(o) { "@babel/helpers - typeof"; return AutoSync_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AutoSync_typeof(o); }
function AutoSync_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function AutoSync_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, AutoSync_toPropertyKey(o.key), o); } }
function AutoSync_createClass(e, r, t) { return r && AutoSync_defineProperties(e.prototype, r), t && AutoSync_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function AutoSync_toPropertyKey(t) { var i = AutoSync_toPrimitive(t, "string"); return "symbol" == AutoSync_typeof(i) ? i : i + ""; }
function AutoSync_toPrimitive(t, r) { if ("object" != AutoSync_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != AutoSync_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }


/**
 * textarea auto sync.
 */
var AutoSync = /*#__PURE__*/function () {
  function AutoSync(context) {
    var _this = this;
    AutoSync_classCallCheck(this, AutoSync);
    this.$note = context.layoutInfo.note;
    this.events = {
      'summernote.change': function summernoteChange() {
        _this.$note.val(context.invoke('code'));
      }
    };
  }
  return AutoSync_createClass(AutoSync, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return dom.isTextarea(this.$note[0]);
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/AutoReplace.js
function AutoReplace_typeof(o) { "@babel/helpers - typeof"; return AutoReplace_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AutoReplace_typeof(o); }
function AutoReplace_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function AutoReplace_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, AutoReplace_toPropertyKey(o.key), o); } }
function AutoReplace_createClass(e, r, t) { return r && AutoReplace_defineProperties(e.prototype, r), t && AutoReplace_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function AutoReplace_toPropertyKey(t) { var i = AutoReplace_toPrimitive(t, "string"); return "symbol" == AutoReplace_typeof(i) ? i : i + ""; }
function AutoReplace_toPrimitive(t, r) { if ("object" != AutoReplace_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != AutoReplace_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }



var AutoReplace = /*#__PURE__*/function () {
  function AutoReplace(context) {
    var _this = this;
    AutoReplace_classCallCheck(this, AutoReplace);
    this.context = context;
    this.options = context.options.replace || {};
    this.keys = [key.code.ENTER, key.code.SPACE, key.code.PERIOD, key.code.COMMA, key.code.SEMICOLON, key.code.SLASH];
    this.previousKeydownCode = null;
    this.events = {
      'summernote.keyup': function summernoteKeyup(we, event) {
        if (!event.isDefaultPrevented()) {
          _this.handleKeyup(event);
        }
      },
      'summernote.keydown': function summernoteKeydown(we, event) {
        _this.handleKeydown(event);
      }
    };
  }
  return AutoReplace_createClass(AutoReplace, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return !!this.options.match;
    }
  }, {
    key: "initialize",
    value: function initialize() {
      this.lastWord = null;
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.lastWord = null;
    }
  }, {
    key: "replace",
    value: function replace() {
      if (!this.lastWord) {
        return;
      }
      var self = this;
      var keyword = this.lastWord.toString();
      this.options.match(keyword, function (match) {
        if (match) {
          var node = '';
          if (typeof match === 'string') {
            node = dom.createText(match);
          } else if (match instanceof jQuery) {
            node = match[0];
          } else if (match instanceof Node) {
            node = match;
          }
          if (!node) return;
          self.lastWord.insertNode(node);
          self.lastWord = null;
          self.context.invoke('editor.focus');
        }
      });
    }
  }, {
    key: "handleKeydown",
    value: function handleKeydown(event) {
      // this forces it to remember the last whole word, even if multiple termination keys are pressed
      // before the previous key is let go.
      if (this.previousKeydownCode && lists.contains(this.keys, this.previousKeydownCode)) {
        this.previousKeydownCode = event.keyCode;
        return;
      }
      if (lists.contains(this.keys, event.keyCode)) {
        var wordRange = this.context.invoke('editor.createRange').getWordRange();
        this.lastWord = wordRange;
      }
      this.previousKeydownCode = event.keyCode;
    }
  }, {
    key: "handleKeyup",
    value: function handleKeyup(event) {
      if (lists.contains(this.keys, event.keyCode)) {
        this.replace();
      }
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Placeholder.js
function Placeholder_typeof(o) { "@babel/helpers - typeof"; return Placeholder_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Placeholder_typeof(o); }
function Placeholder_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Placeholder_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Placeholder_toPropertyKey(o.key), o); } }
function Placeholder_createClass(e, r, t) { return r && Placeholder_defineProperties(e.prototype, r), t && Placeholder_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Placeholder_toPropertyKey(t) { var i = Placeholder_toPrimitive(t, "string"); return "symbol" == Placeholder_typeof(i) ? i : i + ""; }
function Placeholder_toPrimitive(t, r) { if ("object" != Placeholder_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Placeholder_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var Placeholder = /*#__PURE__*/function () {
  function Placeholder(context) {
    var _this = this;
    Placeholder_classCallCheck(this, Placeholder);
    this.context = context;
    this.$editingArea = context.layoutInfo.editingArea;
    this.options = context.options;
    if (this.options.inheritPlaceholder === true) {
      // get placeholder value from the original element
      this.options.placeholder = this.context.$note.attr('placeholder') || this.options.placeholder;
    }
    this.events = {
      'summernote.init summernote.change': function summernoteInitSummernoteChange() {
        _this.update();
      },
      'summernote.codeview.toggled': function summernoteCodeviewToggled() {
        _this.update();
      }
    };
  }
  return Placeholder_createClass(Placeholder, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return !!this.options.placeholder;
    }
  }, {
    key: "initialize",
    value: function initialize() {
      var _this2 = this;
      this.$placeholder = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div class="note-placeholder"></div>');
      this.$placeholder.on('click', function () {
        _this2.context.invoke('focus');
      }).html(this.options.placeholder).prependTo(this.$editingArea);
      this.update();
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$placeholder.remove();
    }
  }, {
    key: "update",
    value: function update() {
      var isShow = !this.context.invoke('codeview.isActivated') && this.context.invoke('editor.isEmpty');
      this.$placeholder.toggle(isShow);
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Buttons.js
function Buttons_typeof(o) { "@babel/helpers - typeof"; return Buttons_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Buttons_typeof(o); }
function Buttons_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Buttons_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Buttons_toPropertyKey(o.key), o); } }
function Buttons_createClass(e, r, t) { return r && Buttons_defineProperties(e.prototype, r), t && Buttons_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Buttons_toPropertyKey(t) { var i = Buttons_toPrimitive(t, "string"); return "symbol" == Buttons_typeof(i) ? i : i + ""; }
function Buttons_toPrimitive(t, r) { if ("object" != Buttons_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Buttons_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }




var Buttons = /*#__PURE__*/function () {
  function Buttons(context) {
    Buttons_classCallCheck(this, Buttons);
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.context = context;
    this.$toolbar = context.layoutInfo.toolbar;
    this.options = context.options;
    this.lang = this.options.langInfo;
    this.invertedKeyMap = func.invertObject(this.options.keyMap[env.isMac ? 'mac' : 'pc']);
  }
  return Buttons_createClass(Buttons, [{
    key: "representShortcut",
    value: function representShortcut(editorMethod) {
      var shortcut = this.invertedKeyMap[editorMethod];
      if (!this.options.shortcuts || !shortcut) {
        return '';
      }
      if (env.isMac) {
        shortcut = shortcut.replace('CMD', '⌘').replace('SHIFT', '⇧');
      }
      shortcut = shortcut.replace('BACKSLASH', '\\').replace('SLASH', '/').replace('LEFTBRACKET', '[').replace('RIGHTBRACKET', ']');
      return ' (' + shortcut + ')';
    }
  }, {
    key: "button",
    value: function button(o) {
      if (!this.options.tooltip && o.tooltip) {
        delete o.tooltip;
      }
      o.container = this.options.container;
      return this.ui.button(o);
    }
  }, {
    key: "initialize",
    value: function initialize() {
      this.addToolbarButtons();
      this.addImagePopoverButtons();
      this.addLinkPopoverButtons();
      this.addTablePopoverButtons();
      this.fontInstalledMap = {};
    }
  }, {
    key: "destroy",
    value: function destroy() {
      delete this.fontInstalledMap;
    }
  }, {
    key: "isFontInstalled",
    value: function isFontInstalled(name) {
      if (!Object.prototype.hasOwnProperty.call(this.fontInstalledMap, name)) {
        this.fontInstalledMap[name] = env.isFontInstalled(name) || lists.contains(this.options.fontNamesIgnoreCheck, name);
      }
      return this.fontInstalledMap[name];
    }
  }, {
    key: "isFontDeservedToAdd",
    value: function isFontDeservedToAdd(name) {
      name = name.toLowerCase();
      return name !== '' && this.isFontInstalled(name) && env.genericFontFamilies.indexOf(name) === -1;
    }
  }, {
    key: "colorPalette",
    value: function colorPalette(className, tooltip, backColor, foreColor) {
      var _this = this;
      return this.ui.buttonGroup({
        className: 'note-color ' + className,
        children: [this.button({
          className: 'note-current-color-button',
          contents: this.ui.icon(this.options.icons.font + ' note-recent-color'),
          tooltip: tooltip,
          click: function click(event) {
            var $button = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.currentTarget);
            if (backColor && foreColor) {
              _this.context.invoke('editor.color', {
                backColor: $button.attr('data-backColor'),
                foreColor: $button.attr('data-foreColor')
              });
            } else if (backColor) {
              _this.context.invoke('editor.color', {
                backColor: $button.attr('data-backColor')
              });
            } else if (foreColor) {
              _this.context.invoke('editor.color', {
                foreColor: $button.attr('data-foreColor')
              });
            }
          },
          callback: function callback($button) {
            var $recentColor = $button.find('.note-recent-color');
            if (backColor) {
              $recentColor.css('background-color', _this.options.colorButton.backColor);
              $button.attr('data-backColor', _this.options.colorButton.backColor);
            }
            if (foreColor) {
              $recentColor.css('color', _this.options.colorButton.foreColor);
              $button.attr('data-foreColor', _this.options.colorButton.foreColor);
            } else {
              $recentColor.css('color', 'transparent');
            }
          }
        }), this.button({
          className: 'dropdown-toggle',
          contents: this.ui.dropdownButtonContents('', this.options),
          tooltip: this.lang.color.more,
          data: {
            toggle: 'dropdown'
          }
        }), this.ui.dropdown({
          items: (backColor ? ['<div class="note-palette">', '<div class="note-palette-title">' + this.lang.color.background + '</div>', '<div>', '<button type="button" class="note-color-reset btn btn-light btn-default" data-event="backColor" data-value="transparent">', this.lang.color.transparent, '</button>', '</div>', '<div class="note-holder" data-event="backColor"><!-- back colors --></div>', '<div>', '<button type="button" class="note-color-select btn btn-light btn-default" data-event="openPalette" data-value="backColorPicker-' + this.options.id + '">', this.lang.color.cpSelect, '</button>', '<input type="color" id="backColorPicker-' + this.options.id + '" class="note-btn note-color-select-btn" value="' + this.options.colorButton.backColor + '" data-event="backColorPalette-' + this.options.id + '">', '</div>', '<div class="note-holder-custom" id="backColorPalette-' + this.options.id + '" data-event="backColor"></div>', '</div>'].join('') : '') + (foreColor ? ['<div class="note-palette">', '<div class="note-palette-title">' + this.lang.color.foreground + '</div>', '<div>', '<button type="button" class="note-color-reset btn btn-light btn-default" data-event="removeFormat" data-value="foreColor">', this.lang.color.resetToDefault, '</button>', '</div>', '<div class="note-holder" data-event="foreColor"><!-- fore colors --></div>', '<div>', '<button type="button" class="note-color-select btn btn-light btn-default" data-event="openPalette" data-value="foreColorPicker-' + this.options.id + '">', this.lang.color.cpSelect, '</button>', '<input type="color" id="foreColorPicker-' + this.options.id + '" class="note-btn note-color-select-btn" value="' + this.options.colorButton.foreColor + '" data-event="foreColorPalette-' + this.options.id + '">', '</div>',
          // Fix missing Div, Commented to find easily if it's wrong
          '<div class="note-holder-custom" id="foreColorPalette-' + this.options.id + '" data-event="foreColor"></div>', '</div>'].join('') : ''),
          callback: function callback($dropdown) {
            $dropdown.find('.note-holder').each(function (idx, item) {
              var $holder = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item);
              $holder.append(_this.ui.palette({
                colors: _this.options.colors,
                colorsName: _this.options.colorsName,
                eventName: $holder.data('event'),
                container: _this.options.container,
                tooltip: _this.options.tooltip
              }).render());
            });
            /* TODO: do we have to record recent custom colors within cookies? */
            var customColors = [['#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF', '#FFFFFF']];
            $dropdown.find('.note-holder-custom').each(function (idx, item) {
              var $holder = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item);
              $holder.append(_this.ui.palette({
                colors: customColors,
                colorsName: customColors,
                eventName: $holder.data('event'),
                container: _this.options.container,
                tooltip: _this.options.tooltip
              }).render());
            });
            $dropdown.find('input[type=color]').each(function (idx, item) {
              external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item).on("change", function () {
                var $chip = $dropdown.find('#' + external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this).data('event')).find('.note-color-btn').first();
                var color = this.value.toUpperCase();
                $chip.css('background-color', color).attr('aria-label', color).attr('data-value', color).attr('data-original-title', color);
                $chip.trigger('click');
              });
            });
          },
          click: function click(event) {
            event.stopPropagation();
            var $parent = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('.' + className).find('.note-dropdown-menu');
            var $button = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.target);
            var eventName = $button.data('event');
            var value = $button.attr('data-value');
            if (eventName === 'openPalette') {
              var $picker = $parent.find('#' + value);
              var $palette = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()($parent.find('#' + $picker.data('event')).find('.note-color-row')[0]);

              // Shift palette chips
              var $chip = $palette.find('.note-color-btn').last().detach();

              // Set chip attributes
              var color = $picker.val();
              $chip.css('background-color', color).attr('aria-label', color).attr('data-value', color).attr('data-original-title', color);
              $palette.prepend($chip);
              $picker.trigger('click');
            } else {
              if (lists.contains(['backColor', 'foreColor'], eventName)) {
                var key = eventName === 'backColor' ? 'background-color' : 'color';
                var $color = $button.closest('.note-color').find('.note-recent-color');
                var $currentButton = $button.closest('.note-color').find('.note-current-color-button');
                $color.css(key, value);
                $currentButton.attr('data-' + eventName, value);
              }
              _this.context.invoke('editor.' + eventName, value);
            }
          }
        })]
      }).render();
    }
  }, {
    key: "addToolbarButtons",
    value: function addToolbarButtons() {
      var _this2 = this;
      this.context.memo('button.style', function () {
        return _this2.ui.buttonGroup([_this2.button({
          className: 'dropdown-toggle',
          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.magic), _this2.options),
          tooltip: _this2.lang.style.style,
          data: {
            toggle: 'dropdown'
          }
        }), _this2.ui.dropdown({
          className: 'dropdown-style',
          items: _this2.options.styleTags,
          title: _this2.lang.style.style,
          template: function template(item) {
            // TBD: need to be simplified
            if (typeof item === 'string') {
              item = {
                tag: item,
                title: Object.prototype.hasOwnProperty.call(_this2.lang.style, item) ? _this2.lang.style[item] : item
              };
            }
            var tag = item.tag;
            var title = item.title;
            var style = item.style ? ' style="' + item.style + '" ' : '';
            var className = item.className ? ' class="' + item.className + '"' : '';
            return '<' + tag + style + className + '>' + title + '</' + tag + '>';
          },
          click: _this2.context.createInvokeHandler('editor.formatBlock')
        })]).render();
      });
      var _loop = function _loop() {
        var item = _this2.options.styleTags[styleIdx];
        _this2.context.memo('button.style.' + item, function () {
          return _this2.button({
            className: 'note-btn-style-' + item,
            contents: '<div data-value="' + item + '">' + item.toUpperCase() + '</div>',
            tooltip: _this2.lang.style[item],
            click: _this2.context.createInvokeHandler('editor.formatBlock')
          }).render();
        });
      };
      for (var styleIdx = 0, styleLen = this.options.styleTags.length; styleIdx < styleLen; styleIdx++) {
        _loop();
      }
      this.context.memo('button.bold', function () {
        return _this2.button({
          className: 'note-btn-bold',
          contents: _this2.ui.icon(_this2.options.icons.bold),
          tooltip: _this2.lang.font.bold + _this2.representShortcut('bold'),
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.bold')
        }).render();
      });
      this.context.memo('button.italic', function () {
        return _this2.button({
          className: 'note-btn-italic',
          contents: _this2.ui.icon(_this2.options.icons.italic),
          tooltip: _this2.lang.font.italic + _this2.representShortcut('italic'),
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.italic')
        }).render();
      });
      this.context.memo('button.underline', function () {
        return _this2.button({
          className: 'note-btn-underline',
          contents: _this2.ui.icon(_this2.options.icons.underline),
          tooltip: _this2.lang.font.underline + _this2.representShortcut('underline'),
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.underline')
        }).render();
      });
      this.context.memo('button.clear', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.eraser),
          tooltip: _this2.lang.font.clear + _this2.representShortcut('removeFormat'),
          click: _this2.context.createInvokeHandler('editor.removeFormat')
        }).render();
      });
      this.context.memo('button.strikethrough', function () {
        return _this2.button({
          className: 'note-btn-strikethrough',
          contents: _this2.ui.icon(_this2.options.icons.strikethrough),
          tooltip: _this2.lang.font.strikethrough + _this2.representShortcut('strikethrough'),
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.strikethrough')
        }).render();
      });
      this.context.memo('button.superscript', function () {
        return _this2.button({
          className: 'note-btn-superscript',
          contents: _this2.ui.icon(_this2.options.icons.superscript),
          tooltip: _this2.lang.font.superscript,
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.superscript')
        }).render();
      });
      this.context.memo('button.subscript', function () {
        return _this2.button({
          className: 'note-btn-subscript',
          contents: _this2.ui.icon(_this2.options.icons.subscript),
          tooltip: _this2.lang.font.subscript,
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.subscript')
        }).render();
      });
      this.context.memo('button.fontname', function () {
        var styleInfo = _this2.context.invoke('editor.currentStyle');
        if (_this2.options.addDefaultFonts) {
          // Add 'default' fonts into the fontnames array if not exist
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(styleInfo['font-family'].split(','), function (idx, fontname) {
            fontname = fontname.trim().replace(/['"]+/g, '');
            if (_this2.isFontDeservedToAdd(fontname)) {
              if (_this2.options.fontNames.indexOf(fontname) === -1) {
                _this2.options.fontNames.push(fontname);
              }
            }
          });
        }
        return _this2.ui.buttonGroup([_this2.button({
          className: 'dropdown-toggle',
          contents: _this2.ui.dropdownButtonContents('<span class="note-current-fontname"></span>', _this2.options),
          tooltip: _this2.lang.font.name,
          data: {
            toggle: 'dropdown'
          }
        }), _this2.ui.dropdownCheck({
          className: 'dropdown-fontname',
          checkClassName: _this2.options.icons.menuCheck,
          items: _this2.options.fontNames.filter(_this2.isFontInstalled.bind(_this2)),
          title: _this2.lang.font.name,
          template: function template(item) {
            return '<span style="font-family: ' + env.validFontName(item) + '">' + item + '</span>';
          },
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.fontName')
        })]).render();
      });
      this.context.memo('button.fontsize', function () {
        return _this2.ui.buttonGroup([_this2.button({
          className: 'dropdown-toggle',
          contents: _this2.ui.dropdownButtonContents('<span class="note-current-fontsize"></span>', _this2.options),
          tooltip: _this2.lang.font.size,
          data: {
            toggle: 'dropdown'
          }
        }), _this2.ui.dropdownCheck({
          className: 'dropdown-fontsize',
          checkClassName: _this2.options.icons.menuCheck,
          items: _this2.options.fontSizes,
          title: _this2.lang.font.size,
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.fontSize')
        })]).render();
      });
      this.context.memo('button.fontsizeunit', function () {
        return _this2.ui.buttonGroup([_this2.button({
          className: 'dropdown-toggle',
          contents: _this2.ui.dropdownButtonContents('<span class="note-current-fontsizeunit"></span>', _this2.options),
          tooltip: _this2.lang.font.sizeunit,
          data: {
            toggle: 'dropdown'
          }
        }), _this2.ui.dropdownCheck({
          className: 'dropdown-fontsizeunit',
          checkClassName: _this2.options.icons.menuCheck,
          items: _this2.options.fontSizeUnits,
          title: _this2.lang.font.sizeunit,
          click: _this2.context.createInvokeHandlerAndUpdateState('editor.fontSizeUnit')
        })]).render();
      });
      this.context.memo('button.color', function () {
        return _this2.colorPalette('note-color-all', _this2.lang.color.recent, true, true);
      });
      this.context.memo('button.forecolor', function () {
        return _this2.colorPalette('note-color-fore', _this2.lang.color.foreground, false, true);
      });
      this.context.memo('button.backcolor', function () {
        return _this2.colorPalette('note-color-back', _this2.lang.color.background, true, false);
      });
      this.context.memo('button.ul', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.unorderedlist),
          tooltip: _this2.lang.lists.unordered + _this2.representShortcut('insertUnorderedList'),
          click: _this2.context.createInvokeHandler('editor.insertUnorderedList')
        }).render();
      });
      this.context.memo('button.ol', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.orderedlist),
          tooltip: _this2.lang.lists.ordered + _this2.representShortcut('insertOrderedList'),
          click: _this2.context.createInvokeHandler('editor.insertOrderedList')
        }).render();
      });
      var justifyLeft = this.button({
        contents: this.ui.icon(this.options.icons.alignLeft),
        tooltip: this.lang.paragraph.left + this.representShortcut('justifyLeft'),
        click: this.context.createInvokeHandler('editor.justifyLeft')
      });
      var justifyCenter = this.button({
        contents: this.ui.icon(this.options.icons.alignCenter),
        tooltip: this.lang.paragraph.center + this.representShortcut('justifyCenter'),
        click: this.context.createInvokeHandler('editor.justifyCenter')
      });
      var justifyRight = this.button({
        contents: this.ui.icon(this.options.icons.alignRight),
        tooltip: this.lang.paragraph.right + this.representShortcut('justifyRight'),
        click: this.context.createInvokeHandler('editor.justifyRight')
      });
      var justifyFull = this.button({
        contents: this.ui.icon(this.options.icons.alignJustify),
        tooltip: this.lang.paragraph.justify + this.representShortcut('justifyFull'),
        click: this.context.createInvokeHandler('editor.justifyFull')
      });
      var outdent = this.button({
        contents: this.ui.icon(this.options.icons.outdent),
        tooltip: this.lang.paragraph.outdent + this.representShortcut('outdent'),
        click: this.context.createInvokeHandler('editor.outdent')
      });
      var indent = this.button({
        contents: this.ui.icon(this.options.icons.indent),
        tooltip: this.lang.paragraph.indent + this.representShortcut('indent'),
        click: this.context.createInvokeHandler('editor.indent')
      });
      this.context.memo('button.justifyLeft', func.invoke(justifyLeft, 'render'));
      this.context.memo('button.justifyCenter', func.invoke(justifyCenter, 'render'));
      this.context.memo('button.justifyRight', func.invoke(justifyRight, 'render'));
      this.context.memo('button.justifyFull', func.invoke(justifyFull, 'render'));
      this.context.memo('button.outdent', func.invoke(outdent, 'render'));
      this.context.memo('button.indent', func.invoke(indent, 'render'));
      this.context.memo('button.paragraph', function () {
        return _this2.ui.buttonGroup([_this2.button({
          className: 'dropdown-toggle',
          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.alignLeft), _this2.options),
          tooltip: _this2.lang.paragraph.paragraph,
          data: {
            toggle: 'dropdown'
          }
        }), _this2.ui.dropdown([_this2.ui.buttonGroup({
          className: 'note-align',
          children: [justifyLeft, justifyCenter, justifyRight, justifyFull]
        }), _this2.ui.buttonGroup({
          className: 'note-list',
          children: [outdent, indent]
        })])]).render();
      });
      this.context.memo('button.height', function () {
        return _this2.ui.buttonGroup([_this2.button({
          className: 'dropdown-toggle',
          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.textHeight), _this2.options),
          tooltip: _this2.lang.font.height,
          data: {
            toggle: 'dropdown'
          }
        }), _this2.ui.dropdownCheck({
          items: _this2.options.lineHeights,
          checkClassName: _this2.options.icons.menuCheck,
          className: 'dropdown-line-height',
          title: _this2.lang.font.height,
          click: _this2.context.createInvokeHandler('editor.lineHeight')
        })]).render();
      });
      this.context.memo('button.table', function () {
        return _this2.ui.buttonGroup([_this2.button({
          className: 'dropdown-toggle',
          contents: _this2.ui.dropdownButtonContents(_this2.ui.icon(_this2.options.icons.table), _this2.options),
          tooltip: _this2.lang.table.table,
          data: {
            toggle: 'dropdown'
          }
        }), _this2.ui.dropdown({
          title: _this2.lang.table.table,
          className: 'note-table',
          items: ['<div class="note-dimension-picker">', '<div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"></div>', '<div class="note-dimension-picker-highlighted"></div>', '<div class="note-dimension-picker-unhighlighted"></div>', '</div>', '<div class="note-dimension-display">1 x 1</div>'].join('')
        })], {
          callback: function callback($node) {
            var $catcher = $node.find('.note-dimension-picker-mousecatcher');
            $catcher.css({
              width: _this2.options.insertTableMaxSize.col + 'em',
              height: _this2.options.insertTableMaxSize.row + 'em'
            }).on('mousedown', _this2.context.createInvokeHandler('editor.insertTable')).on('mousemove', _this2.tableMoveHandler.bind(_this2));
          }
        }).render();
      });
      this.context.memo('button.link', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.link),
          tooltip: _this2.lang.link.link + _this2.representShortcut('linkDialog.show'),
          click: _this2.context.createInvokeHandler('linkDialog.show')
        }).render();
      });
      this.context.memo('button.picture', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.picture),
          tooltip: _this2.lang.image.image,
          click: _this2.context.createInvokeHandler('imageDialog.show')
        }).render();
      });
      this.context.memo('button.video', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.video),
          tooltip: _this2.lang.video.video,
          click: _this2.context.createInvokeHandler('videoDialog.show')
        }).render();
      });
      this.context.memo('button.hr', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.minus),
          tooltip: _this2.lang.hr.insert + _this2.representShortcut('insertHorizontalRule'),
          click: _this2.context.createInvokeHandler('editor.insertHorizontalRule')
        }).render();
      });
      this.context.memo('button.fullscreen', function () {
        return _this2.button({
          className: 'btn-fullscreen note-codeview-keep',
          contents: _this2.ui.icon(_this2.options.icons.arrowsAlt),
          tooltip: _this2.lang.options.fullscreen,
          click: _this2.context.createInvokeHandler('fullscreen.toggle')
        }).render();
      });
      this.context.memo('button.codeview', function () {
        return _this2.button({
          className: 'btn-codeview note-codeview-keep',
          contents: _this2.ui.icon(_this2.options.icons.code),
          tooltip: _this2.lang.options.codeview,
          click: _this2.context.createInvokeHandler('codeview.toggle')
        }).render();
      });
      this.context.memo('button.redo', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.redo),
          tooltip: _this2.lang.history.redo + _this2.representShortcut('redo'),
          click: _this2.context.createInvokeHandler('editor.redo')
        }).render();
      });
      this.context.memo('button.undo', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.undo),
          tooltip: _this2.lang.history.undo + _this2.representShortcut('undo'),
          click: _this2.context.createInvokeHandler('editor.undo')
        }).render();
      });
      this.context.memo('button.help', function () {
        return _this2.button({
          contents: _this2.ui.icon(_this2.options.icons.question),
          tooltip: _this2.lang.options.help,
          click: _this2.context.createInvokeHandler('helpDialog.show')
        }).render();
      });
    }

    /**
     * image: [
     *   ['imageResize', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']],
     *   ['float', ['floatLeft', 'floatRight', 'floatNone']],
     *   ['remove', ['removeMedia']],
     * ],
     */
  }, {
    key: "addImagePopoverButtons",
    value: function addImagePopoverButtons() {
      var _this3 = this;
      // Image Size Buttons
      this.context.memo('button.resizeFull', function () {
        return _this3.button({
          contents: '<span class="note-fontsize-10">100%</span>',
          tooltip: _this3.lang.image.resizeFull,
          click: _this3.context.createInvokeHandler('editor.resize', '1')
        }).render();
      });
      this.context.memo('button.resizeHalf', function () {
        return _this3.button({
          contents: '<span class="note-fontsize-10">50%</span>',
          tooltip: _this3.lang.image.resizeHalf,
          click: _this3.context.createInvokeHandler('editor.resize', '0.5')
        }).render();
      });
      this.context.memo('button.resizeQuarter', function () {
        return _this3.button({
          contents: '<span class="note-fontsize-10">25%</span>',
          tooltip: _this3.lang.image.resizeQuarter,
          click: _this3.context.createInvokeHandler('editor.resize', '0.25')
        }).render();
      });
      this.context.memo('button.resizeNone', function () {
        return _this3.button({
          contents: _this3.ui.icon(_this3.options.icons.rollback),
          tooltip: _this3.lang.image.resizeNone,
          click: _this3.context.createInvokeHandler('editor.resize', '0')
        }).render();
      });

      // Float Buttons
      this.context.memo('button.floatLeft', function () {
        return _this3.button({
          contents: _this3.ui.icon(_this3.options.icons.floatLeft),
          tooltip: _this3.lang.image.floatLeft,
          click: _this3.context.createInvokeHandler('editor.floatMe', 'left')
        }).render();
      });
      this.context.memo('button.floatRight', function () {
        return _this3.button({
          contents: _this3.ui.icon(_this3.options.icons.floatRight),
          tooltip: _this3.lang.image.floatRight,
          click: _this3.context.createInvokeHandler('editor.floatMe', 'right')
        }).render();
      });
      this.context.memo('button.floatNone', function () {
        return _this3.button({
          contents: _this3.ui.icon(_this3.options.icons.rollback),
          tooltip: _this3.lang.image.floatNone,
          click: _this3.context.createInvokeHandler('editor.floatMe', 'none')
        }).render();
      });

      // Remove Buttons
      this.context.memo('button.removeMedia', function () {
        return _this3.button({
          contents: _this3.ui.icon(_this3.options.icons.trash),
          tooltip: _this3.lang.image.remove,
          click: _this3.context.createInvokeHandler('editor.removeMedia')
        }).render();
      });
    }
  }, {
    key: "addLinkPopoverButtons",
    value: function addLinkPopoverButtons() {
      var _this4 = this;
      this.context.memo('button.linkDialogShow', function () {
        return _this4.button({
          contents: _this4.ui.icon(_this4.options.icons.link),
          tooltip: _this4.lang.link.edit,
          click: _this4.context.createInvokeHandler('linkDialog.show')
        }).render();
      });
      this.context.memo('button.unlink', function () {
        return _this4.button({
          contents: _this4.ui.icon(_this4.options.icons.unlink),
          tooltip: _this4.lang.link.unlink,
          click: _this4.context.createInvokeHandler('editor.unlink')
        }).render();
      });
    }

    /**
     * table : [
     *  ['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']],
     *  ['delete', ['deleteRow', 'deleteCol', 'deleteTable']]
     * ],
     */
  }, {
    key: "addTablePopoverButtons",
    value: function addTablePopoverButtons() {
      var _this5 = this;
      this.context.memo('button.addRowUp', function () {
        return _this5.button({
          className: 'btn-md',
          contents: _this5.ui.icon(_this5.options.icons.rowAbove),
          tooltip: _this5.lang.table.addRowAbove,
          click: _this5.context.createInvokeHandler('editor.addRow', 'top')
        }).render();
      });
      this.context.memo('button.addRowDown', function () {
        return _this5.button({
          className: 'btn-md',
          contents: _this5.ui.icon(_this5.options.icons.rowBelow),
          tooltip: _this5.lang.table.addRowBelow,
          click: _this5.context.createInvokeHandler('editor.addRow', 'bottom')
        }).render();
      });
      this.context.memo('button.addColLeft', function () {
        return _this5.button({
          className: 'btn-md',
          contents: _this5.ui.icon(_this5.options.icons.colBefore),
          tooltip: _this5.lang.table.addColLeft,
          click: _this5.context.createInvokeHandler('editor.addCol', 'left')
        }).render();
      });
      this.context.memo('button.addColRight', function () {
        return _this5.button({
          className: 'btn-md',
          contents: _this5.ui.icon(_this5.options.icons.colAfter),
          tooltip: _this5.lang.table.addColRight,
          click: _this5.context.createInvokeHandler('editor.addCol', 'right')
        }).render();
      });
      this.context.memo('button.deleteRow', function () {
        return _this5.button({
          className: 'btn-md',
          contents: _this5.ui.icon(_this5.options.icons.rowRemove),
          tooltip: _this5.lang.table.delRow,
          click: _this5.context.createInvokeHandler('editor.deleteRow')
        }).render();
      });
      this.context.memo('button.deleteCol', function () {
        return _this5.button({
          className: 'btn-md',
          contents: _this5.ui.icon(_this5.options.icons.colRemove),
          tooltip: _this5.lang.table.delCol,
          click: _this5.context.createInvokeHandler('editor.deleteCol')
        }).render();
      });
      this.context.memo('button.deleteTable', function () {
        return _this5.button({
          className: 'btn-md',
          contents: _this5.ui.icon(_this5.options.icons.trash),
          tooltip: _this5.lang.table.delTable,
          click: _this5.context.createInvokeHandler('editor.deleteTable')
        }).render();
      });
    }
  }, {
    key: "build",
    value: function build($container, groups) {
      for (var groupIdx = 0, groupLen = groups.length; groupIdx < groupLen; groupIdx++) {
        var group = groups[groupIdx];
        var groupName = Array.isArray(group) ? group[0] : group;
        var buttons = Array.isArray(group) ? group.length === 1 ? [group[0]] : group[1] : [group];
        var $group = this.ui.buttonGroup({
          className: 'note-' + groupName
        }).render();
        for (var idx = 0, len = buttons.length; idx < len; idx++) {
          var btn = this.context.memo('button.' + buttons[idx]);
          if (btn) {
            $group.append(typeof btn === 'function' ? btn(this.context) : btn);
          }
        }
        $group.appendTo($container);
      }
    }

    /**
     * @param {jQuery} [$container]
     */
  }, {
    key: "updateCurrentStyle",
    value: function updateCurrentStyle($container) {
      var $cont = $container || this.$toolbar;
      var styleInfo = this.context.invoke('editor.currentStyle');
      this.updateBtnStates($cont, {
        '.note-btn-bold': function noteBtnBold() {
          return styleInfo['font-bold'] === 'bold';
        },
        '.note-btn-italic': function noteBtnItalic() {
          return styleInfo['font-italic'] === 'italic';
        },
        '.note-btn-underline': function noteBtnUnderline() {
          return styleInfo['font-underline'] === 'underline';
        },
        '.note-btn-subscript': function noteBtnSubscript() {
          return styleInfo['font-subscript'] === 'subscript';
        },
        '.note-btn-superscript': function noteBtnSuperscript() {
          return styleInfo['font-superscript'] === 'superscript';
        },
        '.note-btn-strikethrough': function noteBtnStrikethrough() {
          return styleInfo['font-strikethrough'] === 'strikethrough';
        }
      });
      if (styleInfo['font-family']) {
        var fontNames = styleInfo['font-family'].split(',').map(function (name) {
          return name.replace(/[\'\"]/g, '').replace(/\s+$/, '').replace(/^\s+/, '');
        });
        var fontName = lists.find(fontNames, this.isFontInstalled.bind(this));
        $cont.find('.dropdown-fontname a').each(function (idx, item) {
          var $item = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item);
          // always compare string to avoid creating another func.
          var isChecked = $item.data('value') + '' === fontName + '';
          $item.toggleClass('checked', isChecked);
        });
        $cont.find('.note-current-fontname').text(fontName).css('font-family', fontName);
      }
      if (styleInfo['font-size']) {
        var fontSize = styleInfo['font-size'];
        $cont.find('.dropdown-fontsize a').each(function (idx, item) {
          var $item = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item);
          // always compare with string to avoid creating another func.
          var isChecked = $item.data('value') + '' === fontSize + '';
          $item.toggleClass('checked', isChecked);
        });
        $cont.find('.note-current-fontsize').text(fontSize);
        var fontSizeUnit = styleInfo['font-size-unit'];
        $cont.find('.dropdown-fontsizeunit a').each(function (idx, item) {
          var $item = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item);
          var isChecked = $item.data('value') + '' === fontSizeUnit + '';
          $item.toggleClass('checked', isChecked);
        });
        $cont.find('.note-current-fontsizeunit').text(fontSizeUnit);
      }
      if (styleInfo['line-height']) {
        var lineHeight = styleInfo['line-height'];
        $cont.find('.dropdown-line-height a').each(function (idx, item) {
          var $item = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item);
          // always compare with string to avoid creating another func.
          var isChecked = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(item).data('value') + '' === lineHeight + '';
          $item.toggleClass('checked', isChecked);
        });
        $cont.find('.note-current-line-height').text(lineHeight);
      }
    }
  }, {
    key: "updateBtnStates",
    value: function updateBtnStates($container, infos) {
      var _this6 = this;
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(infos, function (selector, pred) {
        _this6.ui.toggleBtnActive($container.find(selector), pred());
      });
    }
  }, {
    key: "tableMoveHandler",
    value: function tableMoveHandler(event) {
      var PX_PER_EM = 18;
      var $picker = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.target.parentNode); // target is mousecatcher
      var $dimensionDisplay = $picker.next();
      var $catcher = $picker.find('.note-dimension-picker-mousecatcher');
      var $highlighted = $picker.find('.note-dimension-picker-highlighted');
      var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');
      var posOffset;
      // HTML5 with jQuery - e.offsetX is undefined in Firefox
      if (event.offsetX === undefined) {
        var posCatcher = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.target).offset();
        posOffset = {
          x: event.pageX - posCatcher.left,
          y: event.pageY - posCatcher.top
        };
      } else {
        posOffset = {
          x: event.offsetX,
          y: event.offsetY
        };
      }
      var dim = {
        c: Math.ceil(posOffset.x / PX_PER_EM) || 1,
        r: Math.ceil(posOffset.y / PX_PER_EM) || 1
      };
      $highlighted.css({
        width: dim.c + 'em',
        height: dim.r + 'em'
      });
      $catcher.data('value', dim.c + 'x' + dim.r);
      if (dim.c > 3 && dim.c < this.options.insertTableMaxSize.col) {
        $unhighlighted.css({
          width: dim.c + 1 + 'em'
        });
      }
      if (dim.r > 3 && dim.r < this.options.insertTableMaxSize.row) {
        $unhighlighted.css({
          height: dim.r + 1 + 'em'
        });
      }
      $dimensionDisplay.html(dim.c + ' x ' + dim.r);
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/Toolbar.js
function Toolbar_typeof(o) { "@babel/helpers - typeof"; return Toolbar_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Toolbar_typeof(o); }
function Toolbar_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function Toolbar_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, Toolbar_toPropertyKey(o.key), o); } }
function Toolbar_createClass(e, r, t) { return r && Toolbar_defineProperties(e.prototype, r), t && Toolbar_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function Toolbar_toPropertyKey(t) { var i = Toolbar_toPrimitive(t, "string"); return "symbol" == Toolbar_typeof(i) ? i : i + ""; }
function Toolbar_toPrimitive(t, r) { if ("object" != Toolbar_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Toolbar_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var Toolbar = /*#__PURE__*/function () {
  function Toolbar(context) {
    Toolbar_classCallCheck(this, Toolbar);
    this.context = context;
    this.$window = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(window);
    this.$document = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document);
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.$note = context.layoutInfo.note;
    this.$editor = context.layoutInfo.editor;
    this.$toolbar = context.layoutInfo.toolbar;
    this.$editable = context.layoutInfo.editable;
    this.$statusbar = context.layoutInfo.statusbar;
    this.options = context.options;
    this.isFollowing = false;
    this.followScroll = this.followScroll.bind(this);
  }
  return Toolbar_createClass(Toolbar, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return !this.options.airMode;
    }
  }, {
    key: "initialize",
    value: function initialize() {
      var _this = this;
      this.options.toolbar = this.options.toolbar || [];
      if (!this.options.toolbar.length) {
        this.$toolbar.hide();
      } else {
        this.context.invoke('buttons.build', this.$toolbar, this.options.toolbar);
      }
      if (this.options.toolbarContainer) {
        this.$toolbar.appendTo(this.options.toolbarContainer);
      }
      this.changeContainer(false);
      this.$note.on('summernote.keyup summernote.mouseup summernote.change', function () {
        _this.context.invoke('buttons.updateCurrentStyle');
      });
      this.context.invoke('buttons.updateCurrentStyle');
      if (this.options.followingToolbar) {
        this.$window.on('scroll resize', this.followScroll);
      }
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$toolbar.children().remove();
      if (this.options.followingToolbar) {
        this.$window.off('scroll resize', this.followScroll);
      }
    }
  }, {
    key: "followScroll",
    value: function followScroll() {
      if (this.$editor.hasClass('fullscreen')) {
        return false;
      }
      var editorHeight = this.$editor.outerHeight();
      var editorWidth = this.$editor.width();
      var toolbarHeight = this.$toolbar.height();
      var statusbarHeight = this.$statusbar.height();

      // check if the web app is currently using another static bar
      var otherBarHeight = 0;
      if (this.options.otherStaticBar) {
        otherBarHeight = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.otherStaticBar).outerHeight();
      }
      var currentOffset = this.$document.scrollTop();
      var editorOffsetTop = this.$editor.offset().top;
      var editorOffsetBottom = editorOffsetTop + editorHeight;
      var activateOffset = editorOffsetTop - otherBarHeight;
      var deactivateOffsetBottom = editorOffsetBottom - otherBarHeight - toolbarHeight - statusbarHeight;
      if (!this.isFollowing && currentOffset > activateOffset && currentOffset < deactivateOffsetBottom - toolbarHeight) {
        this.isFollowing = true;
        this.$editable.css({
          marginTop: this.$toolbar.outerHeight()
        });
        this.$toolbar.css({
          position: 'fixed',
          top: otherBarHeight,
          width: editorWidth,
          zIndex: 1000
        });
      } else if (this.isFollowing && (currentOffset < activateOffset || currentOffset > deactivateOffsetBottom)) {
        this.isFollowing = false;
        this.$toolbar.css({
          position: 'relative',
          top: 0,
          width: '100%',
          zIndex: 'auto'
        });
        this.$editable.css({
          marginTop: ''
        });
      }
    }
  }, {
    key: "changeContainer",
    value: function changeContainer(isFullscreen) {
      if (isFullscreen) {
        this.$toolbar.prependTo(this.$editor);
      } else {
        if (this.options.toolbarContainer) {
          this.$toolbar.appendTo(this.options.toolbarContainer);
        }
      }
      if (this.options.followingToolbar) {
        this.followScroll();
      }
    }
  }, {
    key: "updateFullscreen",
    value: function updateFullscreen(isFullscreen) {
      this.ui.toggleBtnActive(this.$toolbar.find('.btn-fullscreen'), isFullscreen);
      this.changeContainer(isFullscreen);
    }
  }, {
    key: "updateCodeview",
    value: function updateCodeview(isCodeview) {
      this.ui.toggleBtnActive(this.$toolbar.find('.btn-codeview'), isCodeview);
      if (isCodeview) {
        this.deactivate();
      } else {
        this.activate();
      }
    }
  }, {
    key: "activate",
    value: function activate(isIncludeCodeview) {
      var $btn = this.$toolbar.find('button');
      if (!isIncludeCodeview) {
        $btn = $btn.not('.note-codeview-keep');
      }
      this.ui.toggleBtn($btn, true);
    }
  }, {
    key: "deactivate",
    value: function deactivate(isIncludeCodeview) {
      var $btn = this.$toolbar.find('button');
      if (!isIncludeCodeview) {
        $btn = $btn.not('.note-codeview-keep');
      }
      this.ui.toggleBtn($btn, false);
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/LinkDialog.js
function LinkDialog_typeof(o) { "@babel/helpers - typeof"; return LinkDialog_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, LinkDialog_typeof(o); }
function LinkDialog_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function LinkDialog_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, LinkDialog_toPropertyKey(o.key), o); } }
function LinkDialog_createClass(e, r, t) { return r && LinkDialog_defineProperties(e.prototype, r), t && LinkDialog_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function LinkDialog_toPropertyKey(t) { var i = LinkDialog_toPrimitive(t, "string"); return "symbol" == LinkDialog_typeof(i) ? i : i + ""; }
function LinkDialog_toPrimitive(t, r) { if ("object" != LinkDialog_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != LinkDialog_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }




var LinkDialog_MAILTO_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
var LinkDialog_TEL_PATTERN = /^(\+?\d{1,3}[\s-]?)?(\d{1,4})[\s-]?(\d{1,4})[\s-]?(\d{1,4})$/;
var LinkDialog_URL_SCHEME_PATTERN = /^([A-Za-z][A-Za-z0-9+-.]*\:|#|\/)/;
var LinkDialog = /*#__PURE__*/function () {
  function LinkDialog(context) {
    LinkDialog_classCallCheck(this, LinkDialog);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.$body = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document.body);
    this.$editor = context.layoutInfo.editor;
    this.options = context.options;
    this.lang = this.options.langInfo;
    context.memo('help.linkDialog.show', this.options.langInfo.help['linkDialog.show']);
  }
  return LinkDialog_createClass(LinkDialog, [{
    key: "initialize",
    value: function initialize() {
      var $container = this.options.dialogsInBody ? this.$body : this.options.container;
      var body = ['<div class="form-group note-form-group">', "<label for=\"note-dialog-link-txt-".concat(this.options.id, "\" class=\"note-form-label\">").concat(this.lang.link.textToDisplay, "</label>"), "<input id=\"note-dialog-link-txt-".concat(this.options.id, "\" class=\"note-link-text form-control note-form-control note-input\" type=\"text\"/>"), '</div>', '<div class="form-group note-form-group">', "<label for=\"note-dialog-link-url-".concat(this.options.id, "\" class=\"note-form-label\">").concat(this.lang.link.url, "</label>"), "<input id=\"note-dialog-link-url-".concat(this.options.id, "\" class=\"note-link-url form-control note-form-control note-input\" type=\"text\" value=\"http://\"/>"), '</div>', !this.options.disableLinkTarget ? external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div></div>').append(this.ui.checkbox({
        className: 'sn-checkbox-open-in-new-window',
        text: this.lang.link.openInNewWindow,
        checked: true
      }).render()).html() : ''].join('');
      var buttonClass = 'btn btn-primary note-btn note-btn-primary note-link-btn';
      var footer = "<input type=\"button\" href=\"#\" class=\"".concat(buttonClass, "\" value=\"").concat(this.lang.link.insert, "\" disabled>");
      this.$dialog = this.ui.dialog({
        className: 'link-dialog',
        title: this.lang.link.insert,
        fade: this.options.dialogsFade,
        body: body,
        footer: footer
      }).render().appendTo($container);
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.ui.hideDialog(this.$dialog);
      this.$dialog.remove();
    }
  }, {
    key: "bindEnterKey",
    value: function bindEnterKey($input, $btn) {
      $input.on('keypress', function (event) {
        if (event.keyCode === key.code.ENTER) {
          event.preventDefault();
          $btn.trigger('click');
        }
      });
    }
  }, {
    key: "checkLinkUrl",
    value: function checkLinkUrl(linkUrl) {
      if (LinkDialog_MAILTO_PATTERN.test(linkUrl)) {
        return 'mailto://' + linkUrl;
      } else if (LinkDialog_TEL_PATTERN.test(linkUrl)) {
        return 'tel://' + linkUrl;
      } else if (!LinkDialog_URL_SCHEME_PATTERN.test(linkUrl)) {
        return 'http://' + linkUrl;
      }
      return linkUrl;
    }
  }, {
    key: "onCheckLinkUrl",
    value: function onCheckLinkUrl($input) {
      var _this = this;
      $input.on('blur', function (event) {
        event.target.value = event.target.value == '' ? '' : _this.checkLinkUrl(event.target.value);
      });
    }

    /**
     * toggle update button
     */
  }, {
    key: "toggleLinkBtn",
    value: function toggleLinkBtn($linkBtn, $linkText, $linkUrl) {
      this.ui.toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());
    }

    /**
     * Show link dialog and set event handlers on dialog controls.
     *
     * @param {Object} linkInfo
     * @return {Promise}
     */
  }, {
    key: "showLinkDialog",
    value: function showLinkDialog(linkInfo) {
      var _this2 = this;
      return external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().Deferred(function (deferred) {
        var $linkText = _this2.$dialog.find('.note-link-text');
        var $linkUrl = _this2.$dialog.find('.note-link-url');
        var $linkBtn = _this2.$dialog.find('.note-link-btn');
        var $openInNewWindow = _this2.$dialog.find('.sn-checkbox-open-in-new-window input[type=checkbox]');
        _this2.ui.onDialogShown(_this2.$dialog, function () {
          _this2.context.triggerEvent('dialog.shown');

          // If no url was given and given text is valid URL then copy that into URL Field
          if (!linkInfo.url && func.isValidUrl(linkInfo.text)) {
            linkInfo.url = _this2.checkLinkUrl(linkInfo.text);
          }
          $linkText.on('input paste propertychange', function () {
            // If linktext was modified by input events,
            // cloning text from linkUrl will be stopped.
            var text = $linkText.val();
            var div = document.createElement('div');
            div.innerText = text;
            text = div.innerHTML;
            linkInfo.text = text;
            _this2.toggleLinkBtn($linkBtn, $linkText, $linkUrl);
          }).val(linkInfo.text);
          $linkUrl.on('input paste propertychange', function () {
            // Display same text on `Text to display` as default
            // when linktext has no text
            if (!linkInfo.text) {
              $linkText.val($linkUrl.val());
            }
            _this2.toggleLinkBtn($linkBtn, $linkText, $linkUrl);
          }).val(linkInfo.url);
          if (!env.isSupportTouch) {
            $linkUrl.trigger('focus');
          }
          _this2.toggleLinkBtn($linkBtn, $linkText, $linkUrl);
          _this2.bindEnterKey($linkUrl, $linkBtn);
          _this2.bindEnterKey($linkText, $linkBtn);
          _this2.onCheckLinkUrl($linkUrl);
          var isNewWindowChecked = linkInfo.isNewWindow !== undefined ? linkInfo.isNewWindow : _this2.context.options.linkTargetBlank;
          $openInNewWindow.prop('checked', isNewWindowChecked);
          $linkBtn.one('click', function (event) {
            event.preventDefault();
            deferred.resolve({
              range: linkInfo.range,
              url: $linkUrl.val(),
              text: $linkText.val(),
              isNewWindow: $openInNewWindow.is(':checked')
            });
            _this2.ui.hideDialog(_this2.$dialog);
          });
        });
        _this2.ui.onDialogHidden(_this2.$dialog, function () {
          // detach events
          $linkText.off();
          $linkUrl.off();
          $linkBtn.off();
          if (deferred.state() === 'pending') {
            deferred.reject();
          }
        });
        _this2.ui.showDialog(_this2.$dialog);
      }).promise();
    }

    /**
     * @param {Object} layoutInfo
     */
  }, {
    key: "show",
    value: function show() {
      var _this3 = this;
      var linkInfo = this.context.invoke('editor.getLinkInfo');
      this.context.invoke('editor.saveRange');
      this.showLinkDialog(linkInfo).then(function (linkInfo) {
        _this3.context.invoke('editor.restoreRange');
        _this3.context.invoke('editor.createLink', linkInfo);
      }).fail(function () {
        _this3.context.invoke('editor.restoreRange');
      });
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/LinkPopover.js
function LinkPopover_typeof(o) { "@babel/helpers - typeof"; return LinkPopover_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, LinkPopover_typeof(o); }
function LinkPopover_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function LinkPopover_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, LinkPopover_toPropertyKey(o.key), o); } }
function LinkPopover_createClass(e, r, t) { return r && LinkPopover_defineProperties(e.prototype, r), t && LinkPopover_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function LinkPopover_toPropertyKey(t) { var i = LinkPopover_toPrimitive(t, "string"); return "symbol" == LinkPopover_typeof(i) ? i : i + ""; }
function LinkPopover_toPrimitive(t, r) { if ("object" != LinkPopover_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != LinkPopover_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }



var LinkPopover = /*#__PURE__*/function () {
  function LinkPopover(context) {
    var _this = this;
    LinkPopover_classCallCheck(this, LinkPopover);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.options = context.options;
    this.events = {
      'summernote.keyup summernote.mouseup summernote.change summernote.scroll': function summernoteKeyupSummernoteMouseupSummernoteChangeSummernoteScroll() {
        _this.update();
      },
      'summernote.disable summernote.dialog.shown': function summernoteDisableSummernoteDialogShown() {
        _this.hide();
      },
      'summernote.blur': function summernoteBlur(we, event) {
        if (event.originalEvent && event.originalEvent.relatedTarget) {
          if (!_this.$popover[0].contains(event.originalEvent.relatedTarget)) {
            _this.hide();
          }
        } else {
          _this.hide();
        }
      }
    };
  }
  return LinkPopover_createClass(LinkPopover, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return !lists.isEmpty(this.options.popover.link);
    }
  }, {
    key: "initialize",
    value: function initialize() {
      this.$popover = this.ui.popover({
        className: 'note-link-popover',
        callback: function callback($node) {
          var $content = $node.find('.popover-content,.note-popover-content');
          $content.prepend('<span><a target="_blank"></a>&nbsp;</span>');
        }
      }).render().appendTo(this.options.container);
      var $content = this.$popover.find('.popover-content,.note-popover-content');
      this.context.invoke('buttons.build', $content, this.options.popover.link);
      this.$popover.on('mousedown', function (event) {
        event.preventDefault();
      });
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$popover.remove();
    }
  }, {
    key: "update",
    value: function update() {
      // Prevent focusing on editable when invoke('code') is executed
      if (!this.context.invoke('editor.hasFocus')) {
        this.hide();
        return;
      }
      var rng = this.context.invoke('editor.getLastRange');
      if (rng.isCollapsed() && rng.isOnAnchor()) {
        var anchor = dom.ancestor(rng.sc, dom.isAnchor);
        var href = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(anchor).attr('href');
        this.$popover.find('a').attr('href', href).text(href);
        var pos = dom.posFromPlaceholder(anchor);
        var containerOffset = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.container).offset();
        pos.top -= containerOffset.top;
        pos.left -= containerOffset.left;
        this.$popover.css({
          display: 'block',
          left: pos.left,
          top: pos.top
        });
      } else {
        this.hide();
      }
    }
  }, {
    key: "hide",
    value: function hide() {
      this.$popover.hide();
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/ImageDialog.js
function ImageDialog_typeof(o) { "@babel/helpers - typeof"; return ImageDialog_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, ImageDialog_typeof(o); }
function ImageDialog_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function ImageDialog_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, ImageDialog_toPropertyKey(o.key), o); } }
function ImageDialog_createClass(e, r, t) { return r && ImageDialog_defineProperties(e.prototype, r), t && ImageDialog_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function ImageDialog_toPropertyKey(t) { var i = ImageDialog_toPrimitive(t, "string"); return "symbol" == ImageDialog_typeof(i) ? i : i + ""; }
function ImageDialog_toPrimitive(t, r) { if ("object" != ImageDialog_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != ImageDialog_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }



var ImageDialog = /*#__PURE__*/function () {
  function ImageDialog(context) {
    ImageDialog_classCallCheck(this, ImageDialog);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.$body = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document.body);
    this.$editor = context.layoutInfo.editor;
    this.options = context.options;
    this.lang = this.options.langInfo;
  }
  return ImageDialog_createClass(ImageDialog, [{
    key: "initialize",
    value: function initialize() {
      var imageLimitation = '';
      if (this.options.maximumImageFileSize) {
        var unit = Math.floor(Math.log(this.options.maximumImageFileSize) / Math.log(1024));
        var readableSize = (this.options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 + ' ' + ' KMGTP'[unit] + 'B';
        imageLimitation = "<small>".concat(this.lang.image.maximumFileSize + ' : ' + readableSize, "</small>");
      }
      var $container = this.options.dialogsInBody ? this.$body : this.options.container;
      var body = ['<div class="form-group note-form-group note-group-select-from-files">', '<label for="note-dialog-image-file-' + this.options.id + '" class="note-form-label">' + this.lang.image.selectFromFiles + '</label>', '<input id="note-dialog-image-file-' + this.options.id + '" class="note-image-input form-control-file note-form-control note-input" ', ' type="file" name="files" accept="' + this.options.acceptImageFileTypes + '" multiple="multiple"/>', imageLimitation, '</div>', '<div class="form-group note-group-image-url">', '<label for="note-dialog-image-url-' + this.options.id + '" class="note-form-label">' + this.lang.image.url + '</label>', '<input id="note-dialog-image-url-' + this.options.id + '" class="note-image-url form-control note-form-control note-input" type="text"/>', '</div>'].join('');
      var buttonClass = 'btn btn-primary note-btn note-btn-primary note-image-btn';
      var footer = "<input type=\"button\" href=\"#\" class=\"".concat(buttonClass, "\" value=\"").concat(this.lang.image.insert, "\" disabled>");
      this.$dialog = this.ui.dialog({
        title: this.lang.image.insert,
        fade: this.options.dialogsFade,
        body: body,
        footer: footer
      }).render().appendTo($container);
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.ui.hideDialog(this.$dialog);
      this.$dialog.remove();
    }
  }, {
    key: "bindEnterKey",
    value: function bindEnterKey($input, $btn) {
      $input.on('keypress', function (event) {
        if (event.keyCode === key.code.ENTER) {
          event.preventDefault();
          $btn.trigger('click');
        }
      });
    }
  }, {
    key: "show",
    value: function show() {
      var _this = this;
      this.context.invoke('editor.saveRange');
      this.showImageDialog().then(function (data) {
        // [workaround] hide dialog before restore range for IE range focus
        _this.ui.hideDialog(_this.$dialog);
        _this.context.invoke('editor.restoreRange');
        if (typeof data === 'string') {
          // image url
          // If onImageLinkInsert set,
          if (_this.options.callbacks.onImageLinkInsert) {
            _this.context.triggerEvent('image.link.insert', data);
          } else {
            _this.context.invoke('editor.insertImage', data);
          }
        } else {
          // array of files
          _this.context.invoke('editor.insertImagesOrCallback', data);
        }
      }).fail(function () {
        _this.context.invoke('editor.restoreRange');
      });
    }

    /**
     * show image dialog
     *
     * @param {jQuery} $dialog
     * @return {Promise}
     */
  }, {
    key: "showImageDialog",
    value: function showImageDialog() {
      var _this2 = this;
      return external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().Deferred(function (deferred) {
        var $imageInput = _this2.$dialog.find('.note-image-input');
        var $imageUrl = _this2.$dialog.find('.note-image-url');
        var $imageBtn = _this2.$dialog.find('.note-image-btn');
        _this2.ui.onDialogShown(_this2.$dialog, function () {
          _this2.context.triggerEvent('dialog.shown');

          // Cloning imageInput to clear element.
          $imageInput.replaceWith($imageInput.clone().on('change', function (event) {
            deferred.resolve(event.target.files || event.target.value);
          }).val(''));
          $imageUrl.on('input paste propertychange', function () {
            _this2.ui.toggleBtn($imageBtn, $imageUrl.val());
          }).val('');
          if (!env.isSupportTouch) {
            $imageUrl.trigger('focus');
          }
          $imageBtn.on('click', function (event) {
            event.preventDefault();
            deferred.resolve($imageUrl.val());
          });
          _this2.bindEnterKey($imageUrl, $imageBtn);
        });
        _this2.ui.onDialogHidden(_this2.$dialog, function () {
          $imageInput.off();
          $imageUrl.off();
          $imageBtn.off();
          if (deferred.state() === 'pending') {
            deferred.reject();
          }
        });
        _this2.ui.showDialog(_this2.$dialog);
      });
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/ImagePopover.js
function ImagePopover_typeof(o) { "@babel/helpers - typeof"; return ImagePopover_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, ImagePopover_typeof(o); }
function ImagePopover_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function ImagePopover_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, ImagePopover_toPropertyKey(o.key), o); } }
function ImagePopover_createClass(e, r, t) { return r && ImagePopover_defineProperties(e.prototype, r), t && ImagePopover_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function ImagePopover_toPropertyKey(t) { var i = ImagePopover_toPrimitive(t, "string"); return "symbol" == ImagePopover_typeof(i) ? i : i + ""; }
function ImagePopover_toPrimitive(t, r) { if ("object" != ImagePopover_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != ImagePopover_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }




/**
 * Image popover module
 *  mouse events that show/hide popover will be handled by Handle.js.
 *  Handle.js will receive the events and invoke 'imagePopover.update'.
 */
var ImagePopover = /*#__PURE__*/function () {
  function ImagePopover(context) {
    var _this = this;
    ImagePopover_classCallCheck(this, ImagePopover);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.editable = context.layoutInfo.editable[0];
    this.options = context.options;
    this.events = {
      'summernote.disable summernote.dialog.shown': function summernoteDisableSummernoteDialogShown() {
        _this.hide();
      },
      'summernote.blur': function summernoteBlur(we, event) {
        if (event.originalEvent && event.originalEvent.relatedTarget) {
          if (!_this.$popover[0].contains(event.originalEvent.relatedTarget)) {
            _this.hide();
          }
        } else {
          _this.hide();
        }
      }
    };
  }
  return ImagePopover_createClass(ImagePopover, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return !lists.isEmpty(this.options.popover.image);
    }
  }, {
    key: "initialize",
    value: function initialize() {
      this.$popover = this.ui.popover({
        className: 'note-image-popover'
      }).render().appendTo(this.options.container);
      var $content = this.$popover.find('.popover-content,.note-popover-content');
      this.context.invoke('buttons.build', $content, this.options.popover.image);
      this.$popover.on('mousedown', function (event) {
        event.preventDefault();
      });
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$popover.remove();
    }
  }, {
    key: "update",
    value: function update(target, event) {
      if (dom.isImg(target)) {
        var position = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(target).offset();
        var containerOffset = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.container).offset();
        var pos = {};
        if (this.options.popatmouse) {
          pos.left = event.pageX - 20;
          pos.top = event.pageY;
        } else {
          pos = position;
        }
        pos.top -= containerOffset.top;
        pos.left -= containerOffset.left;
        this.$popover.css({
          display: 'block',
          left: pos.left,
          top: pos.top
        });
      } else {
        this.hide();
      }
    }
  }, {
    key: "hide",
    value: function hide() {
      this.$popover.hide();
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/TablePopover.js
function TablePopover_typeof(o) { "@babel/helpers - typeof"; return TablePopover_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, TablePopover_typeof(o); }
function TablePopover_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function TablePopover_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, TablePopover_toPropertyKey(o.key), o); } }
function TablePopover_createClass(e, r, t) { return r && TablePopover_defineProperties(e.prototype, r), t && TablePopover_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function TablePopover_toPropertyKey(t) { var i = TablePopover_toPrimitive(t, "string"); return "symbol" == TablePopover_typeof(i) ? i : i + ""; }
function TablePopover_toPrimitive(t, r) { if ("object" != TablePopover_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != TablePopover_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }




var TablePopover = /*#__PURE__*/function () {
  function TablePopover(context) {
    var _this = this;
    TablePopover_classCallCheck(this, TablePopover);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.options = context.options;
    this.events = {
      'summernote.mousedown': function summernoteMousedown(we, event) {
        _this.update(event.target);
      },
      'summernote.keyup summernote.scroll summernote.change': function summernoteKeyupSummernoteScrollSummernoteChange() {
        _this.update();
      },
      'summernote.disable summernote.dialog.shown': function summernoteDisableSummernoteDialogShown() {
        _this.hide();
      },
      'summernote.blur': function summernoteBlur(we, event) {
        if (event.originalEvent && event.originalEvent.relatedTarget) {
          if (!_this.$popover[0].contains(event.originalEvent.relatedTarget)) {
            _this.hide();
          }
        } else {
          _this.hide();
        }
      }
    };
  }
  return TablePopover_createClass(TablePopover, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return !lists.isEmpty(this.options.popover.table);
    }
  }, {
    key: "initialize",
    value: function initialize() {
      this.$popover = this.ui.popover({
        className: 'note-table-popover'
      }).render().appendTo(this.options.container);
      var $content = this.$popover.find('.popover-content,.note-popover-content');
      this.context.invoke('buttons.build', $content, this.options.popover.table);

      // [workaround] Disable Firefox's default table editor
      if (env.isFF) {
        document.execCommand('enableInlineTableEditing', false, false);
      }
      this.$popover.on('mousedown', function (event) {
        event.preventDefault();
      });
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$popover.remove();
    }
  }, {
    key: "update",
    value: function update(target) {
      if (this.context.isDisabled()) {
        return false;
      }
      var isCell = dom.isCell(target) || dom.isCell(target === null || target === void 0 ? void 0 : target.parentElement);
      if (isCell) {
        var pos = dom.posFromPlaceholder(target);
        var containerOffset = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.container).offset();
        pos.top -= containerOffset.top;
        pos.left -= containerOffset.left;
        this.$popover.css({
          display: 'block',
          left: pos.left,
          top: pos.top
        });
      } else {
        this.hide();
      }
      return isCell;
    }
  }, {
    key: "hide",
    value: function hide() {
      this.$popover.hide();
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/VideoDialog.js
function VideoDialog_typeof(o) { "@babel/helpers - typeof"; return VideoDialog_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, VideoDialog_typeof(o); }
function VideoDialog_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function VideoDialog_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, VideoDialog_toPropertyKey(o.key), o); } }
function VideoDialog_createClass(e, r, t) { return r && VideoDialog_defineProperties(e.prototype, r), t && VideoDialog_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function VideoDialog_toPropertyKey(t) { var i = VideoDialog_toPrimitive(t, "string"); return "symbol" == VideoDialog_typeof(i) ? i : i + ""; }
function VideoDialog_toPrimitive(t, r) { if ("object" != VideoDialog_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != VideoDialog_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }



var VideoDialog = /*#__PURE__*/function () {
  function VideoDialog(context) {
    VideoDialog_classCallCheck(this, VideoDialog);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.$body = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document.body);
    this.$editor = context.layoutInfo.editor;
    this.options = context.options;
    this.lang = this.options.langInfo;
  }
  return VideoDialog_createClass(VideoDialog, [{
    key: "initialize",
    value: function initialize() {
      var $container = this.options.dialogsInBody ? this.$body : this.options.container;
      var body = ['<div class="form-group note-form-group row-fluid">', "<label for=\"note-dialog-video-url-".concat(this.options.id, "\" class=\"note-form-label\">").concat(this.lang.video.url, " <small class=\"text-muted\">").concat(this.lang.video.providers, "</small></label>"), "<input id=\"note-dialog-video-url-".concat(this.options.id, "\" class=\"note-video-url form-control note-form-control note-input\" type=\"text\"/>"), '</div>'].join('');
      var buttonClass = 'btn btn-primary note-btn note-btn-primary note-video-btn';
      var footer = "<input type=\"button\" href=\"#\" class=\"".concat(buttonClass, "\" value=\"").concat(this.lang.video.insert, "\" disabled>");
      this.$dialog = this.ui.dialog({
        title: this.lang.video.insert,
        fade: this.options.dialogsFade,
        body: body,
        footer: footer
      }).render().appendTo($container);
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.ui.hideDialog(this.$dialog);
      this.$dialog.remove();
    }
  }, {
    key: "bindEnterKey",
    value: function bindEnterKey($input, $btn) {
      $input.on('keypress', function (event) {
        if (event.keyCode === key.code.ENTER) {
          event.preventDefault();
          $btn.trigger('click');
        }
      });
    }
  }, {
    key: "createVideoNode",
    value: function createVideoNode(url) {
      // video url patterns(youtube, instagram, vimeo, dailymotion, youku, peertube, mp4, ogg, webm)
      var ytRegExp = /(?:youtu\.be\/|youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=|shorts\/|live\/))([^&\n?]+)(?:.*[?&]t=([^&\n]+))?.*/;
      var ytRegExpForStart = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/;
      var ytMatch = url.match(ytRegExp);
      var gdRegExp = /(?:\.|\/\/)drive\.google\.com\/file\/d\/(.[a-zA-Z0-9_-]*)\/view/;
      var gdMatch = url.match(gdRegExp);
      var igRegExp = /(?:www\.|\/\/)instagram\.com\/(reel|p)\/(.[a-zA-Z0-9_-]*)/;
      var igMatch = url.match(igRegExp);
      var vRegExp = /\/\/vine\.co\/v\/([a-zA-Z0-9]+)/;
      var vMatch = url.match(vRegExp);
      var vimRegExp = /\/\/(player\.)?vimeo\.com\/([a-z]*\/)*(\d+)[?]?.*/;
      var vimMatch = url.match(vimRegExp);
      var dmRegExp = /.+dailymotion.com\/(video|hub)\/([^_]+)[^#]*(#video=([^_&]+))?/;
      var dmMatch = url.match(dmRegExp);
      var youkuRegExp = /\/\/v\.youku\.com\/v_show\/id_(\w+)=*\.html/;
      var youkuMatch = url.match(youkuRegExp);
      var peerTubeRegExp = /\/\/(.*)\/videos\/watch\/([^?]*)(?:\?(?:start=(\w*))?(?:&stop=(\w*))?(?:&loop=([10]))?(?:&autoplay=([10]))?(?:&muted=([10]))?)?/;
      var peerTubeMatch = url.match(peerTubeRegExp);
      var qqRegExp = /\/\/v\.qq\.com.*?vid=(.+)/;
      var qqMatch = url.match(qqRegExp);
      var qqRegExp2 = /\/\/v\.qq\.com\/x?\/?(page|cover).*?\/([^\/]+)\.html\??.*/;
      var qqMatch2 = url.match(qqRegExp2);
      var mp4RegExp = /^.+.(mp4|m4v)$/;
      var mp4Match = url.match(mp4RegExp);
      var oggRegExp = /^.+.(ogg|ogv)$/;
      var oggMatch = url.match(oggRegExp);
      var webmRegExp = /^.+.(webm)$/;
      var webmMatch = url.match(webmRegExp);
      var fbRegExp = /(?:www\.|\/\/)facebook\.com\/([^\/]+)\/videos\/([0-9]+)/;
      var fbMatch = url.match(fbRegExp);
      var $video;
      if (ytMatch && ytMatch[1].length === 11) {
        var youtubeId = ytMatch[1];
        var start = 0;
        if (typeof ytMatch[2] !== 'undefined') {
          var ytMatchForStart = ytMatch[2].match(ytRegExpForStart);
          if (ytMatchForStart) {
            for (var n = [3600, 60, 1], i = 0, r = n.length; i < r; i++) {
              start += typeof ytMatchForStart[i + 1] !== 'undefined' ? n[i] * parseInt(ytMatchForStart[i + 1], 10) : 0;
            }
          } else {
            start = parseInt(ytMatch[2], 10);
          }
        }
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', '//www.youtube.com/embed/' + youtubeId + (start > 0 ? '?start=' + start : '')).attr('width', '640').attr('height', '360');
      } else if (gdMatch && gdMatch[0].length) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', 'https://drive.google.com/file/d/' + gdMatch[1] + '/preview').attr('width', '640').attr('height', '480');
      } else if (igMatch && igMatch[0].length) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', 'https://instagram.com/p/' + igMatch[2] + '/embed/').attr('width', '612').attr('height', '710').attr('scrolling', 'no').attr('allowtransparency', 'true');
      } else if (vMatch && vMatch[0].length) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', vMatch[0] + '/embed/simple').attr('width', '600').attr('height', '600').attr('class', 'vine-embed');
      } else if (vimMatch && vimMatch[3].length) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>').attr('frameborder', 0).attr('src', '//player.vimeo.com/video/' + vimMatch[3]).attr('width', '640').attr('height', '360');
      } else if (dmMatch && dmMatch[2].length) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', '//www.dailymotion.com/embed/video/' + dmMatch[2]).attr('width', '640').attr('height', '360');
      } else if (youkuMatch && youkuMatch[1].length) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>').attr('frameborder', 0).attr('height', '498').attr('width', '510').attr('src', '//player.youku.com/embed/' + youkuMatch[1]);
      } else if (peerTubeMatch && peerTubeMatch[0].length) {
        var begin = 0;
        if (peerTubeMatch[2] !== 'undefined') begin = peerTubeMatch[2];
        var end = 0;
        if (peerTubeMatch[3] !== 'undefined') end = peerTubeMatch[3];
        var loop = 0;
        if (peerTubeMatch[4] !== 'undefined') loop = peerTubeMatch[4];
        var autoplay = 0;
        if (peerTubeMatch[5] !== 'undefined') autoplay = peerTubeMatch[5];
        var muted = 0;
        if (peerTubeMatch[6] !== 'undefined') muted = peerTubeMatch[6];
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe allowfullscreen sandbox="allow-same-origin allow-scripts allow-popups">').attr('frameborder', 0).attr('src', '//' + peerTubeMatch[1] + '/videos/embed/' + peerTubeMatch[2] + "?loop=" + loop + "&autoplay=" + autoplay + "&muted=" + muted + (begin > 0 ? '&start=' + begin : '') + (end > 0 ? '&end=' + start : '')).attr('width', '560').attr('height', '315');
      } else if (qqMatch && qqMatch[1].length || qqMatch2 && qqMatch2[2].length) {
        var vid = qqMatch && qqMatch[1].length ? qqMatch[1] : qqMatch2[2];
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe webkitallowfullscreen mozallowfullscreen allowfullscreen>').attr('frameborder', 0).attr('height', '310').attr('width', '500').attr('src', 'https://v.qq.com/txp/iframe/player.html?vid=' + vid + '&amp;auto=0');
      } else if (mp4Match || oggMatch || webmMatch) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<video controls>').attr('src', url).attr('width', '640').attr('height', '360');
      } else if (fbMatch && fbMatch[0].length) {
        $video = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<iframe>').attr('frameborder', 0).attr('src', 'https://www.facebook.com/plugins/video.php?href=' + encodeURIComponent(fbMatch[0]) + '&show_text=0&width=560').attr('width', '560').attr('height', '301').attr('scrolling', 'no').attr('allowtransparency', 'true');
      } else {
        // this is not a known video link. Now what, Cat? Now what?
        return false;
      }
      $video.addClass('note-video-clip');
      return $video[0];
    }
  }, {
    key: "show",
    value: function show() {
      var _this = this;
      var text = this.context.invoke('editor.getSelectedText');
      this.context.invoke('editor.saveRange');
      this.showVideoDialog(text).then(function (url) {
        // [workaround] hide dialog before restore range for IE range focus
        _this.ui.hideDialog(_this.$dialog);
        _this.context.invoke('editor.restoreRange');

        // build node
        var $node = _this.createVideoNode(url);
        if ($node) {
          // insert video node
          _this.context.invoke('editor.insertNode', $node);
        }
      }).fail(function () {
        _this.context.invoke('editor.restoreRange');
      });
    }

    /**
     * show video dialog
     *
     * @param {jQuery} $dialog
     * @return {Promise}
     */
  }, {
    key: "showVideoDialog",
    value: function showVideoDialog( /* text */
    ) {
      var _this2 = this;
      return external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().Deferred(function (deferred) {
        var $videoUrl = _this2.$dialog.find('.note-video-url');
        var $videoBtn = _this2.$dialog.find('.note-video-btn');
        _this2.ui.onDialogShown(_this2.$dialog, function () {
          _this2.context.triggerEvent('dialog.shown');
          $videoUrl.on('input paste propertychange', function () {
            _this2.ui.toggleBtn($videoBtn, $videoUrl.val());
          });
          if (!env.isSupportTouch) {
            $videoUrl.trigger('focus');
          }
          $videoBtn.on('click', function (event) {
            event.preventDefault();
            deferred.resolve($videoUrl.val());
          });
          _this2.bindEnterKey($videoUrl, $videoBtn);
        });
        _this2.ui.onDialogHidden(_this2.$dialog, function () {
          $videoUrl.off();
          $videoBtn.off();
          if (deferred.state() === 'pending') {
            deferred.reject();
          }
        });
        _this2.ui.showDialog(_this2.$dialog);
      });
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/HelpDialog.js
function HelpDialog_typeof(o) { "@babel/helpers - typeof"; return HelpDialog_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, HelpDialog_typeof(o); }
function HelpDialog_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function HelpDialog_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, HelpDialog_toPropertyKey(o.key), o); } }
function HelpDialog_createClass(e, r, t) { return r && HelpDialog_defineProperties(e.prototype, r), t && HelpDialog_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function HelpDialog_toPropertyKey(t) { var i = HelpDialog_toPrimitive(t, "string"); return "symbol" == HelpDialog_typeof(i) ? i : i + ""; }
function HelpDialog_toPrimitive(t, r) { if ("object" != HelpDialog_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != HelpDialog_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }


var HelpDialog = /*#__PURE__*/function () {
  function HelpDialog(context) {
    HelpDialog_classCallCheck(this, HelpDialog);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.$body = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document.body);
    this.$editor = context.layoutInfo.editor;
    this.options = context.options;
    this.lang = this.options.langInfo;
  }
  return HelpDialog_createClass(HelpDialog, [{
    key: "initialize",
    value: function initialize() {
      var $container = this.options.dialogsInBody ? this.$body : this.options.container;
      var body = ['<p class="text-center">', '<a href="http://summernote.org/" target="_blank" rel="noopener noreferrer">Summernote 0.9.1</a> · ', '<a href="https://github.com/summernote/summernote" target="_blank" rel="noopener noreferrer">Project</a> · ', '<a href="https://github.com/summernote/summernote/issues" target="_blank" rel="noopener noreferrer">Issues</a>', '</p>'].join('');
      this.$dialog = this.ui.dialog({
        title: this.lang.options.help,
        fade: this.options.dialogsFade,
        body: this.createShortcutList(),
        footer: body,
        callback: function callback($node) {
          $node.find('.modal-body,.note-modal-body').css({
            'max-height': 300,
            'overflow': 'scroll'
          });
        }
      }).render().appendTo($container);
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.ui.hideDialog(this.$dialog);
      this.$dialog.remove();
    }
  }, {
    key: "createShortcutList",
    value: function createShortcutList() {
      var _this = this;
      var keyMap = this.options.keyMap[env.isMac ? 'mac' : 'pc'];
      return Object.keys(keyMap).map(function (key) {
        var command = keyMap[key];
        var $row = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div><div class="help-list-item"></div></div>');
        $row.append(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<label><kbd>' + key + '</kdb></label>').css({
          'width': 180,
          'margin-right': 10
        })).append(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<span></span>').html(_this.context.memo('help.' + command) || command));
        return $row.html();
      }).join('');
    }

    /**
     * show help dialog
     *
     * @return {Promise}
     */
  }, {
    key: "showHelpDialog",
    value: function showHelpDialog() {
      var _this2 = this;
      return external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().Deferred(function (deferred) {
        _this2.ui.onDialogShown(_this2.$dialog, function () {
          _this2.context.triggerEvent('dialog.shown');
          deferred.resolve();
        });
        _this2.ui.showDialog(_this2.$dialog);
      }).promise();
    }
  }, {
    key: "show",
    value: function show() {
      var _this3 = this;
      this.context.invoke('editor.saveRange');
      this.showHelpDialog().then(function () {
        _this3.context.invoke('editor.restoreRange');
      });
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/AirPopover.js
function AirPopover_typeof(o) { "@babel/helpers - typeof"; return AirPopover_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, AirPopover_typeof(o); }
function AirPopover_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function AirPopover_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, AirPopover_toPropertyKey(o.key), o); } }
function AirPopover_createClass(e, r, t) { return r && AirPopover_defineProperties(e.prototype, r), t && AirPopover_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function AirPopover_toPropertyKey(t) { var i = AirPopover_toPrimitive(t, "string"); return "symbol" == AirPopover_typeof(i) ? i : i + ""; }
function AirPopover_toPrimitive(t, r) { if ("object" != AirPopover_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != AirPopover_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }



var AIRMODE_POPOVER_X_OFFSET = -5;
var AIRMODE_POPOVER_Y_OFFSET = 5;
var AirPopover = /*#__PURE__*/function () {
  function AirPopover(context) {
    var _this = this;
    AirPopover_classCallCheck(this, AirPopover);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.options = context.options;
    this.hidable = true;
    this.onContextmenu = false;
    this.pageX = null;
    this.pageY = null;
    this.events = {
      'summernote.contextmenu': function summernoteContextmenu(event) {
        if (_this.options.editing) {
          event.preventDefault();
          event.stopPropagation();
          _this.onContextmenu = true;
          _this.update(true);
        }
      },
      'summernote.mousedown': function summernoteMousedown(we, event) {
        _this.pageX = event.pageX;
        _this.pageY = event.pageY;
      },
      'summernote.keyup summernote.mouseup summernote.scroll': function summernoteKeyupSummernoteMouseupSummernoteScroll(we, event) {
        if (_this.options.editing && !_this.onContextmenu) {
          if (event.type == 'keyup') {
            var range = _this.context.invoke('editor.getLastRange');
            var wordRange = range.getWordRange();
            var bnd = func.rect2bnd(lists.last(wordRange.getClientRects()));
            _this.pageX = bnd.left;
            _this.pageY = bnd.top;
          } else {
            _this.pageX = event.pageX;
            _this.pageY = event.pageY;
          }
          _this.update();
        }
        _this.onContextmenu = false;
      },
      'summernote.disable summernote.change summernote.dialog.shown summernote.blur': function summernoteDisableSummernoteChangeSummernoteDialogShownSummernoteBlur() {
        _this.hide();
      },
      'summernote.focusout': function summernoteFocusout() {
        if (!_this.$popover.is(':active,:focus')) {
          _this.hide();
        }
      }
    };
  }
  return AirPopover_createClass(AirPopover, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return this.options.airMode && !lists.isEmpty(this.options.popover.air);
    }
  }, {
    key: "initialize",
    value: function initialize() {
      var _this2 = this;
      this.$popover = this.ui.popover({
        className: 'note-air-popover'
      }).render().appendTo(this.options.container);
      var $content = this.$popover.find('.popover-content');
      this.context.invoke('buttons.build', $content, this.options.popover.air);

      // disable hiding this popover preemptively by 'summernote.blur' event.
      this.$popover.on('mousedown', function () {
        _this2.hidable = false;
      });
      // (re-)enable hiding after 'summernote.blur' has been handled (aka. ignored).
      this.$popover.on('mouseup', function () {
        _this2.hidable = true;
      });
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$popover.remove();
    }
  }, {
    key: "update",
    value: function update(forcelyOpen) {
      var styleInfo = this.context.invoke('editor.currentStyle');
      if (styleInfo.range && (!styleInfo.range.isCollapsed() || forcelyOpen)) {
        var rect = {
          left: this.pageX,
          top: this.pageY
        };
        var containerOffset = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.container).offset();
        rect.top -= containerOffset.top;
        rect.left -= containerOffset.left;
        this.$popover.css({
          display: 'block',
          left: Math.max(rect.left, 0) + AIRMODE_POPOVER_X_OFFSET,
          top: rect.top + AIRMODE_POPOVER_Y_OFFSET
        });
        this.context.invoke('buttons.updateCurrentStyle', this.$popover);
      } else {
        this.hide();
      }
    }
  }, {
    key: "updateCodeview",
    value: function updateCodeview(isCodeview) {
      this.ui.toggleBtnActive(this.$popover.find('.btn-codeview'), isCodeview);
      if (isCodeview) {
        this.hide();
      }
    }
  }, {
    key: "hide",
    value: function hide() {
      if (this.hidable) {
        this.$popover.hide();
      }
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/module/HintPopover.js
function HintPopover_typeof(o) { "@babel/helpers - typeof"; return HintPopover_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, HintPopover_typeof(o); }
function HintPopover_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function HintPopover_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, HintPopover_toPropertyKey(o.key), o); } }
function HintPopover_createClass(e, r, t) { return r && HintPopover_defineProperties(e.prototype, r), t && HintPopover_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function HintPopover_toPropertyKey(t) { var i = HintPopover_toPrimitive(t, "string"); return "symbol" == HintPopover_typeof(i) ? i : i + ""; }
function HintPopover_toPrimitive(t, r) { if ("object" != HintPopover_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != HintPopover_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }






var POPOVER_DIST = 5;
var HintPopover = /*#__PURE__*/function () {
  function HintPopover(context) {
    var _this = this;
    HintPopover_classCallCheck(this, HintPopover);
    this.context = context;
    this.ui = (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.ui;
    this.$editable = context.layoutInfo.editable;
    this.options = context.options;
    this.hint = this.options.hint || [];
    this.direction = this.options.hintDirection || 'bottom';
    this.hints = Array.isArray(this.hint) ? this.hint : [this.hint];
    this.events = {
      'summernote.keyup': function summernoteKeyup(we, event) {
        if (!event.isDefaultPrevented()) {
          _this.handleKeyup(event);
        }
      },
      'summernote.keydown': function summernoteKeydown(we, event) {
        _this.handleKeydown(event);
      },
      'summernote.disable summernote.dialog.shown summernote.blur': function summernoteDisableSummernoteDialogShownSummernoteBlur() {
        _this.hide();
      }
    };
  }
  return HintPopover_createClass(HintPopover, [{
    key: "shouldInitialize",
    value: function shouldInitialize() {
      return this.hints.length > 0;
    }
  }, {
    key: "initialize",
    value: function initialize() {
      var _this2 = this;
      this.lastWordRange = null;
      this.matchingWord = null;
      this.$popover = this.ui.popover({
        className: 'note-hint-popover',
        hideArrow: true,
        direction: ''
      }).render().appendTo(this.options.container);
      this.$popover.hide();
      this.$content = this.$popover.find('.popover-content,.note-popover-content');
      this.$content.on('click', '.note-hint-item', function (event) {
        _this2.$content.find('.active').removeClass('active');
        external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.currentTarget).addClass('active');
        _this2.replace();
      });
      this.$popover.on('mousedown', function (event) {
        event.preventDefault();
      });
    }
  }, {
    key: "destroy",
    value: function destroy() {
      this.$popover.remove();
    }
  }, {
    key: "selectItem",
    value: function selectItem($item) {
      this.$content.find('.active').removeClass('active');
      $item.addClass('active');
      this.$content[0].scrollTop = $item[0].offsetTop - this.$content.innerHeight() / 2;
    }
  }, {
    key: "moveDown",
    value: function moveDown() {
      var $current = this.$content.find('.note-hint-item.active');
      var $next = $current.next();
      if ($next.length) {
        this.selectItem($next);
      } else {
        var $nextGroup = $current.parent().next();
        if (!$nextGroup.length) {
          $nextGroup = this.$content.find('.note-hint-group').first();
        }
        this.selectItem($nextGroup.find('.note-hint-item').first());
      }
    }
  }, {
    key: "moveUp",
    value: function moveUp() {
      var $current = this.$content.find('.note-hint-item.active');
      var $prev = $current.prev();
      if ($prev.length) {
        this.selectItem($prev);
      } else {
        var $prevGroup = $current.parent().prev();
        if (!$prevGroup.length) {
          $prevGroup = this.$content.find('.note-hint-group').last();
        }
        this.selectItem($prevGroup.find('.note-hint-item').last());
      }
    }
  }, {
    key: "replace",
    value: function replace() {
      var $item = this.$content.find('.note-hint-item.active');
      if ($item.length) {
        var node = this.nodeFromItem($item);
        // If matchingWord length = 0 -> capture OK / open hint / but as mention capture "" (\w*)
        if (this.matchingWord !== null && this.matchingWord.length === 0) {
          this.lastWordRange.so = this.lastWordRange.eo;
          // Else si > 0 and normal case -> adjust range "before" for correct position of insertion
        } else if (this.matchingWord !== null && this.matchingWord.length > 0 && !this.lastWordRange.isCollapsed()) {
          var rangeCompute = this.lastWordRange.eo - this.lastWordRange.so - this.matchingWord.length;
          if (rangeCompute > 0) {
            this.lastWordRange.so += rangeCompute;
          }
        }
        this.lastWordRange.insertNode(node);
        if (this.options.hintSelect === 'next') {
          var blank = document.createTextNode('');
          external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(node).after(blank);
          range.createFromNodeBefore(blank).select();
        } else {
          range.createFromNodeAfter(node).select();
        }
        this.lastWordRange = null;
        this.hide();
        this.context.invoke('editor.focus');
        this.context.triggerEvent('change', this.$editable.html(), this.$editable);
      }
    }
  }, {
    key: "nodeFromItem",
    value: function nodeFromItem($item) {
      var hint = this.hints[$item.data('index')];
      var item = $item.data('item');
      var node = hint.content ? hint.content(item) : item;
      if (typeof node === 'string') {
        node = dom.createText(node);
      }
      return node;
    }
  }, {
    key: "createItemTemplates",
    value: function createItemTemplates(hintIdx, items) {
      var hint = this.hints[hintIdx];
      return items.map(function (item, idx) {
        var $item = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div class="note-hint-item"></div>');
        $item.append(hint.template ? hint.template(item) : item + '');
        $item.data({
          'index': hintIdx,
          'item': item
        });
        if (hintIdx === 0 && idx === 0) {
          $item.addClass('active');
        }
        return $item;
      });
    }
  }, {
    key: "handleKeydown",
    value: function handleKeydown(event) {
      if (!this.$popover.is(':visible')) {
        return;
      }
      if (event.keyCode === key.code.ENTER) {
        event.preventDefault();
        this.replace();
      } else if (event.keyCode === key.code.UP) {
        event.preventDefault();
        this.moveUp();
      } else if (event.keyCode === key.code.DOWN) {
        event.preventDefault();
        this.moveDown();
      }
    }
  }, {
    key: "searchKeyword",
    value: function searchKeyword(index, keyword, callback) {
      var hint = this.hints[index];
      if (hint && hint.match.test(keyword) && hint.search) {
        var matches = hint.match.exec(keyword);
        this.matchingWord = matches[0];
        hint.search(matches[1], callback);
      } else {
        callback();
      }
    }
  }, {
    key: "createGroup",
    value: function createGroup(idx, keyword) {
      var _this3 = this;
      var $group = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div class="note-hint-group note-hint-group-' + idx + '"></div>');
      this.searchKeyword(idx, keyword, function (items) {
        items = items || [];
        if (items.length) {
          $group.html(_this3.createItemTemplates(idx, items));
          _this3.show();
        }
      });
      return $group;
    }
  }, {
    key: "handleKeyup",
    value: function handleKeyup(event) {
      var _this4 = this;
      if (!lists.contains([key.code.ENTER, key.code.UP, key.code.DOWN], event.keyCode)) {
        var _range = this.context.invoke('editor.getLastRange');
        var wordRange, keyword;
        if (this.options.hintMode === 'words') {
          wordRange = _range.getWordsRange(_range);
          keyword = wordRange.toString();
          this.hints.forEach(function (hint) {
            if (hint.match.test(keyword)) {
              wordRange = _range.getWordsMatchRange(hint.match);
              return false;
            }
          });
          if (!wordRange) {
            this.hide();
            return;
          }
          keyword = wordRange.toString();
        } else {
          wordRange = _range.getWordRange();
          keyword = wordRange.toString();
        }
        if (this.hints.length && keyword) {
          this.$content.empty();
          var bnd = func.rect2bnd(lists.last(wordRange.getClientRects()));
          var containerOffset = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.container).offset();
          if (bnd) {
            bnd.top -= containerOffset.top;
            bnd.left -= containerOffset.left;
            this.$popover.hide();
            this.lastWordRange = wordRange;
            this.hints.forEach(function (hint, idx) {
              if (hint.match.test(keyword)) {
                _this4.createGroup(idx, keyword).appendTo(_this4.$content);
              }
            });
            // select first .note-hint-item
            this.$content.find('.note-hint-item').first().addClass('active');

            // set position for popover after group is created
            if (this.direction === 'top') {
              this.$popover.css({
                left: bnd.left,
                top: bnd.top - this.$popover.outerHeight() - POPOVER_DIST
              });
            } else {
              this.$popover.css({
                left: bnd.left,
                top: bnd.top + bnd.height + POPOVER_DIST
              });
            }
          }
        } else {
          this.hide();
        }
      }
    }
  }, {
    key: "show",
    value: function show() {
      this.$popover.show();
    }
  }, {
    key: "hide",
    value: function hide() {
      this.$popover.hide();
    }
  }]);
}();

;// CONCATENATED MODULE: ./src/js/settings.js




























(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend((external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote, {
  version: '0.9.1',
  plugins: {},
  dom: dom,
  range: range,
  lists: lists,
  options: {
    langInfo: (external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote.lang['en-US'],
    editing: true,
    modules: {
      'editor': Editor,
      'clipboard': Clipboard,
      'dropzone': Dropzone,
      'codeview': CodeView,
      'statusbar': Statusbar,
      'fullscreen': Fullscreen,
      'handle': Handle,
      // FIXME: HintPopover must be front of autolink
      //  - Script error about range when Enter key is pressed on hint popover
      'hintPopover': HintPopover,
      'autoLink': AutoLink,
      'autoSync': AutoSync,
      'autoReplace': AutoReplace,
      'placeholder': Placeholder,
      'buttons': Buttons,
      'toolbar': Toolbar,
      'linkDialog': LinkDialog,
      'linkPopover': LinkPopover,
      'imageDialog': ImageDialog,
      'imagePopover': ImagePopover,
      'tablePopover': TablePopover,
      'videoDialog': VideoDialog,
      'helpDialog': HelpDialog,
      'airPopover': AirPopover
    },
    buttons: {},
    lang: 'en-US',
    followingToolbar: false,
    toolbarPosition: 'top',
    otherStaticBar: '',
    // toolbar
    codeviewKeepButton: false,
    toolbar: [['style', ['style']], ['font', ['bold', 'underline', 'clear']], ['fontname', ['fontname']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph']], ['table', ['table']], ['insert', ['link', 'picture', 'video']], ['view', ['fullscreen', 'codeview', 'help']]],
    // popover
    popatmouse: true,
    popover: {
      image: [['resize', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']], ['float', ['floatLeft', 'floatRight', 'floatNone']], ['remove', ['removeMedia']]],
      link: [['link', ['linkDialogShow', 'unlink']]],
      table: [['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']], ['delete', ['deleteRow', 'deleteCol', 'deleteTable']]],
      air: [['color', ['color']], ['font', ['bold', 'underline', 'clear']], ['para', ['ul', 'paragraph']], ['table', ['table']], ['insert', ['link', 'picture']], ['view', ['fullscreen', 'codeview']]]
    },
    // link options
    linkAddNoReferrer: false,
    addLinkNoOpener: false,
    // air mode: inline editor
    airMode: false,
    overrideContextMenu: false,
    // TBD

    width: null,
    height: null,
    linkTargetBlank: true,
    focus: false,
    tabDisable: false,
    tabSize: 4,
    styleWithCSS: false,
    shortcuts: true,
    textareaAutoSync: true,
    tooltip: 'auto',
    container: null,
    maxTextLength: 0,
    blockquoteBreakingLevel: 2,
    spellCheck: true,
    disableGrammar: false,
    placeholder: null,
    inheritPlaceholder: false,
    // TODO: need to be documented
    recordEveryKeystroke: false,
    historyLimit: 200,
    // TODO: need to be documented
    showDomainOnlyForAutolink: false,
    // TODO: need to be documented
    hintMode: 'word',
    hintSelect: 'after',
    hintDirection: 'bottom',
    styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
    fontNames: ['Arial', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande', 'Tahoma', 'Times New Roman', 'Verdana'],
    fontNamesIgnoreCheck: [],
    addDefaultFonts: true,
    fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],
    fontSizeUnits: ['px', 'pt'],
    // pallete colors(n x n)
    colors: [['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'], ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'], ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'], ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'], ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'], ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'], ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'], ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']],
    // http://chir.ag/projects/name-that-color/
    colorsName: [['Black', 'Tundora', 'Dove Gray', 'Star Dust', 'Pale Slate', 'Gallery', 'Alabaster', 'White'], ['Red', 'Orange Peel', 'Yellow', 'Green', 'Cyan', 'Blue', 'Electric Violet', 'Magenta'], ['Azalea', 'Karry', 'Egg White', 'Zanah', 'Botticelli', 'Tropical Blue', 'Mischka', 'Twilight'], ['Tonys Pink', 'Peach Orange', 'Cream Brulee', 'Sprout', 'Casper', 'Perano', 'Cold Purple', 'Careys Pink'], ['Mandy', 'Rajah', 'Dandelion', 'Olivine', 'Gulf Stream', 'Viking', 'Blue Marguerite', 'Puce'], ['Guardsman Red', 'Fire Bush', 'Golden Dream', 'Chelsea Cucumber', 'Smalt Blue', 'Boston Blue', 'Butterfly Bush', 'Cadillac'], ['Sangria', 'Mai Tai', 'Buddha Gold', 'Forest Green', 'Eden', 'Venice Blue', 'Meteorite', 'Claret'], ['Rosewood', 'Cinnamon', 'Olive', 'Parsley', 'Tiber', 'Midnight Blue', 'Valentino', 'Loulou']],
    colorButton: {
      foreColor: '#000000',
      backColor: '#FFFF00'
    },
    lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],
    tableClassName: 'table table-bordered',
    insertTableMaxSize: {
      col: 10,
      row: 10
    },
    // By default, dialogs are attached in container.
    dialogsInBody: false,
    dialogsFade: false,
    maximumImageFileSize: null,
    acceptImageFileTypes: "image/*",
    allowClipboardImagePasting: true,
    callbacks: {
      onBeforeCommand: null,
      onBlur: null,
      onBlurCodeview: null,
      onChange: null,
      onChangeCodeview: null,
      onDialogShown: null,
      onEnter: null,
      onFocus: null,
      onImageLinkInsert: null,
      onImageUpload: null,
      onImageUploadError: null,
      onInit: null,
      onKeydown: null,
      onKeyup: null,
      onMousedown: null,
      onMouseup: null,
      onPaste: null,
      onScroll: null
    },
    codemirror: {
      mode: 'text/html',
      htmlMode: true,
      lineNumbers: true
    },
    codeviewFilter: true,
    codeviewFilterRegex: /<\/*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|ilayer|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|t(?:itle|extarea)|xml)[^>]*?>/gi,
    codeviewIframeFilter: true,
    codeviewIframeWhitelistSrc: [],
    codeviewIframeWhitelistSrcBase: ['www.youtube.com', 'www.youtube-nocookie.com', 'www.facebook.com', 'vine.co', 'instagram.com', 'player.vimeo.com', 'www.dailymotion.com', 'player.youku.com', 'jumpingbean.tv', 'v.qq.com'],
    keyMap: {
      pc: {
        'ESC': 'escape',
        'ENTER': 'insertParagraph',
        'CTRL+Z': 'undo',
        'CTRL+Y': 'redo',
        'TAB': 'tab',
        'SHIFT+TAB': 'untab',
        'CTRL+B': 'bold',
        'CTRL+I': 'italic',
        'CTRL+U': 'underline',
        'CTRL+SHIFT+S': 'strikethrough',
        'CTRL+BACKSLASH': 'removeFormat',
        'CTRL+SHIFT+L': 'justifyLeft',
        'CTRL+SHIFT+E': 'justifyCenter',
        'CTRL+SHIFT+R': 'justifyRight',
        'CTRL+SHIFT+J': 'justifyFull',
        'CTRL+SHIFT+NUM7': 'insertUnorderedList',
        'CTRL+SHIFT+NUM8': 'insertOrderedList',
        'CTRL+LEFTBRACKET': 'outdent',
        'CTRL+RIGHTBRACKET': 'indent',
        'CTRL+NUM0': 'formatPara',
        'CTRL+NUM1': 'formatH1',
        'CTRL+NUM2': 'formatH2',
        'CTRL+NUM3': 'formatH3',
        'CTRL+NUM4': 'formatH4',
        'CTRL+NUM5': 'formatH5',
        'CTRL+NUM6': 'formatH6',
        'CTRL+ENTER': 'insertHorizontalRule',
        'CTRL+K': 'linkDialog.show'
      },
      mac: {
        'ESC': 'escape',
        'ENTER': 'insertParagraph',
        'CMD+Z': 'undo',
        'CMD+SHIFT+Z': 'redo',
        'TAB': 'tab',
        'SHIFT+TAB': 'untab',
        'CMD+B': 'bold',
        'CMD+I': 'italic',
        'CMD+U': 'underline',
        'CMD+SHIFT+S': 'strikethrough',
        'CMD+BACKSLASH': 'removeFormat',
        'CMD+SHIFT+L': 'justifyLeft',
        'CMD+SHIFT+E': 'justifyCenter',
        'CMD+SHIFT+R': 'justifyRight',
        'CMD+SHIFT+J': 'justifyFull',
        'CMD+SHIFT+NUM7': 'insertUnorderedList',
        'CMD+SHIFT+NUM8': 'insertOrderedList',
        'CMD+LEFTBRACKET': 'outdent',
        'CMD+RIGHTBRACKET': 'indent',
        'CMD+NUM0': 'formatPara',
        'CMD+NUM1': 'formatH1',
        'CMD+NUM2': 'formatH2',
        'CMD+NUM3': 'formatH3',
        'CMD+NUM4': 'formatH4',
        'CMD+NUM5': 'formatH5',
        'CMD+NUM6': 'formatH6',
        'CMD+ENTER': 'insertHorizontalRule',
        'CMD+K': 'linkDialog.show'
      }
    },
    icons: {
      'align': 'note-icon-align',
      'alignCenter': 'note-icon-align-center',
      'alignJustify': 'note-icon-align-justify',
      'alignLeft': 'note-icon-align-left',
      'alignRight': 'note-icon-align-right',
      'rowBelow': 'note-icon-row-below',
      'colBefore': 'note-icon-col-before',
      'colAfter': 'note-icon-col-after',
      'rowAbove': 'note-icon-row-above',
      'rowRemove': 'note-icon-row-remove',
      'colRemove': 'note-icon-col-remove',
      'indent': 'note-icon-align-indent',
      'outdent': 'note-icon-align-outdent',
      'arrowsAlt': 'note-icon-arrows-alt',
      'bold': 'note-icon-bold',
      'caret': 'note-icon-caret',
      'circle': 'note-icon-circle',
      'close': 'note-icon-close',
      'code': 'note-icon-code',
      'eraser': 'note-icon-eraser',
      'floatLeft': 'note-icon-float-left',
      'floatRight': 'note-icon-float-right',
      'font': 'note-icon-font',
      'frame': 'note-icon-frame',
      'italic': 'note-icon-italic',
      'link': 'note-icon-link',
      'unlink': 'note-icon-chain-broken',
      'magic': 'note-icon-magic',
      'menuCheck': 'note-icon-menu-check',
      'minus': 'note-icon-minus',
      'orderedlist': 'note-icon-orderedlist',
      'pencil': 'note-icon-pencil',
      'picture': 'note-icon-picture',
      'question': 'note-icon-question',
      'redo': 'note-icon-redo',
      'rollback': 'note-icon-rollback',
      'square': 'note-icon-square',
      'strikethrough': 'note-icon-strikethrough',
      'subscript': 'note-icon-subscript',
      'superscript': 'note-icon-superscript',
      'table': 'note-icon-table',
      'textHeight': 'note-icon-text-height',
      'trash': 'note-icon-trash',
      'underline': 'note-icon-underline',
      'undo': 'note-icon-undo',
      'unorderedlist': 'note-icon-unorderedlist',
      'video': 'note-icon-video'
    }
  }
});
;// CONCATENATED MODULE: ./src/js/renderer.js
function renderer_typeof(o) { "@babel/helpers - typeof"; return renderer_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, renderer_typeof(o); }
function renderer_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function renderer_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, renderer_toPropertyKey(o.key), o); } }
function renderer_createClass(e, r, t) { return r && renderer_defineProperties(e.prototype, r), t && renderer_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function renderer_toPropertyKey(t) { var i = renderer_toPrimitive(t, "string"); return "symbol" == renderer_typeof(i) ? i : i + ""; }
function renderer_toPrimitive(t, r) { if ("object" != renderer_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != renderer_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var Renderer = /*#__PURE__*/function () {
  function Renderer(markup, children, options, callback) {
    renderer_classCallCheck(this, Renderer);
    this.markup = markup;
    this.children = children;
    this.options = options;
    this.callback = callback;
  }
  return renderer_createClass(Renderer, [{
    key: "render",
    value: function render($parent) {
      var $node = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.markup);
      if (this.options && this.options.contents) {
        $node.html(this.options.contents);
      }
      if (this.options && this.options.className) {
        $node.addClass(this.options.className);
      }
      if (this.options && this.options.data) {
        external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().each(this.options.data, function (k, v) {
          $node.attr('data-' + k, v);
        });
      }
      if (this.options && this.options.click) {
        $node.on('click', this.options.click);
      }
      if (this.children) {
        var $container = $node.find('.note-children-container');
        this.children.forEach(function (child) {
          child.render($container.length ? $container : $node);
        });
      }
      if (this.callback) {
        this.callback($node, this.options);
      }
      if (this.options && this.options.callback) {
        this.options.callback($node);
      }
      if ($parent) {
        $parent.append($node);
      }
      return $node;
    }
  }]);
}();
/* harmony default export */ const renderer = ({
  create: function create(markup, callback) {
    return function () {
      var options = renderer_typeof(arguments[1]) === 'object' ? arguments[1] : arguments[0];
      var children = Array.isArray(arguments[0]) ? arguments[0] : [];
      if (options && options.children) {
        children = options.children;
      }
      return new Renderer(markup, children, options, callback);
    };
  }
});
;// CONCATENATED MODULE: ./src/styles/lite/js/TooltipUI.js
function TooltipUI_typeof(o) { "@babel/helpers - typeof"; return TooltipUI_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, TooltipUI_typeof(o); }
function TooltipUI_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function TooltipUI_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, TooltipUI_toPropertyKey(o.key), o); } }
function TooltipUI_createClass(e, r, t) { return r && TooltipUI_defineProperties(e.prototype, r), t && TooltipUI_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function TooltipUI_toPropertyKey(t) { var i = TooltipUI_toPrimitive(t, "string"); return "symbol" == TooltipUI_typeof(i) ? i : i + ""; }
function TooltipUI_toPrimitive(t, r) { if ("object" != TooltipUI_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != TooltipUI_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var TooltipUI = /*#__PURE__*/function () {
  function TooltipUI($node, options) {
    TooltipUI_classCallCheck(this, TooltipUI);
    this.$node = $node;
    this.options = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend({}, {
      title: '',
      target: options.container,
      trigger: 'hover focus',
      placement: 'bottom'
    }, options);

    // create tooltip node
    this.$tooltip = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(['<div class="note-tooltip">', '<div class="note-tooltip-arrow"></div>', '<div class="note-tooltip-content"></div>', '</div>'].join(''));

    // define event
    if (this.options.trigger !== 'manual') {
      var showCallback = this.show.bind(this);
      var hideCallback = this.hide.bind(this);
      var toggleCallback = this.toggle.bind(this);
      this.options.trigger.split(' ').forEach(function (eventName) {
        if (eventName === 'hover') {
          $node.off('mouseenter mouseleave');
          $node.on('mouseenter', showCallback).on('mouseleave', hideCallback);
        } else if (eventName === 'click') {
          $node.on('click', toggleCallback);
        } else if (eventName === 'focus') {
          $node.on('focus', showCallback).on('blur', hideCallback);
        }
      });
    }
  }
  return TooltipUI_createClass(TooltipUI, [{
    key: "show",
    value: function show() {
      var $node = this.$node;
      var offset = $node.offset();
      var targetOffset = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.target).offset();
      offset.top -= targetOffset.top;
      offset.left -= targetOffset.left;
      var $tooltip = this.$tooltip;
      var title = this.options.title || $node.attr('title') || $node.data('title');
      var placement = this.options.placement || $node.data('placement');
      $tooltip.addClass(placement);
      $tooltip.find('.note-tooltip-content').text(title);
      $tooltip.appendTo(this.options.target);
      var nodeWidth = $node.outerWidth();
      var nodeHeight = $node.outerHeight();
      var tooltipWidth = $tooltip.outerWidth();
      var tooltipHeight = $tooltip.outerHeight();
      if (placement === 'bottom') {
        $tooltip.css({
          top: offset.top + nodeHeight,
          left: offset.left + (nodeWidth / 2 - tooltipWidth / 2)
        });
      } else if (placement === 'top') {
        $tooltip.css({
          top: offset.top - tooltipHeight,
          left: offset.left + (nodeWidth / 2 - tooltipWidth / 2)
        });
      } else if (placement === 'left') {
        $tooltip.css({
          top: offset.top + (nodeHeight / 2 - tooltipHeight / 2),
          left: offset.left - tooltipWidth
        });
      } else if (placement === 'right') {
        $tooltip.css({
          top: offset.top + (nodeHeight / 2 - tooltipHeight / 2),
          left: offset.left + nodeWidth
        });
      }
      $tooltip.addClass('in');
    }
  }, {
    key: "hide",
    value: function hide() {
      var _this = this;
      this.$tooltip.removeClass('in');
      setTimeout(function () {
        _this.$tooltip.remove();
      }, 200);
    }
  }, {
    key: "toggle",
    value: function toggle() {
      if (this.$tooltip.hasClass('in')) {
        this.hide();
      } else {
        this.show();
      }
    }
  }]);
}();
/* harmony default export */ const js_TooltipUI = (TooltipUI);
;// CONCATENATED MODULE: ./src/styles/lite/js/DropdownUI.js
function DropdownUI_typeof(o) { "@babel/helpers - typeof"; return DropdownUI_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, DropdownUI_typeof(o); }
function DropdownUI_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function DropdownUI_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, DropdownUI_toPropertyKey(o.key), o); } }
function DropdownUI_createClass(e, r, t) { return r && DropdownUI_defineProperties(e.prototype, r), t && DropdownUI_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function DropdownUI_toPropertyKey(t) { var i = DropdownUI_toPrimitive(t, "string"); return "symbol" == DropdownUI_typeof(i) ? i : i + ""; }
function DropdownUI_toPrimitive(t, r) { if ("object" != DropdownUI_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != DropdownUI_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var DropdownUI = /*#__PURE__*/function () {
  function DropdownUI($node, options) {
    DropdownUI_classCallCheck(this, DropdownUI);
    this.$button = $node;
    this.options = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend({}, {
      target: options.container
    }, options);
    this.setEvent();
  }
  return DropdownUI_createClass(DropdownUI, [{
    key: "setEvent",
    value: function setEvent() {
      var _this = this;
      this.$button.on('click', function (e) {
        _this.toggle();
        e.stopImmediatePropagation();
      });
    }
  }, {
    key: "clear",
    value: function clear() {
      var $parent = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('.note-btn-group.open');
      $parent.find('.note-btn.active').removeClass('active');
      $parent.removeClass('open');
    }
  }, {
    key: "show",
    value: function show() {
      this.$button.addClass('active');
      this.$button.parent().addClass('open');
      var $dropdown = this.$button.next();
      var offset = $dropdown.offset();
      var width = $dropdown.outerWidth();
      var windowWidth = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(window).width();
      var targetMarginRight = parseFloat(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this.options.target).css('margin-right'));
      if (offset.left + width > windowWidth - targetMarginRight) {
        $dropdown.css('margin-left', windowWidth - targetMarginRight - (offset.left + width));
      } else {
        $dropdown.css('margin-left', '');
      }
    }
  }, {
    key: "hide",
    value: function hide() {
      this.$button.removeClass('active');
      this.$button.parent().removeClass('open');
    }
  }, {
    key: "toggle",
    value: function toggle() {
      var isOpened = this.$button.parent().hasClass('open');
      this.clear();
      if (isOpened) {
        this.hide();
      } else {
        this.show();
      }
    }
  }]);
}();
external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document).on('click.note-dropdown-menu', function (e) {
  if (!external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(e.target).closest('.note-btn-group').length) {
    external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('.note-btn-group.open .note-btn.active').removeClass('active');
    external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('.note-btn-group.open').removeClass('open');
  }
});
external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(document).on('click.note-dropdown-menu', function (e) {
  external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(e.target).closest('.note-dropdown-menu').parent().removeClass('open');
  external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(e.target).closest('.note-dropdown-menu').parent().find('.note-btn.active').removeClass('active');
});
/* harmony default export */ const js_DropdownUI = (DropdownUI);
;// CONCATENATED MODULE: ./src/styles/lite/js/ModalUI.js
function ModalUI_typeof(o) { "@babel/helpers - typeof"; return ModalUI_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, ModalUI_typeof(o); }
function ModalUI_classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
function ModalUI_defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, ModalUI_toPropertyKey(o.key), o); } }
function ModalUI_createClass(e, r, t) { return r && ModalUI_defineProperties(e.prototype, r), t && ModalUI_defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function ModalUI_toPropertyKey(t) { var i = ModalUI_toPrimitive(t, "string"); return "symbol" == ModalUI_typeof(i) ? i : i + ""; }
function ModalUI_toPrimitive(t, r) { if ("object" != ModalUI_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != ModalUI_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }

var ModalUI = /*#__PURE__*/function () {
  function ModalUI($node /*, options */) {
    ModalUI_classCallCheck(this, ModalUI);
    this.$modal = $node;
    this.$backdrop = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<div class="note-modal-backdrop"></div>');
  }
  return ModalUI_createClass(ModalUI, [{
    key: "show",
    value: function show() {
      var _this = this;
      this.$backdrop.appendTo(document.body).show();
      this.$modal.addClass('open').show();
      this.$modal.trigger('note.modal.show');
      this.$modal.off('click', '.close').on('click', '.close', this.hide.bind(this));
      this.$modal.on('keydown', function (event) {
        if (event.which === 27) {
          event.preventDefault();
          _this.hide();
        }
      });
    }
  }, {
    key: "hide",
    value: function hide() {
      this.$modal.removeClass('open').hide();
      this.$backdrop.hide();
      this.$modal.trigger('note.modal.hide');
      this.$modal.off('keydown');
    }
  }]);
}();
/* harmony default export */ const js_ModalUI = (ModalUI);
;// CONCATENATED MODULE: ./src/styles/lite/summernote-lite.js







var editor = renderer.create('<div class="note-editor note-frame"></div>');
var toolbar = renderer.create('<div class="note-toolbar" role="toolbar"></div>');
var editingArea = renderer.create('<div class="note-editing-area"></div>');
var codable = renderer.create('<textarea class="note-codable" aria-multiline="true"></textarea>');
var editable = renderer.create('<div class="note-editable" contentEditable="true" role="textbox" aria-multiline="true"></div>');
var statusbar = renderer.create(['<output class="note-status-output" role="status" aria-live="polite"></output>', '<div class="note-statusbar" role="status">', '<div class="note-resizebar" aria-label="resize">', '<div class="note-icon-bar"></div>', '<div class="note-icon-bar"></div>', '<div class="note-icon-bar"></div>', '</div>', '</div>'].join(''));
var airEditor = renderer.create('<div class="note-editor note-airframe"></div>');
var airEditable = renderer.create(['<div class="note-editable" contentEditable="true" role="textbox" aria-multiline="true"></div>', '<output class="note-status-output" role="status" aria-live="polite"></output>'].join(''));
var buttonGroup = renderer.create('<div class="note-btn-group"></div>');
var summernote_lite_button = renderer.create('<button type="button" class="note-btn" tabindex="-1"></button>', function ($node, options) {
  // set button type
  if (options && options.tooltip) {
    $node.attr({
      'aria-label': options.tooltip
    });
    $node.data('_lite_tooltip', new js_TooltipUI($node, {
      title: options.tooltip,
      container: options.container
    })).on('click', function (e) {
      external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(e.currentTarget).data('_lite_tooltip').hide();
    });
  }
  if (options.contents) {
    $node.html(options.contents);
  }
  if (options && options.data && options.data.toggle === 'dropdown') {
    $node.data('_lite_dropdown', new js_DropdownUI($node, {
      container: options.container
    }));
  }
  if (options && options.codeviewKeepButton) {
    $node.addClass('note-codeview-keep');
  }
});
var dropdown = renderer.create('<div class="note-dropdown-menu" role="list"></div>', function ($node, options) {
  var markup = Array.isArray(options.items) ? options.items.map(function (item) {
    var value = typeof item === 'string' ? item : item.value || '';
    var content = options.template ? options.template(item) : item;
    var $temp = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<a class="note-dropdown-item" href="#" data-value="' + value + '" role="listitem" aria-label="' + value + '"></a>');
    $temp.html(content).data('item', item);
    return $temp;
  }) : options.items;
  $node.html(markup).attr({
    'aria-label': options.title
  });
  $node.on('click', '> .note-dropdown-item', function (e) {
    var $a = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this);
    var item = $a.data('item');
    var value = $a.data('value');
    if (item.click) {
      item.click($a);
    } else if (options.itemClick) {
      options.itemClick(e, item, value);
    }
  });
  if (options && options.codeviewKeepButton) {
    $node.addClass('note-codeview-keep');
  }
});
var dropdownCheck = renderer.create('<div class="note-dropdown-menu note-check" role="list"></div>', function ($node, options) {
  var markup = Array.isArray(options.items) ? options.items.map(function (item) {
    var value = typeof item === 'string' ? item : item.value || '';
    var content = options.template ? options.template(item) : item;
    var $temp = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()('<a class="note-dropdown-item" href="#" data-value="' + value + '" role="listitem" aria-label="' + item + '"></a>');
    $temp.html([icon(options.checkClassName), ' ', content]).data('item', item);
    return $temp;
  }) : options.items;
  $node.html(markup).attr({
    'aria-label': options.title
  });
  $node.on('click', '> .note-dropdown-item', function (e) {
    var $a = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this);
    var item = $a.data('item');
    var value = $a.data('value');
    if (item.click) {
      item.click($a);
    } else if (options.itemClick) {
      options.itemClick(e, item, value);
    }
  });
  if (options && options.codeviewKeepButton) {
    $node.addClass('note-codeview-keep');
  }
});
var dropdownButtonContents = function dropdownButtonContents(contents, options) {
  return contents + ' ' + icon(options.icons.caret, 'span');
};
var dropdownButton = function dropdownButton(opt, callback) {
  return buttonGroup([summernote_lite_button({
    className: 'dropdown-toggle',
    contents: opt.title + ' ' + icon('note-icon-caret'),
    tooltip: opt.tooltip,
    data: {
      toggle: 'dropdown'
    }
  }), dropdown({
    className: opt.className,
    items: opt.items,
    template: opt.template,
    itemClick: opt.itemClick
  })], {
    callback: callback
  }).render();
};
var dropdownCheckButton = function dropdownCheckButton(opt, callback) {
  return buttonGroup([summernote_lite_button({
    className: 'dropdown-toggle',
    contents: opt.title + ' ' + icon('note-icon-caret'),
    tooltip: opt.tooltip,
    data: {
      toggle: 'dropdown'
    }
  }), dropdownCheck({
    className: opt.className,
    checkClassName: opt.checkClassName,
    items: opt.items,
    template: opt.template,
    itemClick: opt.itemClick
  })], {
    callback: callback
  }).render();
};
var paragraphDropdownButton = function paragraphDropdownButton(opt) {
  return buttonGroup([summernote_lite_button({
    className: 'dropdown-toggle',
    contents: opt.title + ' ' + icon('note-icon-caret'),
    tooltip: opt.tooltip,
    data: {
      toggle: 'dropdown'
    }
  }), dropdown([buttonGroup({
    className: 'note-align',
    children: opt.items[0]
  }), buttonGroup({
    className: 'note-list',
    children: opt.items[1]
  })])]).render();
};
var tableMoveHandler = function tableMoveHandler(event, col, row) {
  var PX_PER_EM = 18;
  var $picker = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.target.parentNode); // target is mousecatcher
  var $dimensionDisplay = $picker.next();
  var $catcher = $picker.find('.note-dimension-picker-mousecatcher');
  var $highlighted = $picker.find('.note-dimension-picker-highlighted');
  var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');
  var posOffset;
  // HTML5 with jQuery - e.offsetX is undefined in Firefox
  if (event.offsetX === undefined) {
    var posCatcher = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.target).offset();
    posOffset = {
      x: event.pageX - posCatcher.left,
      y: event.pageY - posCatcher.top
    };
  } else {
    posOffset = {
      x: event.offsetX,
      y: event.offsetY
    };
  }
  var dim = {
    c: Math.ceil(posOffset.x / PX_PER_EM) || 1,
    r: Math.ceil(posOffset.y / PX_PER_EM) || 1
  };
  $highlighted.css({
    width: dim.c + 'em',
    height: dim.r + 'em'
  });
  $catcher.data('value', dim.c + 'x' + dim.r);
  if (dim.c > 3 && dim.c < col) {
    $unhighlighted.css({
      width: dim.c + 1 + 'em'
    });
  }
  if (dim.r > 3 && dim.r < row) {
    $unhighlighted.css({
      height: dim.r + 1 + 'em'
    });
  }
  $dimensionDisplay.html(dim.c + ' x ' + dim.r);
};
var tableDropdownButton = function tableDropdownButton(opt) {
  return buttonGroup([summernote_lite_button({
    className: 'dropdown-toggle',
    contents: opt.title + ' ' + icon('note-icon-caret'),
    tooltip: opt.tooltip,
    data: {
      toggle: 'dropdown'
    }
  }), dropdown({
    className: 'note-table',
    items: ['<div class="note-dimension-picker">', '<div class="note-dimension-picker-mousecatcher" data-event="insertTable" data-value="1x1"></div>', '<div class="note-dimension-picker-highlighted"></div>', '<div class="note-dimension-picker-unhighlighted"></div>', '</div>', '<div class="note-dimension-display">1 x 1</div>'].join('')
  })], {
    callback: function callback($node) {
      var $catcher = $node.find('.note-dimension-picker-mousecatcher');
      $catcher.css({
        width: opt.col + 'em',
        height: opt.row + 'em'
      }).on('mouseup', opt.itemClick).on('mousemove', function (e) {
        tableMoveHandler(e, opt.col, opt.row);
      });
    }
  }).render();
};
var palette = renderer.create('<div class="note-color-palette"></div>', function ($node, options) {
  var contents = [];
  for (var row = 0, rowSize = options.colors.length; row < rowSize; row++) {
    var eventName = options.eventName;
    var colors = options.colors[row];
    var colorsName = options.colorsName[row];
    var buttons = [];
    for (var col = 0, colSize = colors.length; col < colSize; col++) {
      var color = colors[col];
      var colorName = colorsName[col];
      buttons.push(['<button type="button" class="note-btn note-color-btn"', 'style="background-color:', color, '" ', 'data-event="', eventName, '" ', 'data-value="', color, '" ', 'data-title="', colorName, '" ', 'aria-label="', colorName, '" ', 'data-toggle="button" tabindex="-1"></button>'].join(''));
    }
    contents.push('<div class="note-color-row">' + buttons.join('') + '</div>');
  }
  $node.html(contents.join(''));
  $node.find('.note-color-btn').each(function () {
    external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this).data('_lite_tooltip', new js_TooltipUI(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this), {
      container: options.container
    }));
  });
});
var colorDropdownButton = function colorDropdownButton(opt, type) {
  return buttonGroup({
    className: 'note-color',
    children: [summernote_lite_button({
      className: 'note-current-color-button',
      contents: opt.title,
      tooltip: opt.lang.color.recent,
      click: opt.currentClick,
      callback: function callback($button) {
        var $recentColor = $button.find('.note-recent-color');
        if (type !== 'foreColor') {
          $recentColor.css('background-color', '#FFFF00');
          $button.attr('data-backColor', '#FFFF00');
        }
      }
    }), summernote_lite_button({
      className: 'dropdown-toggle',
      contents: icon('note-icon-caret'),
      tooltip: opt.lang.color.more,
      data: {
        toggle: 'dropdown'
      }
    }), dropdown({
      items: ['<div>', '<div class="note-btn-group btn-background-color">', '<div class="note-palette-title">' + opt.lang.color.background + '</div>', '<div>', '<button type="button" class="note-color-reset note-btn note-btn-block" data-event="backColor" data-value="transparent">', opt.lang.color.transparent, '</button>', '</div>', '<div class="note-holder" data-event="backColor"></div>', '<div class="btn-sm">', '<input type="color" id="html5bcp" class="note-btn btn-default" value="#21104A" style="width:100%;" data-value="cp">', '<button type="button" class="note-color-reset btn" data-event="backColor" data-value="cpbackColor">', opt.lang.color.cpSelect, '</button>', '</div>', '</div>', '<div class="note-btn-group btn-foreground-color">', '<div class="note-palette-title">' + opt.lang.color.foreground + '</div>', '<div>', '<button type="button" class="note-color-reset note-btn note-btn-block" data-event="removeFormat" data-value="foreColor">', opt.lang.color.resetToDefault, '</button>', '</div>', '<div class="note-holder" data-event="foreColor"></div>', '<div class="btn-sm">', '<input type="color" id="html5fcp" class="note-btn btn-default" value="#21104A" style="width:100%;" data-value="cp">', '<button type="button" class="note-color-reset btn" data-event="foreColor" data-value="cpforeColor">', opt.lang.color.cpSelect, '</button>', '</div>', '</div>', '</div>'].join(''),
      callback: function callback($dropdown) {
        $dropdown.find('.note-holder').each(function () {
          var $holder = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(this);
          $holder.append(palette({
            colors: opt.colors,
            eventName: $holder.data('event')
          }).render());
        });
        if (type === 'fore') {
          $dropdown.find('.btn-background-color').hide();
          $dropdown.css({
            'min-width': '210px'
          });
        } else if (type === 'back') {
          $dropdown.find('.btn-foreground-color').hide();
          $dropdown.css({
            'min-width': '210px'
          });
        }
      },
      click: function click(event) {
        var $button = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()(event.target);
        var eventName = $button.data('event');
        var value = $button.data('value');
        var foreinput = document.getElementById('html5fcp').value;
        var backinput = document.getElementById('html5bcp').value;
        if (value === 'cp') {
          event.stopPropagation();
        } else if (value === 'cpbackColor') {
          value = backinput;
        } else if (value === 'cpforeColor') {
          value = foreinput;
        }
        if (eventName && value) {
          var key = eventName === 'backColor' ? 'background-color' : 'color';
          var $color = $button.closest('.note-color').find('.note-recent-color');
          var $currentButton = $button.closest('.note-color').find('.note-current-color-button');
          $color.css(key, value);
          $currentButton.attr('data-' + eventName, value);
          if (type === 'fore') {
            opt.itemClick('foreColor', value);
          } else if (type === 'back') {
            opt.itemClick('backColor', value);
          } else {
            opt.itemClick(eventName, value);
          }
        }
      }
    })]
  }).render();
};
var dialog = renderer.create('<div class="note-modal" aria-hidden="false" tabindex="-1" role="dialog"></div>', function ($node, options) {
  if (options.fade) {
    $node.addClass('fade');
  }
  $node.attr({
    'aria-label': options.title
  });
  $node.html(['<div class="note-modal-content">', options.title ? '<div class="note-modal-header"><button type="button" class="close" aria-label="Close" aria-hidden="true"><i class="note-icon-close"></i></button><h4 class="note-modal-title">' + options.title + '</h4></div>' : '', '<div class="note-modal-body">' + options.body + '</div>', options.footer ? '<div class="note-modal-footer">' + options.footer + '</div>' : '', '</div>'].join(''));
  $node.data('modal', new js_ModalUI($node, options));
});
var videoDialog = function videoDialog(opt) {
  var body = '<div class="note-form-group">' + '<label for="note-dialog-video-url-' + opt.id + '" class="note-form-label">' + opt.lang.video.url + ' <small class="text-muted">' + opt.lang.video.providers + '</small></label>' + '<input id="note-dialog-video-url-' + opt.id + '" class="note-video-url note-input" type="text"/>' + '</div>';
  var footer = ['<button type="button" href="#" class="note-btn note-btn-primary note-video-btn disabled" disabled>', opt.lang.video.insert, '</button>'].join('');
  return dialog({
    title: opt.lang.video.insert,
    fade: opt.fade,
    body: body,
    footer: footer
  }).render();
};
var imageDialog = function imageDialog(opt) {
  var body = '<div class="note-form-group note-group-select-from-files">' + '<label for="note-dialog-image-file-' + opt.id + '" class="note-form-label">' + opt.lang.image.selectFromFiles + '</label>' + '<input id="note-dialog-image-file-' + opt.id + '" class="note-note-image-input note-input" type="file" name="files" accept="image/*" multiple="multiple"/>' + opt.imageLimitation + '</div>' + '<div class="note-form-group">' + '<label for="note-dialog-image-url-' + opt.id + '" class="note-form-label">' + opt.lang.image.url + '</label>' + '<input id="note-dialog-image-url-' + opt.id + '" class="note-image-url note-input" type="text"/>' + '</div>';
  var footer = ['<button href="#" type="button" class="note-btn note-btn-primary note-btn-large note-image-btn disabled" disabled>', opt.lang.image.insert, '</button>'].join('');
  return dialog({
    title: opt.lang.image.insert,
    fade: opt.fade,
    body: body,
    footer: footer
  }).render();
};
var linkDialog = function linkDialog(opt) {
  var body = '<div class="note-form-group">' + '<label for="note-dialog-link-txt-' + opt.id + '" class="note-form-label">' + opt.lang.link.textToDisplay + '</label>' + '<input id="note-dialog-link-txt-' + opt.id + '" class="note-link-text note-input" type="text"/>' + '</div>' + '<div class="note-form-group">' + '<label for="note-dialog-link-url-' + opt.id + '" class="note-form-label">' + opt.lang.link.url + '</label>' + '<input id="note-dialog-link-url-' + opt.id + '" class="note-link-url note-input" type="text" value="http://"/>' + '</div>' + (!opt.disableLinkTarget ? '<div class="checkbox"><label for="note-dialog-link-nw-' + opt.id + '"><input id="note-dialog-link-nw-' + opt.id + '" type="checkbox" checked> ' + opt.lang.link.openInNewWindow + '</label></div>' : '');
  var footer = ['<button href="#" type="button" class="note-btn note-btn-primary note-link-btn disabled" disabled>', opt.lang.link.insert, '</button>'].join('');
  return dialog({
    className: 'link-dialog',
    title: opt.lang.link.insert,
    fade: opt.fade,
    body: body,
    footer: footer
  }).render();
};
var popover = renderer.create(['<div class="note-popover bottom">', '<div class="note-popover-arrow"></div>', '<div class="popover-content note-children-container"></div>', '</div>'].join(''), function ($node, options) {
  var direction = typeof options.direction !== 'undefined' ? options.direction : 'bottom';
  $node.addClass(direction).hide();
  if (options.hideArrow) {
    $node.find('.note-popover-arrow').hide();
  }
});
var summernote_lite_checkbox = renderer.create('<div class="checkbox"></div>', function ($node, options) {
  $node.html(['<label' + (options.id ? ' for="note-' + options.id + '"' : '') + '>', '<input role="checkbox" type="checkbox"' + (options.id ? ' id="note-' + options.id + '"' : ''), options.checked ? ' checked' : '', ' aria-checked="' + (options.checked ? 'true' : 'false') + '"/>', options.text ? options.text : '', '</label>'].join(''));
});
var icon = function icon(iconClassName, tagName) {
  if (iconClassName.match(/^</)) {
    return iconClassName;
  }
  tagName = tagName || 'i';
  return '<' + tagName + ' class="' + iconClassName + '"></' + tagName + '>';
};
var ui = function ui(editorOptions) {
  return {
    editor: editor,
    toolbar: toolbar,
    editingArea: editingArea,
    codable: codable,
    editable: editable,
    statusbar: statusbar,
    airEditor: airEditor,
    airEditable: airEditable,
    buttonGroup: buttonGroup,
    button: summernote_lite_button,
    dropdown: dropdown,
    dropdownCheck: dropdownCheck,
    dropdownButton: dropdownButton,
    dropdownButtonContents: dropdownButtonContents,
    dropdownCheckButton: dropdownCheckButton,
    paragraphDropdownButton: paragraphDropdownButton,
    tableDropdownButton: tableDropdownButton,
    colorDropdownButton: colorDropdownButton,
    palette: palette,
    dialog: dialog,
    videoDialog: videoDialog,
    imageDialog: imageDialog,
    linkDialog: linkDialog,
    popover: popover,
    checkbox: summernote_lite_checkbox,
    icon: icon,
    options: editorOptions,
    toggleBtn: function toggleBtn($btn, isEnable) {
      $btn.toggleClass('disabled', !isEnable);
      $btn.attr('disabled', !isEnable);
    },
    toggleBtnActive: function toggleBtnActive($btn, isActive) {
      $btn.toggleClass('active', isActive);
    },
    check: function check($dom, value) {
      $dom.find('.checked').removeClass('checked');
      $dom.find('[data-value="' + value + '"]').addClass('checked');
    },
    onDialogShown: function onDialogShown($dialog, handler) {
      $dialog.one('note.modal.show', handler);
    },
    onDialogHidden: function onDialogHidden($dialog, handler) {
      $dialog.one('note.modal.hide', handler);
    },
    showDialog: function showDialog($dialog) {
      $dialog.data('modal').show();
    },
    hideDialog: function hideDialog($dialog) {
      $dialog.data('modal').hide();
    },
    /**
     * get popover content area
     *
     * @param $popover
     * @returns {*}
     */
    getPopoverContent: function getPopoverContent($popover) {
      return $popover.find('.note-popover-content');
    },
    /**
     * get dialog's body area
     *
     * @param $dialog
     * @returns {*}
     */
    getDialogBody: function getDialogBody($dialog) {
      return $dialog.find('.note-modal-body');
    },
    createLayout: function createLayout($note) {
      var $editor = (editorOptions.airMode ? airEditor([editingArea([codable(), airEditable()])]) : editorOptions.toolbarPosition === 'bottom' ? editor([editingArea([codable(), editable()]), toolbar(), statusbar()]) : editor([toolbar(), editingArea([codable(), editable()]), statusbar()])).render();
      $editor.insertAfter($note);
      return {
        note: $note,
        editor: $editor,
        toolbar: $editor.find('.note-toolbar'),
        editingArea: $editor.find('.note-editing-area'),
        editable: $editor.find('.note-editable'),
        codable: $editor.find('.note-codable'),
        statusbar: $editor.find('.note-statusbar')
      };
    },
    removeLayout: function removeLayout($note, layoutInfo) {
      $note.html(layoutInfo.editable.html());
      layoutInfo.editor.remove();
      $note.off('summernote'); // remove summernote custom event
      $note.show();
    }
  };
};
(external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote = external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default().extend((external_root_jQuery_commonjs_jquery_commonjs2_jquery_amd_jquery_default()).summernote, {
  ui_template: ui,
  "interface": 'lite'
});
/******/ 	return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=summernote-lite.js.map
(function (factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof module === 'object' && module.exports) {
        module.exports = factory(require('jquery'));
    } else {
        factory(window.jQuery);
    }
}
(function ($) {
    'use strict';

    $.extend(true, $.summernote.lang, {
        'en-US': {
            mediaManager: {
                tooltip: 'Browse Media'
            }
        }
    });

    $.extend($.summernote.options, {
        mediaManager: {
            icon: '<i class="fa-solid fa-server" style="line-height: 19px; position: relative; top: 2px;"></i>'
        },
        keyMap: {
            mac: $.extend($.summernote.options.keyMap.mac, {
                'CMD+SHIFT+I': 'mediaManager.show'
            }),
            pc: $.extend($.summernote.options.keyMap.pc, {
                'CTRL+SHIFT+I': 'mediaManager.show'
            })
        }
    });

    $.extend($.summernote.plugins, {
        'mediaManager': function (context) {
            var self = this;
            var ui = $.summernote.ui,
                options = context.options,
                lang = options.langInfo;

            context.memo('button.mediaManager', function () {
                return ui.button({
                    contents: options.mediaManager.icon,
                    container: false,
                    tooltip: lang.mediaManager.tooltip,
                    codeviewKeepButton: true,
                    click: function () {
                        context.invoke('mediaManager.show');
                    }
                }).render();
            });

            this.initialize = function () {
                // Nothing to initialize since the modal is a bootstrap modal with the contents pre-populated
                // using Blade and AlpineJS for dynamic behavior.
                // @see {MODULE}/resources/views/admin/cms/partials/list/files.blade.php
            };

            this.show = function () {
                $('#media-modal').modal('show');
            };
        }
    });
}));
(function (factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof module === 'object' && module.exports) {
        module.exports = factory(require('jquery'));
    } else {
        factory(window.jQuery);
    }
}
(function ($) {
    'use strict';

    function imageAdjustedHeight(heightInputValue, imageOriginalWidth, imageOriginalHeight) {
        return parseInt(heightInputValue * (imageOriginalHeight / imageOriginalWidth), 10);
    }

    function imageAdjustedWidth(widthInputValue, imageOriginalWidth, imageOriginalHeight) {
        return parseInt(widthInputValue * (imageOriginalWidth / imageOriginalHeight), 10);
    }

    $.extend(true, $.summernote.lang, {
        'en-US': {
            imageAttributes: {
                edit: 'Edit Attributes',
                titleLabel: 'Title',
                altLabel: 'Alternative Text',
                linkLabel: 'Link',
                targetLabel: 'Open in a new window/tab?',
                tooltip: 'Edit Image',
                dialogSaveBtnMessage: 'Save',
                dialogTitle: 'Change Image Attributes',
                widthLabel: 'Width',
                heightLabel: 'Height',
                imageLockLabel: 'Lock',
                resizeLabel: 'Resize'
            }
        }
    });

    $.extend($.summernote.options, {
        imageAttributes: {
            icon: '<i class="note-icon-pencil" />',
            linkClass: 'note-link',
            manageAspectRatio: true // true = Lock the Image Width/Height, Default to true
        }
    });

    $.extend($.summernote.plugins, {
        'imageAttributes': function (context) {
            var self = this;
            var ui = $.summernote.ui,
                $editable = context.layoutInfo.editable,
                options = context.options,
                $editor = context.layoutInfo.editor,
                lang = options.langInfo,
                $note = context.layoutInfo.note;

            context.memo('button.imageAttributes', function () {
                var button = ui.button({
                    contents: options.imageAttributes.icon,
                    container: false,
                    tooltip: lang.imageAttributes.tooltip,
                    click: function () {
                        context.invoke('imageAttributes.show');
                    }
                });
                return button.render();
            });

            this.initialize = function () {
                // Determine whether the modal appends in Body or Inside the Editor
                var $container = options.imageAttributes.dialogsInBody ? $(document.body) : $editor;

                var body = '<div style="padding: 15px 30px">' +
                    '<div class="form-group">' +
                        '<label class="note-form-label">' + lang.imageAttributes.linkLabel + '</label>' +
                        '<input class="form-control note-input note-image-link" type="text" />' +
                    '</div>' +
                    '<div class="form-group">' +
                        '<label class="note-form-label">' +
                            '<input class="note-input note-image-link-target" type="checkbox" />' +
                            '<span style="font-weight: normal; padding-left: 10px">' +
                                lang.imageAttributes.targetLabel +
                            '</span>' +
                        '</label>' +
                    '</div>' +
                    '<div class="form-group">' +
                        '<label class="note-form-label">' + lang.imageAttributes.altLabel + '</label>' +
                        '<input class="form-control note-input note-image-alt-text" type="text" />' +
                    '</div>' +
                    '<div class="row">' +
                        '<div class="form-group col-sm-4">' +
                            '<label class="note-form-label">' + lang.imageAttributes.widthLabel +'</label>' +
                            '<input class="form-control note-input note-image-width" type="number" />' +
                        '</div>' +
                        '<div class="form-group col-sm-4">' +
                            '<label class="note-form-label">' + lang.imageAttributes.heightLabel + '</label>' +
                            '<input class="form-control note-input note-image-height" type="number" />' +
                        '</div>' +
                        '<div class="form-group col-sm-4">' +
                            '<label class="note-form-label">' + lang.imageAttributes.imageLockLabel + '</label>' +
                            '<div class="btn-group btn-group-sm" style="display: block; margin: 3px 0 0 5px;">' +
                                '<button type="button" class="btn btn-default lock-button" style="height:30px;">' +
                                    '<span class="fa-solid fa-lock" aria-hidden="false"></span>' +
                                    '<span class="fa-solid fa-unlock hide" aria-hidden="true"></span>' +
                                '</button>' +
                                '<button type="button" ' +
                                   'class="btn btn-default reset-size-buttton" ' +
                                    'aria-label="Resize" data-toggle="tooltip" ' +
                                    'title="' + lang.imageAttributes.resizeLabel + '">' +
                                    '<span class="fa-solid fa-repeat" aria-hidden="false"></span>' +
                                '</button>' +
                            '</div>' +
                        '</div>' +
                    '</div>' +
                '</div>';

                var footer = '<button href="#" class="btn btn-primary note-image-title-btn note-btn">' +
                             lang.imageAttributes.dialogSaveBtnMessage +
                             '</button>';

                this.$dialog = ui.dialog({
                    title: lang.imageAttributes.dialogTitle,
                    body: body,
                    footer: footer
                }).render().appendTo($container);

            };

            this.destroy = function () {
                ui.hideDialog(this.$dialog);
                this.$dialog.remove();
            };

            this.bindEnterKey = function ($input, $btn) {
                $input.on('keypress', function (event) {
                    if (event.keyCode === 13) {
                        $btn.trigger('click');
                    }
                });
            };

            this.show = function () {
                var $img = $($editable.data('target'));
                var _imgInfo = {
                    alt: $img.attr('alt'),
                    link: $img.parent('a').attr('href'),
                    target: $img.parent('a').attr('target') === 'blank',
                    width: $img.width(),
                    height: $img.height()
                };

                var img = new Image();
                img.onload = function () {
                    _imgInfo.naturalWidth = img.width;
                    _imgInfo.naturalHeight = img.height;
                };
                img.src = $img.attr('src');

                this.showLinkDialog(_imgInfo)
                    .then(function (imgInfo) {
                        ui.hideDialog(self.$dialog);
                        var isAnyChangeMade = false;

                        // NOTE: Must add more conditions if any new field is being added!
                        if (
                            _imgInfo.link !== imgInfo.link ||
                            _imgInfo.target !== imgInfo.target ||
                            _imgInfo.alt !== imgInfo.alt ||
                            _imgInfo.width !== imgInfo.width ||
                            _imgInfo.height !== imgInfo.height
                        ) {
                            isAnyChangeMade = true;
                        }

                        if (imgInfo.alt) {
                            $img.attr('alt', imgInfo.alt);
                        }
                        else {
                            $img.removeAttr('alt');
                        }

                        if (imgInfo.title) {
                            $img.attr('title', imgInfo.title);
                        }
                        else {
                            $img.removeAttr('title');
                        }

                        if (imgInfo.width) {
                            $img.css('width', imgInfo.width);
                        }

                        if (imgInfo.height) {
                            $img.css('height', imgInfo.height);
                        }

                        var $parentAnchorLink = $img.parent();
                        var isUpdateLink = (imgInfo.link !== _imgInfo.link);

                        if (! imgInfo.link.length) {
                            $parentAnchorLink.children().first().unwrap();
                        }

                        var $newLink;
                        if (imgInfo.link && isUpdateLink) {
                            if ($parentAnchorLink.is('a')) {
                                $newLink = $parentAnchorLink.attr('href', imgInfo.link);
                            } else {
                                $newLink = $img.wrap('<a href="' + imgInfo.link + '"></a>').parent();
                            }
                        }

                        if (imgInfo.target) {
                            $img.parent('a').attr('target', '_blank').addClass(options.imageAttributes.linkClass);
                        } else {
                            $img.parent('a').removeAttr('target', '_blank').addClass(options.imageAttributes.linkClass);
                        }

                        if (isAnyChangeMade) {
                            var _content = context.invoke('code');

                            $note.val(_content);
                            $note.trigger('summernote.change', _content);
                        }
                    });
            };

            this.showLinkDialog = function (imgInfo) {
                return $.Deferred(function (deferred) {
                    var $imageTitle = self.$dialog.find('.note-image-title-text');
                    var $imageLink = self.$dialog.find('.note-image-link');
                    var $imageTarget = self.$dialog.find('.note-image-link-target');
                    var $imageAlt = self.$dialog.find('.note-image-alt-text');
                    var $editBtn = self.$dialog.find('.note-image-title-btn');
                    var $imageWidthInput = self.$dialog.find('.note-image-width');
                    var $imageHeightInput = self.$dialog.find('.note-image-height');
                    var $lockButton = self.$dialog.find('.lock-button');
                    var $resetSizeButton = self.$dialog.find('.reset-size-buttton');
                    var $unlockIcon = $lockButton.find('.fa-unlock');
                    var $lockIcon = $lockButton.find('.fa-lock');

                    var isLocked = (typeof options.imageAttributes.manageAspectRatio === 'undefined') ?
                        true : options.imageAttributes.manageAspectRatio;

                    if (isLocked){
                        $unlockIcon.addClass('hide').removeClass('show');
                        $lockIcon.addClass('show').removeClass('hide');
                    } else {
                        $unlockIcon.addClass('show').removeClass('hide');
                        $lockIcon.addClass('hide').removeClass('show');
                    }

                    $lockButton.on('click', function (event) {
                        event.preventDefault();
                        isLocked = !isLocked;

                        if (isLocked) {
                            $unlockIcon.addClass('hide').removeClass('show');
                            $lockIcon.addClass('show').removeClass('hide');

                            $imageHeightInput.val(
                                imageAdjustedHeight($imageWidthInput.val(), imgInfo.naturalWidth, imgInfo.naturalHeight
                                )
                            );
                        } else {
                            $unlockIcon.addClass('show').removeClass('hide');
                            $lockIcon.addClass('hide').removeClass('show');
                        }
                    });

                    $resetSizeButton.on('click', function (event) {
                        event.preventDefault();
                        $imageWidthInput.val(imgInfo.width);
                        $imageHeightInput.val(imgInfo.height);
                    });

                    $imageHeightInput.on('input', function () {
                        if (isLocked) {
                            $imageWidthInput.val(
                                imageAdjustedWidth(this.value, imgInfo.naturalWidth, imgInfo.naturalHeight)
                            );
                        }
                    });

                    $imageWidthInput.on('input', function () {
                        if (isLocked) {
                            $imageHeightInput.val(
                                imageAdjustedHeight(this.value, imgInfo.naturalWidth, imgInfo.naturalHeight)
                            );
                        }
                    });

                    ui.onDialogShown(self.$dialog, function () {
                        context.triggerEvent('dialog.shown');

                        $editBtn.on('click', function (event) {
                            event.preventDefault();
                            deferred.resolve({
                                title: $imageTitle.val(),
                                alt: $imageAlt.val(),
                                link: $imageLink.val(),
                                target: $imageTarget.is(':checked'),
                                width: $imageWidthInput.val(),
                                height: $imageHeightInput.val()
                            });
                        });

                        $imageTitle.val(imgInfo.title);
                        self.bindEnterKey($imageTitle, $editBtn);

                        $imageAlt.val(imgInfo.alt);
                        self.bindEnterKey($imageAlt, $editBtn);

                        $imageLink.val(imgInfo.link);
                        self.bindEnterKey($imageLink, $editBtn);

                        $imageTarget.prop('checked', imgInfo.target);

                        $imageWidthInput.val(imgInfo.width);
                        self.bindEnterKey($imageWidthInput, $editBtn);

                        $imageHeightInput.val(imgInfo.height);
                        self.bindEnterKey($imageHeightInput, $editBtn);

                    });

                    ui.onDialogHidden(self.$dialog, function () {
                        $editBtn.off('click');
                        $imageWidthInput.off('input');
                        $imageHeightInput.off('input');
                        $lockButton.off('click');
                        $resetSizeButton.off('click');
                        $unlockIcon.off('click');
                        $lockIcon.off('click');

                        if (deferred.state() === 'pending') {
                            deferred.reject();
                        }
                    });
                    ui.showDialog(self.$dialog);
                });
            };
        }
    });
}));
(function(jQuery, window, document, undefined) {
    'use strict';

    jQuery(document).ready(function($) {

        // preventing double-click on submit buttons
        $(document).on('click', 'button[type="submit"]', function(event) {
            // if the submit button does not have the class submit-autodisable-exclude
            if(!$(this).hasClass('submit-autodisable-exclude')) {
                // disable submit button after it is clicked
                var btnText = $(event.target).text();
                $(event.target).addClass('disabled')
                    .attr('disabled', true)
                    .text('Processing...');

                // delay the form submission to allow UI updates
                setTimeout(function() {
                    // because we disabled the submit button,
                    // we need to submit the form manually
                    $(event.target).closest('form').submit();
                }, 250);

                setTimeout(function() {
                    $(event.target).removeClass('disabled')
                        .removeAttr('disabled')
                        .text(btnText);
                }, 5000);
            }
        });

        $(document).on('click', '#clear-local-storage', function () {
            if (window.hasOwnProperty('localStorage')) {
                window.localStorage.clear();
                window.location.reload(true);
            }
        });

        var initAffixedArea = function(element, options) {
            var affixed = $(element || '.form-affix-actions');
            if (!affixed.length) return;
            var settings = $.extend({
                container: '.form-affix-container',
                sibling: '.form-affix-body'
            }, options);
            affixed.on('affix.bs.affix', function() {
                affixed.css({ width: $(settings.container).outerWidth() - $(settings.sibling).outerWidth() });
            }).on('affix-top.bs.affix', function() {
                affixed.css({ width: '' });
            }).affix({
                offset: { top: affixed.offset().top }
            });

            return affixed;
        };

        var affixed = initAffixedArea();
        (typeof affixed !== 'undefined') && $(window).on('resize', function() {
            if ($(window).width() >= 992) {
                initAffixedArea();
                if (affixed.hasClass('affix')) affixed.trigger('affix.bs.affix');
                if (affixed.hasClass('affix-top')) affixed.trigger('affix-top.bs.affix');
            } else {
                affixed.css({ width: '' });
                affixed.removeClass("affix affix-top affix-bottom")
                affixed.removeData("bs.affix");
                $(window).off('.affix');
            }
        });

        var dismissDevAlert = function($alert) {
            $('body').removeClass('env-local').removeClass('env-staging');
            $alert.remove();
        };

        var $alert = $('#dev-alert');
        var $alertDismiss = $('#dev-alert-dismiss');
        if (window.Ignite.Core.getCookie('dev_alert_dismissed') === '1') {
            dismissDevAlert($alert);
        }
        if ($alertDismiss.length) {
            $alertDismiss.on('click', function(evt) {
                evt.preventDefault();
                dismissDevAlert($alert);
                window.Ignite.Core.setCookie('dev_alert_dismissed', 1, 1);
            });
        }
    });

})(jQuery, window, document);
;(function ($, window, document, undefined) {
    'use strict';

    window.Ignite = window.Ignite || {};
    window.Ignite.Core = {};

    $.extend(window.Ignite.Core, {

        /**
         * Get the path to errors.
         *
         * @param obj
         * @param key
         * @returns {T}
         */
        getPath: function(obj, key) {
            return key.split('.').reduce(function(o, x) {
                return (typeof o === 'undefined' || o === null) ? o : o[x];
            }, obj);
        },

        /**
         * Check if a key is set on an object.
         *
         * @param obj
         * @param key
         * @returns {boolean}
         */
        isset: function(obj, key) {
            return key.split('.').every(function(x) {
                if (typeof obj !== 'object' || obj === null || !(x in obj)) {
                    return false;
                }
                obj = obj[x];
                return true;
            });
        },

        /**
         * Get the errors from the response.
         *
         * @param variable
         * @param path
         * @param defaultMessage
         * @returns {string}
         */
        getResponseErrors: function(variable, path, defaultMessage) {
            var messages = 'No error info provided.';

            if (typeof(defaultMessage) !== 'undefined') {
                messages = defaultMessage;
            }

            if (this.isset(variable, path)) {
                messages = this.getPath(variable, path).join("\n");
                if (messages !== '') {
                    messages += "\n";
                }
            }

            return messages;
        },

        flash: function(message, state, timeout) {
            var $alert = $('<div class="alert"></div>');
            var $close = $('<button data-dismiss=".alert" class="close">&times;</button>');
            var $text  = $('<p class="alert-message"></p>');
            var remove = function() {
                $alert.fadeOut(function() {
                    $(this).remove();
                });
            };

            $alert.addClass('alert-' + (state || 'info'));
            $alert.addClass('alert-floating');
            $close.on('click', remove);
            $text.html(message);
            $alert.append($close);
            $alert.append($text);
            $('body').append($alert);

            if (0 !== timeout) {
                setTimeout(remove, timeout || 3000);
            }
        },

        /**
         * Add commas to number format.
         *
         * @param nStr
         * @returns {string}
         */
        addCommas: function(nStr) {
            nStr += '';
            var x = nStr.split('.');
            var x1 = x[0];
            var x2 = x.length > 1 ? '.' + x[1] : '';
            var rgx = /(\d+)(\d{3})/;
            while (rgx.test(x1)) {
                x1 = x1.replace(rgx, '$1' + ',' + '$2');
            }
            return x1 + x2;
        },

        /**
         * Set a browser cookie.
         *
         * @param cname
         * @param cvalue
         * @param exdays
         */
        setCookie: function(cname, cvalue, exdays) {
            var d = new Date();
            d.setTime(d.getTime() + (exdays*24*60*60*1000));
            var expires = 'expires=' + d.toUTCString();
            document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/';
        },

        /**
         * Get a browser cookie.
         *
         * @param cname
         * @returns {string}
         */
        getCookie: function(cname) {
            var name = cname + '=';
            var decodedCookie = decodeURIComponent(document.cookie);
            var ca = decodedCookie.split(';');

            for(var i = 0; i < ca.length; i++) {
                var c = ca[i];
                while (c.charAt(0) === ' ') {
                    c = c.substring(1);
                }
                if (c.indexOf(name) === 0) {
                    return c.substring(name.length, c.length);
                }
            }

            return '';
        },

        codifyField: function(source, target) {
            var $source = $(source);
            var $target = $(target);

            if (! $target.attr('disabled') && ! $target.attr('readonly')) {
              $source.on('keyup', function() {
                $target.val(
                  $.trim($source.val())
                    .toLowerCase()
                    .replace(/[^a-z0-9]+|\s+/gmi, '_')
                    .replace(/[\-]+$/g, '')
                );
              });
            }
        }
    });

})(jQuery, window, document);

(function(jQuery, window, document, undefined) {
  'use strict';

  jQuery(function($) {
    $('.select2').select2().on('select2:select', function() {
      $(this).focus();
    });

    var elems = Array.prototype.slice.call(document.querySelectorAll('.js-switch'));
    elems.forEach(function(html) {
      var switchery = new window.Switchery(html, {size: 'small'});
    });

    $('[data-toggle="tooltip"]').tooltip();
  });
})(jQuery, window, document);
